BarryServer : Git

All the code for all my projects
// BarryServer : Git / Orion / blob / e59e4fe0bbf5a3f56db0700ee49a81131b590f9c / task / signal.c

// Related

Orion

Barry Moving signal handlers into separate namespace 7ae31b0 (2 years, 4 months ago)
/*
 * This file handles signals to tasks.  It handles blocking signals, and
 * registering the signal handlers.  It send/dispatches signals to tasks and
 * runs the registered signal handlers when appropriate.
 */

#include <stdint.h>
#include <errno.h>
#include "task.h"

extern TaskQueue tasks;

/* Handle the signals for a task */
void
handle_signals(void)
{
	if (!(current->sigset & ~current->blockedSignals))
		return;

	int signal;
	for (signal = 0; signal < 32; signal++) {
		if (!(current->sigset & (1 << (signal - 1))))
			continue;
		current->status = signal;
		terminate();
	}
}

/* Send a signal to a task */
void
send_sig(Task *target, int sig)
{
	target->sigset |= (1 << (sig - 1));
}

/* Send a signal to a thread */
int
tgkill(pid_t tgid, pid_t tid, int sig)
{
	if (sig < 0 || sig >= 32)
		return -EINVAL;

	Task *task = find_task(tid);
	if (!task || task->tgid != tgid)
		return -ESRCH;
	if (sig)
		send_sig(task, sig);

	return 0;
}

/* Send a signal to a process */
int
kill(pid_t pid, int sig)
{
	if (sig < 0 || sig >= 32)
		return -EINVAL;

	int sent = 0;
	Task *task;
	for (task = tasks.start; task; task = task->tnext) {
		if (task->tgid != pid)
			continue;
		if (sig)
			send_sig(task, sig);
		sent++;
	}

	return sent ? 0 : -ESRCH;
}

/* Install a signal handler */
sighandler_t
signal(int signum, sighandler_t handler)
{
	if (signum < 0 || signum >= 32)
		return (sighandler_t) -EINVAL;

	if (!verify_access(handler, 8, PROT_EXEC))
		return (sighandler_t) -EFAULT;

	sighandler_t old = current->signals->sig_handler[signum];
	current->signals->sig_handler[signum] = handler;
	return old;
}

/* Examine and change blocked signals */
int
sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
{
	if (!verify_access(set, sizeof(sigset_t), PROT_READ))
		return -EFAULT;
	if (!verify_access(oldset, sizeof(sigset_t), PROT_WRITE))
		return -EFAULT;

	if (oldset)
		*oldset = current->blockedSignals;

	if (!set)
		return 0;

	switch (how) {
	case SIG_BLOCK:
		current->blockedSignals |= *set;
		return 0;
	case SIG_UNBLOCK:
		current->blockedSignals &= ~*set;
		return 0;
	case SIG_SETMASK:
		current->blockedSignals = *set;
		return 0;
	default:
		return -EINVAL;
	}
}