/* * Wine signal handling * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_SYSCALL_H # include #else # ifdef HAVE_SYS_SYSCALL_H # include # endif #endif #include "miscemu.h" #include "selectors.h" #include "sig_context.h" #include "winsock.h" /* Global variable to save %fs register while in 16-bit code */ WORD CALLTO16_Current_fs; /* Linux sigaction function */ #if defined(linux) && defined(__i386__) /* This is the sigaction structure from the Linux 2.1.20 kernel. */ #undef sa_handler struct kernel_sigaction { void (*sa_handler)(); unsigned long sa_mask; unsigned long sa_flags; void (*sa_restorer)(); }; /* Similar to the sigaction function in libc, except it leaves alone the restorer field, which is used to specify the signal stack address */ static __inline__ int wine_sigaction( int sig, struct kernel_sigaction *new, struct kernel_sigaction *old ) { #ifdef __PIC__ __asm__ __volatile__( "pushl %%ebx\n\t" "movl %2,%%ebx\n\t" "int $0x80\n\t" "popl %%ebx" : "=a" (sig) : "0" (SYS_sigaction), "g" (sig), "c" (new), "d" (old) ); #else __asm__ __volatile__( "int $0x80" : "=a" (sig) : "0" (SYS_sigaction), "b" (sig), "c" (new), "d" (old) ); #endif /* __PIC__ */ if (sig>=0) return 0; errno = -sig; return -1; } #endif /* linux && __i386__ */ /* Signal stack */ static char SIGNAL_Stack[16384]; static sigset_t async_signal_set; /********************************************************************** * SIGNAL_child * * wait4 terminated child processes */ static HANDLER_DEF(SIGNAL_child) { HANDLER_INIT(); #ifdef HAVE_WAIT4 wait4( 0, NULL, WNOHANG, NULL); #elif defined (HAVE_WAITPID) /* I am sort-of guessing that this is the same as the wait4 call. */ waitpid (0, NULL, WNOHANG); #else wait(NULL); #endif } /********************************************************************** * SIGNAL_SetHandler */ void SIGNAL_SetHandler( int sig, void (*func)(), int flags ) { int ret; #if defined(linux) && defined(__i386__) struct kernel_sigaction sig_act; sig_act.sa_handler = func; sig_act.sa_flags = SA_RESTART | (flags) ? SA_NOMASK : 0; sig_act.sa_mask = 0; /* Point to the top of the stack, minus 4 just in case, and make it aligned */ sig_act.sa_restorer = (void (*)())((int)(SIGNAL_Stack + sizeof(SIGNAL_Stack) - 4) & ~3); ret = wine_sigaction( sig, &sig_act, NULL ); #else /* linux && __i386__ */ struct sigaction sig_act; sig_act.sa_handler = func; sigemptyset( &sig_act.sa_mask ); # if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) sig_act.sa_flags = SA_ONSTACK; # elif defined (__svr4__) || defined(_SCO_DS) sig_act.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART; # elif defined(__EMX__) sig_act.sa_flags = 0; /* FIXME: EMX has only SA_ACK and SA_SYSV */ # else sig_act.sa_flags = 0; # endif ret = sigaction( sig, &sig_act, NULL ); #endif /* linux && __i386__ */ if (ret < 0) { perror( "sigaction" ); exit(1); } } extern void stop_wait(int a); extern void WINSOCK_sigio(int a); /********************************************************************** * SIGNAL_Init */ BOOL32 SIGNAL_Init(void) { extern void SYNC_SetupSignals(void); #ifdef HAVE_WORKING_SIGALTSTACK struct sigaltstack ss; ss.ss_sp = SIGNAL_Stack; ss.ss_size = sizeof(SIGNAL_Stack); ss.ss_flags = 0; if (sigaltstack(&ss, NULL) < 0) { perror("sigstack"); return FALSE; } #endif /* HAVE_SIGALTSTACK */ sigemptyset(&async_signal_set); SIGNAL_SetHandler( SIGCHLD, (void (*)())SIGNAL_child, 1); #ifdef CONFIG_IPC sigaddset(&async_signal_set, SIGUSR2); SIGNAL_SetHandler( SIGUSR2, (void (*)())stop_wait, 1); /* For IPC */ #endif #ifdef SIGIO sigaddset(&async_signal_set, SIGIO); SIGNAL_SetHandler( SIGIO, (void (*)())WINSOCK_sigio, 0); #endif sigaddset(&async_signal_set, SIGALRM); /* ignore SIGPIPE so that WINSOCK can get a EPIPE error instead */ signal (SIGPIPE, SIG_IGN); SYNC_SetupSignals(); return TRUE; } /********************************************************************** * SIGNAL_MaskAsyncEvents */ void SIGNAL_MaskAsyncEvents( BOOL32 flag ) { sigprocmask( (flag) ? SIG_BLOCK : SIG_UNBLOCK , &async_signal_set, NULL); }