示例#1
0
/*!	\brief sigaction() for the specified thread.
	A \a threadID is < 0 specifies the current thread.
*/
int
sigaction_etc(thread_id threadID, int signal, const struct sigaction *act,
	struct sigaction *oldAction)
{
	struct thread *thread;
	cpu_status state;
	status_t error = B_OK;

	if (signal < 1 || signal > MAX_SIGNO
		|| (SIGNAL_TO_MASK(signal) & ~BLOCKABLE_SIGNALS) != 0)
		return B_BAD_VALUE;

	state = disable_interrupts();
	GRAB_THREAD_LOCK();

	thread = (threadID < 0
		? thread_get_current_thread()
		: thread_get_thread_struct_locked(threadID));

	if (thread) {
		if (oldAction) {
			// save previous sigaction structure
			memcpy(oldAction, &thread->sig_action[signal - 1],
				sizeof(struct sigaction));
		}

		if (act) {
			T(SigAction(thread, 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;
		}

		if (act && act->sa_handler == SIG_IGN) {
			// remove pending signal if it should now be ignored
			atomic_and(&thread->sig_pending, ~SIGNAL_TO_MASK(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
			atomic_and(&thread->sig_pending, ~SIGNAL_TO_MASK(signal));
		}
	} else
		error = B_BAD_THREAD_ID;

	RELEASE_THREAD_LOCK();
	restore_interrupts(state);

	return error;
}
示例#2
0
int
send_signal_etc(pid_t id, uint signal, uint32 flags)
{
	status_t status = B_BAD_THREAD_ID;
	struct thread *thread;
	cpu_status state = 0;

	if (signal < 0 || signal > MAX_SIGNO)
		return B_BAD_VALUE;

	T(SendSignal(id, signal, flags));

	if ((flags & SIGNAL_FLAG_TEAMS_LOCKED) == 0)
		state = disable_interrupts();

	if (id > 0) {
		// send a signal to the specified thread

		GRAB_THREAD_LOCK();

		thread = thread_get_thread_struct_locked(id);
		if (thread != NULL)
			status = deliver_signal(thread, signal, flags);
	} else {
		// send a signal to the specified process group
		// (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
			id = thread_get_current_thread()->team->id;
		} else
			id = -id;

		if ((flags & SIGNAL_FLAG_TEAMS_LOCKED) == 0)
			GRAB_TEAM_LOCK();

		group = team_get_process_group_locked(NULL, id);
		if (group != NULL) {
			struct team *team, *next;

			// Send a signal to all teams in this process group

			for (team = group->teams; team != NULL; team = next) {
				next = team->group_next;
				id = team->id;

				GRAB_THREAD_LOCK();

				thread = thread_get_thread_struct_locked(id);
				if (thread != NULL) {
					// we don't stop because of an error sending the signal; we
					// rather want to send as much signals as possible
					status = deliver_signal(thread, signal, flags);
				}

				RELEASE_THREAD_LOCK();
			}
		}

		if ((flags & SIGNAL_FLAG_TEAMS_LOCKED) == 0)
			RELEASE_TEAM_LOCK();

		GRAB_THREAD_LOCK();
	}

	if ((flags & (B_DO_NOT_RESCHEDULE | SIGNAL_FLAG_TEAMS_LOCKED)) == 0)
		scheduler_reschedule_if_necessary_locked();

	RELEASE_THREAD_LOCK();

	if ((flags & SIGNAL_FLAG_TEAMS_LOCKED) == 0)
		restore_interrupts(state);

	return status;
}
示例#3
0
文件: signal.c 项目: HTshandou/newos
int
handle_signals(struct thread *thread)
{
	uint32 signalMask = thread->sig_pending & (~thread->sig_block_mask);
	int i, sig, global_resched = 0;
	struct sigaction *handler;

#if NOISY_SIGNAL
	dprintf("handle_signals: thread 0x%x, sig_pending 0x%x, signalMask 0x%x\n", 
		thread->id, thread->sig_pending, signalMask);
#endif

	if (signalMask == 0)
		return 0;

	for (i = 0; i < NSIG; i++) {
		if (signalMask & 0x1) {
			sig = i + 1;
			handler = &thread->sig_action[i];
			signalMask >>= 1;
			thread->sig_pending &= ~(1L << i);

			dprintf("SIG: thread 0x%x received signal %s\n", thread->id, sigstr[sig]);

			if (handler->sa_handler == SIG_IGN) {
				// signal is to be ignored
				// XXX apply zombie cleaning on SIGCHLD
				continue;
			}
			if (handler->sa_handler == SIG_DFL) {
				// default signal behaviour
				switch (sig) {
					case SIGCHLD:
					case SIGWINCH:
					case SIGCONT:
						continue;

					case SIGSTOP:
					case SIGTSTP:
					case SIGTTIN:
					case SIGTTOU:
						thread->next_state = THREAD_STATE_SUSPENDED;
						global_resched = 1;
						continue;

					case SIGHUP:
					case SIGINT:
					case SIGQUIT:
					case SIGILL:
					case SIGABRT:
					case SIGPIPE:
					case SIGFPE:
					case SIGSEGV:
					case SIGALRM:
					case SIGTRAP:
						dprintf("Shutting down thread 0x%x due to signal #%d (%s)\n", thread->id, sig, sigstr[sig]);
					case SIGKILL:
					case SIGKILLTHR:
					default:
						RELEASE_THREAD_LOCK();
						int_restore_interrupts();
						thread_exit(ERR_TASK_THREAD_KILLED);
				}
			}

			// XXX it's not safe to call arch_setup_signal_frame with interrupts disabled
			// since it writes to the user stack and may page fault.
			//
			// User defined signal handler
			dprintf("### Setting up custom signal handler frame...\n");
			arch_setup_signal_frame(thread, handler, sig, thread->sig_block_mask);

			if (handler->sa_flags & SA_ONESHOT)
				handler->sa_handler = SIG_DFL;
			if (!(handler->sa_flags & SA_NOMASK))
				thread->sig_block_mask |= (handler->sa_mask | (1L << (sig-1))) & BLOCKABLE_SIGS;

			return global_resched;
		} else