1/*$Header: /p/tcsh/cvsroot/tcsh/win32/signal.c,v 1.11 2006/08/25 17:49:57 christos Exp $*/
2/*-
3 * Copyright (c) 1980, 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31/*
32 * signal.c: Signal emulation hacks.
33 * -amol
34 *
35 */
36#define WIN32_LEAN_AND_MEAN
37#include <windows.h>
38#include <errno.h>
39#include <stdlib.h>
40#include "ntport.h"
41#include "forkdata.h"
42#include "signal.h"
43
44#pragma warning(disable:4055)
45
46#define SIGBAD(signo)        ( (signo) <=0 || (signo) >=NSIG)
47#define fast_sigmember(a,b)  ( (*(a) & (1 << (b-1)) ) )
48#define inc_pending(a)       (gPending[(a)]+=1)
49
50#define suspend_main_thread() SuspendThread(hmainthr)
51#define resume_main_thread() ResumeThread(hmainthr)
52
53int generic_handler(DWORD);
54int ctrl_handler(DWORD);
55
56typedef struct _child_list {
57	DWORD dwProcessId;
58	DWORD exitcode;
59	struct _child_list *next;
60}ChildListNode;
61
62Sigfunc *handlers[NSIG]={0};
63static unsigned long gPending[NSIG]={0};
64static unsigned long gBlockMask = 0;
65
66static ChildListNode *clist_h; //head of list
67static ChildListNode *clist_t; // tail of list
68
69static CRITICAL_SECTION sigcritter;
70static HANDLE hmainthr;
71static HANDLE hsigsusp;
72static int __is_suspended = 0;
73static HANDLE __halarm=0;
74
75extern HANDLE __h_con_alarm,__h_con_int, __h_con_hup;
76
77// must be done before fork;
78void nt_init_signals(void) {
79
80	SetConsoleCtrlHandler((PHANDLER_ROUTINE)ctrl_handler,TRUE);
81	InitializeCriticalSection(&sigcritter);
82
83	clist_t = clist_h = NULL;
84
85
86	if (!DuplicateHandle(GetCurrentProcess(),
87					GetCurrentThread(),
88					GetCurrentProcess(),
89					&hmainthr,
90					0,
91					FALSE,
92					DUPLICATE_SAME_ACCESS)){
93		ExitProcess(GetLastError());
94	}
95	hsigsusp = CreateEvent(NULL,FALSE,FALSE,NULL);
96	__h_con_alarm=CreateEvent(NULL,FALSE,FALSE,NULL);
97	__h_con_int=CreateEvent(NULL,FALSE,FALSE,NULL);
98	__h_con_hup=CreateEvent(NULL,FALSE,FALSE,NULL);
99	if (!hsigsusp)
100		abort();
101
102}
103void nt_cleanup_signals(void) {
104	if (__forked)
105		return;
106	DeleteCriticalSection(&sigcritter);
107	CloseHandle(hmainthr);
108	CloseHandle(hsigsusp);
109	CloseHandle(__h_con_alarm);
110	CloseHandle(__h_con_int);
111	CloseHandle(__h_con_hup);
112	CloseHandle(__halarm);
113}
114int sigaddset(sigset_t *set, int signo) {
115
116	if (SIGBAD(signo)) {
117		errno = EINVAL;
118		return -1;
119	}
120	*set |= 1 << (signo-1);
121	return 0;
122}
123int sigdelset(sigset_t *set, int signo) {
124	if (SIGBAD(signo)) {
125		errno = EINVAL;
126		return -1;
127	}
128	*set &= ~( 1 << (signo-1));
129
130	return 0;
131
132}
133int sigismember(const sigset_t *set, int signo) {
134	if (SIGBAD(signo)) {
135		errno = EINVAL;
136		return -1;
137	}
138
139	return ( (*set & (1 <<(signo-1)) ) != 0);
140
141}
142void deliver_pending(void) {
143	unsigned long temp;
144	int sig=1;
145
146	temp = ~gBlockMask;
147	while(temp && (sig < NSIG)) {
148
149		if (temp & 0x01){
150			if (gPending[sig]){
151				//gPending[sig]=0;
152                do {
153                    dprintf("deliver_pending for sig %d\n",sig);
154                    gPending[sig]--;
155                    generic_handler(sig);
156                }while(gPending[sig] != 0);
157			}
158		}
159		temp >>= 1;
160		sig++;
161	}
162}
163int sigprocmask(int how, const sigset_t *set, sigset_t*oset) {
164
165	if (oset)
166		*oset = gBlockMask;
167	if (set) {
168		switch (how) {
169			case SIG_BLOCK:
170				gBlockMask |= *set;
171				break;
172			case SIG_UNBLOCK:
173				gBlockMask &= (~(*set));
174				break;
175			case SIG_SETMASK:
176				gBlockMask = *set;
177				break;
178			default:
179				break;
180		}
181	}
182	if (how != SIG_BLOCK)
183		deliver_pending();
184
185	return 0;
186
187}
188int sigsuspend(const sigset_t *mask) {
189	sigset_t omask;
190
191
192	EnterCriticalSection(&sigcritter);
193	__is_suspended++;
194	LeaveCriticalSection(&sigcritter);
195
196	sigprocmask(SIG_SETMASK,mask,&omask);
197
198    dprintf("suspending main thread susp count %d\n",__is_suspended);
199    do {
200        WaitForSingleObject(hsigsusp,INFINITE);
201    }while(__is_suspended > 0);
202
203
204	sigprocmask(SIG_SETMASK,&omask,0);
205	errno = EINTR;
206	return -1;
207
208}
209
210int sigaction(int signo, const struct sigaction *act, struct sigaction *oact) {
211
212	if (SIGBAD(signo)) {
213		errno = EINVAL;
214		return -1;
215	}
216
217	if(oact){
218			oact->sa_handler = handlers[signo];
219			oact->sa_mask = 0;
220			oact->sa_flags =0;
221	}
222	if ((signo == SIGHUP) && (act && (act->sa_handler == SIG_IGN))
223						&& __forked)
224		__nt_child_nohupped = 1;
225	if (act)
226		handlers[signo]=act->sa_handler;
227
228	return 0;
229
230}
231int ctrl_handler(DWORD event) {
232
233	if (event == CTRL_C_EVENT || event == CTRL_BREAK_EVENT) {
234		SetEvent(__h_con_int);
235		return TRUE;
236	}
237	if (event == CTRL_CLOSE_EVENT) {
238		SetEvent(__h_con_hup);
239		return TRUE;
240	}
241
242	return generic_handler(event+1);
243}
244int generic_handler(DWORD signo) {
245
246	int blocked=0;
247
248	if (SIGBAD(signo) )
249		return FALSE;
250	switch (signo) {
251		case SIGINT:
252			if (handlers[signo] != SIG_IGN){
253				if (fast_sigmember(&gBlockMask,signo) ) {
254					inc_pending(signo);
255					blocked=1;
256				}
257				else if (handlers[signo] == SIG_DFL)
258					ExitProcess(0xC000013AL);
259				else
260					handlers[signo](signo);
261			}
262			break;
263		case SIGBREAK:
264			if (handlers[signo] != SIG_IGN){
265				if (fast_sigmember(&gBlockMask,signo) ) {
266					inc_pending(signo);
267					blocked=1;
268				}
269				else if (handlers[signo] == SIG_DFL)
270					ExitProcess(0xC000013AL);
271				else
272					handlers[signo](signo);
273			}
274			break;
275		case SIGHUP: //CTRL_CLOSE_EVENT
276			if (handlers[signo] != SIG_IGN){
277				if (fast_sigmember(&gBlockMask,signo) ) {
278					inc_pending(signo);
279					blocked=1;
280				}
281				else if (handlers[signo] == SIG_DFL)
282					ExitProcess(604);
283				else
284					handlers[signo](signo);
285			}
286			break;
287		case SIGTERM: //CTRL_LOGOFF_EVENT
288			if (handlers[signo] != SIG_IGN){
289				if (fast_sigmember(&gBlockMask,signo) ) {
290					inc_pending(signo);
291					blocked=1;
292				}
293				else if (handlers[signo] == SIG_DFL)
294					ExitProcess(604);
295				else
296					handlers[signo](signo);
297			}
298			else
299				ExitProcess(604);
300			break;
301		case SIGKILL: //CTRL_SHUTDOWN_EVENT
302			if (handlers[signo] != SIG_IGN){
303				if (fast_sigmember(&gBlockMask,signo) ) {
304					inc_pending(signo);
305					blocked=1;
306				}
307				else if (handlers[signo] == SIG_DFL)
308					ExitProcess(604);
309				else
310					handlers[signo](signo);
311			}
312			else
313				ExitProcess(604);
314			break;
315		case SIGALRM:
316			if (handlers[signo] != SIG_IGN){
317				if (fast_sigmember(&gBlockMask,signo) ) {
318					inc_pending(signo);
319					blocked=1;
320				}
321				else if (handlers[signo] == SIG_DFL)
322					ExitProcess(604);
323				else
324					handlers[signo](signo);
325			}
326			break;
327		case SIGCHLD:
328			if (handlers[signo] != SIG_IGN){
329				if (fast_sigmember(&gBlockMask,signo) ) {
330                    dprintf("inc pending for sig %d count %d\n",signo,
331                        gPending[signo]);
332					inc_pending(signo);
333					blocked=1;
334				}
335				else if (handlers[signo] != SIG_DFL)
336					handlers[signo](signo);
337			}
338			break;
339		default:
340			ExitProcess(604);
341			break;
342	}
343    if (!blocked && __is_suspended) {
344        EnterCriticalSection(&sigcritter);
345        __is_suspended--;
346        LeaveCriticalSection(&sigcritter);
347        dprintf("releasing suspension is_suspsend = %d\n",__is_suspended);
348        SetEvent(hsigsusp);
349    }
350	return TRUE;
351}
352Sigfunc *_nt_signal(int signal, Sigfunc * handler) {
353
354	Sigfunc *old;
355
356	if (SIGBAD(signal)) {
357		errno = EINVAL;
358		return SIG_ERR;
359	}
360	if (signal == SIGHUP  && handler == SIG_IGN && __forked) {
361		__nt_child_nohupped = 1;
362	}
363
364
365	old = handlers[signal];
366	handlers[signal] = handler;
367
368
369	return old;
370}
371int waitpid(pid_t pid, int *statloc, int options) {
372
373	ChildListNode *temp;
374	int retcode;
375
376	UNREFERENCED_PARAMETER(options);
377	errno = EINVAL;
378	if (pid != -1)
379		return -1;
380
381	EnterCriticalSection(&sigcritter);
382		if (!clist_h)
383			retcode =0;
384		else {
385			retcode = clist_h->dwProcessId;
386			if (statloc) *statloc = clist_h->exitcode;
387			temp = clist_h;
388			clist_h = clist_h->next;
389			heap_free(temp);
390		}
391	LeaveCriticalSection(&sigcritter);
392
393	errno = 0;
394	return retcode;
395
396}
397unsigned int __alarm_set=0;
398
399void CALLBACK alarm_callback( unsigned long interval) {
400
401	int rc;
402
403	rc = WaitForSingleObject(__halarm,interval*1000);
404	if (rc != WAIT_TIMEOUT)
405		return ;
406
407	SetEvent(__h_con_alarm);
408	__alarm_set = 0;
409	return;
410
411	// consoleread() now waits for above event, and calls generic_handler to
412	// handle SIGALRM in the main thread. That helps me avoid
413	// problems with  fork() when we are in a secondary thread.
414	//
415	// This means sched, periodic etc will not be signalled unless consoleread
416	// is called, but that's a reasonable risk, i think.
417	// -amol 4/10/97
418
419}
420unsigned int alarm(unsigned int seconds) {
421
422	unsigned int temp;
423	static unsigned int prev_val=0;
424	HANDLE ht;
425	DWORD tid;
426	SECURITY_ATTRIBUTES secd;
427
428	secd.nLength=sizeof(secd);
429	secd.lpSecurityDescriptor=NULL;
430	secd.bInheritHandle=TRUE;
431
432
433	if (!__halarm) {
434		__halarm=CreateEvent(&secd,FALSE,FALSE,NULL);
435	}
436	if(__alarm_set )
437		SetEvent(__halarm);
438
439	if (!seconds){
440		__alarm_set=0;
441		return 0;
442	}
443	__alarm_set = 1;
444
445	ht = CreateThread(NULL,gdwStackSize,
446				(LPTHREAD_START_ROUTINE)alarm_callback,
447				(void*)UIntToPtr(seconds),
448				0,&tid);
449	if (ht)
450		CloseHandle(ht);
451
452	temp = prev_val;
453	prev_val = seconds*1000;
454
455	return temp;
456}
457void add_to_child_list(DWORD dwpid,DWORD exitcode) {
458	if (clist_h == NULL) {
459		clist_h = heap_alloc(sizeof(ChildListNode));
460		if (!clist_h)
461			goto end;
462		clist_h->dwProcessId = dwpid;
463		clist_h->exitcode = exitcode;
464		clist_h->next= NULL;
465		clist_t = clist_h;
466	}
467	else {
468		clist_t->next = heap_alloc(sizeof(ChildListNode));
469		if (!clist_t->next)
470			goto end;
471		clist_t = clist_t->next;
472		clist_t->dwProcessId= dwpid;
473		clist_h->exitcode = exitcode;
474		clist_t->next = NULL;
475	}
476end:
477	;
478}
479void sig_child_callback(DWORD pid,DWORD exitcode) {
480
481	DWORD ecode = 0;
482
483	EnterCriticalSection(&sigcritter);
484	add_to_child_list(pid,exitcode);
485	suspend_main_thread();
486	//
487	// pchild() tries to reset(), which crashes the thread
488	//
489	__try {
490		generic_handler(SIGCHLD);
491	}
492	__except(ecode = GetExceptionCode()) {
493		;
494	}
495	resume_main_thread();
496	LeaveCriticalSection(&sigcritter);
497
498}
499struct thread_args {
500	DWORD pid;
501	HANDLE hproc;
502};
503void sigchild_thread(struct thread_args *args) {
504
505	DWORD exitcode=0;
506	WaitForSingleObject(args->hproc,INFINITE);
507	GetExitCodeProcess(args->hproc,&exitcode);
508	CloseHandle(args->hproc);
509	sig_child_callback(args->pid,exitcode);
510	ffree(args);
511    dprintf("exiting sigchild thread for pid %d\n",args->pid);
512}
513void start_sigchild_thread(HANDLE hproc, DWORD pid) {
514
515	struct thread_args *args=fmalloc(sizeof(struct thread_args));
516	DWORD tid;
517	HANDLE hthr;
518	args->hproc = hproc;
519	args->pid = pid;
520
521    dprintf("creating sigchild thread for pid %d\n",pid);
522	hthr = CreateThread(NULL,
523							gdwStackSize,
524							(LPTHREAD_START_ROUTINE)sigchild_thread,
525							(LPVOID)args,
526							0,
527							&tid);
528
529
530	CloseHandle(hthr);
531
532}
533int kill(int pid, int sig) {
534
535    HANDLE hproc;
536    int ret =0;
537    extern DWORD gdwPlatform;
538    BOOL is_winnt = TRUE;
539
540    errno = EPERM;
541    is_winnt = (gdwPlatform != VER_PLATFORM_WIN32_WINDOWS);
542
543    if(is_winnt) {
544        if(pid < 0)
545        {
546            if (pid == -1)
547                return -1;
548            pid = -pid; //no groups that we can actually do anything with.
549
550        }
551    }
552    else { //win9x has -ve pids
553        if(pid > 0)
554        {
555            if (pid == 1)
556                return -1;
557            pid = -pid; //no groups that we can actually do anything with.
558
559        }
560    }
561
562
563    switch(sig) {
564        case 0:
565        case 7:
566            hproc = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid);
567            if (hproc  == NULL) {
568                errno = ESRCH;
569                ret = -1;
570                dprintf("proc %d not found\n",pid);
571            }
572            else{
573                dprintf("proc %d found\n",pid);
574            }
575            if (sig == 7) {
576                if (!TerminateProcess(hproc,0xC000013AL) ) {
577                    ret = -1;
578                }
579            }
580            CloseHandle(hproc);
581            break;
582        case 1:
583            if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
584                ret = -1;
585            break;
586        case 2:
587            if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
588                ret = -1;
589            break;
590        case 3:
591            if (kill_by_wm_close(pid) <0 ) {
592                errno = ESRCH;
593                ret = -1;
594            }
595        default:
596            break;
597    }
598    return ret;
599}
600//
601// nice(niceness)
602//
603// where niceness is an integer in the range -6 to +7
604//
605// A usual foreground process starts at level 9 in the chart below
606//
607// the range -6 to +7 takes it from Base priority 15 down to 2.
608//
609// Note that level 1 or > 15 are not allowed.
610//
611// Priority Level 11 (niceness -2) or greater affects system performance,
612//	so use with care.
613//
614// niceness defaults to  +4, which is lowest for background normal class.
615// As in unix, +ve niceness indicates lower priorities.
616
617/***************************************************************************
618Niceness    Base    Priority class/thread priority
619
620            1    Idle, normal, or high class,    THREAD_PRIORITY_IDLE
621
622+7          2    Idle class,                     THREAD_PRIORITY_LOWEST
623+6          3    Idle class,                     THREAD_PRIORITY_BELOW_NORMAL
624+5          4    Idle class,                     THREAD_PRIORITY_NORMAL
625+4          5    Background normal class,        THREAD_PRIORITY_LOWEST
626                    Idle class,                  THREAD_PRIORITY_ABOVE_NORMAL
627+3          6    Background normal class,        THREAD_PRIORITY_BELOW_NORMAL
628                    Idle class,                  THREAD_PRIORITY_HIGHEST
629+2          7    Foreground normal class,        THREAD_PRIORITY_LOWEST
630                    Background normal class,     THREAD_PRIORITY_NORMAL
631+1          8    Foreground normal class,        THREAD_PRIORITY_BELOW_NORMAL
632                    Background normal class,     THREAD_PRIORITY_ABOVE_NORMAL
633 0          9    Foreground normal class,        THREAD_PRIORITY_NORMAL
634                    Background normal class,     THREAD_PRIORITY_HIGHEST
635-1          10   Foreground normal class,        THREAD_PRIORITY_ABOVE_NORMAL
636-2          11    High class,                    THREAD_PRIORITY_LOWEST
637                    Foreground normal class,     THREAD_PRIORITY_HIGHEST
638-3          12    High class,                    THREAD_PRIORITY_BELOW_NORMAL
639-4          13    High class,                    THREAD_PRIORITY_NORMAL
640-5          14    High class,                    THREAD_PRIORITY_ABOVE_NORMAL
641-6          15    Idle, normal, or high class,   THREAD_PRIORITY_TIME_CRITICAL
642                  High class,                    THREAD_PRIORITY_HIGHEST
643
644
645    16    Real-time class, THREAD_PRIORITY_IDLE
646    22    Real-time class, THREAD_PRIORITY_LOWEST
647    23    Real-time class, THREAD_PRIORITY_BELOW_NORMAL
648    24    Real-time class, THREAD_PRIORITY_NORMAL
649    25    Real-time class, THREAD_PRIORITY_ABOVE_NORMAL
650    26    Real-time class, THREAD_PRIORITY_HIGHEST
651    31    Real-time class, THREAD_PRIORITY_TIME_CRITICAL
652****************************************************************************/
653int nice(int niceness) {
654
655    DWORD pclass = IDLE_PRIORITY_CLASS;
656    int priority = THREAD_PRIORITY_NORMAL;
657
658    if (niceness < -6 || niceness > 7) {
659        errno = EPERM;
660        return -1;
661    }
662    switch (niceness) {
663        case 7:
664            pclass = IDLE_PRIORITY_CLASS;
665            priority = THREAD_PRIORITY_LOWEST;
666            break;
667        case 6:
668            pclass = IDLE_PRIORITY_CLASS;
669            priority = THREAD_PRIORITY_BELOW_NORMAL;
670            break;
671        case 5:
672            pclass = IDLE_PRIORITY_CLASS;
673            priority = THREAD_PRIORITY_NORMAL;
674            break;
675        case 4:
676            pclass = IDLE_PRIORITY_CLASS;
677            priority = THREAD_PRIORITY_ABOVE_NORMAL;
678            break;
679        case 3:
680            pclass = IDLE_PRIORITY_CLASS;
681            priority = THREAD_PRIORITY_HIGHEST;
682            break;
683        case 2:
684            pclass = NORMAL_PRIORITY_CLASS;
685            priority = THREAD_PRIORITY_LOWEST;
686            break;
687        case 1:
688            pclass = NORMAL_PRIORITY_CLASS;
689            priority = THREAD_PRIORITY_BELOW_NORMAL;
690            break;
691        case (-1):
692            pclass = NORMAL_PRIORITY_CLASS;
693            priority = THREAD_PRIORITY_ABOVE_NORMAL;
694            break;
695        case (-2):
696            pclass = NORMAL_PRIORITY_CLASS;
697            priority = THREAD_PRIORITY_HIGHEST;
698            break;
699        case (-3):
700            pclass = HIGH_PRIORITY_CLASS;
701            priority = THREAD_PRIORITY_BELOW_NORMAL;
702            break;
703        case (-4):
704            pclass = HIGH_PRIORITY_CLASS;
705            priority = THREAD_PRIORITY_NORMAL;
706            break;
707        case (-5):
708            pclass = HIGH_PRIORITY_CLASS;
709            priority = THREAD_PRIORITY_ABOVE_NORMAL;
710            break;
711        case (-6):
712            pclass = HIGH_PRIORITY_CLASS;
713            priority = THREAD_PRIORITY_HIGHEST;
714            break;
715        default:
716            break;
717    }
718
719    if (!SetPriorityClass(GetCurrentProcess(),pclass)){
720        errno = EPERM;
721        return -1;
722    }
723    if (!SetThreadPriority(GetCurrentThread(),priority)){
724        errno = EPERM;
725        return -1;
726    }
727	return -1;
728}
729