libc: Add support for the new time functionality in the kernel

This commit is contained in:
apio 2022-10-30 09:08:29 +01:00
parent 688a640a16
commit 324fb42ee2
5 changed files with 183 additions and 25 deletions

View File

@ -16,7 +16,7 @@
#define SYS_execv 12
#define SYS_fcntl 13
#define SYS_mprotect 14
#define SYS_clock 15
#define SYS_clock_gettime 15
#define SYS_mkdir 16
#define SYS_fork 17
#define SYS_waitpid 18

View File

@ -34,4 +34,7 @@ typedef int uid_t;
/* Type representing a group ID. */
typedef int gid_t;
/* Type representing a system clock. */
typedef int clockid_t;
#endif

View File

@ -16,19 +16,27 @@ struct tm
int tm_wday;
int tm_yday;
int tm_isdst;
long tm_gmtoff;
const char* tm_zone;
};
// Captures elapsed time.
// Captures elapsed time with microsecond precision.
struct timeval
{
time_t tv_sec;
suseconds_t tv_usec;
};
#define CLOCKS_PER_SEC 1000 // Number of clock_t per second.
// Captures elapsed time with nanosecond precision.
struct timespec
{
time_t tv_sec;
long tv_nsec;
};
#define CLOCKS_PER_SEC 10000000 // Number of clock_t per second.
#define CLOCK_REALTIME 0
#define CLOCK_MONOTONIC 1
#define CLOCK_PROCTIME 2
#ifdef __cplusplus
extern "C"
@ -39,11 +47,36 @@ extern "C"
* get the value in seconds. */
clock_t clock(void);
/* FIXME: For now, is an alias for clock(), but in seconds. */
/* Returns the current UNIX time in seconds, which is also stored in tloc if it is nonnull. */
time_t time(time_t* tloc);
struct tm* localtime(const time_t* timep); // Not implemented.
struct tm* gmtime(const time_t* timep); // Not implemented.
/* Retrieves precise time from a specific system clock. */
int clock_gettime(clockid_t clock_id, struct timespec* tp);
/* Converts the UNIX timestamp time to broken-down time in UTC. */
struct tm* gmtime(const time_t* time);
/* Converts the UNIX timestamp time to broken-down time in UTC. Thread-safe. */
struct tm* gmtime_r(const time_t* time, struct tm* result);
/* Converts the UNIX timestamp time to broken-down time in local time. */
struct tm* localtime(const time_t* time);
/* Converts the UNIX timestamp time to broken-down time in local time. Thread-safe. */
struct tm* localtime_r(const time_t* time, struct tm* result);
/* Returns a string representation of the broken-down time in the time structure. */
char* asctime(const struct tm* time);
/* Fills buf with the string representation of the broken-down time in the time structure. Thread-safe. */
char* asctime_r(const struct tm* time, char buf[26]);
/* Returns a string representation of time. */
char* ctime(const time_t* time);
/* Fills buf with a string representation of time. Thread-safe. */
char* ctime_r(const time_t* time, char buf[26]);
size_t strftime(char* str, size_t max, const char* format, const struct tm* time); // Not implemented.
char* ctime(const time_t* timep); // Not implemented.

View File

