/* * The handling of small unions, like the sigval argument to sigqueue, * is architecture dependent. We have adopted the convention that the * value itself is passed in the storage which crosses the kernel * protection boundary. This procedure will accept a scalar argument, * and store it in the appropriate value member of the sigsend_t structure. */ int sigqueue(pid_t pid, int sig, /* union sigval */ void *value, int si_code, int block) { int error; sigsend_t v; sigqhdr_t *sqh; proc_t *p = curproc; /* The si_code value must indicate the signal will be queued */ if (pid <= 0 || !sigwillqueue(sig, si_code)) return (set_errno(EINVAL)); if ((sqh = p->p_sigqhdr) == NULL) { /* Allocate sigqueue pool first time */ sqh = sigqhdralloc(sizeof (sigqueue_t), _SIGQUEUE_MAX); mutex_enter(&p->p_lock); if (p->p_sigqhdr == NULL) { /* hang the pool head on proc */ p->p_sigqhdr = sqh; } else { /* another lwp allocated the pool, free ours */ sigqhdrfree(sqh); sqh = p->p_sigqhdr; } mutex_exit(&p->p_lock); } do { bzero(&v, sizeof (v)); v.sig = sig; v.checkperm = 1; v.sicode = si_code; v.value.sival_ptr = value; if ((error = sigqkill(pid, &v)) != EAGAIN || !block) break; /* block waiting for another chance to allocate a sigqueue_t */ mutex_enter(&sqh->sqb_lock); while (sqh->sqb_count == 0) { if (!cv_wait_sig(&sqh->sqb_cv, &sqh->sqb_lock)) { error = EINTR; break; } } mutex_exit(&sqh->sqb_lock); } while (error == EAGAIN); if (error) return (set_errno(error)); return (0); }
int signotify(int cmd, siginfo_t *siginfo, signotify_id_t *sn_id) { k_siginfo_t info; signotify_id_t id; proc_t *p; proc_t *cp = curproc; signotifyq_t *snqp; struct cred *cr; sigqueue_t *sqp; sigqhdr_t *sqh; u_longlong_t sid; model_t datamodel = get_udatamodel(); if (copyin(sn_id, &id, sizeof (signotify_id_t))) return (set_errno(EFAULT)); if (id.sn_index >= _SIGNOTIFY_MAX || id.sn_index < 0) return (set_errno(EINVAL)); switch (cmd) { case SN_PROC: /* get snid for the given user address of signotifyid_t */ sid = get_sigid(cp, (caddr_t)sn_id); if (id.sn_pid > 0) { mutex_enter(&pidlock); if ((p = prfind(id.sn_pid)) != NULL) { mutex_enter(&p->p_lock); if (p->p_signhdr != NULL) { snqp = SIGN_PTR(p, id.sn_index); if (snqp->sn_snid == sid) { mutex_exit(&p->p_lock); mutex_exit(&pidlock); return (set_errno(EBUSY)); } } mutex_exit(&p->p_lock); } mutex_exit(&pidlock); } if (copyin_siginfo(datamodel, siginfo, &info)) return (set_errno(EFAULT)); /* The si_code value must indicate the signal will be queued */ if (!sigwillqueue(info.si_signo, info.si_code)) return (set_errno(EINVAL)); if (cp->p_signhdr == NULL) { /* Allocate signotify pool first time */ sqh = sigqhdralloc(sizeof (signotifyq_t), _SIGNOTIFY_MAX); mutex_enter(&cp->p_lock); if (cp->p_signhdr == NULL) { /* hang the pool head on proc */ cp->p_signhdr = sqh; } else { /* another lwp allocated the pool, free ours */ sigqhdrfree(sqh); } } else { mutex_enter(&cp->p_lock); } sqp = sigqalloc(cp->p_signhdr); if (sqp == NULL) { mutex_exit(&cp->p_lock); return (set_errno(EAGAIN)); } cr = CRED(); sqp->sq_info = info; sqp->sq_info.si_pid = cp->p_pid; sqp->sq_info.si_ctid = PRCTID(cp); sqp->sq_info.si_zoneid = getzoneid(); sqp->sq_info.si_uid = crgetruid(cr); /* fill the signotifyq_t fields */ ((signotifyq_t *)sqp)->sn_snid = sid; mutex_exit(&cp->p_lock); /* complete the signotify_id_t fields */ id.sn_index = (signotifyq_t *)sqp - SIGN_PTR(cp, 0); id.sn_pid = cp->p_pid; break; case SN_CANCEL: case SN_SEND: sid = get_sigid(cp, (caddr_t)sn_id); mutex_enter(&pidlock); if ((id.sn_pid <= 0) || ((p = prfind(id.sn_pid)) == NULL)) { mutex_exit(&pidlock); return (set_errno(EINVAL)); } mutex_enter(&p->p_lock); mutex_exit(&pidlock); if (p->p_signhdr == NULL) { mutex_exit(&p->p_lock); return (set_errno(EINVAL)); } snqp = SIGN_PTR(p, id.sn_index); if (snqp->sn_snid == 0) { mutex_exit(&p->p_lock); return (set_errno(EINVAL)); } if (snqp->sn_snid != sid) { mutex_exit(&p->p_lock); return (set_errno(EINVAL)); } snqp->sn_snid = 0; /* cmd == SN_CANCEL or signo == 0 (SIGEV_NONE) */ if (((sigqueue_t *)snqp)->sq_info.si_signo <= 0) cmd = SN_CANCEL; sigqsend(cmd, p, 0, (sigqueue_t *)snqp); mutex_exit(&p->p_lock); id.sn_pid = 0; id.sn_index = 0; break; default : return (set_errno(EINVAL)); } if (copyout(&id, sn_id, sizeof (signotify_id_t))) return (set_errno(EFAULT)); return (0); }