BarryServer : Git

All the code for all my projects
// BarryServer : Git / Nucleus / commit / 9d6eb508c283ff07934a3007f68d4f0c933d5430 / task / signals.c

// Related

Nucleus

Barry Signals and small task functions 9d6eb50 (3 years, 2 months ago)
diff --git a/task/signals.c b/task/signals.c
new file mode 100644
index 0000000..47d8c9b
--- /dev/null
+++ b/task/signals.c
@@ -0,0 +1,126 @@
+/*
+ * 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 <signal.h>
+#include <errno.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;
+	}
+}