summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kernel/Process.cpp62
-rw-r--r--Kernel/Process.h2
-rw-r--r--Kernel/Syscall.cpp4
-rw-r--r--Kernel/Syscall.h12
-rw-r--r--Kernel/Thread.cpp9
-rw-r--r--Kernel/Thread.h1
-rw-r--r--Kernel/UnixTypes.h10
-rw-r--r--Libraries/LibC/time.cpp14
-rw-r--r--Libraries/LibC/time.h18
9 files changed, 126 insertions, 6 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 77b4e83021..98107a2b2f 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -3154,3 +3154,65 @@ int Process::sys$getrandom(void* buffer, size_t buffer_size, unsigned int flags
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;
+ }
+}
diff --git a/Kernel/Process.h b/Kernel/Process.h
index 9be94c58d4..9513a91237 100644
--- a/Kernel/Process.h
+++ b/Kernel/Process.h
@@ -157,6 +157,8 @@ public:
int sys$sleep(unsigned seconds);
int sys$usleep(useconds_t usec);
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$uname(utsname*);
int sys$readlink(const char*, char*, ssize_t);
diff --git a/Kernel/Syscall.cpp b/Kernel/Syscall.cpp
index 36eec19782..b313c20729 100644
--- a/Kernel/Syscall.cpp
+++ b/Kernel/Syscall.cpp
@@ -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);
case Syscall::SC_getrandom:
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:
kprintf("<%u> int0x82: Unknown function %u requested {%x, %x, %x}\n", current->process().pid(), function, arg1, arg2, arg3);
return -ENOSYS;
diff --git a/Kernel/Syscall.h b/Kernel/Syscall.h
index 860d7e7e88..8d5ce8c18b 100644
--- a/Kernel/Syscall.h
+++ b/Kernel/Syscall.h
@@ -8,6 +8,7 @@
extern "C" {
struct timeval;
+struct timespec;
}
#define ENUMERATE_SYSCALLS \
@@ -131,7 +132,9 @@ struct timeval;
__ENUMERATE_SYSCALL(realpath) \
__ENUMERATE_SYSCALL(get_process_name) \
__ENUMERATE_SYSCALL(fchdir) \
- __ENUMERATE_SYSCALL(getrandom)
+ __ENUMERATE_SYSCALL(getrandom) \
+ __ENUMERATE_SYSCALL(clock_gettime) \
+ __ENUMERATE_SYSCALL(clock_nanosleep)
namespace Syscall {
@@ -181,6 +184,13 @@ struct SC_select_params {
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 {
int sockfd;
const void* data;
diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp
index ca6a3271ae..ef12fb74c4 100644
--- a/Kernel/Thread.cpp
+++ b/Kernel/Thread.cpp
@@ -154,6 +154,15 @@ u64 Thread::sleep(u32 ticks)
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
{
switch (state()) {
diff --git a/Kernel/Thread.h b/Kernel/Thread.h
index e0e34ad853..f8f54f6724 100644
--- a/Kernel/Thread.h
+++ b/Kernel/Thread.h
@@ -220,6 +220,7 @@ public:
VirtualAddress thread_specific_data() const { return m_thread_specific_data; }
u64 sleep(u32 ticks);
+ u64 sleep_until(u64 wakeup_time);
enum class BlockResult {
WokeNormally,
diff --git a/Kernel/UnixTypes.h b/Kernel/UnixTypes.h
index e4a0c8ed4c..52122f8727 100644
--- a/Kernel/UnixTypes.h
+++ b/Kernel/UnixTypes.h
@@ -382,6 +382,16 @@ struct timeval {
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
struct utsname {
diff --git a/Libraries/LibC/time.cpp b/Libraries/LibC/time.cpp
index 6024664fed..8a301b3bb5 100644
--- a/Libraries/LibC/time.cpp
+++ b/Libraries/LibC/time.cpp
@@ -117,4 +117,18 @@ clock_t clock()
times(&tms);
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, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
}
diff --git a/Libraries/LibC/time.h b/Libraries/LibC/time.h
index 0a720dadf4..fec9076e99 100644
--- a/Libraries/LibC/time.h
+++ b/Libraries/LibC/time.h
@@ -36,15 +36,23 @@ char* asctime(const struct tm*);
#define CLOCKS_PER_SEC 1000
clock_t clock();
+struct timespec {
+ time_t tv_sec;
+ 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)
-// This is c++11+, but we have no macro for that now.
-struct timespec {
- time_t tv_sec;
- long tv_nsec;
-};
__END_DECLS