Kernel: Remove SYS_SLEEP and cleanup SYS_NANOSLEEP

`sleep` is now implemented in terms of `nanosleep`. `nanosleep` is now
more precise and handles overflow when calculating wakeup time. I don't
think anything was depending on this, but I could see a program sleeping
for max time to block until signal.
This commit is contained in:
2026-06-30 20:11:26 +03:00
parent 20663b533b
commit d241975ce1
7 changed files with 45 additions and 48 deletions

View File

@@ -59,7 +59,7 @@ signal_trampoline:
addl $24, %esp addl $24, %esp
// restore sigmask // restore sigmask
movl $79, %eax // SYS_SIGPROCMASK movl $78, %eax // SYS_SIGPROCMASK
movl $3, %ebx // SIG_SETMASK movl $3, %ebx // SIG_SETMASK
leal 72(%esp), %ecx // set leal 72(%esp), %ecx // set
xorl %edx, %edx // oset xorl %edx, %edx // oset

View File

@@ -61,7 +61,7 @@ signal_trampoline:
addq $40, %rsp addq $40, %rsp
// restore sigmask // restore sigmask
movq $79, %rdi // SYS_SIGPROCMASK movq $78, %rdi // SYS_SIGPROCMASK
movq $3, %rsi // SIG_SETMASK movq $3, %rsi // SIG_SETMASK
leaq 192(%rsp), %rdx // set leaq 192(%rsp), %rdx // set
xorq %r10, %r10 // oset xorq %r10, %r10 // oset

View File

@@ -68,7 +68,6 @@ namespace Kernel
BAN::ErrorOr<long> sys_exec(const char* path, const char* const* argv, const char* const* envp); BAN::ErrorOr<long> sys_exec(const char* path, const char* const* argv, const char* const* envp);
BAN::ErrorOr<long> sys_wait(pid_t pid, int* stat_loc, int options); BAN::ErrorOr<long> sys_wait(pid_t pid, int* stat_loc, int options);
BAN::ErrorOr<long> sys_sleep(int seconds);
BAN::ErrorOr<long> sys_nanosleep(const timespec* rqtp, timespec* rmtp); BAN::ErrorOr<long> sys_nanosleep(const timespec* rqtp, timespec* rmtp);
BAN::ErrorOr<long> sys_setitimer(int which, const itimerval* value, itimerval* ovalue); BAN::ErrorOr<long> sys_setitimer(int which, const itimerval* value, itimerval* ovalue);

View File

