source: rtems/cpukit/posix/src/psignal.c @ 07d880f4

4.104.114.84.95
Last change on this file since 07d880f4 was 07d880f4, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/99 at 20:45:31

Split psignal.c into many more files. This reduced the amount of
object code that has to be loaded just for initializing the signal
manager.

  • Property mode set to 100644
File size: 10.9 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <assert.h>
6#include <errno.h>
7#include <pthread.h>
8#include <signal.h>
9
10#include <rtems/system.h>
11#include <rtems/score/isr.h>
12#include <rtems/score/thread.h>
13#include <rtems/score/tqdata.h>
14#include <rtems/score/wkspace.h>
15#include <rtems/posix/seterr.h>
16#include <rtems/posix/threadsup.h>
17#include <rtems/posix/psignal.h>
18#include <rtems/posix/pthread.h>
19#include <rtems/posix/time.h>
20
21/*** PROCESS WIDE STUFF ****/
22
23sigset_t  _POSIX_signals_Pending;
24
25struct sigaction _POSIX_signals_Vectors[ SIG_ARRAY_MAX ];
26
27Watchdog_Control _POSIX_signals_Alarm_timer;
28
29Thread_queue_Control _POSIX_signals_Wait_queue;
30
31Chain_Control _POSIX_signals_Inactive_siginfo;
32Chain_Control _POSIX_signals_Siginfo[ SIG_ARRAY_MAX ];
33
34struct sigaction _POSIX_signals_Default_vectors[ SIG_ARRAY_MAX ] = {
35  /* NO SIGNAL 0 */  SIGACTION_IGNORE,
36  /* SIGHUP    1 */  SIGACTION_TERMINATE,
37  /* SIGINT    2 */  SIGACTION_TERMINATE,
38  /* SIGQUIT   3 */  SIGACTION_TERMINATE,
39  /* SIGILL    4 */  SIGACTION_TERMINATE,
40  /* SIGTRAP   5 */  SIGACTION_TERMINATE,
41  /* SIGIOT    6 */  SIGACTION_TERMINATE,
42  /* SIGABRT   6     SIGACTION_TERMINATE, -- alias for SIGIOT */
43  /* SIGEMT    7 */  SIGACTION_TERMINATE,
44  /* SIGFPE    8 */  SIGACTION_TERMINATE,
45  /* SIGKILL   9 */  SIGACTION_TERMINATE,
46  /* SIGBUS   10 */  SIGACTION_TERMINATE,
47  /* SIGSEGV  11 */  SIGACTION_TERMINATE,
48  /* SIGSYS   12 */  SIGACTION_TERMINATE,
49  /* SIGPIPE  13 */  SIGACTION_TERMINATE,
50  /* SIGALRM  14 */  SIGACTION_TERMINATE,
51  /* SIGTERM  15 */  SIGACTION_TERMINATE,
52  /* SIGUSR1  16 */  SIGACTION_TERMINATE,
53  /* SIGUSR2  17 */  SIGACTION_TERMINATE,
54  /* SIGRTMIN 18 */  SIGACTION_IGNORE,
55  /* SIGRT    19 */  SIGACTION_IGNORE,
56  /* SIGRT    20 */  SIGACTION_IGNORE,
57  /* SIGRT    21 */  SIGACTION_IGNORE,
58  /* SIGRT    22 */  SIGACTION_IGNORE,
59  /* SIGRT    23 */  SIGACTION_IGNORE,
60  /* SIGRT    24 */  SIGACTION_IGNORE,
61  /* SIGRT    25 */  SIGACTION_IGNORE,
62  /* SIGRT    26 */  SIGACTION_IGNORE,
63  /* SIGRT    27 */  SIGACTION_IGNORE,
64  /* SIGRT    28 */  SIGACTION_IGNORE,
65  /* SIGRT    29 */  SIGACTION_IGNORE,
66  /* SIGRT    30 */  SIGACTION_IGNORE,
67  /* SIGRT    31 */  SIGACTION_IGNORE,
68  /* SIGRTMAX 32 */  SIGACTION_IGNORE
69};
70
71/*PAGE
72 *
73 *  _POSIX_signals_Abormal_termination_handler
74 *
75 */
76
77void _POSIX_signals_Abormal_termination_handler( int signo )
78{
79  exit( 1 );
80}
81
82/*PAGE
83 *
84 *  _POSIX_signals_Unblock_thread
85 */
86
87/* XXX this routine could probably be cleaned up */
88boolean _POSIX_signals_Unblock_thread(
89  Thread_Control  *the_thread,
90  int              signo,
91  siginfo_t       *info
92)
93{
94  POSIX_API_Control  *api;
95  sigset_t            mask;
96  siginfo_t          *the_info = NULL;
97
98  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
99
100  mask = signo_to_mask( signo );
101
102  /*
103   *  Is the thread is specifically waiting for a signal?
104   */
105
106  if ( _States_Is_interruptible_signal( the_thread->current_state ) ) {
107
108    if ( (the_thread->Wait.option & mask) || (~api->signals_blocked & mask) ) {
109      the_thread->Wait.return_code = EINTR;
110
111      the_info = (siginfo_t *) the_thread->Wait.return_argument;
112
113      if ( !info ) {
114        the_info->si_signo = signo;
115        the_info->si_code = SI_USER;
116        the_info->si_value.sival_int = 0;
117      } else {
118        *the_info = *info;
119      }
120     
121      _Thread_queue_Extract_with_proxy( the_thread );
122      return TRUE;
123    }
124
125    /*
126     *  This should only be reached via pthread_kill().
127     */
128
129    return FALSE;
130  }
131
132  if ( ~api->signals_blocked & mask ) {
133    the_thread->do_post_task_switch_extension = TRUE;
134
135    if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) {
136      the_thread->Wait.return_code = EINTR;
137      if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) )
138        _Thread_queue_Extract_with_proxy( the_thread );
139      else if ( _States_Is_delaying(the_thread->current_state)){
140        if ( _Watchdog_Is_active( &the_thread->Timer ) )
141          (void) _Watchdog_Remove( &the_thread->Timer );
142        _Thread_Unblock( the_thread );
143      }
144    }
145  }
146  return FALSE;
147
148}
149
150/*PAGE
151 *
152 *  _POSIX_signals_Set_process_signals
153 */
154 
155void _POSIX_signals_Set_process_signals(
156  sigset_t   mask
157)
158{
159  ISR_Level  level;
160 
161  _ISR_Disable( level );
162    if ( !_POSIX_signals_Pending )
163      _Thread_Do_post_task_switch_extension++;
164    _POSIX_signals_Pending |= mask;
165  _ISR_Enable( level );
166}
167
168/*PAGE
169 *
170 *  _POSIX_signals_Clear_process_signals
171 */
172
173void _POSIX_signals_Clear_process_signals(
174  sigset_t   mask
175)
176{
177  ISR_Level  level;
178
179  _ISR_Disable( level );
180    _POSIX_signals_Pending &= ~mask;
181    if ( !_POSIX_signals_Pending && _Thread_Do_post_task_switch_extension )
182      _Thread_Do_post_task_switch_extension--;
183  _ISR_Enable( level );
184}
185
186/*PAGE
187 *
188 *  _POSIX_signals_Clear_signals
189 */
190 
191boolean _POSIX_signals_Clear_signals(
192  POSIX_API_Control  *api,
193  int                 signo,
194  siginfo_t          *info,
195  boolean             is_global,
196  boolean             check_blocked
197)
198{
199  sigset_t                    mask;
200  sigset_t                    signals_blocked;
201  ISR_Level                   level;
202  boolean                     do_callout;
203  POSIX_signals_Siginfo_node *psiginfo;
204 
205  mask = signo_to_mask( signo );
206 
207  do_callout = FALSE;
208 
209  /* set blocked signals based on if checking for them, SIGNAL_ALL_MASK
210   * insures that no signals are blocked and all are checked.
211   */
212
213  if ( check_blocked )
214    signals_blocked = ~api->signals_blocked;
215  else
216    signals_blocked = SIGNAL_ALL_MASK;
217
218  /* XXX this is not right for siginfo type signals yet */
219  /* XXX since they can't be cleared the same way */
220 
221  _ISR_Disable( level );
222    if ( is_global ) {
223       if ( mask & (_POSIX_signals_Pending & signals_blocked) ) {
224         if ( _POSIX_signals_Vectors[ signo ].sa_flags == SA_SIGINFO ) {
225           psiginfo = (POSIX_signals_Siginfo_node *)
226             _Chain_Get_unprotected( &_POSIX_signals_Siginfo[ signo ] );
227           if ( _Chain_Is_empty( &_POSIX_signals_Siginfo[ signo ] ) )
228             _POSIX_signals_Clear_process_signals( mask );
229           if ( psiginfo ) {
230             *info = psiginfo->Info;
231             _Chain_Append_unprotected(
232               &_POSIX_signals_Inactive_siginfo,
233               &psiginfo->Node
234             );
235           } else
236             do_callout = FALSE;
237         } else
238           _POSIX_signals_Clear_process_signals( mask );
239         do_callout = TRUE;
240       }
241    } else {
242      if ( mask & (api->signals_pending & signals_blocked) ) {
243        api->signals_pending &= ~mask;
244        do_callout = TRUE;
245      }
246    }
247  _ISR_Enable( level );
248  return do_callout;
249}
250
251
252/*PAGE
253 *
254 *  _POSIX_signals_Check_signal
255 */
256
257boolean _POSIX_signals_Check_signal(
258  POSIX_API_Control  *api,
259  int                 signo,
260  boolean             is_global
261)
262{
263  siginfo_t                   siginfo_struct;
264  sigset_t                    saved_signals_blocked;
265
266  if ( ! _POSIX_signals_Clear_signals( api, signo, &siginfo_struct,
267                                       is_global, TRUE ) )
268    return FALSE;
269
270  /*
271   *  Since we made a union of these, only one test is necessary but this is
272   *  safer.
273   */
274
275  assert( _POSIX_signals_Vectors[ signo ].sa_handler ||
276          _POSIX_signals_Vectors[ signo ].sa_sigaction );
277 
278  /*
279   *  Just to prevent sending a signal which is currently being ignored.
280   */
281
282  if ( _POSIX_signals_Vectors[ signo ].sa_handler == SIG_IGN )
283    return FALSE;
284
285  /*
286   *  Block the signals requested in sa_mask
287   */
288
289  saved_signals_blocked = api->signals_blocked;
290  api->signals_blocked |= _POSIX_signals_Vectors[ signo ].sa_mask;
291
292  switch ( _POSIX_signals_Vectors[ signo ].sa_flags ) {
293    case SA_SIGINFO:
294      assert( is_global );
295
296      (*_POSIX_signals_Vectors[ signo ].sa_sigaction)(
297        signo,
298        &siginfo_struct,
299        NULL        /* context is undefined per 1003.1b-1993, p. 66 */
300      );
301      break;
302    default:
303      (*_POSIX_signals_Vectors[ signo ].sa_handler)( signo );
304      break;
305  }
306
307  /*
308   *  Restore the previous set of blocked signals
309   */
310 
311  api->signals_blocked = saved_signals_blocked;
312
313  return TRUE;
314}
315
316void _POSIX_signals_Post_switch_extension(
317  Thread_Control  *the_thread
318)
319{
320  POSIX_API_Control  *api;
321  int                 signo;
322  ISR_Level           level;
323
324  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
325
326  /*
327   *  If we invoke any user code, there is the possibility that
328   *  a new signal has been posted that we should process so we
329   *  restart the loop if a signal handler was invoked.
330   *
331   *  The first thing done is to check there are any signals to be
332   *  processed at all.  No point in doing this loop otherwise.
333   */
334
335restart:
336  _ISR_Disable( level );
337    if ( !(~api->signals_blocked &
338          (api->signals_pending | _POSIX_signals_Pending)) ) {
339     _ISR_Enable( level );
340     return;
341   }
342  _ISR_Enable( level );
343
344  for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) {
345
346    if ( _POSIX_signals_Check_signal( api, signo, FALSE ) )
347      goto restart;
348
349    if ( _POSIX_signals_Check_signal( api, signo, TRUE ) )
350      goto restart;
351
352  }
353
354/* XXX - add __SIGFIRSTNOTRT or something like that to newlib siginfo.h */
355
356  for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) {
357
358    if ( _POSIX_signals_Check_signal( api, signo, FALSE ) )
359      goto restart;
360 
361    if ( _POSIX_signals_Check_signal( api, signo, TRUE ) )
362      goto restart;
363
364  }
365
366}
367
368/*PAGE
369 *
370 *  _POSIX_signals_Alarm_TSR
371 */
372 
373void _POSIX_signals_Alarm_TSR(
374  Objects_Id      id,
375  void           *argument
376)
377{
378  int status;
379
380  status = kill( getpid(), SIGALRM );
381  /* XXX can't print from an ISR, should this be fatal? */
382  assert( !status );
383}
384
385/*PAGE
386 *
387 *  _POSIX_signals_Manager_Initialization
388 */
389
390void _POSIX_signals_Manager_Initialization(
391  int  maximum_queued_signals
392)
393{
394  unsigned32 signo;
395
396  /*
397   *  Insure we have the same number of vectors and default vector entries
398   */
399
400  assert(
401   sizeof(_POSIX_signals_Vectors) == sizeof(_POSIX_signals_Default_vectors)
402  );
403
404  memcpy(
405    _POSIX_signals_Vectors,
406    _POSIX_signals_Default_vectors,
407    sizeof( _POSIX_signals_Vectors )
408  );
409 
410  /*
411   *  Initialize the set of pending signals for the entire process
412   */
413
414  sigemptyset( &_POSIX_signals_Pending );
415
416  /*
417   *  Initialize the timer used to implement alarm().
418   */
419
420  _Watchdog_Initialize(
421    &_POSIX_signals_Alarm_timer,
422    _POSIX_signals_Alarm_TSR,
423    0,
424    NULL
425  );
426 
427  /*
428   *  Initialize the queue we use to block for signals
429   */
430 
431  _Thread_queue_Initialize(
432    &_POSIX_signals_Wait_queue,
433    OBJECTS_NO_CLASS,
434    THREAD_QUEUE_DISCIPLINE_PRIORITY,
435    STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL,
436    NULL,
437    EAGAIN
438  );
439
440  /* XXX status codes */
441
442  /*
443   *  Allocate the siginfo pools.
444   */
445
446  for ( signo=1 ; signo<= SIGRTMAX ; signo++ )
447    _Chain_Initialize_empty( &_POSIX_signals_Siginfo[ signo ] );
448
449  _Chain_Initialize(
450    &_POSIX_signals_Inactive_siginfo,
451    _Workspace_Allocate_or_fatal_error(
452      maximum_queued_signals * sizeof( POSIX_signals_Siginfo_node )
453    ),
454    maximum_queued_signals,
455    sizeof( POSIX_signals_Siginfo_node )
456  );
457}
Note: See TracBrowser for help on using the repository browser.