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;
+ }
+}