BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / blob / master / task / signals.c

// Related

Nucleus

Barry System headers (remove libc dependency) 18495cf (3 years, 2 months ago)
/*
 * This file implements the Signals namespace and the associated signal
 * functions.  It registers and dispatches signals to tasks and allows them to
 * register signal handlers, which it runs when appropriate.
 */

#include <sys/errno.h>
#include <sys/signal.h>
#include <nucleus/memory.h>
#include <nucleus/object.h>
#include <nucleus/task.h>

/* Signals namespace */
struct Signals {
	Object obj;
	sighandler_t sig_handler[32];
	sigset_t sigset;
	sigset_t blocked;
};

static void signals_copy(Object *, Object *);

/* Signals object type */
ObjectType signalsType = {
	.name = "SIGNALS",
	.size = sizeof(Signals),
	.copy = signals_copy,
};

/* Copy a Signals object */
static void
signals_copy(Object *a, Object *b)
{
	Signals *sa = (void *) a, *sb = (void *) b;
	int i;
	for (i = 0; i < 32; i++)
		sb->sig_handler[i] = sa->sig_handler[i];
	sb->sigset = sa->sigset;
	sb->blocked = sa->blocked;
}

/* Send a signal to a task */
void
send_signal(Task *target, int sig)
{
	target->signals->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_signal(task, sig);

	return 0;
}

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

	size_t sent = 0;
	Task *task;
	foreach (taskType.objects, task) {
		if (task->tgid != pid)
			continue;
		if (sig)
			send_signal(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 - 1];
	current->signals->sig_handler[signum - 1] = handler;
	return old;
}

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

	if (oldset)
		*oldset = current->signals->blocked;
	if (!set)
		return 0;

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