diff --git a/src/signal_handler.c b/src/signal_handler.c index 57cc5ba398bccbb39c709d439a4303725e66f1a9..24d7cb0a7d7619eef85355798fa463300091e95d 100644 --- a/src/signal_handler.c +++ b/src/signal_handler.c @@ -25,7 +25,7 @@ #include "main.h" #include <signal.h> -RCSID("$Id: signal_handler.c,v 1.134 1999/05/26 07:08:11 hubbe Exp $"); +RCSID("$Id: signal_handler.c,v 1.135 1999/06/03 06:10:00 hubbe Exp $"); #ifdef HAVE_PASSWD_H # include <passwd.h> @@ -110,6 +110,93 @@ RCSID("$Id: signal_handler.c,v 1.134 1999/05/26 07:08:11 hubbe Exp $"); #undef USE_SIGCHILD #endif +#if defined(USE_SIGCHILD) && defined(__linux__) && _REENTRANT +#define NEED_SIGNAL_SAFE_FIFO +#endif + + +#ifndef NEED_SIGNAL_SAFE_FIFO + +#ifdef DEBUG +#define SAFE_FIFO_DEBUG_BEGIN() do {\ + static volatile int inside=0; \ + if(inside) \ + fatal("You need to define NEED_SIGNAL_SAFE_FIFO in signal_handler.c!\n"); \ + inside=1; + +#define SAFE_FIFO_DEBUG_END() inside=0; }while(0) +#endif + +#define DECLARE_FIFO(pre,TYPE) \ + static volatile TYPE PIKE_CONCAT(pre,buf) [SIGNAL_BUFFER]; \ + static volatile int PIKE_CONCAT(pre,_first)=0,PIKE_CONCAT(pre,_last)=0 + +#define BEGIN_FIFO_PUSH(pre,TYPE) do { \ + int PIKE_CONCAT(pre,_tmp_)=PIKE_CONCAT(pre,_first) + 1; \ + if(PIKE_CONCAT(pre,_tmp_) > SIGNAL_BUFFER) PIKE_CONCAT(pre,_tmp_)=0 + +#define FIFO_DATA(pre,TYPE) ( PIKE_CONCAT(pre,buf)[PIKE_CONCAT(pre,_tmp_)] ) + +#define END_FIFO_PUSH(pre,TYPE) PIKE_CONCAT(pre,_first)=PIKE_CONCAT(pre,_tmp_); } while(0) + + +#define QUICK_CHECK_FIFO(pre,TYPE) ( PIKE_CONCAT(pre,_first) != PIKE_CONCAT(pre,_last) ) + +#define BEGIN_FIFO_LOOP(pre,TYPE) do { \ + int PIKE_CONCAT(pre,_tmp2_)=PIKE_CONCAT(pre,_first); \ + while(PIKE_CONCAT(pre,_last) != PIKE_CONCAT(pre,_tmp2_)) \ + { \ + int PIKE_CONCAT(pre,_tmp_); \ + if( ++ PIKE_CONCAT(pre,_last) == SIGNAL_BUFFER) \ + PIKE_CONCAT(pre,_last)=0; \ + PIKE_CONCAT(pre,_tmp_)=PIKE_CONCAT(pre,_last) + +#define END_FIFO_LOOP(pre,TYPE) } }while(0) + +#define INIT_FIFO(pre,TYPE) + +#else + +#define DECLARE_FIFO(pre,TYPE) \ + static int PIKE_CONCAT(pre,_fd)[2]; \ + static volatile sig_atomic_t PIKE_CONCAT(pre,_data_available) + +#define BEGIN_FIFO_PUSH(pre,TYPE) do { TYPE PIKE_CONCAT(pre,_tmp_) + +#define FIFO_DATA(pre,TYPE) PIKE_CONCAT(pre,_tmp_) + +#define END_FIFO_PUSH(pre,TYPE) \ + while( write(PIKE_CONCAT(pre,_fd)[1],(char *)&PIKE_CONCAT(pre,_tmp_),sizeof(PIKE_CONCAT(pre,_tmp_))) < 0 && errno==EINTR); \ + PIKE_CONCAT(pre,_data_available)=1; \ + } while(0) + + +#define QUICK_CHECK_FIFO(pre,TYPE) PIKE_CONCAT(pre,_data_available) + +#define BEGIN_FIFO_LOOP(pre,TYPE) do { \ + TYPE PIKE_CONCAT(pre,_tmp_); \ + PIKE_CONCAT(pre,_data_available)=0; \ + while(read(PIKE_CONCAT(pre,_fd)[0],(char *)&PIKE_CONCAT(pre,_tmp_),sizeof(PIKE_CONCAT(pre,_tmp_)))==sizeof(PIKE_CONCAT(pre,_tmp_))) \ + { + +#define END_FIFO_LOOP(pre,TYPE) } }while(0) + +#define INIT_FIFO(pre,TYPE) do { \ + if(pike_make_pipe(PIKE_CONCAT(pre,_fd)) <0) \ + fatal("Couldn't create buffer " #pre ".\n"); \ + \ + set_nonblocking(PIKE_CONCAT(pre,_fd)[0],1); \ + set_nonblocking(PIKE_CONCAT(pre,_fd)[1],1); \ + set_close_on_exec(PIKE_CONCAT(pre,_fd)[0], 1); \ + set_close_on_exec(PIKE_CONCAT(pre,_fd)[1], 1); \ +}while(0) + +#endif + +#ifndef SAFE_FIFO_DEBUG_END +#define SAFE_FIFO_DEBUG_BEGIN() do { +#define SAFE_FIFO_DEBUG_END() }while(0) +#endif /* Added so we are able to patch older versions of Pike. */ #ifndef add_ref @@ -122,10 +209,11 @@ static int set_priority( int pid, char *to ); static struct svalue signal_callbacks[MAX_SIGNALS]; static void (*default_signals[MAX_SIGNALS])(INT32); -static unsigned char sigbuf[SIGNAL_BUFFER]; -static int firstsig, lastsig; static struct callback *signal_evaluator_callback =0; +DECLARE_FIFO(sig,char); + + #ifdef USE_PID_MAPPING static void report_child(int pid, WAITSTATUSTYPE status); @@ -135,14 +223,13 @@ static void report_child(int pid, #ifdef USE_SIGCHILD static RETSIGTYPE receive_sigchild(int signum); -struct wait_data { +typedef struct wait_data_s { pid_t pid; WAITSTATUSTYPE status; -}; +} wait_data; + +DECLARE_FIFO(wait,wait_data); -static volatile struct wait_data wait_buf[WAIT_BUFFER]; -static volatile int firstwait=0; -static volatile int lastwait=0; #endif @@ -362,21 +449,15 @@ static struct sigdesc signal_desc []={ static void register_signal(int signum) { - int tmp; - - tmp=firstsig+1; - if(tmp == SIGNAL_BUFFER) tmp=0; - if(tmp != lastsig) - { - sigbuf[tmp]=signum; - firstsig=tmp; - } + BEGIN_FIFO_PUSH(sig,char); + FIFO_DATA(sig,char)=signum; + END_FIFO_PUSH(sig,char); wake_up_backend(); - } static RETSIGTYPE receive_signal(int signum) { + SAFE_FIFO_DEBUG_BEGIN(); if ((signum < 0) || (signum >= MAX_SIGNALS)) { /* Some OSs (Solaris 2.6) send a bad signum sometimes. * SIGCHLD is the safest signal to substitute. @@ -390,6 +471,7 @@ static RETSIGTYPE receive_signal(int signum) } register_signal(signum); + SAFE_FIFO_DEBUG_END(); #ifdef SIGNAL_ONESHOT my_signal(signum, receive_signal); #endif @@ -450,43 +532,47 @@ void check_signals(struct callback *foo, void *bar, void *gazonk) if(d_flag>5) do_debug(); #endif - if(firstsig != lastsig && !signalling) + + if(QUICK_CHECK_FIFO(sig,char) && !signalling) { - int tmp=firstsig; signalling=1; SET_ONERROR(ebuf,unset_signalling,0); - while(lastsig != tmp) - { - if(++lastsig == SIGNAL_BUFFER) lastsig=0; + BEGIN_FIFO_LOOP(sig,char); #ifdef USE_SIGCHILD - if(sigbuf[lastsig]==SIGCHLD) - { - int tmp2 = firstwait; - while(lastwait != tmp2) - { - if(++lastwait == WAIT_BUFFER) lastwait=0; - report_child(wait_buf[lastwait].pid, - wait_buf[lastwait].status); - } - } + if(FIFO_DATA(sig,char)==SIGCHLD) + { + BEGIN_FIFO_LOOP(wait,wait_data); + + if(!FIFO_DATA(wait,wait_data).pid) + fatal("FIFO_DATA(wait,wait_data).pid=0 NEED_SIGNAL_SAFE_FIFO is " +#ifndef NEED_SIGNAL_SAFE_FIFO + "not " +#endif + "defined.\n"); + + process_done(FIFO_DATA(wait,wait_data).pid,"check_signals"); + report_child(FIFO_DATA(wait,wait_data).pid, + FIFO_DATA(wait,wait_data).status); + + END_FIFO_LOOP(wait,wait_data); + } #endif - if(IS_ZERO(signal_callbacks + sigbuf[lastsig])) - { - if(default_signals[sigbuf[lastsig]]) - default_signals[sigbuf[lastsig]](sigbuf[lastsig]); - }else{ - push_int(sigbuf[lastsig]); - apply_svalue(signal_callbacks + sigbuf[lastsig], 1); - pop_stack(); - } + if(IS_ZERO(signal_callbacks + FIFO_DATA(sig,char))) + { + if(default_signals[FIFO_DATA(sig,char)]) + default_signals[FIFO_DATA(sig,char)](FIFO_DATA(sig,char)); + }else{ + push_int(FIFO_DATA(sig,char)); + apply_svalue(signal_callbacks + FIFO_DATA(sig,char), 1); + pop_stack(); } + END_FIFO_LOOP(sig,char); UNSET_ONERROR(ebuf); - signalling=0; } } @@ -650,6 +736,8 @@ static void f_signame(int args) #if PIKE_DEBUG char process_info[65536]; +int last_pid_p; +int last_pids[4096]; #define P_NOT_STARTED 0 #define P_RUNNING 1 @@ -657,11 +745,29 @@ char process_info[65536]; #define P_RUNNING_AGAIN 3 #define P_DONE_AGAIN 4 +void dump_process_history(pid_t pid) +{ + int e; + if(pid < 1 || pid > 65536) + fatal("Pid out of range: %ld\n",(long)pid); + + fprintf(stderr,"Process history:"); + for(e=MAXIMUM(-4095,-last_pid_p);e<0;e++) + { + fprintf(stderr," %d",last_pids[ (last_pid_p + e) & 4095]); + } + + fprintf(stderr,"\nProblem pid = %d, status = %d\n",pid,process_info[pid]); +} + + void process_started(pid_t pid) { - if(pid < 0 || pid > 65536) + if(pid < 1 || pid > 65536) fatal("Pid out of range: %ld\n",(long)pid); + last_pids[last_pid_p++ & 4095]=pid; + switch(process_info[pid]) { case P_NOT_STARTED: @@ -671,16 +777,18 @@ void process_started(pid_t pid) case P_DONE_AGAIN: process_info[pid]=P_RUNNING_AGAIN; + break; default: + dump_process_history(pid); fatal("Process debug: Pid %ld started without stopping! (status=%d)\n",(long)pid,process_info[pid]); } } -void process_done(pid_t pid) +void process_done(pid_t pid, char *from) { - if(pid < 0 || pid > 65536) - fatal("Pid out of range: %ld\n",(long)pid); + if(pid < 1 || pid > 65536) + fatal("Pid out of range in %s: %ld\n",from,(long)pid); switch(process_info[pid]) { case P_RUNNING: @@ -689,14 +797,17 @@ void process_done(pid_t pid) break; default: - fatal("Process debug: Unknown child %ld! (status=%d)\n",(long)pid,process_info[pid]); + dump_process_history(pid); + fatal("Process debug: Unknown child %ld in %s! (status=%d)\n",(long)pid,from,process_info[pid]); } } + #else #define process_started(PID) -#define process_done(PID) +#define process_done(PID,FROM) +#define dump_process_history(PID) #endif @@ -727,31 +838,34 @@ void process_done(pid_t pid) #ifdef USE_SIGCHILD + static RETSIGTYPE receive_sigchild(int signum) { pid_t pid; WAITSTATUSTYPE status; - + + SAFE_FIFO_DEBUG_BEGIN(); + try_reap_again: /* We carefully reap what we saw */ pid=MY_WAIT_ANY(&status, WNOHANG); if(pid>0) { - int tmp2=firstwait+1; - if(tmp2 == WAIT_BUFFER) tmp2=0; - if(tmp2 != lastwait) - { - wait_buf[tmp2].pid=pid; - wait_buf[tmp2].status=status; - firstwait=tmp2; - goto try_reap_again; - } + BEGIN_FIFO_PUSH(wait,wait_data); + FIFO_DATA(wait,wait_data).pid=pid; + FIFO_DATA(wait,wait_data).status=status; + END_FIFO_PUSH(wait,wait_data); + goto try_reap_again; } register_signal(SIGCHLD); + + SAFE_FIFO_DEBUG_END(); + #ifdef SIGNAL_ONESHOT my_signal(signum, receive_sigchild); #endif + } #endif @@ -814,9 +928,8 @@ static void report_child(int pid, { #ifdef PROC_DEBUG /* FIXME: This won't work if WAITSTATUSTYPE == union wait. */ - fprintf(stderr, "report_child(%d, %d)\n", (int)pid, (int)status); + fprintf(stderr, "report_child(%d, %d)\n", (int)pid, *(int *) &status); #endif /* PROC_DEBUG */ - process_done(pid); if(pid_mapping) { struct svalue *s, key; @@ -933,6 +1046,7 @@ static TH_RETURN_TYPE wait_thread(void *data) #ifdef PROC_DEBUG fprintf(stderr, "wait thread: reporting the event!\n"); #endif + process_done(pid,"wait_thread"); report_child(pid, status); co_broadcast(& process_status_change); @@ -1017,7 +1131,8 @@ static void f_pid_status_wait(INT32 args) s=low_mapping_lookup(pid_mapping, &key); if(s && s->type == T_OBJECT && s->u.object == fp->current_object) { - error("Operating system failure: " + dump_process_history(pid); + fatal("Operating system failure: " "Pike lost track of a child, pid=%d, errno=%d.\n",pid,err); } @@ -1028,16 +1143,26 @@ static void f_pid_status_wait(INT32 args) THREADS_ALLOW(); pid=WAITPID(pid,& status,0); THREADS_DISALLOW(); - if(pid > -1) + if(pid > 0) { + process_done(pid,"->wait"); report_child(pid, status); - }else{ - switch(errno) + } + else + { + + if(pid<0) { - case EINTR: break; - - default: - err=errno; + switch(errno) + { + case EINTR: break; + + default: + err=errno; + } + }else{ + /* This should not happen! */ + fatal("Pid = 0 in waitpid(%d)\n",pid); } } @@ -2898,6 +3023,10 @@ void f_atexit(INT32 args) void init_signals(void) { int e; + + INIT_FIFO(sig,char); + INIT_FIFO(wait,wait_data); + #ifdef USE_SIGCHILD my_signal(SIGCHLD, receive_sigchild); #endif @@ -2940,8 +3069,6 @@ void init_signals(void) for(e=0;e<MAX_SIGNALS;e++) signal_callbacks[e].type=T_INT; - firstsig=lastsig=0; - if(!signal_evaluator_callback) { signal_evaluator_callback=add_to_callback(&evaluator_callbacks, diff --git a/src/signal_handler.h b/src/signal_handler.h index 6bc75f6fc31d9cc2355d5c0a7a5dd83cf0a3a480..1fd1f83e603c3f1095ba84345f5106c7e1197fa3 100644 --- a/src/signal_handler.h +++ b/src/signal_handler.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: signal_handler.h,v 1.8 1999/04/12 05:27:49 hubbe Exp $ + * $Id: signal_handler.h,v 1.9 1999/06/03 06:10:01 hubbe Exp $ */ #ifndef SIGNAL_H #define SIGNAL_H @@ -18,7 +18,7 @@ void my_signal(int sig, sigfunctype fun); void check_signals(struct callback *foo, void *bar, void *gazonk); void set_default_signal_handler(int signum, void (*func)(INT32)); void process_started(pid_t pid); -void process_done(pid_t pid); +void process_done(pid_t pid, char *from); struct wait_data; struct pid_status; struct perishables; diff --git a/src/testsuite.in b/src/testsuite.in index e0d975ed40a16ac8b3e9f6f7f59071eb0cf79bce..28a62f5399268a657f4d5aa61955d7e6f69ba6a6 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -1,4 +1,4 @@ -stest_true([["$Id: testsuite.in,v 1.173 1999/06/02 18:59:38 grubba Exp $"]]) +stest_true([["$Id: testsuite.in,v 1.174 1999/06/03 06:10:02 hubbe Exp $"]]) cond([[all_constants()->_verify_internals]], [[ test_do(_verify_internals()) @@ -3230,20 +3230,58 @@ cond([[ file_stat("/bin/cat") && file_stat("/dev/null") && all_constants()->thre cond([[ file_stat("/bin/cat") && file_stat("/dev/null") && all_constants()->thread_create && (cpp("__NT__")/"\n")[1]=="__NT__" ]], [[ + test_do([[ for(int q=0;q<100;q++) { - Threads.Fifo fifo=Threads.Fifo(); + array fnord=({}); + Thread.Fifo fifo=Thread.Fifo(); for(int e=0;e<10;e++) { - thread_create(lamba() { + fnord+=({ thread_create(lambda() { Process.create_process(({"/bin/cat","/dev/null"})); fifo->read(); - }); + }) }); } for(int e=0;e<50;e++) Stdio.Port()->bind(0); for(int e=0;e<10;e++) fifo->write(1); + fnord->wait(); } + ]]) +]]) + +cond([[ file_stat("/bin/sleep") && all_constants()->thread_create && (cpp("__NT__")/"\n")[1]=="__NT__" ]], +[[ +test_any([[ + class Fnord + { +int gnapp(int t) +{ + int e; + for(e=0;e<7;e++) + { + for(int d=0;d<150;d++) + { + object o=Process.create_process(({"/bin/sleep","99999"})); + kill( o->pid(), 9 ); + o->wait(); + } +// werror("%d",t); + } + return -1; +} + +array start() +{ + array a=({}); + for(int e=0;e<10;e++) + a+=({thread_create(gnapp,e)}); + return a; +} +}; + +return Fnord()->start()->wait()-({ -1 }); +]],[[ ({}) ]]) ]]) diff --git a/src/threads.c b/src/threads.c index 92c7e7a3701e9e86ce0b4bcfca6482edba61bef9..dbc18a16e4663edcea1e2d2d6ce74b5290edd010 100644 --- a/src/threads.c +++ b/src/threads.c @@ -1,5 +1,5 @@ #include "global.h" -RCSID("$Id: threads.c,v 1.97 1999/05/13 17:43:37 grubba Exp $"); +RCSID("$Id: threads.c,v 1.98 1999/06/03 06:10:03 hubbe Exp $"); int num_threads = 1; int threads_disabled = 0; @@ -622,9 +622,11 @@ void f_thread_create(INT32 args) arg->id=clone_object(thread_id_prog,0); OBJ2THREAD(arg->id)->status=THREAD_RUNNING; - tmp=th_create(& OBJ2THREAD(arg->id)->id, - new_thread_func, - arg); + do { + tmp=th_create(& OBJ2THREAD(arg->id)->id, + new_thread_func, + arg); + } while( tmp == EINTR ); if(!tmp) {