BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / commit / d41a53cbc7d055b1c00cf0a339dbed6925f4f02c / task / time.c

// Related

Orion

Barry Importing existing Orion kernel d41a53c (2 years, 4 months ago)
diff --git a/task/time.c b/task/time.c
new file mode 100644
index 0000000..f81d496
--- /dev/null
+++ b/task/time.c
@@ -0,0 +1,183 @@
+/*
+ * This file controls the system clock and contains the functions related to
+ * getting and setting the time from various sources.  It keeps a monotonic
+ * clock internally, but can also make use of the tasks' clocks, and the RTC.
+ */
+
+#include <stdint.h>
+#include <sys/times.h>
+#include <errno.h>
+#include "task.h"
+#include "../proc/proc.h"
+#include "../io.h"
+
+#define RTC_SECONDS 0x00
+#define RTC_MINUTES 0x02
+#define RTC_HOURS   0x04
+#define RTC_WEEKDAY 0x06
+#define RTC_DAY     0x07
+#define RTC_MONTH   0x08
+#define RTC_YEAR    0x09
+#define RTC_CENTURY 0x32
+
+#define LEAP_YEAR(x) ((((x % 4) == 0) && ((x % 100) != 0)) || ((x % 400) == 0))
+
+extern TaskQueue readyQueue;
+
+uint32_t monotonicClock = 0, millis = 0;
+uint8_t slice[MAX_CPUS] = {0};
+TaskQueue sleepQueue;
+
+/* Read an RTC register */
+static uint8_t
+read_rtc(uint8_t index)
+{
+	outb(0x70, 0x80 | index);
+	io_wait();
+	return inb(0x71);
+}
+
+/* Timer interrupt */
+void
+timer_handler(InterruptFrame *frame)
+{
+	/* Monotonic clock */
+	millis++;
+	if (millis == 1000) {
+		monotonicClock++;
+		millis = 0;
+	}
+
+	/* Sleeping processes */
+	Task *proc = sleepQueue.start, *prev = NULL;
+	for (proc = sleepQueue.start; proc; prev = proc, proc = proc->next) {
+		if (proc->sleepExpiry > (monotonicClock * 1000) + millis)
+			break;
+		if (prev)
+			prev->next = proc->next;
+		if (sleepQueue.start == proc)
+			sleepQueue.start = proc->next;
+		if (sleepQueue.end == proc)
+			sleepQueue.end = NULL;
+		add_to_queue(&readyQueue, proc);
+	}
+
+	/* Account timeslice */
+	slice[CPUID]++;
+	if (!current)
+		return;
+
+	/* Account task time */
+	if (in_syscall())
+		current->systime++;
+	else
+		current->usertime++;
+
+	/* Call scheduler */
+	if (slice[CPUID] < current->priority)
+		return;
+	slice[CPUID] = 0;
+	schedule();
+}
+
+/* Sleep for a specified time (milliseconds) */
+int
+sleep(uint32_t ms)
+{
+	current->sleepExpiry = (monotonicClock * 1000) + millis + ms;
+
+	/* Add to sorted sleep TaskQueue */
+	TaskQueue *q = &sleepQueue;
+	Task *task, *prev = NULL;
+	acquire(&q->lock);
+	if (!q->start) {
+		q->start = current;
+		q->end = current;
+		current->next = NULL;
+	} else {
+		for (task = q->start; task; prev = task, task = task->next)
+			if (task->sleepExpiry > current->sleepExpiry)
+				break;
+		if (!prev) {
+			current->next = q->start;
+			q->start = current;
+		} else {
+			current->next = task;
+			prev->next = current;
+		}
+	}
+	release(&q->lock);
+
+	block_task(SLEEP);
+	return 0;
+}
+
+/* Get epoch time */
+time_t
+time(time_t *tloc)
+{
+	if (!verify_access(tloc, sizeof(time_t), PROT_WRITE))
+		return -EFAULT;
+
+	/* Length of months for normal and leap years */
+	const uint16_t monthLen[2][12] = {
+		{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+		{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+	};
+
+	uint16_t i;
+	uint8_t second, minute, hour, day, month, year, cent;
+	time_t time = 0;
+	uint8_t years = 0, leapYears = 0;
+
+	second = read_rtc(RTC_SECONDS);
+	minute = read_rtc(RTC_MINUTES);
+	hour   = read_rtc(RTC_HOURS);
+	day    = read_rtc(RTC_DAY);
+	month  = read_rtc(RTC_MONTH);
+	year   = read_rtc(RTC_YEAR);
+	cent   = read_rtc(RTC_CENTURY);
+
+	second = (second & 0x0F) + ((second        / 16) * 10);
+	minute = (minute & 0x0F) + ((minute        / 16) * 10);
+	hour   = ((hour  & 0x0F) + (((hour & 0x70) / 16) * 10)) | (hour & 0x80);
+	day    = (day    & 0x0F) + ((day           / 16) * 10);
+	month  = (month  & 0x0F) + ((month         / 16) * 10);
+	year   = (year   & 0x0F) + ((year          / 16) * 10);
+	cent   = (cent   & 0x0F) + ((cent          / 16) * 10);
+
+	for (i = 1970; i < (cent * 100) + year; i++)
+		if (LEAP_YEAR(i))
+			leapYears++;
+		else
+			years++;
+	time += ((years * 365) + (leapYears * 366)) * 86400;
+
+	for (i = 0; i < month - 1; i++)
+		time += monthLen[LEAP_YEAR(year)][i] * 86400;
+
+	time += (day - 1) * 86400;
+	time += hour * 3600;
+	time += minute * 60;
+	time += second;
+
+	if (tloc)
+		*tloc = time;
+
+	return time;
+}
+
+/* Get process times */
+clock_t
+times(Times *buf)
+{
+	if (!verify_access(buf, sizeof(Times), PROT_WRITE))
+		return -EFAULT;
+	if (buf) {
+		buf->utime = current->usertime;
+		buf->stime = current->systime;
+		buf->cutime = current->usertime;
+		buf->cstime = current->systime;
+	}
+	return (monotonicClock * 1000) + millis;
+}