/***************************************************************************** * * * DH_SIG.C * * * * Freely redistributable and modifiable. Use at your own risk. * * * * Copyright 1994 The Downhill Project * * * *****************************************************************************/ #if !defined(lint) && !defined(_NOIDENT) static const char* rcsid = "@(#)$RCSfile: dh_sig.c,v $ $Revision: 1.1 $ (DOWNHILL) $Date: 2006/02/07 17:25:06 $"; #endif /* Include stuff *************************************************************/ #include "INCLUDE/DH.H" #include #include #include #include #include #include /* Define stuff ************************************************************ */ /* Signal groupings ======================================================== */ #define DOWNHILL_SIGNAL_REAL_EXIT case SIGABRT: \ case SIGFPE: \ case SIGILL: \ case SIGINT: \ case SIGSEGV: \ case SIGTERM: #define DOWNHILL_SIGNAL_REAL_IGNORE #define DOWNHILL_SIGNAL_FAKE_EXIT case SIGHUP: \ case SIGQUIT: #define DOWNHILL_SIGNAL_FAKE_IGNORE case SIGCHLD: \ case SIGUSR1: \ case SIGUSR2: \ case SIGCONT: \ case SIGTTOU: \ case SIGPIPE: #define DOWNHILL_SIGNAL_ALL DOWNHILL_SIGNAL_REAL_EXIT \ DOWNHILL_SIGNAL_REAL_IGNORE \ DOWNHILL_SIGNAL_FAKE_EXIT \ DOWNHILL_SIGNAL_FAKE_IGNORE /* Struct stuff **************************************************************/ struct downhill_Signal_Struct { void (*signal_Handler)(int,...); int signal_Count; int signal_Extra; sigset_t signal_Mask; int signal_Flags; }; /* Static stuff **************************************************************/ static struct downhill_Signal_Struct* downhill_Signal_Info = NULL; static sigset_t downhill_Sigset_Mask = 0; static int downhill_Signal_Interrupt = FALSE; /* Function stuff ************************************************************/ /* Return if an interrupt has occured ====================================== */ int downhill_Signal_IsInterrupted(void) { downhill_Signal_Interrupt = FALSE; Downhill_Signal_Check(); return downhill_Signal_Interrupt; } /* Handle a signal ========================================================= */ static void downhill_Signal_Handle(int signal_Number,...) { va_list va_List; /* Start up the variable argument stuff */ va_start(va_List,signal_Number); /* Check to see if we're masking this signal */ if (sigismember(&downhill_Sigset_Mask,signal_Number)) { downhill_Signal_Info[signal_Number].signal_Count++; if (signal_Number == SIGFPE) { downhill_Signal_Info[signal_Number].signal_Extra = va_arg(va_List,int); } } else { /* Do a signal's action */ if (downhill_Signal_Info[signal_Number].signal_Handler == (void (*)(int, ...)) SIG_DFL) { switch (signal_Number) { DOWNHILL_SIGNAL_REAL_EXIT DOWNHILL_SIGNAL_FAKE_EXIT exit(3); DOWNHILL_SIGNAL_REAL_IGNORE DOWNHILL_SIGNAL_FAKE_IGNORE break; default: fprintf(stderr, "Unknown signal %d -- ignored\n", signal_Number); } } else if (downhill_Signal_Info[signal_Number].signal_Handler == (void (*)(int, ...)) SIG_IGN) { /* Ignore */ } else { void (*signal_HandlerOld)(int,...); /* Do we reset the handler? */ signal_HandlerOld = downhill_Signal_Info[signal_Number].signal_Handler; #if (_DOWNHILL_POSIX_SOURCE == 0) if (downhill_Signal_Info[signal_Number].signal_Flags& SA_RESETHAND) { downhill_Signal_Info[signal_Number]. signal_Handler = (void (*)(int, ...)) SIG_DFL; } #endif /* Do the action */ if ((signal_Number == SIGCHLD) && (downhill_Signal_Info[signal_Number].signal_Flags& SA_NOCLDSTOP)) { /* Ignore SIGCHLD */ } else { sigset_t sigset_MaskOriginal = downhill_Sigset_Mask; sigset_t sigset_MaskNew = downhill_Signal_Info[ signal_Number].signal_Mask; /* Set the new signal mask */ sigaddset(&sigset_MaskNew,signal_Number); sigprocmask(SIG_BLOCK,&sigset_MaskNew,NULL); /* Execute the handler */ if (signal_Number == SIGFPE) { signal_HandlerOld(signal_Number,va_arg( va_List,int)); } else { signal_HandlerOld(signal_Number); } /* Restore the signal mask */ sigprocmask(SIG_SETMASK,&sigset_MaskOriginal, NULL); /* Does this signal cause an interrupt? */ #if (_DOWNHILL_POSIX_SOURCE == 0) if (downhill_Signal_Info[signal_Number]. signal_Flags&SA_INTERRUPT) { downhill_Signal_Interrupt = TRUE; } #endif } } } } /* Init the signal re-direction ============================================ */ static int downhill_Signal_Init(void) { /* Skip this if we've already done it */ if (downhill_Signal_Info == NULL) { int signal_Index; /* Get some memory */ downhill_Signal_Info = (struct downhill_Signal_Struct *) calloc(sizeof(struct downhill_Signal_Struct),NSIG); if (downhill_Signal_Info == NULL) { errno = ENOMEM; return FALSE; } /* Set everything up */ for (signal_Index = 1;signal_Index < NSIG;signal_Index++) { switch (signal_Index) { DOWNHILL_SIGNAL_REAL_EXIT DOWNHILL_SIGNAL_REAL_IGNORE #undef signal downhill_Signal_Info[signal_Index]. signal_Handler = (void (*)(int, ...)) signal(signal_Index, (void (*)(int)) downhill_Signal_Handle); break; default: downhill_Signal_Info[signal_Index]. signal_Handler = (void (*)(int, ...)) SIG_DFL; break; } } } return TRUE; } /* Set a signal action ===================================================== */ int sigaction(int signal_Number,struct sigaction* sigaction_Info, struct sigaction* sigaction_InfoOld) { /* Make sure we're init'd */ if (!downhill_Signal_Init()) { return -1; } /* Set the signal */ switch (signal_Number) { DOWNHILL_SIGNAL_ALL if (sigaction_InfoOld != NULL) { sigaction_InfoOld->sa_handler = (void (*)(void)) downhill_Signal_Info[signal_Number]. signal_Handler; sigaction_InfoOld->sa_mask = downhill_Signal_Info[signal_Number]. signal_Mask; sigaction_InfoOld->sa_flags = downhill_Signal_Info[signal_Number]. signal_Flags; } if (sigaction_Info != NULL) { downhill_Signal_Info[signal_Number]. signal_Handler = (void (*)(int, ...)) sigaction_Info->sa_handler; downhill_Signal_Info[signal_Number]. signal_Count = 0; downhill_Signal_Info[signal_Number]. signal_Extra = 0; downhill_Signal_Info[signal_Number]. signal_Mask = sigaction_Info->sa_mask; downhill_Signal_Info[signal_Number]. signal_Flags = sigaction_Info->sa_flags; } break; default: errno = EINVAL; return -1; } return 0; } /* Set the action of a signal ============================================== */ void (*Downhill_Signal_Set(int signal_Number, void (*signal_Handler)(int,...)))(int,...) { void (*signal_HandlerOld)(int,...); /* Make sure we're init'd */ if (!downhill_Signal_Init()) { return (void (*)(int, ...)) SIG_ERR; } /* Make set the signal */ switch (signal_Number) { DOWNHILL_SIGNAL_ALL signal_HandlerOld = downhill_Signal_Info[signal_Number].signal_Handler; downhill_Signal_Info[signal_Number].signal_Handler = signal_Handler; downhill_Signal_Info[signal_Number].signal_Count = 0; downhill_Signal_Info[signal_Number].signal_Extra = 0; downhill_Signal_Info[signal_Number].signal_Mask = 0; downhill_Signal_Info[signal_Number].signal_Flags = 0; return signal_HandlerOld; } errno = EINVAL; return (void (*)(int, ...)) SIG_ERR; } /* Add a signal to a set =================================================== */ int sigaddset(sigset_t* sigset_Info,int signal_Number) { switch (signal_Number) { DOWNHILL_SIGNAL_ALL (*sigset_Info) |= ~1< 0) { sigaddset(sigset_Info,signal_Index); } } return 0; } /* Change the blocked signals ============================================== */ int sigprocmask(int mask_Function,sigset_t* sigset_Info, sigset_t* sigset_InfoOld) { int signal_Index; sigset_t sigset_MaskOld = downhill_Sigset_Mask; /* Make sure we're init'd */ if (!downhill_Signal_Init()) { return -1; } /* Return the current value */ if (sigset_InfoOld != NULL) { *sigset_InfoOld = sigset_MaskOld; } /* Set the new mask */ switch (mask_Function) { case SIG_BLOCK: downhill_Sigset_Mask |= (*sigset_Info); break; case SIG_UNBLOCK: /* DOME */ break; case SIG_SETMASK: if (sigset_Info != NULL) { downhill_Sigset_Mask = *sigset_Info; } break; default: errno = EINVAL; return -1; } /* And release any signals that were pending */ for (signal_Index = 1;signal_Index < NSIG;signal_Index++) { if ((!sigismember(&downhill_Sigset_Mask,signal_Index)) && (sigismember(&sigset_MaskOld,signal_Index)) && (downhill_Signal_Info[signal_Index].signal_Count > 0)) { if (signal_Index == SIGFPE) { downhill_Signal_Handle(signal_Index, downhill_Signal_Info[signal_Index]. signal_Extra); } else { downhill_Signal_Handle(signal_Index); } } } return 0; } /* Suspend the process until a signal ====================================== */ int sigsuspend(sigset_t* sigset_Info) { sigset_t sigset_MaskOriginal = downhill_Sigset_Mask; /* Set the new mask */ sigprocmask(SIG_SETMASK,sigset_Info,NULL); /* Wait for the signal */ pause(); /* Reset the old mask */ sigprocmask(SIG_SETMASK,&sigset_MaskOriginal,NULL); return -1; } /* Raise a signal ========================================================== */ int Downhill_Signal_Raise(int signal_Number) { if (!downhill_Signal_Init()) { return -1; } /* Raise the signal */ switch (signal_Number) { DOWNHILL_SIGNAL_ALL downhill_Signal_Handle(signal_Number); break; default: errno = EINVAL; return -1; } return 0; } /* Set signal mask ========================================================= */ #if (_DOWNHILL_POSIX_SOURCE == 0) unsigned long sigsetmask(unsigned long signal_MaskNew) { unsigned long signal_MaskOld = downhill_Sigset_Mask; if (sigprocmask(SIG_SETMASK,(sigset_t*)(&signal_MaskNew),NULL) == -1) { return (unsigned long)-1; } return signal_MaskOld; } #endif /* Add signals to mask ===================================================== */ #if (_DOWNHILL_POSIX_SOURCE == 0) unsigned long sigblock(unsigned long signal_MaskNew) { /* Block a specific group of signals */ return sigsetmask(downhill_Sigset_Mask|signal_MaskNew); } #endif /* Hold a signal =========================================================== */ #if (_DOWNHILL_POSIX_SOURCE == 0) int sighold(int signal_Number) { /* Block a specific signal */ if (sigblock(sigmask(signal_Number)) == -1) { return -1; } return 0; } #endif /* Release a signal ======================================================== */ #if (_DOWNHILL_POSIX_SOURCE == 0) int sigrelse(int signal_Number) { /* Release a specific signal */ if (sigsetmask(downhill_Sigset_Mask&(~sigmask(signal_Number))) == -1) { return -1; } return 0; } #endif /* Check for faked SIGCHLD signals ========================================= */ void Downhill_Signal_CheckSigchld(void) { pid_t process_Id; /* See if any children are no longer there */ process_Id = downhill_Process_GetStatusAny(NULL); if (process_Id > 0) { if (!downhill_Process_IsSignaled(process_Id)) { downhill_Process_Signal(process_Id); Downhill_Signal_Raise(SIGCHLD); } } } /* Check for faked SIGUSR1 signals ========================================= */ void Downhill_Signal_CheckSigusr1(void) { } /* Check for faked SIGUSR2 signals ========================================= */ void Downhill_Signal_CheckSigusr2(void) { } /* Check for faked SIGHUP signals ========================================== */ void Downhill_Signal_CheckSighup(void) { } /* Check for faked SIGQUIT signals ========================================= */ void Downhill_Signal_CheckSigquit(void) { } /* Check for faked SIGCONT signals ========================================= */ void Downhill_Signal_CheckSigcont(void) { } /* Check for faked SIGTTOU signals ========================================= */ void Downhill_Signal_CheckSigttou(void) { } /* Check for faked SIGPIPE signals ========================================= */ void Downhill_Signal_CheckSigpipe(void) { } /* Check for faked signals ================================================= */ void Downhill_Signal_Check(void) { /* Check all the dummied signals */ Downhill_Signal_CheckSigchld(); Downhill_Signal_CheckSigusr1(); Downhill_Signal_CheckSigusr2(); Downhill_Signal_CheckSighup(); Downhill_Signal_CheckSigquit(); Downhill_Signal_CheckSigcont(); Downhill_Signal_CheckSigttou(); Downhill_Signal_CheckSigpipe(); }