1226f694e6
gets signals operating based on a TailQ, and is good enough to run X11, GNOME, and do job control. There are some intricate parts which could be more refined to match the sigset_t versions, but those require further evaluation of directions in which our signal system can expand and contract to fit our needs. After this has been in the tree for a while, I will make in kernel API changes, most notably to trapsignal(9) and sendsig(9), to use ksiginfo more robustly, such that we can actually pass information with our (queued) signals to the userland. That will also result in using a struct ksiginfo pointer, rather than a signal number, in a lot of kern_sig.c, to refer to an individual pending signal queue member, but right now there is no defined behaviour for such. CODAFS is unfinished in this regard because the logic is unclear in some places. Sponsored by: New Gold Technology Reviewed by: bde, tjr, jake [an older version, logic similar]
302 lines
6.2 KiB
C
302 lines
6.2 KiB
C
/*-
|
|
* Copyright (c) 2002 New Gold Technology. All rights reserved.
|
|
* Copyright (c) 2002 Juli Mallett. All rights reserved.
|
|
*
|
|
* This software was written by Juli Mallett <jmallett@FreeBSD.org> for the
|
|
* FreeBSD project. Redistribution and use in source and binary forms, with
|
|
* or without modification, are permitted provided that the following
|
|
* conditions are met:
|
|
*
|
|
* 1. Redistribution of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* 2. Redistribution in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/kernel.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/signalvar.h>
|
|
#include <sys/proc.h>
|
|
#include <sys/errno.h>
|
|
#include <sys/lock.h>
|
|
#include <sys/malloc.h>
|
|
#include <sys/mutex.h>
|
|
#include <sys/signal.h>
|
|
#include <sys/ksiginfo.h>
|
|
|
|
MALLOC_DEFINE(M_KSIGINFO, "ksiginfos", "Kernel signal info structures");
|
|
|
|
int
|
|
ksiginfo_alloc(struct ksiginfo **ksip, int signo)
|
|
{
|
|
int error;
|
|
struct ksiginfo *ksi;
|
|
|
|
error = 0;
|
|
|
|
ksi = malloc(sizeof *ksi, M_KSIGINFO, M_ZERO | M_WAITOK);
|
|
KASSERT(ksi != NULL, ("ksiginfo_alloc(%d): allocation failed.", signo));
|
|
if (ksi == NULL) {
|
|
error = ENOMEM;
|
|
goto out;
|
|
}
|
|
ksi->ksi_signo = signo;
|
|
if (curproc != NULL) {
|
|
ksi->ksi_pid = curproc->p_pid;
|
|
ksi->ksi_ruid = curproc->p_ucred->cr_uid;
|
|
}
|
|
out:
|
|
*ksip = ksi;
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
ksiginfo_dequeue(struct ksiginfo **ksip, struct proc *p, int signo)
|
|
{
|
|
int error;
|
|
struct ksiginfo *ksi;
|
|
|
|
error = 0;
|
|
ksi = NULL;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (TAILQ_EMPTY(&p->p_sigq)) {
|
|
error = EDOOFUS;
|
|
goto out;
|
|
}
|
|
if (!signo) {
|
|
ksi = TAILQ_FIRST(&p->p_sigq);
|
|
goto out;
|
|
}
|
|
TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) {
|
|
if (ksi->ksi_signo == signo)
|
|
goto out;
|
|
}
|
|
error = ESRCH;
|
|
ksi = NULL;
|
|
out:
|
|
if (ksi != NULL)
|
|
TAILQ_REMOVE(&p->p_sigq, ksi, ksi_queue);
|
|
*ksip = ksi;
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
ksiginfo_destroy(struct ksiginfo **ksip)
|
|
{
|
|
int error;
|
|
struct ksiginfo *ksi;
|
|
|
|
error = 0;
|
|
|
|
ksi = *ksip;
|
|
if (ksi == NULL) {
|
|
error = EDOOFUS;
|
|
goto out;
|
|
}
|
|
free(ksi, M_KSIGINFO);
|
|
ksi = NULL;
|
|
out:
|
|
*ksip = ksi;
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
ksiginfo_to_sigset_t(struct proc *p, sigset_t *setp)
|
|
{
|
|
int error;
|
|
sigset_t set;
|
|
struct ksiginfo *ksi;
|
|
|
|
error = 0;
|
|
SIGEMPTYSET(set);
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
/*
|
|
* We could set EDOOFUS here, however if there are no queued
|
|
* signals, then an empty signal set _is_ valid.
|
|
*/
|
|
if (TAILQ_EMPTY(&p->p_sigq))
|
|
goto out;
|
|
TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue)
|
|
SIGADDSET(set, ksi->ksi_signo);
|
|
out:
|
|
*setp = set;
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
signal_add(struct proc *p, struct ksiginfo *ksi, int signo)
|
|
{
|
|
int error;
|
|
|
|
error = 0;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (ksi == NULL) {
|
|
PROC_UNLOCK(p);
|
|
error = ksiginfo_alloc(&ksi, signo);
|
|
PROC_LOCK(p);
|
|
if (error)
|
|
goto out;
|
|
}
|
|
TAILQ_INSERT_HEAD(&p->p_sigq, ksi, ksi_queue);
|
|
out:
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
signal_delete(struct proc *p, struct ksiginfo *ksi, int signo)
|
|
{
|
|
int error;
|
|
|
|
error = 0;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (ksi == NULL) {
|
|
while (signal_queued(p, signo)) {
|
|
error = ksiginfo_dequeue(&ksi, p, signo);
|
|
if (error)
|
|
goto out;
|
|
error = ksiginfo_destroy(&ksi);
|
|
if (error)
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
if (ksi != NULL) {
|
|
TAILQ_REMOVE(&p->p_sigq, ksi, ksi_queue);
|
|
ksiginfo_destroy(&ksi);
|
|
}
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
signal_delete_mask(struct proc *p, int mask)
|
|
{
|
|
int error;
|
|
struct ksiginfo *ksi, *prev;
|
|
|
|
error = 0;
|
|
ksi = prev = NULL;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (TAILQ_EMPTY(&p->p_sigq))
|
|
goto out;
|
|
TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) {
|
|
if (prev != NULL) {
|
|
TAILQ_REMOVE(&p->p_sigq, prev, ksi_queue);
|
|
error = ksiginfo_destroy(&prev);
|
|
if (error)
|
|
goto out;
|
|
}
|
|
if (sigmask(ksi->ksi_signo) & mask)
|
|
prev = ksi;
|
|
}
|
|
if (prev != NULL) {
|
|
TAILQ_REMOVE(&p->p_sigq, prev, ksi_queue);
|
|
error = ksiginfo_destroy(&prev);
|
|
/*
|
|
* XXX - Could just fall off the bottom...
|
|
*/
|
|
if (error)
|
|
goto out;
|
|
}
|
|
out:
|
|
return (error);
|
|
}
|
|
|
|
int
|
|
signal_pending(struct proc *p)
|
|
{
|
|
int error, pending;
|
|
sigset_t set;
|
|
|
|
error = 0;
|
|
pending = 0;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (TAILQ_EMPTY(&p->p_sigq))
|
|
goto out;
|
|
if (p->p_flag & P_TRACED) {
|
|
pending = 1;
|
|
goto out;
|
|
}
|
|
error = ksiginfo_to_sigset_t(p, &set);
|
|
if (error)
|
|
goto out;
|
|
pending = !sigsetmasked(&set, &p->p_sigmask);
|
|
if (pending)
|
|
goto out;
|
|
out:
|
|
return (pending);
|
|
}
|
|
|
|
int
|
|
signal_queued(struct proc *p, int signo)
|
|
{
|
|
int error, pending;
|
|
struct ksiginfo *ksi;
|
|
|
|
error = 0;
|
|
pending = 0;
|
|
ksi = NULL;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (TAILQ_EMPTY(&p->p_sigq))
|
|
goto out;
|
|
/*
|
|
* Since we know the queue is not empty, we can just do
|
|
* pending = TAILQ_FIRST(&p->p_sigq)->ksi_signo, if the
|
|
* signo is 0, however since we have to use at least one
|
|
* more TailQ manipulation macro either way, might as well
|
|
* just do it like this, as I think it optimises better,
|
|
* even if the failure case is more expensive.
|
|
*/
|
|
TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) {
|
|
pending = !signo || ksi->ksi_signo == signo;
|
|
if (pending)
|
|
goto out;
|
|
}
|
|
out:
|
|
return (pending);
|
|
}
|
|
|
|
int
|
|
signal_queued_mask(struct proc *p, sigset_t mask)
|
|
{
|
|
int pending;
|
|
struct ksiginfo *ksi;
|
|
|
|
pending = 0;
|
|
ksi = NULL;
|
|
|
|
PROC_LOCK_ASSERT(p, MA_OWNED);
|
|
if (TAILQ_EMPTY(&p->p_sigq))
|
|
goto out;
|
|
TAILQ_FOREACH(ksi, &p->p_sigq, ksi_queue) {
|
|
if (SIGISMEMBER(mask, ksi->ksi_signo)) {
|
|
pending = ksi->ksi_signo;
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
return (pending);
|
|
}
|