mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 20:17:41 +00:00
Kernel+LibC: Implement clock_gettime() and clock_nanosleep()
Only the CLOCK_MONOTONIC clock is supported at the moment, and it only has millisecond precision. :^)
This commit is contained in:
parent
73b2cb9ed8
commit
cc68654a44
9 changed files with 127 additions and 7 deletions
|
@ -3154,3 +3154,65 @@ int Process::sys$getrandom(void* buffer, size_t buffer_size, unsigned int flags
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Process::sys$clock_gettime(clockid_t clock_id, timespec* ts)
|
||||||
|
{
|
||||||
|
if (!validate_write_typed(ts))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
switch (clock_id) {
|
||||||
|
case CLOCK_MONOTONIC:
|
||||||
|
ts->tv_sec = g_uptime / TICKS_PER_SECOND;
|
||||||
|
ts->tv_nsec = (g_uptime % TICKS_PER_SECOND) * 1000000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Process::sys$clock_nanosleep(const Syscall::SC_clock_nanosleep_params* params)
|
||||||
|
{
|
||||||
|
if (!validate_read_typed(params))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (params->requested_sleep && !validate_read_typed(params->requested_sleep))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (params->remaining_sleep && !validate_write_typed(params->remaining_sleep))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
clockid_t clock_id = params->clock_id;
|
||||||
|
int flags = params->flags;
|
||||||
|
bool is_absolute = flags & TIMER_ABSTIME;
|
||||||
|
auto* requested_sleep = params->requested_sleep;
|
||||||
|
auto* remaining_sleep = params->remaining_sleep;
|
||||||
|
|
||||||
|
switch (clock_id) {
|
||||||
|
case CLOCK_MONOTONIC: {
|
||||||
|
u64 wakeup_time;
|
||||||
|
if (is_absolute) {
|
||||||
|
u64 time_to_wake = (requested_sleep->tv_sec * 1000 + requested_sleep->tv_nsec / 1000000);
|
||||||
|
wakeup_time = current->sleep_until(time_to_wake);
|
||||||
|
} else {
|
||||||
|
u32 ticks_to_sleep = (requested_sleep->tv_sec * 1000 + requested_sleep->tv_nsec / 1000000);
|
||||||
|
if (!ticks_to_sleep)
|
||||||
|
return 0;
|
||||||
|
wakeup_time = current->sleep(ticks_to_sleep);
|
||||||
|
}
|
||||||
|
if (wakeup_time > g_uptime) {
|
||||||
|
u32 ticks_left = wakeup_time - g_uptime;
|
||||||
|
if (!is_absolute && remaining_sleep) {
|
||||||
|
remaining_sleep->tv_sec = ticks_left / TICKS_PER_SECOND;
|
||||||
|
ticks_left -= remaining_sleep->tv_sec * TICKS_PER_SECOND;
|
||||||
|
remaining_sleep->tv_nsec = ticks_left * 1000000;
|
||||||
|
}
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -157,6 +157,8 @@ public:
|
||||||
int sys$sleep(unsigned seconds);
|
int sys$sleep(unsigned seconds);
|
||||||
int sys$usleep(useconds_t usec);
|
int sys$usleep(useconds_t usec);
|
||||||
int sys$gettimeofday(timeval*);
|
int sys$gettimeofday(timeval*);
|
||||||
|
int sys$clock_gettime(clockid_t, timespec*);
|
||||||
|
int sys$clock_nanosleep(const Syscall::SC_clock_nanosleep_params*);
|
||||||
int sys$gethostname(char*, ssize_t);
|
int sys$gethostname(char*, ssize_t);
|
||||||
int sys$uname(utsname*);
|
int sys$uname(utsname*);
|
||||||
int sys$readlink(const char*, char*, ssize_t);
|
int sys$readlink(const char*, char*, ssize_t);
|
||||||
|
|
|
@ -315,6 +315,10 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3
|
||||||
return current->process().sys$realpath((const char*)arg1, (char*)arg2, (size_t)arg3);
|
return current->process().sys$realpath((const char*)arg1, (char*)arg2, (size_t)arg3);
|
||||||
case Syscall::SC_getrandom:
|
case Syscall::SC_getrandom:
|
||||||
return current->process().sys$getrandom((void*)arg1, (size_t)arg2, (unsigned int)arg3);
|
return current->process().sys$getrandom((void*)arg1, (size_t)arg2, (unsigned int)arg3);
|
||||||
|
case Syscall::SC_clock_gettime:
|
||||||
|
return current->process().sys$clock_gettime((clockid_t)arg1, (timespec*)arg2);
|
||||||
|
case Syscall::SC_clock_nanosleep:
|
||||||
|
return current->process().sys$clock_nanosleep((const Syscall::SC_clock_nanosleep_params*)arg1);
|
||||||
default:
|
default:
|
||||||
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
|
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
struct timeval;
|
struct timeval;
|
||||||
|
struct timespec;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ENUMERATE_SYSCALLS \
|
#define ENUMERATE_SYSCALLS \
|
||||||
|
@ -131,7 +132,9 @@ struct timeval;
|
||||||
__ENUMERATE_SYSCALL(realpath) \
|
__ENUMERATE_SYSCALL(realpath) \
|
||||||
__ENUMERATE_SYSCALL(get_process_name) \
|
__ENUMERATE_SYSCALL(get_process_name) \
|
||||||
__ENUMERATE_SYSCALL(fchdir) \
|
__ENUMERATE_SYSCALL(fchdir) \
|
||||||
__ENUMERATE_SYSCALL(getrandom)
|
__ENUMERATE_SYSCALL(getrandom) \
|
||||||
|
__ENUMERATE_SYSCALL(clock_gettime) \
|
||||||
|
__ENUMERATE_SYSCALL(clock_nanosleep)
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
||||||
|
@ -181,6 +184,13 @@ struct SC_select_params {
|
||||||
struct timeval* timeout;
|
struct timeval* timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_clock_nanosleep_params {
|
||||||
|
int clock_id;
|
||||||
|
int flags;
|
||||||
|
const struct timespec* requested_sleep;
|
||||||
|
struct timespec* remaining_sleep;
|
||||||
|
};
|
||||||
|
|
||||||
struct SC_sendto_params {
|
struct SC_sendto_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
const void* data;
|
const void* data;
|
||||||
|
|
|
@ -154,6 +154,15 @@ u64 Thread::sleep(u32 ticks)
|
||||||
return wakeup_time;
|
return wakeup_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 Thread::sleep_until(u64 wakeup_time)
|
||||||
|
{
|
||||||
|
ASSERT(state() == Thread::Running);
|
||||||
|
auto ret = current->block<Thread::SleepBlocker>(wakeup_time);
|
||||||
|
if (wakeup_time > g_uptime)
|
||||||
|
ASSERT(ret == Thread::BlockResult::InterruptedBySignal);
|
||||||
|
return wakeup_time;
|
||||||
|
}
|
||||||
|
|
||||||
const char* Thread::state_string() const
|
const char* Thread::state_string() const
|
||||||
{
|
{
|
||||||
switch (state()) {
|
switch (state()) {
|
||||||
|
|
|
@ -220,6 +220,7 @@ public:
|
||||||
VirtualAddress thread_specific_data() const { return m_thread_specific_data; }
|
VirtualAddress thread_specific_data() const { return m_thread_specific_data; }
|
||||||
|
|
||||||
u64 sleep(u32 ticks);
|
u64 sleep(u32 ticks);
|
||||||
|
u64 sleep_until(u64 wakeup_time);
|
||||||
|
|
||||||
enum class BlockResult {
|
enum class BlockResult {
|
||||||
WokeNormally,
|
WokeNormally,
|
||||||
|
|
|
@ -382,6 +382,16 @@ struct timeval {
|
||||||
suseconds_t tv_usec;
|
suseconds_t tv_usec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct timespec {
|
||||||
|
time_t tv_sec;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int clockid_t;
|
||||||
|
|
||||||
|
#define CLOCK_MONOTONIC 1
|
||||||
|
#define TIMER_ABSTIME 99
|
||||||
|
|
||||||
#define UTSNAME_ENTRY_LEN 65
|
#define UTSNAME_ENTRY_LEN 65
|
||||||
|
|
||||||
struct utsname {
|
struct utsname {
|
||||||
|
|
|
@ -117,4 +117,18 @@ clock_t clock()
|
||||||
times(&tms);
|
times(&tms);
|
||||||
return tms.tms_utime + tms.tms_stime;
|
return tms.tms_utime + tms.tms_stime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clock_gettime(clockid_t clock_id, struct timespec* ts)
|
||||||
|
{
|
||||||
|
int rc = syscall(SC_clock_gettime, clock_id, ts);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int clock_nanosleep(clockid_t clock_id, int flags, const struct timespec* requested_sleep, struct timespec* remaining_sleep)
|
||||||
|
{
|
||||||
|
Syscall::SC_clock_nanosleep_params params { clock_id, flags, requested_sleep, remaining_sleep };
|
||||||
|
int rc = syscall(SC_clock_nanosleep, ¶ms);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,15 +36,23 @@ char* asctime(const struct tm*);
|
||||||
#define CLOCKS_PER_SEC 1000
|
#define CLOCKS_PER_SEC 1000
|
||||||
clock_t clock();
|
clock_t clock();
|
||||||
|
|
||||||
double difftime(time_t, time_t);
|
|
||||||
size_t strftime(char* s, size_t max, const char* format, const struct tm*);
|
|
||||||
|
|
||||||
#define difftime(t1, t0) (double)(t1 - t0)
|
|
||||||
|
|
||||||
// This is c++11+, but we have no macro for that now.
|
|
||||||
struct timespec {
|
struct timespec {
|
||||||
time_t tv_sec;
|
time_t tv_sec;
|
||||||
long tv_nsec;
|
long tv_nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef int clockid_t;
|
||||||
|
|
||||||
|
#define CLOCK_MONOTONIC 1
|
||||||
|
#define TIMER_ABSTIME 99
|
||||||
|
|
||||||
|
int clock_gettime(clockid_t, struct timespec*);
|
||||||
|
int clock_nanosleep(clockid_t, int flags, const struct timespec* requested_sleep, struct timespec* remaining_sleep);
|
||||||
|
|
||||||
|
double difftime(time_t, time_t);
|
||||||
|
size_t strftime(char* s, size_t max, const char* format, const struct tm*);
|
||||||
|
|
||||||
|
#define difftime(t1, t0) (double)(t1 - t0)
|
||||||
|
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue