diff --git a/headers/private/kernel/ksignal.h b/headers/private/kernel/ksignal.h index e80c013fd5..72e071c420 100644 --- a/headers/private/kernel/ksignal.h +++ b/headers/private/kernel/ksignal.h @@ -40,6 +40,7 @@ extern status_t _user_sigprocmask(int how, const sigset_t *set, extern status_t _user_sigaction(int sig, const struct sigaction *newAction, struct sigaction *oldAction); extern bigtime_t _user_set_alarm(bigtime_t time, uint32 mode); +extern status_t _user_sigwait(const sigset_t *set, int *_signal); extern status_t _user_sigsuspend(const sigset_t *mask); extern status_t _user_sigpending(sigset_t *set); extern status_t _user_set_signal_stack(const stack_t *newUserStack, diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index 12c739bc87..9f50dcfd05 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -131,6 +131,7 @@ extern status_t _kern_sigprocmask(int how, const sigset_t *set, extern status_t _kern_sigaction(int sig, const struct sigaction *action, struct sigaction *oldAction); extern bigtime_t _kern_set_alarm(bigtime_t time, uint32 mode); +extern status_t _kern_sigwait(const sigset_t *set, int *_signal); extern status_t _kern_sigsuspend(const sigset_t *mask); extern status_t _kern_sigpending(sigset_t *set); extern status_t _kern_set_signal_stack(const stack_t *newStack, @@ -248,7 +249,7 @@ extern status_t _kern_resize_area(area_id area, size_t newSize); extern area_id _kern_transfer_area(area_id area, void **_address, uint32 addressSpec, team_id target); extern status_t _kern_set_area_protection(area_id area, uint32 newProtection); -extern area_id _kern_clone_area(const char *name, void **_address, uint32 addressSpec, +extern area_id _kern_clone_area(const char *name, void **_address, uint32 addressSpec, uint32 protection, area_id sourceArea); extern status_t _kern_reserve_heap_address_range(addr_t* _address, uint32 addressSpec, addr_t size); @@ -296,7 +297,7 @@ extern int32 _kern_atomic_set(vint32 *value, int32 newValue); extern int32 _kern_atomic_test_and_set(vint32 *value, int32 newValue, int32 testAgainst); extern int32 _kern_atomic_add(vint32 *value, int32 addValue); extern int32 _kern_atomic_and(vint32 *value, int32 andValue); -extern int32 _kern_atomic_or(vint32 *value, int32 orValue); +extern int32 _kern_atomic_or(vint32 *value, int32 orValue); extern int32 _kern_atomic_get(vint32 *value); #endif // ATOMIC_FUNCS_ARE_SYSCALLS @@ -305,7 +306,7 @@ extern int64 _kern_atomic_set64(vint64 *value, int64 newValue); extern int64 _kern_atomic_test_and_set64(vint64 *value, int64 newValue, int64 testAgainst); extern int64 _kern_atomic_add64(vint64 *value, int64 addValue); extern int64 _kern_atomic_and64(vint64 *value, int64 andValue); -extern int64 _kern_atomic_or64(vint64 *value, int64 orValue); +extern int64 _kern_atomic_or64(vint64 *value, int64 orValue); extern int64 _kern_atomic_get64(vint64 *value); #endif // ATOMIC64_FUNCS_ARE_SYSCALLS diff --git a/src/system/kernel/signal.cpp b/src/system/kernel/signal.cpp index 6aa3ab28f6..eb2766e213 100644 --- a/src/system/kernel/signal.cpp +++ b/src/system/kernel/signal.cpp @@ -7,6 +7,8 @@ /*! POSIX signals handling routines */ +#include + #include #include @@ -17,8 +19,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -203,7 +205,7 @@ class SigProcMask : public AbstractTraceEntry { #endif // SIGNAL_TRACING -// #pragma mark - +// #pragma mark - /*! Updates the thread::flags field according to what signals are pending. @@ -482,7 +484,7 @@ deliver_signal(struct thread *thread, uint signal, uint32 flags) if (flags & B_CHECK_PERMISSION) { // ToDo: introduce euid & uid fields to the team and check permission } - + if (signal == 0) return B_OK; @@ -560,7 +562,7 @@ send_signal_etc(pid_t id, uint signal, uint32 flags) if ((flags & SIGNAL_FLAG_TEAMS_LOCKED) == 0) state = disable_interrupts(); - + if (id > 0) { // send a signal to the specified thread @@ -574,7 +576,7 @@ send_signal_etc(pid_t id, uint signal, uint32 flags) // (the absolute value of the id) struct process_group *group; - + // TODO: handle -1 correctly if (id == 0 || id == -1) { // send a signal to the current team @@ -612,7 +614,7 @@ send_signal_etc(pid_t id, uint signal, uint32 flags) RELEASE_TEAM_LOCK(); GRAB_THREAD_LOCK(); - } + } // ToDo: maybe the scheduler should only be invoked if there is reason to do it? // (ie. deliver_signal() moved some threads in the running queue?) @@ -798,6 +800,46 @@ set_alarm(bigtime_t time, uint32 mode) } +/*! Wait for the specified signals, and return the signal retrieved in + \a _signal. +*/ +int +sigwait(const sigset_t *set, int *_signal) +{ + struct thread *thread = thread_get_current_thread(); + int signalsPending = 0; + + ConditionVariable conditionVar; + conditionVar.Publish(set, "sigwait"); + + while (true) { + ConditionVariableEntry entry; + entry.Wait(set, B_CAN_INTERRUPT); + + if (has_signals_pending(thread)) { + signalsPending = atomic_get(&thread->sig_pending) & *set; + break; + } + } + + conditionVar.Unpublish(); + + update_current_thread_signals_flag(); + + if (signalsPending) { + // select the lowest pending signal to return in _signal + for (int signal = 1; signal < NSIG; signal++) { + if ((SIGNAL_TO_MASK(signal) & signalsPending) != 0) { + *_signal = signal; + return B_OK; + } + } + } + + return B_INTERRUPTED; +} + + /*! Replace the current signal block mask and wait for any event to happen. Before returning, the original signal block mask is reinstantiated. */ @@ -843,7 +885,7 @@ sigpending(sigset_t *set) if (set == NULL) return B_BAD_VALUE; - *set = atomic_get(&thread->sig_pending); + *set = atomic_get(&thread->sig_pending); return B_OK; } @@ -915,6 +957,25 @@ _user_sigaction(int signal, const struct sigaction *userAction, } +status_t +_user_sigwait(const sigset_t *userSet, int *_userSignal) +{ + if (userSet == NULL || _userSignal == NULL) + return B_BAD_VALUE; + + sigset_t set; + if (user_memcpy(&set, userSet, sizeof(sigset_t)) < B_OK) + return B_BAD_ADDRESS; + + int signal; + status_t status = sigwait(&set, &signal); + if (status < B_OK) + return syscall_restart_handle_post(status); + + return user_memcpy(_userSignal, &signal, sizeof(int)); +} + + status_t _user_sigsuspend(const sigset_t *userMask) { diff --git a/src/system/libroot/posix/signal/Jamfile b/src/system/libroot/posix/signal/Jamfile index cd84bbb9a3..e25aca6da0 100644 --- a/src/system/libroot/posix/signal/Jamfile +++ b/src/system/libroot/posix/signal/Jamfile @@ -19,5 +19,6 @@ MergeObject posix_signal.o : sigrelse.cpp sigset.c sigsuspend.c + sigwait.c strsignal.c ; diff --git a/src/system/libroot/posix/signal/sigwait.c b/src/system/libroot/posix/signal/sigwait.c new file mode 100644 index 0000000000..dc0479f66b --- /dev/null +++ b/src/system/libroot/posix/signal/sigwait.c @@ -0,0 +1,18 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + + +int +sigwait(const sigset_t *set, int *_signal) +{ + return _kern_sigwait(set, _signal); + // does not set errno, but returns the error value directly +} +