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