Author: bonefish Date: 2011-05-24 02:51:44 +0200 (Tue, 24 May 2011) New Revision: 41698 Changeset: https://dev.haiku-os.org/changeset/41698 Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp Log: Removed the SIGNAL_FLAG_DONT_RESTART_SYSCALL flag entirely and introduced the kernel internal signal SIGNAL_CONTINUE_THREAD, which is used by resume_thread() instead. This prevents the Haiku thread management from interfering with POSIX semantics. Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h 2011-05-23 23:30:59 UTC (rev 41697) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h 2011-05-24 00:51:44 UTC (rev 41698) @@ -36,7 +36,11 @@ #define SYSCALL_RESTART_PARAMETER_SIZE 32 +// Kernel internal signal to continue a thread. Used by resume_thread(). +// Non-blockable, prevents syscall restart. +#define SIGNAL_CONTINUE_THREAD 64 + struct signal_frame_data { siginfo_t info; ucontext_t context; Modified: haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h 2011-05-23 23:30:59 UTC (rev 41697) +++ haiku/branches/developer/bonefish/signals/headers/private/system/signal_defs.h 2011-05-24 00:51:44 UTC (rev 41698) @@ -22,12 +22,10 @@ #define MAX_SIGNAL_NUMBER SIGNAL_REALTIME_MAX // additional send_signal_etc() flags -#define SIGNAL_FLAG_DONT_RESTART_SYSCALL (0x10000) - // don't restart the syscall interrupted by the signal (in-kernel use only) -#define SIGNAL_FLAG_QUEUING_REQUIRED (0x20000) +#define SIGNAL_FLAG_QUEUING_REQUIRED (0x10000) // force signal queuing, i.e. fail instead of falling back to unqueued // signals, when queuing isn't possible -#define SIGNAL_FLAG_SEND_TO_THREAD (0x40000) +#define SIGNAL_FLAG_SEND_TO_THREAD (0x20000) // interpret the the given ID as a thread_id rather than a team_id (syscall // use only) Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp 2011-05-23 23:30:59 UTC (rev 41697) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp 2011-05-24 00:51:44 UTC (rev 41698) @@ -42,7 +42,8 @@ #endif -#define BLOCKABLE_SIGNALS (~(KILL_SIGNALS | SIGNAL_TO_MASK(SIGSTOP))) +#define BLOCKABLE_SIGNALS (~(KILL_SIGNALS | SIGNAL_TO_MASK(SIGSTOP) \ + | SIGNAL_TO_MASK(SIGNAL_CONTINUE_THREAD))) #define STOP_SIGNALS \ (SIGNAL_TO_MASK(SIGSTOP) | SIGNAL_TO_MASK(SIGTSTP) \ | SIGNAL_TO_MASK(SIGTTIN) | SIGNAL_TO_MASK(SIGTTOU)) @@ -60,7 +61,7 @@ static const struct { const char* name; int32 priority; -} kSignalInfos[SIGNAL_REALTIME_MAX + 1] = { +} kSignalInfos[__MAX_SIGNO + 1] = { {"NONE", -1}, {"HUP", 0}, {"INT", 0}, @@ -101,14 +102,38 @@ {"SIGRT5", 4}, {"SIGRT6", 3}, {"SIGRT7", 2}, - {"SIGRT8", 1} + {"SIGRT8", 1}, + {"invalid 41", 0}, + {"invalid 42", 0}, + {"invalid 43", 0}, + {"invalid 44", 0}, + {"invalid 45", 0}, + {"invalid 46", 0}, + {"invalid 47", 0}, + {"invalid 48", 0}, + {"invalid 49", 0}, + {"invalid 50", 0}, + {"invalid 51", 0}, + {"invalid 52", 0}, + {"invalid 53", 0}, + {"invalid 54", 0}, + {"invalid 55", 0}, + {"invalid 56", 0}, + {"invalid 57", 0}, + {"invalid 58", 0}, + {"invalid 59", 0}, + {"invalid 60", 0}, + {"invalid 61", 0}, + {"invalid 62", 0}, + {"invalid 63", 0}, + {"SIGNAL_CONTINUE_THREAD", 99} }; static inline const char* signal_name(uint32 number) { - return number <= MAX_SIGNAL_NUMBER ? kSignalInfos[number].name : "invalid"; + return number <= __MAX_SIGNO ? kSignalInfos[number].name : "invalid"; } @@ -907,7 +932,13 @@ schedulerLocker.Unlock(); // get the action for the signal - struct sigaction handler = team->SignalActionFor(signal->Number()); + struct sigaction handler; + if (signal->Number() <= MAX_SIGNAL_NUMBER) { + handler = team->SignalActionFor(signal->Number()); + } else { + handler.sa_handler = SIG_DFL; + handler.sa_flags = 0; + } if ((handler.sa_flags & SA_ONESHOT) != 0 && handler.sa_handler != SIG_IGN && handler.sa_handler != SIG_DFL) { @@ -958,6 +989,12 @@ notify_debugger(thread, signal, handler, false); continue; + case SIGNAL_CONTINUE_THREAD: + // prevent syscall restart, but otherwise ignore + restart = false; + atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL); + continue; + case SIGCONT: // notify the debugger if (debugSignal @@ -1225,9 +1262,6 @@ \param flags A bitwise combination of any number of the following: - \c B_CHECK_PERMISSION: Check the caller's permission to send the target thread the signal. - - \c SIGNAL_FLAG_DONT_RESTART_SYSCALL: If the signal interrupts the - thread while waiting in a syscall, the syscall shall not be - restarted automatically, but fail with \c B_INTERRUPTED instead. \return \c B_OK, when the signal was delivered successfully, another error code otherwise. */ @@ -1288,6 +1322,14 @@ thread_interrupt(thread, true); break; + case SIGNAL_CONTINUE_THREAD: + // wake up thread, and interrupt its current syscall + if (thread->state == B_THREAD_SUSPENDED) + scheduler_enqueue_in_run_queue(thread); + + atomic_or(&thread->flags, THREAD_FLAGS_DONT_RESTART_SYSCALL); + break; + case SIGCONT: // Wake up thread if it was suspended, otherwise interrupt it, if // the signal isn't blocked. @@ -1296,9 +1338,6 @@ else if ((SIGNAL_TO_MASK(SIGCONT) & ~thread->sig_block_mask) != 0) thread_interrupt(thread, false); - if ((flags & SIGNAL_FLAG_DONT_RESTART_SYSCALL) != 0) - atomic_or(&thread->flags, THREAD_FLAGS_DONT_RESTART_SYSCALL); - // remove any pending stop signals thread->RemovePendingSignals(STOP_SIGNALS); break; @@ -1332,9 +1371,6 @@ \param flags A bitwise combination of any number of the following: - \c B_CHECK_PERMISSION: Check the caller's permission to send the target thread the signal. - - \c SIGNAL_FLAG_DONT_RESTART_SYSCALL: If the signal interrupts the - thread while waiting in a syscall, the syscall shall not be - restarted automatically, but fail with \c B_INTERRUPTED instead. - \c B_DO_NOT_RESCHEDULE: If clear and a higher level thread has been woken up, the scheduler will be invoked. If set that will not be done explicitly, but rescheduling can still happen, e.g. when the Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp 2011-05-23 23:30:59 UTC (rev 41697) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp 2011-05-24 00:51:44 UTC (rev 41698) @@ -2862,11 +2862,12 @@ Thread* currentThread = thread_get_current_thread(); - Signal signal(SIGCONT, SI_USER, B_OK, currentThread->team->id); - return send_signal_to_thread(id, signal, SIGNAL_FLAG_DONT_RESTART_SYSCALL); - // This retains compatibility to BeOS which documents the - // combination of suspend_thread() and resume_thread() to - // interrupt threads waiting on semaphores. + // Using the kernel internal SIGNAL_CONTINUE_THREAD signal retains + // compatibility to BeOS which documents the combination of suspend_thread() + // and resume_thread() to interrupt threads waiting on semaphores. + Signal signal(SIGNAL_CONTINUE_THREAD, SI_USER, B_OK, + currentThread->team->id); + return send_signal_to_thread(id, signal, 0); }