@ -12,7 +12,6 @@ extern "C" long syscall(long number, ...)
va_start(ap, number);
switch (number)
{
case SYS_clock:
case SYS_yield:
case SYS_fork: result = __luna_syscall0(number); break;
case SYS_exit:
@ -26,6 +25,7 @@ extern "C" long syscall(long number, ...)
case SYS_fstat:
case SYS_stat:
case SYS_dup2:
case SYS_clock_gettime:
case SYS_setuid:
case SYS_setgid:
case SYS_pstat: {

View File

@ -1,42 +1,164 @@
#include <assert.h>
#include <luna.h>
#include <luna/syscall.h>
#include <stdio.h>
#include <sys/syscall.h>
#include <time.h>
#include <unistd.h>
#define SECONDS_PER_DAY 86400
static int isleap(int year)
{
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}
static int make_yday(int year, int month)
{
static const short int upto[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
int yd;
yd = upto[month - 1];
if (month > 2 && isleap(year)) yd++;
return yd;
}
static int day_of_week(int year, int mon, int day)
{
static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
year -= mon < 3;
return (year + year / 4 - year / 100 + year / 400 + t[mon - 1] + day) % 7;
}
static void time_to_struct_tm(time_t time, struct tm* result)
{
result->tm_isdst = 0; // No DST/timezone support for now.
int year = 1970;
while (time > 0)
{
time_t seconds_in_year = (isleap(year) ? 366 : 365) * SECONDS_PER_DAY;
if (seconds_in_year <= time)
{
year++;
time -= seconds_in_year;
continue;
}
break;
}
int month_days[] = {31, isleap(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int month = 0;
while (1)
{
time_t seconds_in_month = month_days[month] * SECONDS_PER_DAY;
if (seconds_in_month <= time)
{
month++;
time -= seconds_in_month;
continue;
}
break;
}
int day = (int)(time / SECONDS_PER_DAY);
time %= SECONDS_PER_DAY;
assert(day < month_days[month]);
int hour = (int)(time / 3600);
time %= 3600;
int min = (int)(time / 60);
time %= 60;
result->tm_year = year - 1900;
result->tm_mon = month + 1;
result->tm_yday = make_yday(year, month + 1) + day; // FIXME: Support tm_wday.
result->tm_wday = day_of_week(year, month + 1, day + 1);
result->tm_mday = day + 1;
result->tm_hour = hour;
result->tm_min = min;
result->tm_sec = (int)time;
}
const char* wday_names[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
const char* month_names[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
extern "C"
{
clock_t clock()
{
return __lc_fast_syscall0(SYS_clock);
struct timespec tp;
clock_gettime(CLOCK_PROCTIME, &tp);
return (tp.tv_sec * CLOCKS_PER_SEC) + (tp.tv_nsec / 1000);
}
time_t time(
time_t* tloc) // Very big FIXME: This is not the time of day, this just returns the same as clock() but in
// seconds. This is definitely wrong, but I'm not implementing a whole time system right now.
time_t time(time_t* tloc)
{
time_t result = (time_t)(syscall(SYS_clock) / CLOCKS_PER_SEC);
if (tloc) { *tloc = result; }
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
if (tloc) { *tloc = tp.tv_sec; }
return tp.tv_sec;
}
int clock_gettime(clockid_t clock_id, struct timespec* tp)
{
return (int)__lc_fast_syscall2(SYS_clock_gettime, clock_id, tp);
}
struct tm* localtime(const time_t* time)
{
static struct tm result;
return localtime_r(time, &result);
}
struct tm* gmtime(const time_t* time)
{
static struct tm result;
return gmtime_r(time, &result);
}
struct tm* localtime_r(const time_t* time, struct tm* result)
{
return gmtime_r(time, result); // FIXME: Implement timezones.
}
struct tm* gmtime_r(const time_t* time, struct tm* result)
{
time_to_struct_tm(*time, result);
return result;
}
struct tm* localtime(const time_t*)
char* asctime_r(const struct tm* time, char buf[26])
{
NOT_IMPLEMENTED("localtime");
snprintf(buf, 26, "%s %s %d %d:%d:%d %d\n", wday_names[time->tm_wday], month_names[time->tm_mon - 1],
time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec, time->tm_year + 1900);
return buf;
}
struct tm* gmtime(const time_t*)
char* asctime(const struct tm* time)
{
NOT_IMPLEMENTED("gmtime");
static char buf[26];
return asctime_r(time, buf);
}
char* ctime_r(const time_t* time, char buf[26])
{
struct tm stm;
return asctime_r(localtime_r(time, &stm), buf);
}
char* ctime(const time_t* time)
{
return asctime(localtime(time));
}
size_t strftime(char*, size_t, const char*, const struct tm*)
{
NOT_IMPLEMENTED("strftime");
}
char* ctime(const time_t*)
{
NOT_IMPLEMENTED("ctime");
}
}