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:
@@ -59,7 +59,7 @@ signal_trampoline:
|
||||
addl $24, %esp
|
||||
|
||||
// restore sigmask
|
||||
movl $79, %eax // SYS_SIGPROCMASK
|
||||
movl $78, %eax // SYS_SIGPROCMASK
|
||||
movl $3, %ebx // SIG_SETMASK
|
||||
leal 72(%esp), %ecx // set
|
||||
xorl %edx, %edx // oset
|
||||
|
||||
@@ -61,7 +61,7 @@ signal_trampoline:
|
||||
addq $40, %rsp
|
||||
|
||||
// restore sigmask
|
||||
movq $79, %rdi // SYS_SIGPROCMASK
|
||||
movq $78, %rdi // SYS_SIGPROCMASK
|
||||
movq $3, %rsi // SIG_SETMASK
|
||||
leaq 192(%rsp), %rdx // set
|
||||
xorq %r10, %r10 // oset
|
||||
|
||||
@@ -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_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_setitimer(int which, const itimerval* value, itimerval* ovalue);
|
||||
|
||||
|
||||
@@ -1036,52 +1036,45 @@ namespace Kernel
|
||||
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)
|
||||
{
|
||||
// take current timestamp ASAP
|
||||
uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
|
||||
timespec rqtp;
|
||||
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);
|
||||
|
||||
const uint64_t sleep_ns = (rqtp.tv_sec * 1'000'000'000) + rqtp.tv_nsec;
|
||||
if (sleep_ns == 0)
|
||||
return 0;
|
||||
const uint64_t waketime_ns = [&rqtp, current_ns]() -> uint64_t {
|
||||
if (BAN::Math::will_multiplication_overflow<uint64_t>(rqtp.tv_sec, 1'000'000'000))
|
||||
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;
|
||||
SystemTimer::get().sleep_until_ns(wake_time_ns);
|
||||
|
||||
const uint64_t current_ns = SystemTimer::get().ns_since_boot();
|
||||
if (current_ns < wake_time_ns)
|
||||
// NOTE: we shouldn't get woken up unless the thread is interrupted but there is no harm in looping
|
||||
while (current_ns < waketime_ns && !Thread::current().is_interrupted_by_signal())
|
||||
{
|
||||
SystemTimer::get().sleep_until_ns(waketime_ns);
|
||||
current_ns = SystemTimer::get().ns_since_boot();
|
||||
}
|
||||
|
||||
if (current_ns < waketime_ns)
|
||||
{
|
||||
const uint64_t remaining_ns = wake_time_ns - current_ns;
|
||||
const timespec remaining_ts = {
|
||||
.tv_sec = static_cast<time_t>(remaining_ns / 1'000'000'000),
|
||||
.tv_nsec = static_cast<long>(remaining_ns % 1'000'000'000),
|
||||
};
|
||||
if (user_rmtp != nullptr)
|
||||
{
|
||||
const uint64_t remaining_ns = waketime_ns - current_ns;
|
||||
const timespec remaining_ts = {
|
||||
.tv_sec = static_cast<time_t>(remaining_ns / 1'000'000'000),
|
||||
.tv_nsec = static_cast<long>(remaining_ns % 1'000'000'000),
|
||||
};
|
||||
TRY(write_to_user(user_rmtp, &remaining_ts, sizeof(timespec)));
|
||||
}
|
||||
return BAN::Error::from_errno(EINTR);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
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");
|
||||
|
||||
#if ARCH(x86_64)
|
||||
|
||||
@@ -16,7 +16,6 @@ __BEGIN_DECLS
|
||||
O(SYS_RENAMEAT, renameat) \
|
||||
O(SYS_FORK, fork) \
|
||||
O(SYS_EXEC, exec) \
|
||||
O(SYS_SLEEP, sleep) \
|
||||
O(SYS_WAIT, wait) \
|
||||
O(SYS_READ_DIR, readdir) \
|
||||
O(SYS_SET_UID, setuid) \
|
||||
|
||||
@@ -622,18 +622,24 @@ int pipe(int fildes[2])
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
pthread_testcancel();
|
||||
unsigned int ret = syscall(SYS_SLEEP, seconds);
|
||||
if (ret > 0)
|
||||
errno = EINTR;
|
||||
return ret;
|
||||
const timespec rq_ts {
|
||||
.tv_sec = seconds,
|
||||
.tv_nsec = 0,
|
||||
};
|
||||
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)
|
||||
{
|
||||
timespec ts;
|
||||
ts.tv_sec = usec / 1'000'000;
|
||||
ts.tv_nsec = (usec % 1'000'000) * 1000;
|
||||
const timespec ts {
|
||||
.tv_sec = static_cast<time_t>(usec / 1'000'000),
|
||||
.tv_nsec = static_cast<long>((usec % 1'000'000) * 1000),
|
||||
};
|
||||
return nanosleep(&ts, nullptr);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user