Skip to content

Commit

Permalink
Implement sigtimedwait
Browse files Browse the repository at this point in the history
  • Loading branch information
tbodt committed Aug 26, 2019
1 parent 68e7dd8 commit d5f9309
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 1 deletion.
1 change: 1 addition & 0 deletions kernel/calls.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ syscall_t syscall_table[] = {
[174] = (syscall_t) sys_rt_sigaction,
[175] = (syscall_t) sys_rt_sigprocmask,
[176] = (syscall_t) sys_rt_sigpending,
[177] = (syscall_t) sys_rt_sigtimedwait,
[179] = (syscall_t) sys_rt_sigsuspend,
[180] = (syscall_t) sys_pread,
[181] = (syscall_t) sys_pwrite,
Expand Down
53 changes: 52 additions & 1 deletion kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ static void deliver_signal_unlocked(struct task *task, int sig, struct siginfo_
sigqueue->info.sig = sig;
list_add_tail(&task->queue, &sigqueue->queue);

if (sigset_has(task->blocked, sig) && signal_is_blockable(sig))
if (sigset_has(task->blocked & ~task->waiting, sig) && signal_is_blockable(sig))
return;

if (task != current) {
Expand Down Expand Up @@ -584,6 +584,57 @@ int_t sys_pause() {
return _EINTR;
}

int_t sys_rt_sigtimedwait(addr_t set_addr, addr_t info_addr, addr_t timeout_addr, uint_t set_size) {
if (set_size != sizeof(sigset_t_))
return _EINVAL;
sigset_t_ set;
if (user_get(set_addr, set))
return _EFAULT;
struct timespec timeout;
if (timeout_addr != 0) {
struct timespec_ fake_timeout;
if (user_get(timeout_addr, fake_timeout))
return _EFAULT;
timeout.tv_sec = fake_timeout.sec;
timeout.tv_nsec = fake_timeout.nsec;
}
STRACE("sigtimedwait(%#llx, %#x, %#x) = ...\n", (long long) set, info_addr, timeout_addr);

lock(&current->sighand->lock);
assert(current->waiting == 0);
current->waiting = set;
int err;
do {
err = wait_for(&current->pause, &current->sighand->lock, timeout_addr == 0 ? NULL : &timeout);
} while (err != 0);
current->waiting = 0;
if (err == _ETIMEDOUT) {
unlock(&current->sighand->lock);
STRACE("sigtimedwait timed out\n");
return _EAGAIN;
}

struct sigqueue *sigqueue;
bool found = false;
list_for_each_entry(&current->queue, sigqueue, queue) {
if (sigset_has(set, sigqueue->info.sig)) {
found = true;
list_remove(&sigqueue->queue);
break;
}
}
if (!found)
return _EINTR;
struct siginfo_ info = sigqueue->info;
free(sigqueue);
if (info_addr != 0)
if (user_put(info_addr, info))
return _EFAULT;
unlock(&current->sighand->lock);
STRACE("done sigtimedwait = %d\n", info.sig);
return info.sig;
}

int do_kill(pid_t_ pid, dword_t sig, pid_t_ tgid) {
STRACE("kill(%d, %d)", pid, sig);
if (sig >= NUM_SIGS)
Expand Down
1 change: 1 addition & 0 deletions kernel/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ dword_t sys_sigaltstack(addr_t ss, addr_t old_ss);

int_t sys_rt_sigsuspend(addr_t mask_addr, uint_t size);
int_t sys_pause(void);
int_t sys_rt_sigtimedwait(addr_t set_addr, addr_t info_addr, addr_t timeout_addr, uint_t set_size);

dword_t sys_kill(pid_t_ pid, dword_t sig);
dword_t sys_tkill(pid_t_ tid, dword_t sig);
Expand Down
1 change: 1 addition & 0 deletions kernel/task.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ struct task {
struct sighand *sighand;
sigset_t_ blocked;
sigset_t_ pending;
sigset_t_ waiting; // if nonzero, an ongoing call to sigtimedwait is waiting on these
struct list queue;
cond_t pause; // please don't signal this
// private
Expand Down

0 comments on commit d5f9309

Please sign in to comment.