Author: bonefish Date: 2011-05-16 03:44:46 +0200 (Mon, 16 May 2011) New Revision: 41522 Changeset: https://dev.haiku-os.org/changeset/41522 Modified: haiku/branches/developer/bonefish/signals/headers/os/kernel/debugger.h haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h haiku/branches/developer/bonefish/signals/src/system/kernel/debug/user_debugger.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp Log: * According to POSIX, signal actions are specified per process, not per thread as done in Haiku. Rectified this: - Moved Thread::sig_action to Team, renamed to fSignalActions, made private, and added accessor methods. - Adjusted the kernel code using the signal actions accordingly. - Removed now superfluous sigaction_etc() from the kernel. - Removed now superfluous thread field from user debugger protocol structures debug_nub_set_signal_handler and debug_nub_get_signal_handler. * Some simplifications of the Team/Thread inline methods in thread_types.h. * Clear pending signals in Thread and Team destructors. * Clear pending team signals on exec. Modified: haiku/branches/developer/bonefish/signals/headers/os/kernel/debugger.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/os/kernel/debugger.h 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/headers/os/kernel/debugger.h 2011-05-16 01:44:46 UTC (rev 41522) @@ -151,7 +151,7 @@ B_DEBUG_MESSAGE_CLEAR_WATCHPOINT, // clear a watchpoint B_DEBUG_MESSAGE_SET_SIGNAL_MASKS, // set/get a thread's masks of signals B_DEBUG_MESSAGE_GET_SIGNAL_MASKS, // the debugger is interested in - B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER, // set/get a thread's signal handler for + B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER, // set/get the team's signal handler for B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER, // a signal B_DEBUG_MESSAGE_PREPARE_HANDOVER, // prepares the debugged team for being @@ -356,7 +356,6 @@ // B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER typedef struct { - thread_id thread; // the thread int signal; // the signal struct sigaction handler; // the new signal handler } debug_nub_set_signal_handler; @@ -365,7 +364,6 @@ typedef struct { port_id reply_port; // port to send the reply to - thread_id thread; // the thread int signal; // the signal } debug_nub_get_signal_handler; Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h 2011-05-16 01:44:46 UTC (rev 41522) @@ -117,9 +117,6 @@ void update_current_thread_signals_flag(); -int sigaction_etc(thread_id threadID, int signal, - const struct sigaction *newAction, struct sigaction *oldAction); - status_t _user_send_signal(pid_t tid, uint sig); status_t _user_sigprocmask(int how, const sigset_t *set, sigset_t *oldSet); status_t _user_sigaction(int sig, const struct sigaction *newAction, Modified: haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h =================================================================== --- haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 2011-05-16 01:44:46 UTC (rev 41522) @@ -310,8 +310,16 @@ const char* const* otherArgs, int otherArgCount); - void RemovePendingSignals(sigset_t mask); + void RemovePendingSignal(int signal) + { fPendingSignals.RemoveSignal(signal); } + void RemovePendingSignals(sigset_t mask) + { fPendingSignals.RemoveSignals(mask); } + void ResetSignals(); + struct sigaction& SignalActionFor(int32 signal) + { return fSignalActions[signal - 1]; } + void InheritSignalActions(Team* parent); + private: Team(bool kernel); @@ -322,6 +330,8 @@ // contents for the team_info::args field PendingSignals fPendingSignals; // protected by scheduler lock + struct sigaction fSignalActions[MAX_SIGNO]; + // protected by fLock }; @@ -349,7 +359,6 @@ sigset_t sig_block_mask; // protected by scheduler lock, // only modified by the thread itself sigset_t sig_temp_enabled; // protected by scheduler lock - struct sigaction sig_action[32]; // protected by fLock addr_t signal_stack_base; // only accessed by this thread size_t signal_stack_size; // only accessed by this thread bool signal_stack_enabled; // only accessed by this thread @@ -462,11 +471,14 @@ sigset_t ThreadPendingSignals() const { return fPendingSignals.AllSignals(); } - inline sigset_t AllPendingSignals() const; - inline void AddPendingSignal(int signal) + sigset_t AllPendingSignals() const + { return fPendingSignals.AllSignals(); } + void AddPendingSignal(int signal) { fPendingSignals.AddSignal(signal); } - inline void RemovePendingSignal(int signal); - inline void RemovePendingSignals(sigset_t mask); + void RemovePendingSignal(int signal) + { fPendingSignals.RemoveSignal(signal); } + void RemovePendingSignals(sigset_t mask) + { fPendingSignals.RemoveSignals(mask); } void ResetSignals(); bool Lock() @@ -580,34 +592,6 @@ }; -inline void -Team::RemovePendingSignals(sigset_t mask) -{ - fPendingSignals.RemoveSignals(mask); -} - - -inline sigset_t -Thread::AllPendingSignals() const -{ - return fPendingSignals.AllSignals(); -} - - -inline void -Thread::RemovePendingSignal(int signal) -{ - fPendingSignals.RemoveSignal(signal); -} - - -inline void -Thread::RemovePendingSignals(sigset_t mask) -{ - fPendingSignals.RemoveSignals(mask); -} - - } // namespace BKernel using BKernel::Team; Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/debug/user_debugger.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/debug/user_debugger.cpp 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/debug/user_debugger.cpp 2011-05-16 01:44:46 UTC (rev 41522) @@ -2135,27 +2135,16 @@ case B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: { // get the parameters - thread_id threadID = message.set_signal_handler.thread; int signal = message.set_signal_handler.signal; struct sigaction &handler = message.set_signal_handler.handler; TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: " - "thread: %ld, signal: %d, handler: %p\n", nubThread->id, - threadID, signal, handler.sa_handler)); + "signal: %d, handler: %p\n", nubThread->id, + signal, handler.sa_handler)); - // check, if the thread exists and is ours - Thread* thread = Thread::GetAndLock(threadID); - if (thread == NULL) - break; - BReference<Thread> threadReference(thread, true); - ThreadLocker threadLocker(thread, true); + // set the handler + sigaction(signal, &handler, NULL); - if (thread->team == thread_get_current_thread()->team) { - // set the handler - threadLocker.Unlock(); - sigaction_etc(threadID, signal, &handler, NULL); - } - break; } @@ -2163,31 +2152,18 @@ { // get the parameters replyPort = message.get_signal_handler.reply_port; - thread_id threadID = message.get_signal_handler.thread; int signal = message.get_signal_handler.signal; status_t result = B_OK; - // check, if the thread exists and is ours - if (Thread* thread = Thread::GetAndLock(threadID)) { - BReference<Thread> threadReference(thread, true); - ThreadLocker threadLocker(thread, true); - - if (thread->team != thread_get_current_thread()->team) - result = B_BAD_VALUE; - } else - result = B_BAD_THREAD_ID; - // get the handler - if (result == B_OK - && sigaction_etc(threadID, signal, NULL, - &reply.get_signal_handler.handler) != 0) { + if (sigaction(signal, NULL, &reply.get_signal_handler.handler) + != 0) { result = errno; } TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER: " - "reply port: %ld, thread: %ld, signal: %d, " - "handler: %p\n", nubThread->id, replyPort, - threadID, signal, + "reply port: %ld, signal: %d, handler: %p\n", nubThread->id, + replyPort, signal, reply.get_signal_handler.handler.sa_handler)); // prepare the message Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp 2011-05-16 01:44:46 UTC (rev 41522) @@ -395,9 +395,8 @@ class SigAction : public AbstractTraceEntry { public: - SigAction(Thread* thread, uint32 signal, const struct sigaction* act) + SigAction(uint32 signal, const struct sigaction* act) : - fThread(thread->id), fSignal(signal), fAction(*act) { @@ -406,15 +405,13 @@ virtual void AddDump(TraceOutput& out) { - out.Print("signal action: thread: %ld, signal: %lu (%s), " - "action: {handler: %p, flags: 0x%x, mask: 0x%lx}", - fThread, fSignal, + out.Print("signal action: signal: %lu (%s), " + "action: {handler: %p, flags: 0x%x, mask: 0x%lx}", fSignal, fSignal < NSIG ? kSignalInfos[fSignal].name : "invalid", fAction.sa_handler, fAction.sa_flags, fAction.sa_mask); } private: - thread_id fThread; uint32 fSignal; struct sigaction fAction; }; @@ -582,6 +579,8 @@ bool handle_signals(Thread* thread) { + Team* team = thread->team; + // get the pending signals that need to be handled InterruptsSpinLocker schedulerLocker(gSchedulerLock); @@ -629,7 +628,7 @@ continue; // clear the signal that we will handle - ThreadLocker threadLocker(thread); + TeamLocker teamLocker(team); schedulerLocker.Lock(); // TODO: Might be a pending team signal. @@ -638,16 +637,16 @@ schedulerLocker.Unlock(); - struct sigaction handler = thread->sig_action[i]; + struct sigaction handler = team->SignalActionFor(signal); if ((handler.sa_flags & SA_ONESHOT) != 0 && handler.sa_handler != SIG_IGN && handler.sa_handler != SIG_DFL) { - thread->sig_action[i].sa_handler = SIG_DFL; + team->SignalActionFor(signal).sa_handler = SIG_DFL; } - threadLocker.Unlock(); + teamLocker.Unlock(); - debugSignal = !(~atomic_get(&thread->team->debug_info.flags) + debugSignal = !(~atomic_get(&team->debug_info.flags) & (B_TEAM_DEBUG_SIGNALS | B_TEAM_DEBUG_DEBUGGER_INSTALLED)); TRACE(("Thread 0x%lx received signal %s\n", thread->id, @@ -679,13 +678,13 @@ continue; // notify threads waiting for team state changes - if (thread == thread->team->main_thread) { - thread->team->LockTeamAndParent(false); + if (thread == team->main_thread) { + team->LockTeamAndParent(false); - team_set_job_control_state(thread->team, + team_set_job_control_state(team, JOB_CONTROL_STATE_CONTINUED, signal, false); - thread->team->UnlockTeamAndParent(); + team->UnlockTeamAndParent(); // The standard states that the system *may* send a // SIGCHLD when a child is continued. I haven't found @@ -703,27 +702,24 @@ continue; // notify threads waiting for team state changes - if (thread == thread->team->main_thread) { - thread->team->LockTeamAndParent(false); + if (thread == team->main_thread) { + team->LockTeamAndParent(false); - team_set_job_control_state(thread->team, + team_set_job_control_state(team, JOB_CONTROL_STATE_STOPPED, signal, false); // send a SIGCHLD to the parent (if it does have // SA_NOCLDSTOP defined) // TODO: We should send the signal to the team, not the // thread. - Thread* parentThread - = thread->team->parent->main_thread; - ThreadLocker parentThreadLocker(parentThread); + Team* parentTeam = team->parent; struct sigaction& parentHandler - = parentThread->sig_action[SIGCHLD - 1]; + = parentTeam->SignalActionFor(SIGCHLD); if ((parentHandler.sa_flags & SA_NOCLDSTOP) == 0) - deliver_signal(parentThread, SIGCHLD, 0); + send_signal_to_team_locked(parentTeam, SIGCHLD, 0); - parentThreadLocker.Unlock(); - thread->team->UnlockTeamAndParent(); + team->UnlockTeamAndParent(); } return true; @@ -737,8 +733,8 @@ // this signal kill the team. Otherwise we send a SIGKILL to // the main thread first, since the signal will kill this // thread only. - if (thread != thread->team->main_thread) - send_signal_to_team(thread->team->id, SIGKILL, 0); + if (thread != team->main_thread) + send_signal_to_team(team->id, SIGKILL, 0); case SIGQUIT: case SIGPOLL: case SIGPROF: @@ -1216,51 +1212,44 @@ A \a threadID is < 0 specifies the current thread. */ static status_t -sigaction_etc_internal(thread_id threadID, int signal, - const struct sigaction* act, struct sigaction* oldAction) +sigaction_internal(int signal, const struct sigaction* act, + struct sigaction* oldAction) { if (signal < 1 || signal > MAX_SIGNO || (SIGNAL_TO_MASK(signal) & ~BLOCKABLE_SIGNALS) != 0) return B_BAD_VALUE; - // get and lock the thread - Thread* thread; - if (threadID < 0) { - thread = thread_get_current_thread(); - thread->AcquireReference(); - thread->Lock(); - } else { - thread = Thread::GetAndLock(threadID); - if (thread == NULL) - return B_BAD_THREAD_ID; - } - BReference<Thread> threadReference(thread, true); - ThreadLocker threadLocker(thread, true); + // get and lock the team + Team* team = thread_get_current_thread()->team; + TeamLocker teamLocker(team); + struct sigaction& teamHandler = team->SignalActionFor(signal); if (oldAction) { // save previous sigaction structure - memcpy(oldAction, &thread->sig_action[signal - 1], - sizeof(struct sigaction)); + *oldAction = teamHandler; } if (act) { - T(SigAction(thread, signal, act)); + T(SigAction(signal, act)); // set new sigaction structure - memcpy(&thread->sig_action[signal - 1], act, sizeof(struct sigaction)); - thread->sig_action[signal - 1].sa_mask &= BLOCKABLE_SIGNALS; + teamHandler = *act; + teamHandler.sa_mask &= BLOCKABLE_SIGNALS; } - if (act && act->sa_handler == SIG_IGN) { - // remove pending signal if it should now be ignored + // Remove pending signal if it should now be ignored and remove pending + // signal for those signals whose default action is to ignore them. + if ((act && act->sa_handler == SIG_IGN) + || (act && act->sa_handler == SIG_DFL + && (SIGNAL_TO_MASK(signal) & DEFAULT_IGNORE_SIGNALS) != 0)) { InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread->RemovePendingSignal(signal); - } else if (act && act->sa_handler == SIG_DFL - && (SIGNAL_TO_MASK(signal) & DEFAULT_IGNORE_SIGNALS) != 0) { - // remove pending signal for those signals whose default - // action is to ignore them - InterruptsSpinLocker schedulerLocker(gSchedulerLock); - thread->RemovePendingSignal(signal); + + team->RemovePendingSignal(signal); + + for (Thread* thread = team->thread_list; thread != NULL; + thread = thread->team_next) { + thread->RemovePendingSignal(signal); + } } return B_OK; @@ -1268,18 +1257,9 @@ int -sigaction_etc(thread_id threadID, int signal, const struct sigaction* act, - struct sigaction* oldAction) -{ - RETURN_AND_SET_ERRNO(sigaction_etc_internal(threadID, signal, act, - oldAction)); -} - - -int sigaction(int signal, const struct sigaction* act, struct sigaction* oldAction) { - return sigaction_etc(-1, signal, act, oldAction); + RETURN_AND_SET_ERRNO(sigaction_internal(signal, act, oldAction)); } Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp 2011-05-16 01:44:46 UTC (rev 41522) @@ -86,7 +86,6 @@ size_t user_stack_size; addr_t user_local_storage; sigset_t sig_block_mask; - struct sigaction sig_action[32]; addr_t signal_stack_base; size_t signal_stack_size; bool signal_stack_enabled; @@ -494,6 +493,8 @@ // init dead/stopped/continued children condition vars dead_children.condition_variable.Init(&dead_children, "team children"); + + ResetSignals(); } @@ -506,6 +507,8 @@ delete_owned_ports(this); sem_delete_owned_sems(this); + fPendingSignals.Clear(); + while (::death_entry* threadDeathEntry = (::death_entry*)list_remove_head_item(&dead_threads)) { free(threadDeathEntry); @@ -762,6 +765,21 @@ } +void +Team::ResetSignals() +{ + fPendingSignals.Clear(); + memset(fSignalActions, 0, sizeof(fSignalActions)); +} + + +void +Team::InheritSignalActions(Team* parent) +{ + memcpy(fSignalActions, parent->fSignalActions, sizeof(fSignalActions)); +} + + // #pragma mark - ProcessGroup @@ -1644,6 +1662,8 @@ } } + team->ResetSignals(); + teamLocker.Unlock(); if (status != B_OK) @@ -1745,8 +1765,6 @@ thread->user_local_storage = forkArgs->user_local_storage; thread->sig_block_mask = forkArgs->sig_block_mask; thread->user_thread = forkArgs->user_thread; - memcpy(thread->sig_action, forkArgs->sig_action, - sizeof(forkArgs->sig_action)); thread->signal_stack_base = forkArgs->signal_stack_base; thread->signal_stack_size = forkArgs->signal_stack_size; thread->signal_stack_enabled = forkArgs->signal_stack_enabled; @@ -1800,6 +1818,9 @@ // Inherit the parent's user/group. inherit_parent_user_and_group(team, parentTeam); + // inherit signal handlers + team->InheritSignalActions(parentTeam); + InterruptsSpinLocker teamsLocker(sTeamHashLock); sTeamHash.Insert(team); @@ -1895,8 +1916,6 @@ forkArgs->user_stack_size = parentThread->user_stack_size; forkArgs->user_local_storage = parentThread->user_local_storage; forkArgs->sig_block_mask = parentThread->sig_block_mask; - memcpy(forkArgs->sig_action, parentThread->sig_action, - sizeof(forkArgs->sig_action)); forkArgs->signal_stack_base = parentThread->signal_stack_base; forkArgs->signal_stack_size = parentThread->signal_stack_size; forkArgs->signal_stack_enabled = parentThread->signal_stack_enabled; @@ -2225,12 +2244,16 @@ // all our children are dead and fail with ECHILD. We check the // condition at this point. if (!ignoreFoundEntriesChecked) { - struct sigaction& handler = thread->sig_action[SIGCHLD - 1]; + teamLocker.Lock(); + + struct sigaction& handler = team->SignalActionFor(SIGCHLD); if ((handler.sa_flags & SA_NOCLDWAIT) != 0 || handler.sa_handler == SIG_IGN) { ignoreFoundEntries = true; } + teamLocker.Unlock(); + ignoreFoundEntriesChecked = true; } } @@ -2603,7 +2626,7 @@ // ignore or block SIGTTOU. Otherwise the group gets a SIGTTOU. if (session->foreground_group != -1 && session->foreground_group != team->group_id - && thread->sig_action[SIGTTOU - 1].sa_handler != SIG_IGN) { + && team->SignalActionFor(SIGTTOU).sa_handler != SIG_IGN) { InterruptsSpinLocker schedulerLocker(gSchedulerLock); if (!is_team_signal_blocked(SIGTTOU)) { Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp =================================================================== --- haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp 2011-05-16 00:21:11 UTC (rev 41521) +++ haiku/branches/developer/bonefish/signals/src/system/kernel/thread.cpp 2011-05-16 01:44:46 UTC (rev 41522) @@ -215,6 +215,8 @@ Thread::~Thread() { + fPendingSignals.Clear(); + if (exit.sem >= 0) delete_sem(exit.sem); if (msg.write_sem >= 0) @@ -340,7 +342,6 @@ fPendingSignals.Clear(); sig_block_mask = 0; sig_temp_enabled = 0; - memset(sig_action, 0, 32 * sizeof(struct sigaction)); signal_stack_base = 0; signal_stack_size = 0; signal_stack_enabled = false;