/* * 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 #include #include #include #include /* 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; } }