@@ -1036,52 +1036,45 @@ namespace Kernel
return child_pid; return child_pid;
} }
BAN::ErrorOr<long> Process::sys_sleep(int seconds)
{
if (seconds == 0)
return 0;
const uint64_t wake_time_ms = SystemTimer::get().ms_since_boot() + (seconds * 1000);
while (!Thread::current().is_interrupted_by_signal())
{
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
if (current_ms >= wake_time_ms)
break;
SystemTimer::get().sleep_until_ms(wake_time_ms);
}
const uint64_t current_ms = SystemTimer::get().ms_since_boot();
if (current_ms < wake_time_ms)
return BAN::Math::div_round_up<long>(wake_time_ms - current_ms, 1000);
return 0;
}
BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* user_rqtp, timespec* user_rmtp) BAN::ErrorOr<long> Process::sys_nanosleep(const timespec* user_rqtp, timespec* user_rmtp)
{ {
// take current timestamp ASAP
uint64_t current_ns = SystemTimer::get().ns_since_boot();
timespec rqtp; timespec rqtp;
TRY(read_from_user(user_rqtp, &rqtp, sizeof(timespec))); TRY(read_from_user(user_rqtp, &rqtp, sizeof(timespec)));
if (rqtp.tv_nsec < 0 || rqtp.tv_nsec >= 1'000'000'000) if (rqtp.tv_sec < 0 || rqtp.tv_nsec < 0 || rqtp.tv_nsec >= 1'000'000'000)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
const uint64_t sleep_ns = (rqtp.tv_sec * 1'000'000'000) + rqtp.tv_nsec; const uint64_t waketime_ns = [&rqtp, current_ns]() -> uint64_t {
if (sleep_ns == 0) if (BAN::Math::will_multiplication_overflow<uint64_t>(rqtp.tv_sec, 1'000'000'000))
return 0; return BAN::numeric_limits<uint64_t>::max();
if (BAN::Math::will_addition_overflow<uint64_t>(rqtp.tv_sec * 1'000'000'000, rqtp.tv_nsec))
return BAN::numeric_limits<uint64_t>::max();
if (BAN::Math::will_addition_overflow<uint64_t>(rqtp.tv_sec * 1'000'000'000 + rqtp.tv_nsec, current_ns))
return BAN::numeric_limits<uint64_t>::max();
return rqtp.tv_sec * 1'000'000'000 + rqtp.tv_nsec + current_ns;
}();
const uint64_t wake_time_ns = SystemTimer::get().ns_since_boot() + sleep_ns; // NOTE: we shouldn't get woken up unless the thread is interrupted but there is no harm in looping
SystemTimer::get().sleep_until_ns(wake_time_ns); while (current_ns < waketime_ns && !Thread::current().is_interrupted_by_signal())
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
if (current_ns < wake_time_ns)
{ {
const uint64_t remaining_ns = wake_time_ns - current_ns; SystemTimer::get().sleep_until_ns(waketime_ns);
current_ns = SystemTimer::get().ns_since_boot();
}
if (current_ns < waketime_ns)
{
if (user_rmtp != nullptr)
{
const uint64_t remaining_ns = waketime_ns - current_ns;
const timespec remaining_ts = { const timespec remaining_ts = {
.tv_sec = static_cast<time_t>(remaining_ns / 1'000'000'000), .tv_sec = static_cast<time_t>(remaining_ns / 1'000'000'000),
.tv_nsec = static_cast<long>(remaining_ns % 1'000'000'000), .tv_nsec = static_cast<long>(remaining_ns % 1'000'000'000),
}; };
if (user_rmtp != nullptr)
TRY(write_to_user(user_rmtp, &remaining_ts, sizeof(timespec))); TRY(write_to_user(user_rmtp, &remaining_ts, sizeof(timespec)));
}
return BAN::Error::from_errno(EINTR); return BAN::Error::from_errno(EINTR);
} }

View File

@@ -15,7 +15,7 @@
namespace Kernel namespace Kernel
{ {
static_assert(SYS_SIGPROCMASK == 79, "this is hard coded in arch/*/Signal.S"); static_assert(SYS_SIGPROCMASK == 78, "this is hard coded in arch/*/Signal.S");
static_assert(SIG_SETMASK == 3, "this is hard coded in arch/*/Signal.S"); static_assert(SIG_SETMASK == 3, "this is hard coded in arch/*/Signal.S");
#if ARCH(x86_64) #if ARCH(x86_64)

View File

@@ -16,7 +16,6 @@ __BEGIN_DECLS
O(SYS_RENAMEAT, renameat) \ O(SYS_RENAMEAT, renameat) \
O(SYS_FORK, fork) \ O(SYS_FORK, fork) \
O(SYS_EXEC, exec) \ O(SYS_EXEC, exec) \
O(SYS_SLEEP, sleep) \
O(SYS_WAIT, wait) \ O(SYS_WAIT, wait) \
O(SYS_READ_DIR, readdir) \ O(SYS_READ_DIR, readdir) \
O(SYS_SET_UID, setuid) \ O(SYS_SET_UID, setuid) \

View File

@@ -622,18 +622,24 @@ int pipe(int fildes[2])
unsigned int sleep(unsigned int seconds) unsigned int sleep(unsigned int seconds)
{ {
pthread_testcancel(); const timespec rq_ts {
unsigned int ret = syscall(SYS_SLEEP, seconds); .tv_sec = seconds,
if (ret > 0) .tv_nsec = 0,
errno = EINTR; };
return ret; timespec rm_ts;
if (nanosleep(&rq_ts, &rm_ts) == 0)
return 0;
if (errno != EINTR)
return seconds;
return rm_ts.tv_sec + !!rm_ts.tv_nsec;
} }
int usleep(useconds_t usec) int usleep(useconds_t usec)
{ {
timespec ts; const timespec ts {
ts.tv_sec = usec / 1'000'000; .tv_sec = static_cast<time_t>(usec / 1'000'000),
ts.tv_nsec = (usec % 1'000'000) * 1000; .tv_nsec = static_cast<long>((usec % 1'000'000) * 1000),
};
return nanosleep(&ts, nullptr); return nanosleep(&ts, nullptr);
} }