diff options
Diffstat (limited to 'win32/signal.c')
| -rw-r--r-- | win32/signal.c | 728 |
1 files changed, 728 insertions, 0 deletions
diff --git a/win32/signal.c b/win32/signal.c new file mode 100644 index 000000000000..facede8c40f0 --- /dev/null +++ b/win32/signal.c @@ -0,0 +1,728 @@ +/*$Header: /p/tcsh/cvsroot/tcsh/win32/signal.c,v 1.12 2010/05/13 22:04:17 amold Exp $*/ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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. + */ + +/* + * signal.c: Signal emulation hacks. + * -amol + * + */ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <errno.h> +#include <stdlib.h> +#include "ntport.h" +#include "forkdata.h" +#include "signal.h" + +#pragma warning(disable:4055) + +#define SIGBAD(signo) ( (signo) <=0 || (signo) >=NSIG) +#define fast_sigmember(a,b) ( (*(a) & (1 << (b-1)) ) ) +#define inc_pending(a) (gPending[(a)]+=1) + +#define suspend_main_thread() SuspendThread(hmainthr) +#define resume_main_thread() ResumeThread(hmainthr) + +int generic_handler(DWORD); +int ctrl_handler(DWORD); + +typedef struct _child_list { + DWORD dwProcessId; + DWORD exitcode; + struct _child_list *next; +}ChildListNode; + +Sigfunc *handlers[NSIG]={0}; +static unsigned long gPending[NSIG]={0}; +static unsigned long gBlockMask = 0; + +static ChildListNode *clist_h; //head of list +static ChildListNode *clist_t; // tail of list + +static CRITICAL_SECTION sigcritter; +static HANDLE hmainthr; +static HANDLE hsigsusp; +static int __is_suspended = 0; +static HANDLE __halarm=0; + +extern HANDLE __h_con_alarm,__h_con_int, __h_con_hup; + +// must be done before fork; +void nt_init_signals(void) { + + SetConsoleCtrlHandler((PHANDLER_ROUTINE)ctrl_handler,TRUE); + InitializeCriticalSection(&sigcritter); + + clist_t = clist_h = NULL; + + + if (!DuplicateHandle(GetCurrentProcess(), + GetCurrentThread(), + GetCurrentProcess(), + &hmainthr, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)){ + ExitProcess(GetLastError()); + } + hsigsusp = CreateEvent(NULL,FALSE,FALSE,NULL); + __h_con_alarm=CreateEvent(NULL,FALSE,FALSE,NULL); + __h_con_int=CreateEvent(NULL,FALSE,FALSE,NULL); + __h_con_hup=CreateEvent(NULL,FALSE,FALSE,NULL); + if (!hsigsusp) + abort(); + +} +void nt_cleanup_signals(void) { + if (__forked) + return; + DeleteCriticalSection(&sigcritter); + CloseHandle(hmainthr); + CloseHandle(hsigsusp); + CloseHandle(__h_con_alarm); + CloseHandle(__h_con_int); + CloseHandle(__h_con_hup); + CloseHandle(__halarm); +} +int sigaddset(sigset_t *set, int signo) { + + if (SIGBAD(signo)) { + errno = EINVAL; + return -1; + } + *set |= 1 << (signo-1); + return 0; +} +int sigdelset(sigset_t *set, int signo) { + if (SIGBAD(signo)) { + errno = EINVAL; + return -1; + } + *set &= ~( 1 << (signo-1)); + + return 0; + +} +int sigismember(const sigset_t *set, int signo) { + if (SIGBAD(signo)) { + errno = EINVAL; + return -1; + } + + return ( (*set & (1 <<(signo-1)) ) != 0); + +} +void deliver_pending(void) { + unsigned long temp; + int sig=1; + + temp = ~gBlockMask; + while(temp && (sig < NSIG)) { + + if (temp & 0x01){ + if (gPending[sig]){ + //gPending[sig]=0; + do { + dprintf("deliver_pending for sig %d\n",sig); + gPending[sig]--; + generic_handler(sig); + }while(gPending[sig] != 0); + } + } + temp >>= 1; + sig++; + } +} +int sigprocmask(int how, const sigset_t *set, sigset_t*oset) { + + if (oset) + *oset = gBlockMask; + if (set) { + switch (how) { + case SIG_BLOCK: + gBlockMask |= *set; + break; + case SIG_UNBLOCK: + gBlockMask &= (~(*set)); + break; + case SIG_SETMASK: + gBlockMask = *set; + break; + default: + break; + } + } + if (how != SIG_BLOCK) + deliver_pending(); + + return 0; + +} +int sigsuspend(const sigset_t *mask) { + sigset_t omask; + + + EnterCriticalSection(&sigcritter); + __is_suspended++; + LeaveCriticalSection(&sigcritter); + + sigprocmask(SIG_SETMASK,mask,&omask); + + dprintf("suspending main thread susp count %d\n",__is_suspended); + do { + WaitForSingleObject(hsigsusp,INFINITE); + }while(__is_suspended > 0); + + + sigprocmask(SIG_SETMASK,&omask,0); + errno = EINTR; + return -1; + +} + +int sigaction(int signo, const struct sigaction *act, struct sigaction *oact) { + + if (SIGBAD(signo)) { + errno = EINVAL; + return -1; + } + + if(oact){ + oact->sa_handler = handlers[signo]; + oact->sa_mask = 0; + oact->sa_flags =0; + } + if ((signo == SIGHUP) && (act && (act->sa_handler == SIG_IGN)) + && __forked) + __nt_child_nohupped = 1; + if (act) + handlers[signo]=act->sa_handler; + + return 0; + +} +int ctrl_handler(DWORD event) { + + if (event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT) { + SetEvent(__h_con_int); + return TRUE; + } + if (event == CTRL_CLOSE_EVENT) { + SetEvent(__h_con_hup); + return TRUE; + } + + return generic_handler(event+1); +} +int generic_handler(DWORD signo) { + + int blocked=0; + + if (SIGBAD(signo) ) + return FALSE; + switch (signo) { + case SIGINT: + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] == SIG_DFL) + ExitProcess(0xC000013AL); + else + handlers[signo](signo); + } + break; + case SIGBREAK: + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] == SIG_DFL) + ExitProcess(0xC000013AL); + else + handlers[signo](signo); + } + break; + case SIGHUP: //CTRL_CLOSE_EVENT + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] == SIG_DFL) + ExitProcess(604); + else + handlers[signo](signo); + } + break; + case SIGTERM: //CTRL_LOGOFF_EVENT + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] == SIG_DFL) + ExitProcess(604); + else + handlers[signo](signo); + } + else + ExitProcess(604); + break; + case SIGKILL: //CTRL_SHUTDOWN_EVENT + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] == SIG_DFL) + ExitProcess(604); + else + handlers[signo](signo); + } + else + ExitProcess(604); + break; + case SIGALRM: + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] == SIG_DFL) + ExitProcess(604); + else + handlers[signo](signo); + } + break; + case SIGCHLD: + if (handlers[signo] != SIG_IGN){ + if (fast_sigmember(&gBlockMask,signo) ) { + dprintf("inc pending for sig %d count %d\n",signo, + gPending[signo]); + inc_pending(signo); + blocked=1; + } + else if (handlers[signo] != SIG_DFL) + handlers[signo](signo); + } + break; + default: + ExitProcess(604); + break; + } + if (!blocked && __is_suspended) { + EnterCriticalSection(&sigcritter); + __is_suspended--; + LeaveCriticalSection(&sigcritter); + dprintf("releasing suspension is_suspsend = %d\n",__is_suspended); + SetEvent(hsigsusp); + } + return TRUE; +} +Sigfunc *_nt_signal(int signal, Sigfunc * handler) { + + Sigfunc *old; + + if (SIGBAD(signal)) { + errno = EINVAL; + return SIG_ERR; + } + if (signal == SIGHUP && handler == SIG_IGN && __forked) { + __nt_child_nohupped = 1; + } + + + old = handlers[signal]; + handlers[signal] = handler; + + + return old; +} +int waitpid(pid_t pid, int *statloc, int options) { + + ChildListNode *temp; + int retcode; + + UNREFERENCED_PARAMETER(options); + errno = EINVAL; + if (pid != -1) + return -1; + + EnterCriticalSection(&sigcritter); + if (!clist_h) + retcode =0; + else { + retcode = clist_h->dwProcessId; + if (statloc) *statloc = clist_h->exitcode; + temp = clist_h; + clist_h = clist_h->next; + heap_free(temp); + } + LeaveCriticalSection(&sigcritter); + + errno = 0; + return retcode; + +} +unsigned int __alarm_set=0; + +void CALLBACK alarm_callback( unsigned long interval) { + + int rc; + + rc = WaitForSingleObject(__halarm,interval*1000); + if (rc != WAIT_TIMEOUT) + return ; + + SetEvent(__h_con_alarm); + __alarm_set = 0; + return; + + // consoleread() now waits for above event, and calls generic_handler to + // handle SIGALRM in the main thread. That helps me avoid + // problems with fork() when we are in a secondary thread. + // + // This means sched, periodic etc will not be signalled unless consoleread + // is called, but that's a reasonable risk, i think. + // -amol 4/10/97 + +} +unsigned int alarm(unsigned int seconds) { + + unsigned int temp; + static unsigned int prev_val=0; + HANDLE ht; + DWORD tid; + SECURITY_ATTRIBUTES secd; + + secd.nLength=sizeof(secd); + secd.lpSecurityDescriptor=NULL; + secd.bInheritHandle=TRUE; + + + if (!__halarm) { + __halarm=CreateEvent(&secd,FALSE,FALSE,NULL); + } + if(__alarm_set ) + SetEvent(__halarm); + + if (!seconds){ + __alarm_set=0; + return 0; + } + __alarm_set = 1; + + ht = CreateThread(NULL,gdwStackSize, + (LPTHREAD_START_ROUTINE)alarm_callback, + (void*)UIntToPtr(seconds), + 0,&tid); + if (ht) + CloseHandle(ht); + + temp = prev_val; + prev_val = seconds*1000; + + return temp; +} +void add_to_child_list(DWORD dwpid,DWORD exitcode) { + if (clist_h == NULL) { + clist_h = heap_alloc(sizeof(ChildListNode)); + if (!clist_h) + goto end; + clist_h->dwProcessId = dwpid; + clist_h->exitcode = exitcode; + clist_h->next= NULL; + clist_t = clist_h; + } + else { + clist_t->next = heap_alloc(sizeof(ChildListNode)); + if (!clist_t->next) + goto end; + clist_t = clist_t->next; + clist_t->dwProcessId= dwpid; + clist_h->exitcode = exitcode; + clist_t->next = NULL; + } +end: + ; +} +void sig_child_callback(DWORD pid,DWORD exitcode) { + + DWORD ecode = 0; + + EnterCriticalSection(&sigcritter); + add_to_child_list(pid,exitcode); + suspend_main_thread(); + // + // pchild() tries to reset(), which crashes the thread + // + __try { + generic_handler(SIGCHLD); + } + __except(ecode = GetExceptionCode()) { + ; + } + resume_main_thread(); + LeaveCriticalSection(&sigcritter); + +} +struct thread_args { + DWORD pid; + HANDLE hproc; +}; +void sigchild_thread(struct thread_args *args) { + + DWORD exitcode=0; + WaitForSingleObject(args->hproc,INFINITE); + GetExitCodeProcess(args->hproc,&exitcode); + CloseHandle(args->hproc); + sig_child_callback(args->pid,exitcode); + dprintf("exiting sigchild thread for pid %d\n",args->pid); + heap_free(args); +} +void start_sigchild_thread(HANDLE hproc, DWORD pid) { + + struct thread_args *args=heap_alloc(sizeof(struct thread_args)); + DWORD tid; + HANDLE hthr; + args->hproc = hproc; + args->pid = pid; + + dprintf("creating sigchild thread for pid %d\n",pid); + hthr = CreateThread(NULL, + gdwStackSize, + (LPTHREAD_START_ROUTINE)sigchild_thread, + (LPVOID)args, + 0, + &tid); + + + CloseHandle(hthr); + +} +int kill(int pid, int sig) { + + HANDLE hproc; + int ret =0; + extern DWORD gdwPlatform; + BOOL is_winnt = TRUE; + + errno = EPERM; + is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS); + + if(is_winnt) { + if(pid < 0) + { + if (pid == -1) + return -1; + pid = -pid; //no groups that we can actually do anything with. + + } + } + else { //win9x has -ve pids + if(pid > 0) + { + if (pid == 1) + return -1; + pid = -pid; //no groups that we can actually do anything with. + + } + } + + + switch(sig) { + case 0: + case 7: + hproc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid); + if (hproc == NULL) { + errno = ESRCH; + ret = -1; + dprintf("proc %d not found\n",pid); + } + else{ + dprintf("proc %d found\n",pid); + } + if (sig == 7) { + if (!TerminateProcess(hproc,0xC000013AL) ) { + ret = -1; + } + } + CloseHandle(hproc); + break; + case 1: + if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid)) + ret = -1; + break; + case 2: + if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid)) + ret = -1; + break; + case 3: + if (kill_by_wm_close(pid) <0 ) { + errno = ESRCH; + ret = -1; + } + default: + break; + } + return ret; +} +// +// nice(niceness) +// +// where niceness is an integer in the range -6 to +7 +// +// A usual foreground process starts at level 9 in the chart below +// +// the range -6 to +7 takes it from Base priority 15 down to 2. +// +// Note that level 1 or > 15 are not allowed. +// +// Priority Level 11 (niceness -2) or greater affects system performance, +// so use with care. +// +// niceness defaults to +4, which is lowest for background normal class. +// As in unix, +ve niceness indicates lower priorities. + +/*************************************************************************** +Niceness Base Priority class/thread priority + + 1 Idle, normal, or high class, THREAD_PRIORITY_IDLE + ++7 2 Idle class, THREAD_PRIORITY_LOWEST ++6 3 Idle class, THREAD_PRIORITY_BELOW_NORMAL ++5 4 Idle class, THREAD_PRIORITY_NORMAL ++4 5 Background normal class, THREAD_PRIORITY_LOWEST + Idle class, THREAD_PRIORITY_ABOVE_NORMAL ++3 6 Background normal class, THREAD_PRIORITY_BELOW_NORMAL + Idle class, THREAD_PRIORITY_HIGHEST ++2 7 Foreground normal class, THREAD_PRIORITY_LOWEST + Background normal class, THREAD_PRIORITY_NORMAL ++1 8 Foreground normal class, THREAD_PRIORITY_BELOW_NORMAL + Background normal class, THREAD_PRIORITY_ABOVE_NORMAL + 0 9 Foreground normal class, THREAD_PRIORITY_NORMAL + Background normal class, THREAD_PRIORITY_HIGHEST +-1 10 Foreground normal class, THREAD_PRIORITY_ABOVE_NORMAL +-2 11 High class, THREAD_PRIORITY_LOWEST + Foreground normal class, THREAD_PRIORITY_HIGHEST +-3 12 High class, THREAD_PRIORITY_BELOW_NORMAL +-4 13 High class, THREAD_PRIORITY_NORMAL +-5 14 High class, THREAD_PRIORITY_ABOVE_NORMAL +-6 15 Idle, normal, or high class, THREAD_PRIORITY_TIME_CRITICAL + High class, THREAD_PRIORITY_HIGHEST + + + 16 Real-time class, THREAD_PRIORITY_IDLE + 22 Real-time class, THREAD_PRIORITY_LOWEST + 23 Real-time class, THREAD_PRIORITY_BELOW_NORMAL + 24 Real-time class, THREAD_PRIORITY_NORMAL + 25 Real-time class, THREAD_PRIORITY_ABOVE_NORMAL + 26 Real-time class, THREAD_PRIORITY_HIGHEST + 31 Real-time class, THREAD_PRIORITY_TIME_CRITICAL +****************************************************************************/ +int nice(int niceness) { + + DWORD pclass = IDLE_PRIORITY_CLASS; + int priority = THREAD_PRIORITY_NORMAL; + + if (niceness < -6 || niceness > 7) { + errno = EPERM; + return -1; + } + switch (niceness) { + case 7: + pclass = IDLE_PRIORITY_CLASS; + priority = THREAD_PRIORITY_LOWEST; + break; + case 6: + pclass = IDLE_PRIORITY_CLASS; + priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case 5: + pclass = IDLE_PRIORITY_CLASS; + priority = THREAD_PRIORITY_NORMAL; + break; + case 4: + pclass = IDLE_PRIORITY_CLASS; + priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case 3: + pclass = IDLE_PRIORITY_CLASS; + priority = THREAD_PRIORITY_HIGHEST; + break; + case 2: + pclass = NORMAL_PRIORITY_CLASS; + priority = THREAD_PRIORITY_LOWEST; + break; + case 1: + pclass = NORMAL_PRIORITY_CLASS; + priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case (-1): + pclass = NORMAL_PRIORITY_CLASS; + priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case (-2): + pclass = NORMAL_PRIORITY_CLASS; + priority = THREAD_PRIORITY_HIGHEST; + break; + case (-3): + pclass = HIGH_PRIORITY_CLASS; + priority = THREAD_PRIORITY_BELOW_NORMAL; + break; + case (-4): + pclass = HIGH_PRIORITY_CLASS; + priority = THREAD_PRIORITY_NORMAL; + break; + case (-5): + pclass = HIGH_PRIORITY_CLASS; + priority = THREAD_PRIORITY_ABOVE_NORMAL; + break; + case (-6): + pclass = HIGH_PRIORITY_CLASS; + priority = THREAD_PRIORITY_HIGHEST; + break; + default: + break; + } + + if (!SetPriorityClass(GetCurrentProcess(),pclass)){ + errno = EPERM; + return -1; + } + if (!SetThreadPriority(GetCurrentThread(),priority)){ + errno = EPERM; + return -1; + } + return -1; +} |
