mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 13:32:33 +01:00
452 lines
11 KiB
C
452 lines
11 KiB
C
/* ==== sig.c =======================================================
|
|
* Copyright (c) 1994 by Chris Provenzano, proven@mit.edu
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions 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.
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
* must display the following acknowledgement:
|
|
* This product includes software developed by Chris Provenzano.
|
|
* 4. The name of Chris Provenzano may not be used to endorse or promote
|
|
* products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``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 CHRIS PROVENZANO 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.
|
|
*
|
|
* Description : All the thread signal functions.
|
|
*
|
|
* 1.32 94/06/12 proven
|
|
* -Started coding this file.
|
|
*/
|
|
|
|
#ifndef lint
|
|
static const char rcsid[] = "$Id$";
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
|
|
#if defined(M_UNIX)
|
|
#define signal(A,B) machdep_sys_signal((A),(B))
|
|
#endif
|
|
|
|
extern void sig_handler_real();
|
|
|
|
struct pthread * pthread_sigwait;
|
|
static sigset_t pending_signals;
|
|
|
|
struct pthread_sigvec {
|
|
void (*vector)();
|
|
sigset_t mask;
|
|
int flags;
|
|
} pthread_sigvec[SIGMAX];
|
|
|
|
/* ==========================================================================
|
|
* pthread_sig_register()
|
|
*
|
|
* Assumes the kernel is locked.
|
|
*/
|
|
int pthread_sig_register(int sig)
|
|
{
|
|
struct pthread ** pthread_ptr, * pthread;
|
|
int ret;
|
|
|
|
/*
|
|
* If we have a siginfo structure and the signal is synchronous then
|
|
* only deliver the signal to the current thread.
|
|
*/
|
|
|
|
/* Check waiting threads for delivery */
|
|
for (pthread_ptr = &pthread_sigwait; (*pthread_ptr);
|
|
pthread_ptr = &((*pthread_ptr)->next)) {
|
|
if (sigismember((*pthread_ptr)->data.sigwait, sig)) {
|
|
pthread=*pthread_ptr;
|
|
*pthread_ptr=(*pthread_ptr)->next;
|
|
|
|
pthread_prio_queue_enq(pthread_current_prio_queue, pthread);
|
|
ret = pthread->pthread_priority;
|
|
*(int *)(pthread->ret) = sig;
|
|
pthread->state = PS_RUNNING;
|
|
|
|
return(ret);
|
|
}
|
|
}
|
|
|
|
/* Check current running thread */
|
|
if (pthread_run) {
|
|
if (!sigismember(&pthread_run->sigmask, sig)) {
|
|
sigaddset(&pthread_run->sigpending, sig);
|
|
pthread_run->sigcount++;
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/* Check any running thread */
|
|
for (pthread = pthread_current_prio_queue->next;
|
|
pthread; pthread = pthread->next) {
|
|
if (!sigismember(&pthread->sigmask, sig)) {
|
|
sigaddset(&pthread->sigpending, sig);
|
|
pthread->sigcount++;
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
/* Check any thread */
|
|
for (pthread = pthread_link_list; pthread; pthread = pthread->pll) {
|
|
if (!sigismember(&pthread->sigmask, sig)) {
|
|
sigaddset(&pthread->sigpending, sig);
|
|
pthread->sigcount++;
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
sigaddset(&pending_signals, sig);
|
|
return(0);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* pthread_sig_default()
|
|
*/
|
|
void pthread_sig_default(int sig)
|
|
{
|
|
sigset_t mask, omask;
|
|
|
|
if (pthread_sigvec[sig].vector == SIG_DFL) {
|
|
/* Set the signal handler to default before issueing the kill */
|
|
signal(sig, SIG_DFL);
|
|
kill(getpid(), sig);
|
|
sigemptyset(&mask);
|
|
sigaddset(&mask, sig);
|
|
machdep_sys_sigprocmask(SIG_UNBLOCK, &mask, &omask);
|
|
signal(sig, sig_handler_real);
|
|
}
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* pthread_sig_process()
|
|
*
|
|
* Assumes the kernel is locked.
|
|
*/
|
|
void pthread_sig_process()
|
|
{
|
|
void (*vector)();
|
|
int i, j;
|
|
|
|
for (i = 1; i < SIGMAX; i++) {
|
|
if (sigismember(&(pthread_run->sigpending), i)) {
|
|
if (! sigismember(&(pthread_run->sigmask), i)) {
|
|
sigdelset(&(pthread_run->sigpending), i);
|
|
pthread_run->sigcount--;
|
|
|
|
if (pthread_sigvec[i].vector == SIG_IGN) {
|
|
continue;
|
|
}
|
|
if (pthread_sigvec[i].vector == SIG_DFL) {
|
|
pthread_sig_default(i);
|
|
continue;
|
|
}
|
|
|
|
{
|
|
sigset_t omask;
|
|
|
|
sigemptyset(&omask);
|
|
/* Save old mask */
|
|
for (j = 1; j < SIGMAX; j++) {
|
|
if (sigismember(&(pthread_run->sigmask), j)) {
|
|
if (sigismember(&(pthread_sigvec[i].mask), j))
|
|
sigaddset(&(pthread_run->sigmask), j);
|
|
sigaddset(&omask, j);
|
|
}
|
|
}
|
|
/* The signal is masked while handling the signal */
|
|
sigaddset(&(pthread_run->sigmask), i);
|
|
|
|
/*
|
|
* Allow interrupts during a signal,
|
|
* but not a change in the vector
|
|
*/
|
|
vector = pthread_sigvec[i].vector;
|
|
if (--pthread_kernel_lock) {
|
|
PANIC();
|
|
}
|
|
vector(i);
|
|
pthread_run->sighandled=1; /* Mark for select; Monty */
|
|
pthread_kernel_lock++;
|
|
|
|
memcpy(&(pthread_run->sigmask), &omask, sizeof(omask));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* pthread_sigmask()
|
|
*
|
|
* It is unclear wheather this call should be implemented as an atomic
|
|
* operation. The resulting mask could be wrong if in the signal
|
|
* handler the thread calls sigprocmask for any signal other than the
|
|
* signal the handler is dealing with.
|
|
*/
|
|
int pthread_sigmask(int how, const sigset_t *set, sigset_t * oset)
|
|
{
|
|
int i;
|
|
|
|
if (oset) {
|
|
sigemptyset(oset);
|
|
for (i = 1; i < SIGMAX; i++) {
|
|
if (sigismember(&(pthread_run->sigmask), i)) {
|
|
sigaddset(oset, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (set) {
|
|
switch(how) {
|
|
case SIG_BLOCK:
|
|
for (i = 1; i < SIGMAX; i++) {
|
|
if (sigismember(set, i)) {
|
|
sigaddset(&(pthread_run->sigmask), i);
|
|
}
|
|
}
|
|
break;
|
|
case SIG_UNBLOCK:
|
|
pthread_sched_prevent();
|
|
for (i = 1; i < SIGMAX; i++) {
|
|
if (sigismember(set, i)) {
|
|
sigdelset(&(pthread_run->sigmask), i);
|
|
if (sigismember(&pending_signals, i)) {
|
|
sigaddset(&(pthread_run->sigpending), i);
|
|
sigdelset(&pending_signals, i);
|
|
pthread_run->sigcount++;
|
|
}
|
|
}
|
|
}
|
|
pthread_sched_resume();
|
|
break;
|
|
case SIG_SETMASK:
|
|
sigfillset(&(pthread_run->sigmask));
|
|
pthread_sched_prevent();
|
|
for (i = 1; i < SIGMAX; i++) {
|
|
if (! sigismember(set, i)) {
|
|
sigdelset(&(pthread_run->sigmask), i);
|
|
if (sigismember(&pending_signals, i)) {
|
|
sigaddset(&(pthread_run->sigpending), i);
|
|
sigdelset(&pending_signals, i);
|
|
pthread_run->sigcount++;
|
|
}
|
|
}
|
|
}
|
|
pthread_sched_resume();
|
|
break;
|
|
default:
|
|
SET_ERRNO(EINVAL);
|
|
return(NOTOK);
|
|
}
|
|
}
|
|
return(OK);
|
|
}
|
|
|
|
int sigprocmask(int how, const sigset_t *set, sigset_t * oset)
|
|
{
|
|
return(pthread_sigmask(how, set, oset));
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* sigwait()
|
|
*/
|
|
int sigwait(const sigset_t * set, int * sig)
|
|
{
|
|
int i;
|
|
|
|
/* Check that sig is valid */
|
|
*sig = 0;
|
|
|
|
pthread_sched_prevent();
|
|
for (i = 1; i < SIGMAX; i++) {
|
|
if (sigismember(set, i)) {
|
|
/* Check personal signals */
|
|
if (sigismember(&(pthread_run->sigpending), i)) {
|
|
sigdelset(&(pthread_run->sigpending), i);
|
|
pthread_sched_resume();
|
|
*sig = i;
|
|
return(OK);
|
|
}
|
|
/* Check kernel signals */
|
|
if (sigismember(&pending_signals, i)) {
|
|
sigdelset(&pending_signals, i);
|
|
pthread_sched_resume();
|
|
*sig = i;
|
|
return(OK);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* No pending signals, wait for one */
|
|
pthread_run->next = pthread_sigwait;
|
|
pthread_sigwait = pthread_run;
|
|
pthread_run->data.sigwait = set;
|
|
pthread_run->ret = sig;
|
|
|
|
SET_PF_AT_CANCEL_POINT(pthread_run); /* This is a cancel point */
|
|
pthread_resched_resume(PS_SIGWAIT);
|
|
CLEAR_PF_AT_CANCEL_POINT(pthread_run); /* No longer at cancel point */
|
|
|
|
return(OK);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* raise()
|
|
*/
|
|
int raise(int sig)
|
|
{
|
|
return(pthread_kill(pthread_self(), sig));
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* sigsuspend()
|
|
*/
|
|
int sigsuspend(const sigset_t * mask)
|
|
{
|
|
int ret_sig, ret;
|
|
sigset_t nm, om;
|
|
|
|
sigfillset(&nm);
|
|
for(ret_sig = 1; ret_sig < SIGMAX; ret_sig++) {
|
|
if (sigismember(mask, ret_sig)) {
|
|
sigdelset(&nm, ret_sig);
|
|
}
|
|
}
|
|
pthread_sigmask(SIG_BLOCK, &nm, &om);
|
|
if ((ret = sigwait(&nm, &ret_sig)) == OK) {
|
|
sigemptyset(&nm);
|
|
sigaddset(&nm, ret_sig);
|
|
pthread_kill(pthread_self(), ret_sig);
|
|
pthread_sigmask(SIG_UNBLOCK, &nm, NULL);
|
|
/* There is a race condition here, it's not worth worring about */
|
|
pthread_sigmask(SIG_BLOCK, &nm, NULL);
|
|
SET_ERRNO(EINTR);
|
|
ret = NOTOK;
|
|
}
|
|
pthread_sigmask(SIG_SETMASK, &om, NULL);
|
|
return(ret);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* pthread_signal()
|
|
*/
|
|
void (*pthread_signal(int sig, void (*dispatch)(int)))()
|
|
{
|
|
void (*odispatch)(int);
|
|
|
|
odispatch = pthread_sigvec[sig].vector;
|
|
if ((sig > 0) && (sig < SIGMAX)) {
|
|
pthread_sigvec[sig].vector = dispatch;
|
|
sigemptyset(&(pthread_sigvec[sig].mask));
|
|
pthread_sigvec[sig].flags = 0;
|
|
}
|
|
return(odispatch);
|
|
}
|
|
|
|
/* ==========================================================================
|
|
* pthread_sigprocmask()
|
|
*/
|
|
int pthread_sigaction(int sig, const struct sigaction * act,
|
|
struct sigaction * oact)
|
|
{
|
|
if ((sig > 0) && (sig < SIGMAX)) {
|
|
if (oact) {
|
|
memcpy(&(oact->sa_mask), &(pthread_sigvec[sig].mask),
|
|
sizeof(sigset_t));
|
|
oact->sa_handler = pthread_sigvec[sig].vector;
|
|
oact->sa_flags = pthread_sigvec[sig].flags;
|
|
}
|
|
if (act) {
|
|
memcpy(&(pthread_sigvec[sig].mask), &(act->sa_mask),
|
|
sizeof(sigset_t));
|
|
pthread_sigvec[sig].vector = act->sa_handler;
|
|
pthread_sigvec[sig].flags = act->sa_flags;
|
|
}
|
|
return(OK);
|
|
}
|
|
SET_ERRNO(EINVAL);
|
|
return(NOTOK);
|
|
}
|
|
|
|
/*
|
|
* The following here are stolen from BSD because I get mutiply defined
|
|
* symbols between sig.o and posix_sig.o in Sun's libc.a under Sunos 4.1.3.
|
|
* The problem is that sigprocmask() is defined in posix_sig.o, in the same
|
|
* module that a lot of other sigset-primitives are defined, and we have
|
|
* our definition of sigprocmask() here, but use those other primitives.
|
|
*/
|
|
|
|
#undef sigemptyset
|
|
#undef sigfillset
|
|
#undef sigaddset
|
|
#undef sigdelset
|
|
#undef sigismember
|
|
|
|
static const sigset_t __sigemptyset = __SIGEMPTYSET;
|
|
int sigemptyset(sigset_t *set)
|
|
{
|
|
*set = __sigemptyset;
|
|
return (0);
|
|
}
|
|
|
|
static const sigset_t __sigfillset = __SIGFILLSET;
|
|
int sigfillset(sigset_t * set)
|
|
{
|
|
*set = __sigfillset;
|
|
return (0);
|
|
}
|
|
|
|
#define _MAXIMUM_SIG NSIG
|
|
|
|
int sigaddset(sigset_t *set, int signo)
|
|
{
|
|
if (signo <= 0 || signo >= _MAXIMUM_SIG) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
__SIGADDSET(set, signo);
|
|
return (0);
|
|
}
|
|
|
|
int sigdelset(sigset_t *set, int signo)
|
|
{
|
|
if (signo <= 0 || signo >= _MAXIMUM_SIG) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
__SIGDELSET(set, signo);
|
|
return (0);
|
|
}
|
|
|
|
int sigismember(const sigset_t *set, int signo)
|
|
{
|
|
if (signo <= 0 || signo >= _MAXIMUM_SIG) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
return(__SIGISMEMBER(set, signo));
|
|
}
|
|
|