aboutsummaryrefslogtreecommitdiff
path: root/win32/signal.c
diff options
context:
space:
mode:
Diffstat (limited to 'win32/signal.c')
-rw-r--r--win32/signal.c728
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;
+}