/[guile]/guile/guile-core/libguile/scmsigs.c
ViewVC logotype

Diff of /guile/guile-core/libguile/scmsigs.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.74 by mvo, Wed Oct 16 16:01:22 2002 UTC revision 1.75 by mvo, Sun Oct 27 20:25:17 2002 UTC
# Line 108  int usleep (); Line 108  int usleep ();
108    
109  /* Scheme vectors with information about a signal.  signal_handlers  /* Scheme vectors with information about a signal.  signal_handlers
110     contains the handler procedure or #f, signal_handler_cells contains     contains the handler procedure or #f, signal_handler_cells contains
111     preallocated cells for queuing the handler in take_signal since we     pre-queued cells for the handler (since we can't do fancy things
112     can't allocate during signal delivery, signal_handler_threads     during signal delivery), signal_cell_handlers contains the SCM
113     points to the thread that a signal should be delivered to.     value to be stuffed into the pre-queued cell upon delivery, and
114       signal_handler_threads points to the thread that a signal should be
115       delivered to.
116  */  */
117  static SCM *signal_handlers;  static SCM *signal_handlers;
118  static SCM signal_handler_cells;  static SCM signal_handler_cells;
119    static SCM signal_cell_handlers;
120  static SCM signal_handler_threads;  static SCM signal_handler_threads;
121    
122  /* saves the original C handlers, when a new handler is installed.  /* saves the original C handlers, when a new handler is installed.
# Line 124  static struct sigaction orig_handlers[NS Line 127  static struct sigaction orig_handlers[NS
127  static SIGRETTYPE (*orig_handlers[NSIG])(int);  static SIGRETTYPE (*orig_handlers[NSIG])(int);
128  #endif  #endif
129    
130    
131  static SIGRETTYPE  static SIGRETTYPE
132  take_signal (int signum)  take_signal (int signum)
133  {  {
134    if (signum >= 0 && signum < NSIG)    if (signum >= 0 && signum < NSIG)
135      {      {
136  #ifdef USE_THREADS        SCM cell = SCM_VECTOR_REF(signal_handler_cells, signum);
137        SCM thread = SCM_VECTOR_REF (signal_handler_threads, signum);        SCM handler = SCM_VECTOR_REF(signal_cell_handlers, signum);
138        scm_i_queue_async_cell (SCM_VECTOR_REF(signal_handler_cells, signum),        SCM thread = SCM_VECTOR_REF(signal_handler_threads, signum);
139                                scm_i_thread_root (thread));        scm_root_state *root = scm_i_thread_root (thread);
140  #else        if (SCM_CONSP (cell))
141        scm_i_queue_async_cell (SCM_VECTOR_REF(signal_handler_cells, signum),          {
142                                scm_root);            SCM_SETCAR (cell, handler);
143  #endif            root->pending_asyncs = 1;
144            }
145      }      }
146      
147  #ifndef HAVE_SIGACTION  #ifndef HAVE_SIGACTION
148    signal (signum, take_signal);    signal (signum, take_signal);
149  #endif  #endif
# Line 156  close_1 (SCM proc, SCM arg) Line 162  close_1 (SCM proc, SCM arg)
162                                             scm_list_2 (proc, arg)));                                             scm_list_2 (proc, arg)));
163  }  }
164    
165    /* Make sure that signal SIGNUM can be delivered to THREAD, using
166       HANDLER.  THREAD and HANDLER must either both be non-#f (which
167       means install the handler), or both #f (which means deinstall an
168       existing handler).
169    */
170    
171    struct install_handler_data {
172      int signum;
173      SCM thread;
174      SCM handler;
175    };
176    
177    static SCM
178    scm_delq_spine_x (SCM cell, SCM list)
179    {
180      SCM s = list, prev = SCM_BOOL_F;
181      
182      while (!SCM_EQ_P (cell, s))
183        {
184          if (SCM_NULLP (s))
185            return list;
186          prev = s;
187          s = SCM_CDR (s);
188        }
189      if (SCM_FALSEP (prev))
190        return SCM_CDR (cell);
191      else
192        {
193          SCM_SETCDR (prev, SCM_CDR (cell));
194          return list;
195        }
196    }
197    
198    static void *
199    really_install_handler (void *data)
200    {
201      struct install_handler_data *args = data;
202      int signum = args->signum;
203      SCM thread = args->thread;
204      SCM handler = args->handler;
205      SCM cell;
206      SCM old_thread;
207    
208      /* The following modifications are done while signals can be
209         delivered.  That is not a real problem since the signal handler
210         will only touch the car of the handler cell and set the
211         pending_asyncs trigger of a thread.  While the data structures
212         are in flux, the signal handler might store the wrong handler in
213         the cell, or set pending_asyncs of the wrong thread.  We fix this
214         at the end by making sure that the cell has the right handler in
215         it, if any, and that pending_asyncs is set for the new thread.
216      */
217    
218      /* Make sure we have a cell. */
219      cell = SCM_VECTOR_REF (signal_handler_cells, signum);
220      if (SCM_FALSEP (cell))
221        {
222          cell = scm_cons (SCM_BOOL_F, SCM_EOL);
223          SCM_VECTOR_SET (signal_handler_cells, signum, cell);
224        }
225    
226      /* Make sure it is queued for the right thread. */
227      old_thread = SCM_VECTOR_REF (signal_handler_threads, signum);
228      if (!SCM_EQ_P (thread, old_thread))
229        {
230          scm_root_state *r;
231          if (!SCM_FALSEP (old_thread))
232            {
233              r = scm_i_thread_root (old_thread);
234              r->signal_asyncs = scm_delq_spine_x (cell, r->signal_asyncs);
235            }
236          if (!SCM_FALSEP (thread))
237            {
238              r = scm_i_thread_root (thread);
239              SCM_SETCDR (cell, r->signal_asyncs);
240              r->signal_asyncs = cell;
241              /* Set pending_asyncs just in case.  A signal that is
242                 delivered while we modify the data structures here might set
243                 pending_asyncs of old_thread. */
244              r->pending_asyncs = 1;
245            }
246          SCM_VECTOR_SET (signal_handler_threads, signum, thread);
247        }
248    
249      /* Set the new handler. */
250      if (SCM_FALSEP (handler))
251        {
252          SCM_VECTOR_SET (*signal_handlers, signum, SCM_BOOL_F);
253          SCM_VECTOR_SET (signal_cell_handlers, signum, SCM_BOOL_F);
254        }
255      else
256        {
257          SCM_VECTOR_SET (*signal_handlers, signum, handler);
258          SCM_VECTOR_SET (signal_cell_handlers, signum,
259                          close_1 (handler, scm_int2num (signum)));
260        }
261    
262      /* Now fix up the cell.  It might contain the old handler but since
263         it is now queued for the new thread, we must make sure that the
264         new handler is run.  Any signal that is delivered during the
265         following code will install the new handler, so we have no
266         problem.
267      */
268      if (!SCM_FALSEP (SCM_CAR (cell)))
269        SCM_SETCAR (cell, SCM_VECTOR_REF (signal_cell_handlers, signum));
270    
271      /* Phfew.  That should be it. */
272      return NULL;
273    }
274    
275    static void
276    install_handler (int signum, SCM thread, SCM handler)
277    {
278      /* We block asyncs while installing the handler.  It would be safe
279         to leave them on, but we might run the wrong handler should a
280         signal be delivered.
281      */
282    
283      struct install_handler_data args;
284      args.signum = signum;
285      args.thread = thread;
286      args.handler = handler;
287      scm_c_call_with_blocked_asyncs (really_install_handler, &args);
288    }
289    
290  /* user interface for installation of signal handlers.  */  /* user interface for installation of signal handlers.  */
291  SCM_DEFINE (scm_sigaction_for_thread, "sigaction", 1, 3, 0,  SCM_DEFINE (scm_sigaction_for_thread, "sigaction", 1, 3, 0,
292             (SCM signum, SCM handler, SCM flags, SCM thread),             (SCM signum, SCM handler, SCM flags, SCM thread),
# Line 224  SCM_DEFINE (scm_sigaction_for_thread, "s Line 355  SCM_DEFINE (scm_sigaction_for_thread, "s
355    if (SCM_UNBNDP (thread))    if (SCM_UNBNDP (thread))
356      thread = scm_current_thread ();      thread = scm_current_thread ();
357    else    else
358      SCM_VALIDATE_THREAD (4, thread);      {
359          SCM_VALIDATE_THREAD (4, thread);
360          if (scm_c_thread_exited_p (thread))
361            SCM_MISC_ERROR ("thread has already exited", SCM_EOL);
362        }
363  #else  #else
364    thread = SCM_BOOL_F;    thread = SCM_BOOL_F;
365  #endif  #endif
# Line 243  SCM_DEFINE (scm_sigaction_for_thread, "s Line 378  SCM_DEFINE (scm_sigaction_for_thread, "s
378  #else  #else
379            chandler = (SIGRETTYPE (*) (int)) SCM_INUM (handler);            chandler = (SIGRETTYPE (*) (int)) SCM_INUM (handler);
380  #endif  #endif
381            SCM_VECTOR_SET (*signal_handlers, csig, SCM_BOOL_F);            install_handler (csig, SCM_BOOL_F, SCM_BOOL_F);
382          }          }
383        else        else
384          SCM_OUT_OF_RANGE (2, handler);          SCM_OUT_OF_RANGE (2, handler);
# Line 258  SCM_DEFINE (scm_sigaction_for_thread, "s Line 393  SCM_DEFINE (scm_sigaction_for_thread, "s
393          {          {
394            action = orig_handlers[csig];            action = orig_handlers[csig];
395            orig_handlers[csig].sa_handler = SIG_ERR;            orig_handlers[csig].sa_handler = SIG_ERR;
396            SCM_VECTOR_SET (*signal_handlers, csig, SCM_BOOL_F);            install_handler (csig, SCM_BOOL_F, SCM_BOOL_F);
   
397          }          }
398  #else  #else
399        if (orig_handlers[csig] == SIG_ERR)        if (orig_handlers[csig] == SIG_ERR)
# Line 268  SCM_DEFINE (scm_sigaction_for_thread, "s Line 402  SCM_DEFINE (scm_sigaction_for_thread, "s
402          {          {
403            chandler = orig_handlers[csig];            chandler = orig_handlers[csig];
404            orig_handlers[csig] = SIG_ERR;            orig_handlers[csig] = SIG_ERR;
405            SCM_VECTOR_SET (*signal_handlers, csig, SCM_BOOL_F);            install_handler (csig, SCM_BOOL_F, SCM_BOOL_F);
406          }          }
407  #endif  #endif
408      }      }
# Line 284  SCM_DEFINE (scm_sigaction_for_thread, "s Line 418  SCM_DEFINE (scm_sigaction_for_thread, "s
418        if (orig_handlers[csig] == SIG_ERR)        if (orig_handlers[csig] == SIG_ERR)
419          save_handler = 1;          save_handler = 1;
420  #endif  #endif
421        SCM_VECTOR_SET (*signal_handlers, csig, handler);        install_handler (csig, thread, handler);
       SCM_VECTOR_SET (signal_handler_cells, csig,  
                       scm_cons (close_1 (handler, signum), SCM_BOOL_F));  
       SCM_VECTOR_SET (signal_handler_threads, csig, thread);  
422      }      }
423    
424    /* XXX - Silently ignore setting handlers for `program error signals'    /* XXX - Silently ignore setting handlers for `program error signals'
# Line 582  scm_init_scmsigs () Line 713  scm_init_scmsigs ()
713                                    scm_c_make_vector (NSIG, SCM_BOOL_F)));                                    scm_c_make_vector (NSIG, SCM_BOOL_F)));
714    signal_handler_cells =    signal_handler_cells =
715      scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));      scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));
716      signal_cell_handlers =
717        scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));
718    signal_handler_threads =    signal_handler_threads =
719      scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));      scm_permanent_object (scm_c_make_vector (NSIG, SCM_BOOL_F));
720    

Legend:
Removed from v.1.74  
changed lines
  Added in v.1.75

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26