From 266dfcc857037f24a1af6d58049d336b92ea1f0c Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Tue, 30 Dec 2014 17:54:42 -0800 Subject: [PATCH] Basic time functions and fix time system call --- bin/shell/shell.c | 23 +++-- include/time.h | 42 +++++++++ lib/libc/SConscript | 1 + lib/libc/printf.c | 54 +++++++++++ lib/libc/time.c | 214 ++++++++++++++++++++++++++++++++++++++++++++ sys/kern/ktime.c | 6 +- 6 files changed, 332 insertions(+), 8 deletions(-) create mode 100644 lib/libc/time.c diff --git a/bin/shell/shell.c b/bin/shell/shell.c index 46fae41..2b7ad7a 100644 --- a/bin/shell/shell.c +++ b/bin/shell/shell.c @@ -2,6 +2,7 @@ #include #include #include +#include // Castor Only #include @@ -34,6 +35,7 @@ Cmd_Help(int argc, const char *argv[]) printf("exit Exit shell\n"); printf("help Display the list of commands\n"); printf("ls List files in a directory\n"); + printf("date Print current date and time\n"); printf("bkpt Trigger a kernel breakpoint\n"); } @@ -110,6 +112,13 @@ Cmd_Cat(int argc, const char *argv[]) } } +void +Cmd_Date(int argc, const char *argv[]) +{ + time_t t = time(NULL); + fputs(ctime(&t), stdout); +} + void Cmd_Hexdump(int argc, const char *argv[]) { @@ -146,21 +155,23 @@ DispatchCommand(char *buf) // execute command if (strcmp(argv[0], "help") == 0) { - Cmd_Help(argc, (const char **)argv); + Cmd_Help(argc, (const char **)argv); } else if (strcmp(argv[0], "bkpt") == 0) { asm volatile("int3"); } else if (strcmp(argv[0], "cat") == 0) { - Cmd_Cat(argc, (const char **)argv); + Cmd_Cat(argc, (const char **)argv); + } else if (strcmp(argv[0], "date") == 0) { + Cmd_Date(argc, (const char **)argv); } else if (strcmp(argv[0], "echo") == 0) { - Cmd_Echo(argc, (const char **)argv); + Cmd_Echo(argc, (const char **)argv); } else if (strcmp(argv[0], "exit") == 0) { - exit(0); + exit(0); } else if (strcmp(argv[0], "ls") == 0) { - Cmd_List(argc, (const char **)argv); + Cmd_List(argc, (const char **)argv); } else if (strcmp(argv[0], "#") == 0) { // Ignore comments } else if (buf[0] != '\0') { - printf("Unknown command '%s'\n", buf); + printf("Unknown command '%s'\n", buf); } } diff --git a/include/time.h b/include/time.h index 25f6c94..4566d84 100644 --- a/include/time.h +++ b/include/time.h @@ -2,5 +2,47 @@ #ifndef __TIME_H__ #define __TIME_H__ +typedef uint64_t time_t; +typedef uint64_t suseconds_t; + +struct tm { + int tm_sec; + int tm_min; + int tm_hour; + int tm_mday; + int tm_mon; + int tm_year; + int tm_wday; + int tm_yday; + int tm_isdst; +}; + +struct timeval +{ + time_t tv_sec; + suseconds_t tv_usec; +}; + +struct timezone { + int tz_minuteswest; + int tz_dsttime; +}; + +time_t time(time_t *t); +char *asctime_r(const struct tm *tm, char *buf); +char *asctime(const struct tm *tm); +char *ctime_r(const time_t *timep, char *buf); +char *ctime(const time_t *timep); +struct tm *gmtime(const time_t *timep); +struct tm *gmtime_r(const time_t *timep, struct tm *result); +struct tm *localtime(const time_t *timep); +struct tm *localtime_r(const time_t *timep, struct tm *result); +time_t mktime(struct tm *tm); + +int gettimeofday(struct timeval *tv, struct timezone *tz); + +// XXX: Not implemented +int settimeofday(const struct timeval *tv, const struct timezone *tz); + #endif /* __TIME_H__ */ diff --git a/lib/libc/SConscript b/lib/libc/SConscript index 88d42a0..39a1be8 100644 --- a/lib/libc/SConscript +++ b/lib/libc/SConscript @@ -12,6 +12,7 @@ src_common = [ "file.c", "string.c", "syscall.c", + "time.c", "printf.c", "posix/mman.c", ] diff --git a/lib/libc/printf.c b/lib/libc/printf.c index 851e39d..e6a0ada 100644 --- a/lib/libc/printf.c +++ b/lib/libc/printf.c @@ -234,3 +234,57 @@ int fprintf(FILE *stream, const char *fmt, ...) return ret; } +typedef struct StrState { + char *buf; + char *cur; + size_t maxlen; +} StrState; + +static void strputc(int c, void *handle) +{ + StrState *state = (StrState *)handle; + + if ((state->maxlen != -1) && + (state->cur - state->buf >= state->maxlen)) { + state->cur[0] = '\0'; + return; + } + + state->cur[0] = c; + state->cur++; +} + +int sprintf(char *str, const char *fmt, ...) +{ + int ret; + va_list ap; + StrState state; + + state.buf = str; + state.cur = str; + state.maxlen = -1; + + va_start(ap, fmt); + ret = kvprintf(fmt, strputc, &state, ap); + va_end(ap); + + return ret; +} + +int snprintf(char *str, size_t n, const char *fmt, ...) +{ + int ret; + va_list ap; + StrState state; + + state.buf = str; + state.cur = str; + state.maxlen = n; + + va_start(ap, fmt); + ret = kvprintf(fmt, strputc, &state, ap); + va_end(ap); + + return ret; +} + diff --git a/lib/libc/time.c b/lib/libc/time.c new file mode 100644 index 0000000..ce255ff --- /dev/null +++ b/lib/libc/time.c @@ -0,0 +1,214 @@ + +#include +#include +#include +#include + +#include + +#define TZ_OFFSET_SECS 0 + +static const char *dayOfWeek[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +static const char *months[12] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +time_t +time(time_t *t) +{ + uint64_t nsec = SystemTime(); + time_t sec = nsec / 1000000000; + + printf("%ld\n", nsec); + + if (t) + *t = sec; + + return sec; +} + +int +gettimeofday(struct timeval *tv, struct timezone *tz) +{ + uint64_t nsec = SystemTime(); + + tv->tv_sec = nsec / 1000000000; + tv->tv_usec = (nsec % 1000000000) / 1000; + + return 0; +} + +int +settimeofday(const struct timeval *tv, const struct timezone *tz) +{ + // set errno + return -1; +} + +char * +asctime_r(const struct tm *tm, char *buf) +{ + // assert(tm->tm_wday < 7); + // assert(tm->tm_mon < 12); + + snprintf(buf, 26, "%s %s %2d %2d:%02d:%02d %4d\n", + dayOfWeek[tm->tm_wday], months[tm->tm_mon], + tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec, tm->tm_year + 1900); + + return buf; +} + +char * +asctime(const struct tm *tm) +{ + static char buf[26]; + return asctime_r(tm, buf); +} + +char * +ctime_r(const time_t *timep, char *buf) +{ + struct tm tm; + return asctime_r(localtime_r(timep, &tm), buf); +} + +char * +ctime(const time_t *timep) +{ + return asctime(localtime(timep)); +} + +static bool +Time_IsLeapYear(uint64_t year) +{ + if ((year % 4) != 0) + return false; + if ((year % 100) != 0) + return true; + if ((year % 400) != 0) + return false; + return true; +} + +static int +Time_DaysInMonth(uint64_t year, uint64_t month) +{ + static const uint64_t days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + + if ((month == 2) && Time_IsLeapYear(year)) + return 29; + else + return days[month]; +} + + +struct tm * +gmtime_r(const time_t *timep, struct tm *tm) +{ + uint64_t secs, mins, hours; + uint64_t days; + uint64_t y, m; + + // Compute seconds + secs = *timep % (60 * 60 * 24); + days = *timep / (60 * 60 * 24); + mins = secs / 60; + secs = secs % 60; + + // Compute minutes + hours = mins / 60; + mins = mins % 60; + + // Compute hours + hours = hours % 24; + + tm->tm_sec = secs; + tm->tm_min = mins; + tm->tm_hour = hours; + + tm->tm_wday = (days + 3) % 7; + + for (y = 1970; ; y++) { + uint64_t daysOfYear; + if (Time_IsLeapYear(y)) { + daysOfYear = 366; + } else { + daysOfYear = 365; + } + + if (days < daysOfYear) { + tm->tm_yday = days; + tm->tm_year = y - 1900; + break; + } + days -= daysOfYear; + } + + for (m = 0; ; m++) { + uint64_t daysOfMonth = Time_DaysInMonth(tm->tm_year + 1900, m); + + if (days < daysOfMonth) { + tm->tm_mday = days; + tm->tm_mon = m; + break; + } + days -= daysOfMonth; + } + + return tm; +} + +struct tm * +gmtime(const time_t *timep) +{ + static struct tm tm; + return gmtime_r(timep, &tm); +} + +struct tm * +localtime_r(const time_t *timep, struct tm *result) +{ + time_t t = *timep - TZ_OFFSET_SECS; + return gmtime_r(&t, result); +} + +struct tm * +localtime(const time_t *timep) +{ + static struct tm tm; + return localtime_r(timep, &tm); +} + +time_t +mktime(struct tm *tm) +{ + uint64_t days = 0; + uint64_t secs = 0; + uint64_t y, m; + + // Convert to UNIX epoch + for (y = 70; y < tm->tm_year; y++) { + if (Time_IsLeapYear(y)) + days += 366; + else + days += 365; + } + + uint64_t yday = 0; + for (m = 0; m < tm->tm_mon; m++) { + yday += Time_DaysInMonth(tm->tm_year + 1900, m); + } + yday += tm->tm_mday; + days += yday; + + secs = 24 * days + tm->tm_hour; + secs = secs * 60 + tm->tm_min; + secs = secs * 60 + tm->tm_sec; + + secs += TZ_OFFSET_SECS; + + return secs; +} + diff --git a/sys/kern/ktime.c b/sys/kern/ktime.c index e41ed25..b91f3b4 100644 --- a/sys/kern/ktime.c +++ b/sys/kern/ktime.c @@ -204,9 +204,11 @@ KTime_GetEpochNS() Spinlock_Lock(&ktimeLock); tscDiff = Time_GetTSC() - ktimeLastTSC; if (ticksPerSecondStable) - epoch = ktimeLastEpoch + tscDiff / (ticksPerSecondStable / 1000000); + epoch = ktimeLastEpoch * 1000000000 + + tscDiff * 1000000000 / ticksPerSecondStable; else - epoch = ktimeLastEpoch + tscDiff / (ticksPerSecond / 1000000); + epoch = ktimeLastEpoch * 1000000000 + + tscDiff * 1000000000 / ticksPerSecond; Spinlock_Unlock(&ktimeLock); return epoch;