source: rtems/c/src/exec/posix/src/psignal.c @ 308aed9b

4.104.114.84.95
Last change on this file since 308aed9b was 20fff72, checked in by Joel Sherrill <joel.sherrill@…>, on 04/27/98 at 13:46:45

Moved POSIX_signals_Siginfo_node structure definition to headers/psignal.h
so confdefs.h could see it.

  • Property mode set to 100644
File size: 30.7 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/*
22 *  Currently 32 signals numbered 1-32 are defined
23 */
24
25#define SIGNAL_EMPTY_MASK  0x00000000
26#define SIGNAL_ALL_MASK    0xffffffff
27
28#define signo_to_mask( _sig ) (1 << ((_sig) - 1))
29
30#define is_valid_signo( _sig ) \
31  ((_sig) >= 1 && (_sig) <= 32 )
32
33/*** PROCESS WIDE STUFF ****/
34
35sigset_t  _POSIX_signals_Pending;
36
37void _POSIX_signals_Abormal_termination_handler( int signo )
38{
39  exit( 1 );
40}
41
42#define _POSIX_signals_Stop_handler NULL
43#define _POSIX_signals_Continue_handler NULL
44
45#define SIGACTION_TERMINATE \
46  { 0, SIGNAL_ALL_MASK, {_POSIX_signals_Abormal_termination_handler} }
47#define SIGACTION_IGNORE \
48  { 0, SIGNAL_ALL_MASK, {SIG_IGN} }
49#define SIGACTION_STOP \
50  { 0, SIGNAL_ALL_MASK, {_POSIX_signals_Stop_handler} }
51#define SIGACTION_CONTINUE \
52  { 0, SIGNAL_ALL_MASK, {_POSIX_signals_Continue_handler} }
53
54#define SIG_ARRAY_MAX  (SIGRTMAX + 1)
55struct sigaction _POSIX_signals_Default_vectors[ SIG_ARRAY_MAX ] = {
56  /* NO SIGNAL 0 */  SIGACTION_IGNORE,
57  /* SIGHUP    1 */  SIGACTION_TERMINATE,
58  /* SIGINT    2 */  SIGACTION_TERMINATE,
59  /* SIGQUIT   3 */  SIGACTION_TERMINATE,
60  /* SIGILL    4 */  SIGACTION_TERMINATE,
61  /* SIGTRAP   5 */  SIGACTION_TERMINATE,
62  /* SIGIOT    6 */  SIGACTION_TERMINATE,
63  /* SIGABRT   6     SIGACTION_TERMINATE, -- alias for SIGIOT */
64  /* SIGEMT    7 */  SIGACTION_TERMINATE,
65  /* SIGFPE    8 */  SIGACTION_TERMINATE,
66  /* SIGKILL   9 */  SIGACTION_TERMINATE,
67  /* SIGBUS   10 */  SIGACTION_TERMINATE,
68  /* SIGSEGV  11 */  SIGACTION_TERMINATE,
69  /* SIGSYS   12 */  SIGACTION_TERMINATE,
70  /* SIGPIPE  13 */  SIGACTION_TERMINATE,
71  /* SIGALRM  14 */  SIGACTION_TERMINATE,
72  /* SIGTERM  15 */  SIGACTION_TERMINATE,
73  /* SIGUSR1  16 */  SIGACTION_TERMINATE,
74  /* SIGUSR2  17 */  SIGACTION_TERMINATE,
75  /* SIGRTMIN 18 */  SIGACTION_IGNORE,
76  /* SIGRT    19 */  SIGACTION_IGNORE,
77  /* SIGRT    20 */  SIGACTION_IGNORE,
78  /* SIGRT    21 */  SIGACTION_IGNORE,
79  /* SIGRT    22 */  SIGACTION_IGNORE,
80  /* SIGRT    23 */  SIGACTION_IGNORE,
81  /* SIGRT    24 */  SIGACTION_IGNORE,
82  /* SIGRT    25 */  SIGACTION_IGNORE,
83  /* SIGRT    26 */  SIGACTION_IGNORE,
84  /* SIGRT    27 */  SIGACTION_IGNORE,
85  /* SIGRT    28 */  SIGACTION_IGNORE,
86  /* SIGRT    29 */  SIGACTION_IGNORE,
87  /* SIGRT    30 */  SIGACTION_IGNORE,
88  /* SIGRT    31 */  SIGACTION_IGNORE,
89  /* SIGRTMAX 32 */  SIGACTION_IGNORE
90};
91
92struct sigaction _POSIX_signals_Vectors[ SIG_ARRAY_MAX ];
93
94Watchdog_Control _POSIX_signals_Alarm_timer;
95
96Thread_queue_Control _POSIX_signals_Wait_queue;
97
98Chain_Control _POSIX_signals_Inactive_siginfo;
99Chain_Control _POSIX_signals_Siginfo[ SIG_ARRAY_MAX ];
100
101/*PAGE
102 *
103 *  XXX - move these
104 */
105
106#define _States_Is_interruptible_signal( _states ) \
107  ( ((_states) & \
108    (STATES_WAITING_FOR_SIGNAL|STATES_INTERRUPTIBLE_BY_SIGNAL)) == \
109      (STATES_WAITING_FOR_SIGNAL|STATES_INTERRUPTIBLE_BY_SIGNAL))
110
111/*PAGE
112 *
113 *  _POSIX_signals_Unblock_thread
114 */
115
116/* XXX this routine could probably be cleaned up */
117boolean _POSIX_signals_Unblock_thread(
118  Thread_Control  *the_thread,
119  int              signo,
120  siginfo_t       *info
121)
122{
123  POSIX_API_Control  *api;
124  sigset_t            mask;
125  siginfo_t          *the_info = NULL;
126
127  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
128
129  mask = signo_to_mask( signo );
130
131  /*
132   *  Is the thread is specifically waiting for a signal?
133   */
134
135  if ( _States_Is_interruptible_signal( the_thread->current_state ) ) {
136
137    if ( (the_thread->Wait.option & mask) || (~api->signals_blocked & mask) ) {
138      the_thread->Wait.return_code = EINTR;
139
140      the_info = (siginfo_t *) the_thread->Wait.return_argument;
141
142      if ( !info ) {
143        the_info->si_signo = signo;
144        the_info->si_code = SI_USER;
145        the_info->si_value.sival_int = 0;
146      } else {
147        *the_info = *info;
148      }
149     
150      _Thread_queue_Extract_with_proxy( the_thread );
151      return TRUE;
152    }
153
154    /*
155     *  This should only be reached via pthread_kill().
156     */
157
158    return FALSE;
159  }
160
161  if ( ~api->signals_blocked & mask ) {
162    the_thread->do_post_task_switch_extension = TRUE;
163
164    if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) {
165      the_thread->Wait.return_code = EINTR;
166      if ( _States_Is_waiting_on_thread_queue(the_thread->current_state) )
167        _Thread_queue_Extract_with_proxy( the_thread );
168      else if ( _States_Is_delaying(the_thread->current_state)){
169        if ( _Watchdog_Is_active( &the_thread->Timer ) )
170          (void) _Watchdog_Remove( &the_thread->Timer );
171        _Thread_Unblock( the_thread );
172      }
173    }
174  }
175  return FALSE;
176
177}
178
179/*PAGE
180 *
181 *  _POSIX_signals_Set_process_signals
182 */
183 
184void _POSIX_signals_Set_process_signals(
185  sigset_t   mask
186)
187{
188  ISR_Level  level;
189 
190  _ISR_Disable( level );
191    if ( !_POSIX_signals_Pending )
192      _Thread_Do_post_task_switch_extension++;
193    _POSIX_signals_Pending |= mask;
194  _ISR_Enable( level );
195}
196
197/*PAGE
198 *
199 *  _POSIX_signals_Clear_process_signals
200 */
201
202void _POSIX_signals_Clear_process_signals(
203  sigset_t   mask
204)
205{
206  ISR_Level  level;
207
208  _ISR_Disable( level );
209    _POSIX_signals_Pending &= ~mask;
210    if ( !_POSIX_signals_Pending )
211      _Thread_Do_post_task_switch_extension--;
212  _ISR_Enable( level );
213}
214
215/*PAGE
216 *
217 *  _POSIX_signals_Clear_signals
218 */
219 
220boolean _POSIX_signals_Clear_signals(
221  POSIX_API_Control  *api,
222  int                 signo,
223  siginfo_t          *info,
224  boolean             is_global,
225  boolean             check_blocked
226)
227{
228  sigset_t                    mask;
229  sigset_t                    signals_blocked;
230  ISR_Level                   level;
231  boolean                     do_callout;
232  POSIX_signals_Siginfo_node *psiginfo;
233 
234  mask = signo_to_mask( signo );
235 
236  do_callout = FALSE;
237 
238  /* set blocked signals based on if checking for them, SIGNAL_ALL_MASK
239   * insures that no signals are blocked and all are checked.
240   */
241
242  if ( check_blocked )
243    signals_blocked = ~api->signals_blocked;
244  else
245    signals_blocked = SIGNAL_ALL_MASK;
246
247  /* XXX this is not right for siginfo type signals yet */
248  /* XXX since they can't be cleared the same way */
249 
250  _ISR_Disable( level );
251    if ( is_global ) {
252       if ( mask & (_POSIX_signals_Pending & signals_blocked) ) {
253         if ( _POSIX_signals_Vectors[ signo ].sa_flags == SA_SIGINFO ) {
254           psiginfo = (POSIX_signals_Siginfo_node *)
255             _Chain_Get_unprotected( &_POSIX_signals_Siginfo[ signo ] );
256           if ( _Chain_Is_empty( &_POSIX_signals_Siginfo[ signo ] ) )
257             _POSIX_signals_Clear_process_signals( mask );
258           if ( psiginfo ) {
259             *info = psiginfo->Info;
260             _Chain_Append_unprotected(
261               &_POSIX_signals_Inactive_siginfo,
262               &psiginfo->Node
263             );
264           } else
265             do_callout = FALSE;
266         } else
267           _POSIX_signals_Clear_process_signals( mask );
268         do_callout = TRUE;
269       }
270    } else {
271      if ( mask & (api->signals_pending & signals_blocked) ) {
272        api->signals_pending &= ~mask;
273        do_callout = TRUE;
274      }
275    }
276  _ISR_Enable( level );
277  return do_callout;
278}
279
280
281/*PAGE
282 *
283 *  _POSIX_signals_Check_signal
284 */
285
286boolean _POSIX_signals_Check_signal(
287  POSIX_API_Control  *api,
288  int                 signo,
289  boolean             is_global
290)
291{
292  siginfo_t                   siginfo_struct;
293  sigset_t                    saved_signals_blocked;
294
295  if ( ! _POSIX_signals_Clear_signals( api, signo, &siginfo_struct,
296                                       is_global, TRUE ) )
297    return FALSE;
298
299  /*
300   *  Since we made a union of these, only one test is necessary but this is
301   *  safer.
302   */
303
304  assert( _POSIX_signals_Vectors[ signo ].sa_handler ||
305          _POSIX_signals_Vectors[ signo ].sa_sigaction );
306 
307  /*
308   *  Just to prevent sending a signal which is currently being ignored.
309   */
310
311  if ( _POSIX_signals_Vectors[ signo ].sa_handler == SIG_IGN )
312    return FALSE;
313
314  /*
315   *  Block the signals requested in sa_mask
316   */
317
318  saved_signals_blocked = api->signals_blocked;
319  api->signals_blocked |= _POSIX_signals_Vectors[ signo ].sa_mask;
320
321  switch ( _POSIX_signals_Vectors[ signo ].sa_flags ) {
322    case SA_SIGINFO:
323      assert( is_global );
324
325      (*_POSIX_signals_Vectors[ signo ].sa_sigaction)(
326        signo,
327        &siginfo_struct,
328        NULL        /* context is undefined per 1003.1b-1993, p. 66 */
329      );
330      break;
331    default:
332      (*_POSIX_signals_Vectors[ signo ].sa_handler)( signo );
333      break;
334  }
335
336  /*
337   *  Restore the previous set of blocked signals
338   */
339 
340  api->signals_blocked = saved_signals_blocked;
341
342  return TRUE;
343}
344
345void _POSIX_signals_Post_switch_extension(
346  Thread_Control  *the_thread
347)
348{
349  POSIX_API_Control  *api;
350  int                 signo;
351  ISR_Level           level;
352
353  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
354
355  /*
356   *  If we invoke any user code, there is the possibility that
357   *  a new signal has been posted that we should process so we
358   *  restart the loop if a signal handler was invoked.
359   *
360   *  The first thing done is to check there are any signals to be
361   *  processed at all.  No point in doing this loop otherwise.
362   */
363
364restart:
365  _ISR_Disable( level );
366    if ( !(~api->signals_blocked &
367          (api->signals_pending | _POSIX_signals_Pending)) ) {
368     _ISR_Enable( level );
369     return;
370   }
371  _ISR_Enable( level );
372
373  for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) {
374
375    if ( _POSIX_signals_Check_signal( api, signo, FALSE ) )
376      goto restart;
377
378    if ( _POSIX_signals_Check_signal( api, signo, TRUE ) )
379      goto restart;
380
381  }
382
383/* XXX - add __SIGFIRSTNOTRT or something like that to newlib siginfo.h */
384
385  for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) {
386
387    if ( _POSIX_signals_Check_signal( api, signo, FALSE ) )
388      goto restart;
389 
390    if ( _POSIX_signals_Check_signal( api, signo, TRUE ) )
391      goto restart;
392
393  }
394
395}
396
397/*PAGE
398 *
399 *  _POSIX_signals_Alarm_TSR
400 */
401 
402void _POSIX_signals_Alarm_TSR(
403  Objects_Id      id,
404  void           *argument
405)
406{
407  int status;
408
409  status = kill( getpid(), SIGALRM );
410  /* XXX can't print from an ISR, should this be fatal? */
411  assert( !status );
412}
413
414/*PAGE
415 *
416 *  _POSIX_signals_Manager_Initialization
417 */
418
419void _POSIX_signals_Manager_Initialization(
420  int  maximum_queued_signals
421)
422{
423  unsigned32 signo;
424
425  /*
426   *  Insure we have the same number of vectors and default vector entries
427   */
428
429  assert(
430   sizeof(_POSIX_signals_Vectors) == sizeof(_POSIX_signals_Default_vectors)
431  );
432
433  memcpy(
434    _POSIX_signals_Vectors,
435    _POSIX_signals_Default_vectors,
436    sizeof( _POSIX_signals_Vectors )
437  );
438 
439  /*
440   *  Initialize the set of pending signals for the entire process
441   */
442
443  sigemptyset( &_POSIX_signals_Pending );
444
445  /*
446   *  Initialize the timer used to implement alarm().
447   */
448
449  _Watchdog_Initialize(
450    &_POSIX_signals_Alarm_timer,
451    _POSIX_signals_Alarm_TSR,
452    0,
453    NULL
454  );
455 
456  /*
457   *  Initialize the queue we use to block for signals
458   */
459 
460  _Thread_queue_Initialize(
461    &_POSIX_signals_Wait_queue,
462    OBJECTS_NO_CLASS,
463    THREAD_QUEUE_DISCIPLINE_PRIORITY,
464    STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL,
465    NULL,
466    EAGAIN
467  );
468
469  /* XXX status codes */
470
471  /*
472   *  Allocate the siginfo pools.
473   */
474
475  for ( signo=1 ; signo<= SIGRTMAX ; signo++ )
476    _Chain_Initialize_empty( &_POSIX_signals_Siginfo[ signo ] );
477
478  _Chain_Initialize(
479    &_POSIX_signals_Inactive_siginfo,
480    _Workspace_Allocate_or_fatal_error(
481      maximum_queued_signals * sizeof( POSIX_signals_Siginfo_node )
482    ),
483    maximum_queued_signals,
484    sizeof( POSIX_signals_Siginfo_node )
485  );
486}
487
488/*
489 *  3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69
490 */
491
492int sigemptyset(
493  sigset_t   *set
494)
495{
496  if ( !set )
497    set_errno_and_return_minus_one( EINVAL );
498
499  *set = 0;
500  return 0;
501}
502
503/*
504 *  3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69
505 */
506
507int sigfillset(
508  sigset_t   *set
509)
510{
511  if ( !set )
512    set_errno_and_return_minus_one( EINVAL );
513
514  *set = SIGNAL_ALL_MASK;
515  return 0;
516}
517
518/*
519 *  3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69
520 */
521
522int sigaddset(
523  sigset_t   *set,
524  int         signo
525)
526{
527  if ( !set )
528    set_errno_and_return_minus_one( EINVAL );
529
530  if ( !signo )
531    return 0;
532
533  if ( !is_valid_signo(signo) )
534    set_errno_and_return_minus_one( EINVAL );
535
536  *set |= signo_to_mask(signo);
537  return 0;
538}
539
540/*
541 *  3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69
542 */
543
544int sigdelset(
545  sigset_t   *set,
546  int         signo
547)
548{
549  if ( !set )
550    set_errno_and_return_minus_one( EINVAL );
551 
552  if ( !signo )
553    return 0;
554
555  if ( !is_valid_signo(signo) )
556    set_errno_and_return_minus_one( EINVAL );
557 
558  *set &= ~signo_to_mask(signo);
559  return 0;
560}
561
562/*
563 *  3.3.3 Manipulate Signal Sets, P1003.1b-1993, p. 69
564 */
565
566int sigismember(
567  const sigset_t   *set,
568  int               signo
569)
570{
571  if ( !set )
572    set_errno_and_return_minus_one( EINVAL );
573 
574  if ( !signo )
575    return 0;
576
577  if ( !is_valid_signo(signo) )
578    set_errno_and_return_minus_one( EINVAL );
579 
580  if ( *set & signo_to_mask(signo) )
581    return 1;
582
583  return 0;
584}
585
586/*
587 *  3.3.4 Examine and Change Signal Action, P1003.1b-1993, p. 70
588 */
589
590int sigaction(
591  int                     sig,
592  const struct sigaction *act,
593  struct sigaction       *oact
594)
595{
596  ISR_Level     level;
597
598  if ( oact )
599    *oact = _POSIX_signals_Vectors[ sig ];
600
601  if ( !sig )
602    return 0;
603
604  if ( !is_valid_signo(sig) )
605    set_errno_and_return_minus_one( EINVAL );
606 
607  /*
608   *  Some signals cannot be ignored (P1003.1b-1993, pp. 70-72 and references.
609   *
610   *  NOTE: Solaris documentation claims to "silently enforce" this which
611   *        contradicts the POSIX specification.
612   */
613
614  if ( sig == SIGKILL )
615    set_errno_and_return_minus_one( EINVAL );
616 
617  /*
618   *  Evaluate the new action structure and set the global signal vector
619   *  appropriately.
620   */
621
622  if ( act ) {
623
624    /*
625     *  Unless the user is installing the default signal actions, then
626     *  we can just copy the provided sigaction structure into the vectors.
627     */
628
629    _ISR_Disable( level );
630      if ( act->sa_handler == SIG_DFL ) {
631        _POSIX_signals_Vectors[ sig ] = _POSIX_signals_Default_vectors[ sig ];
632      } else {
633         _POSIX_signals_Clear_process_signals( signo_to_mask(sig) );
634         _POSIX_signals_Vectors[ sig ] = *act;
635      }
636    _ISR_Enable( level );
637  }
638
639  /*
640   *  No need to evaluate or dispatch because:
641   *
642   *    + If we were ignoring the signal before, none could be pending
643   *      now (signals not posted when SIG_IGN).
644   *    + If we are now ignoring a signal that was previously pending,
645   *      we clear the pending signal indicator.
646   */
647
648  return 0;
649}
650
651/*
652 *  3.3.5 Examine and Change Blocked Signals, P1003.1b-1993, p. 73
653 *
654 *  NOTE: P1003.1c/D10, p. 37 adds pthread_sigmask().
655 *
656 */
657
658int sigprocmask(
659  int               how,
660  const sigset_t   *set,
661  sigset_t         *oset
662)
663{
664  /*
665   *  P1003.1c/Draft 10, p. 38 maps sigprocmask to pthread_sigmask.
666   */
667
668  return pthread_sigmask( how, set, oset );
669}
670
671/*
672 *  3.3.5 Examine and Change Blocked Signals, P1003.1b-1993, p. 73
673 *
674 *  NOTE: P1003.1c/D10, p. 37 adds pthread_sigmask().
675 */
676
677int pthread_sigmask(
678  int               how,
679  const sigset_t   *set,
680  sigset_t         *oset
681)
682{
683  POSIX_API_Control  *api;
684
685  if ( !set && !oset )
686    set_errno_and_return_minus_one( EINVAL );
687
688  api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
689
690  if ( oset )
691    *oset = api->signals_blocked;
692 
693  if ( !set )
694    return 0;
695
696  switch ( how ) {
697    case SIG_BLOCK:
698      api->signals_blocked |= *set;
699      break;
700    case SIG_UNBLOCK:
701      api->signals_blocked &= ~*set;
702      break;
703    case SIG_SETMASK:
704      api->signals_blocked = *set;
705      break;
706    default:
707      set_errno_and_return_minus_one( EINVAL );
708  }
709
710  /* XXX are there critical section problems here? */
711
712  /* XXX evaluate the new set */
713
714  if ( ~api->signals_blocked &
715       (api->signals_pending | _POSIX_signals_Pending) ) {
716    _Thread_Executing->do_post_task_switch_extension = TRUE;
717    _Thread_Dispatch();
718  }
719
720  return 0;
721}
722
723/*
724 *  3.3.6 Examine Pending Signals, P1003.1b-1993, p. 75
725 */
726
727int sigpending(
728  sigset_t  *set
729)
730{
731  POSIX_API_Control  *api;
732 
733  if ( !set )
734    set_errno_and_return_minus_one( EINVAL );
735 
736  api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
737 
738  *set = api->signals_pending | _POSIX_signals_Pending;
739 
740  return 0;
741}
742
743/*
744 *  3.3.7 Wait for a Signal, P1003.1b-1993, p. 75
745 */
746
747int sigsuspend(
748  const sigset_t  *sigmask
749)
750{
751  sigset_t            saved_signals_blocked;
752  sigset_t            all_signals;
753  int                 status;
754  POSIX_API_Control  *api;
755
756  api = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ];
757
758  status = sigprocmask( SIG_BLOCK, sigmask, &saved_signals_blocked );
759 
760  (void) sigfillset( &all_signals );
761
762  status = sigtimedwait( &all_signals, NULL, NULL );
763
764  (void) sigprocmask( SIG_SETMASK, &saved_signals_blocked, NULL );
765
766  return status;
767}
768
769/*
770 *  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
771 *
772 *  NOTE: P1003.1c/D10, p. 39 adds sigwait().
773 */
774
775int sigwaitinfo(
776  const sigset_t  *set,
777  siginfo_t       *info
778)
779{
780  return sigtimedwait( set, info, NULL );
781}
782
783/*
784 *  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
785 *
786 *  NOTE: P1003.1c/D10, p. 39 adds sigwait().
787 */
788
789int _POSIX_signals_Get_highest(
790  sigset_t   set
791)
792{
793  int signo;
794 
795  for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) {
796    if ( set & signo_to_mask( signo ) )
797      return signo;
798  }
799 
800/* XXX - add __SIGFIRSTNOTRT or something like that to newlib siginfo.h */
801
802  for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) {
803    if ( set & signo_to_mask( signo ) )
804      return signo;
805  }
806
807  return 0;
808}
809
810int sigtimedwait(
811  const sigset_t         *set,
812  siginfo_t              *info,
813  const struct timespec  *timeout
814)
815{
816  Thread_Control    *the_thread;
817  POSIX_API_Control *api;
818  Watchdog_Interval  interval;
819  siginfo_t          signal_information;
820  siginfo_t         *the_info;
821  int                signo;
822 
823  the_info = ( info ) ? info : &signal_information;
824
825  the_thread = _Thread_Executing;
826
827  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
828
829  /*
830   *  What if they are already pending?
831   */
832
833  /* API signals pending? */
834
835  if ( *set & api->signals_pending ) {
836    /* XXX real info later */
837    the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending );
838    _POSIX_signals_Clear_signals( api, the_info->si_signo, the_info,
839                                  FALSE, FALSE );
840    the_info->si_code = SI_USER;
841    the_info->si_value.sival_int = 0;
842    return the_info->si_signo;
843  }
844
845  /* Process pending signals? */
846
847  if ( *set & _POSIX_signals_Pending) {
848    signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending );
849    _POSIX_signals_Clear_signals( api, signo, the_info, TRUE, FALSE );
850
851    if ( !info ) {
852      the_info->si_signo = signo;
853      the_info->si_code = SI_USER;
854      the_info->si_value.sival_int = 0;
855    }
856  }
857
858  interval = 0;
859  if ( timeout ) {
860
861    if (timeout->tv_nsec < 0 || timeout->tv_nsec >= TOD_NANOSECONDS_PER_SECOND)
862      set_errno_and_return_minus_one( EINVAL );
863
864    interval = _POSIX_Timespec_to_interval( timeout );
865  }
866
867  the_info->si_signo = -1;
868
869  _Thread_Disable_dispatch();
870    the_thread->Wait.queue           = &_POSIX_signals_Wait_queue;
871    the_thread->Wait.return_code     = EINTR;
872    the_thread->Wait.option          = *set;
873    the_thread->Wait.return_argument = (void *) the_info;
874    _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue );
875    _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval );
876  _Thread_Enable_dispatch();
877
878  errno = _Thread_Executing->Wait.return_code;
879  return the_info->si_signo;
880}
881
882/*
883 *  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
884 *
885 *  NOTE: P1003.1c/D10, p. 39 adds sigwait().
886 */
887
888int sigwait(
889  const sigset_t  *set,
890  int             *sig
891)
892{
893  int status;
894
895  status = sigtimedwait( set, NULL, NULL );
896
897  if ( status != -1 ) {
898    if ( sig )
899      *sig = status;
900    return 0;
901  }
902
903  return errno;
904}
905
906/*PAGE
907 *
908 *  3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68
909 *
910 *  NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS.
911 */
912
913#define _POSIX_signals_Is_interested( _api, _mask ) \
914  ( ~(_api)->signals_blocked & (_mask) )
915         
916int killinfo(
917  pid_t               pid,
918  int                 sig,
919  const union sigval *value
920)
921{
922  sigset_t                     mask;
923  POSIX_API_Control           *api;
924  unsigned32                   the_class;
925  unsigned32                   index;
926  unsigned32                   maximum;
927  Objects_Information         *the_info;
928  Objects_Control            **object_table;
929  Thread_Control              *the_thread;
930  Thread_Control              *interested_thread;
931  Priority_Control             interested_priority;
932  Chain_Control               *the_chain;
933  Chain_Node                  *the_node;
934  siginfo_t                    siginfo_struct;
935  siginfo_t                   *siginfo;
936  POSIX_signals_Siginfo_node  *psiginfo;
937 
938  /*
939   *  Only supported for the "calling process" (i.e. this node).
940   */
941 
942  if( pid != getpid() )
943    set_errno_and_return_minus_one( ESRCH );
944
945  /*
946   *  Validate the signal passed if not 0.
947   */
948 
949  if ( sig && !is_valid_signo(sig) )
950    set_errno_and_return_minus_one( EINVAL );
951
952  /*
953   *  If the signal is being ignored, then we are out of here.
954   */
955
956  if ( !sig || _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN )
957    return 0;
958
959  /*
960   *  P1003.1c/Draft 10, p. 33 says that certain signals should always
961   *  be directed to the executing thread such as those caused by hardware
962   *  faults.
963   */
964
965  switch ( sig ) {
966    case SIGFPE:
967    case SIGILL:
968    case SIGSEGV:
969      return pthread_kill( pthread_self(), sig );
970    default:
971      break;
972  }
973
974  mask = signo_to_mask( sig );
975
976  /*
977   *  Build up a siginfo structure
978   */
979
980  siginfo = &siginfo_struct;
981  siginfo->si_signo = sig;
982  siginfo->si_code = SI_USER;
983  if ( !value ) {
984    siginfo->si_value.sival_int = 0;
985  } else {
986    siginfo->si_value = *value;
987  }
988
989  _Thread_Disable_dispatch();
990
991  /*
992   *  Is the currently executing thread interested?  If so then it will
993   *  get it an execute it as soon as the dispatcher executes.
994   */
995
996  the_thread = _Thread_Executing;
997
998  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
999  if ( _POSIX_signals_Is_interested( api, mask ) ) {
1000    goto process_it;
1001  }
1002
1003  /*
1004   *  Is an interested thread waiting for this signal (sigwait())?
1005   */
1006
1007  /* XXX violation of visibility -- need to define thread queue support */
1008
1009  for( index=0 ;
1010       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
1011       index++ ) {
1012
1013    the_chain = &_POSIX_signals_Wait_queue.Queues.Priority[ index ];
1014 
1015    for ( the_node = the_chain->first ;
1016          !_Chain_Is_tail( the_chain, the_node ) ;
1017          the_node = the_node->next ) {
1018
1019      the_thread = (Thread_Control *)the_node;
1020      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1021
1022      if ((the_thread->Wait.option & mask) || (~api->signals_blocked & mask)) {
1023        goto process_it;
1024      }
1025
1026    }
1027  }
1028
1029  /*
1030   *  Is any other thread interested?  The highest priority interested
1031   *  thread is selected.  In the event of a tie, then the following
1032   *  additional criteria is used:
1033   *
1034   *    + ready thread over blocked
1035   *    + blocked on call interruptible by signal (can return EINTR)
1036   *    + blocked on call not interruptible by signal
1037   *
1038   *  This looks at every thread in the system regardless of the creating API.
1039   *
1040   *  NOTES:
1041   *
1042   *    + rtems internal threads do not receive signals.
1043   */
1044
1045  interested_thread = NULL;
1046  interested_priority = PRIORITY_MAXIMUM + 1;
1047
1048  for ( the_class = OBJECTS_CLASSES_FIRST_THREAD_CLASS;
1049        the_class <= OBJECTS_CLASSES_LAST_THREAD_CLASS;
1050        the_class++ ) {
1051
1052    if ( the_class == OBJECTS_INTERNAL_THREADS )
1053      continue;
1054
1055    the_info = _Objects_Information_table[ the_class ];
1056
1057    if ( !the_info )                        /* manager not installed */
1058      continue;
1059
1060    maximum = the_info->maximum;
1061    object_table = the_info->local_table;
1062
1063    assert( object_table );                 /* always at least 1 entry */
1064
1065    for ( index = 1 ; index <= maximum ; index++ ) {
1066      the_thread = (Thread_Control *) object_table[ index ];
1067
1068      if ( !the_thread )
1069        continue;
1070
1071      /*
1072       *  If this thread is of lower priority than the interested thread,
1073       *  go on to the next thread.
1074       */
1075
1076      if ( the_thread->current_priority > interested_priority )
1077        continue;
1078
1079      /*
1080       *  If this thread is not interested, then go on to the next thread.
1081       */
1082
1083      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1084
1085      if ( !api || !_POSIX_signals_Is_interested( api, mask ) )
1086        continue;
1087
1088      /*
1089       *  Now we know the thread under connsideration is interested.
1090       *  If the thread under consideration is of higher priority, then
1091       *  it becomes the interested thread.
1092       */
1093
1094      if ( the_thread->current_priority < interested_priority ) {
1095        interested_thread   = the_thread;
1096        interested_priority = the_thread->current_priority;
1097        continue;
1098      }
1099
1100      /*
1101       *  Now the thread and the interested thread have the same priority.
1102       *  If the interested thread is ready, then we don't need to send it
1103       *  to a blocked thread.
1104       */
1105
1106      if ( _States_Is_ready( interested_thread->current_state ) )
1107        continue;
1108
1109      /*
1110       *  Now the interested thread is blocked.
1111       *  If the thread we are considering is not, the it becomes the
1112       *  interested thread.
1113       */
1114
1115      if ( _States_Is_ready( the_thread->current_state ) ) {
1116        interested_thread   = the_thread;
1117        interested_priority = the_thread->current_priority;
1118        continue;
1119      }
1120
1121      /*
1122       *  Now we know both threads are blocked.
1123       *  If the interested thread is interruptible, then just use it.
1124       */
1125
1126      /* XXX need a new states macro */
1127      if ( interested_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL )
1128        continue;
1129
1130      /*
1131       *  Now both threads are blocked and the interested thread is not
1132       *  interruptible.
1133       *  If the thread under consideration is interruptible by a signal,
1134       *  then it becomes the interested thread.
1135       */
1136
1137      /* XXX need a new states macro */
1138      if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) {
1139        interested_thread   = the_thread;
1140        interested_priority = the_thread->current_priority;
1141      }
1142    }
1143  }
1144
1145  if ( interested_thread ) {
1146    the_thread = interested_thread;
1147    goto process_it;
1148  }
1149
1150  /*
1151   *  OK so no threads were interested right now.  It will be left on the
1152   *  global pending until a thread receives it.  The global set of threads
1153   *  can change interest in this signal in one of the following ways:
1154   *
1155   *    + a thread is created with the signal unblocked,
1156   *    + pthread_sigmask() unblocks the signal,
1157   *    + sigprocmask() unblocks the signal, OR
1158   *    + sigaction() which changes the handler to SIG_IGN.
1159   */
1160
1161  the_thread = NULL;
1162  goto post_process_signal;
1163
1164  /*
1165   *  We found a thread which was interested, so now we mark that this
1166   *  thread needs to do the post context switch extension so it can
1167   *  evaluate the signals pending.
1168   */
1169
1170process_it:
1171 
1172  the_thread->do_post_task_switch_extension = TRUE;
1173
1174  /*
1175   *  Returns TRUE if the signal was synchronously given to a thread
1176   *  blocked waiting for the signal.
1177   */
1178
1179  if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) {
1180    _Thread_Enable_dispatch();
1181    return 0;
1182  }
1183
1184post_process_signal:
1185
1186  /*
1187   *  We may have woken up a thread but we definitely need to post the
1188   *  signal to the process wide information set.
1189   */
1190
1191  _POSIX_signals_Set_process_signals( mask );
1192
1193  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) {
1194
1195    psiginfo = (POSIX_signals_Siginfo_node *)
1196               _Chain_Get( &_POSIX_signals_Inactive_siginfo );
1197    if ( !psiginfo )
1198      set_errno_and_return_minus_one( EAGAIN );
1199
1200    psiginfo->Info = *siginfo;
1201
1202    _Chain_Append( &_POSIX_signals_Siginfo[ sig ], &psiginfo->Node );
1203  }
1204
1205  _Thread_Enable_dispatch();
1206  return 0;
1207}
1208
1209/*PAGE
1210 *
1211 *  3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68
1212 *
1213 *  NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS.
1214 */
1215
1216int kill(
1217  pid_t pid,
1218  int   sig
1219)
1220{
1221  return killinfo( pid, sig, NULL );
1222}
1223
1224/*
1225 *  3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78
1226 */
1227
1228int sigqueue(
1229  pid_t               pid,
1230  int                 signo,
1231  const union sigval  value
1232)
1233{
1234  return killinfo( pid, signo, &value );
1235}
1236
1237/*
1238 *  3.3.10 Send a Signal to a Thread, P1003.1c/D10, p. 43
1239 */
1240
1241int pthread_kill(
1242  pthread_t   thread,
1243  int         sig
1244)
1245{
1246  POSIX_API_Control  *api;
1247  Thread_Control     *the_thread;
1248  Objects_Locations  location;
1249
1250  if ( sig && !is_valid_signo(sig) )
1251    set_errno_and_return_minus_one( EINVAL );
1252
1253  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO )
1254    set_errno_and_return_minus_one( ENOSYS );
1255
1256  /*
1257   *  RTEMS does not support sending  a siginfo signal to a specific thread.
1258   */
1259
1260  the_thread = _POSIX_Threads_Get( thread, &location );
1261  switch ( location ) {
1262    case OBJECTS_ERROR:
1263    case OBJECTS_REMOTE:
1264      set_errno_and_return_minus_one( ESRCH );
1265    case OBJECTS_LOCAL:
1266      /*
1267       *  If sig == 0 then just validate arguments
1268       */
1269
1270      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1271
1272      if ( sig ) {
1273
1274        if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) {
1275          _Thread_Enable_dispatch();
1276          return 0;
1277        }
1278
1279        /* XXX critical section */
1280
1281        api->signals_pending |= signo_to_mask( sig );
1282
1283        (void) _POSIX_signals_Unblock_thread( the_thread, sig, NULL );
1284
1285        the_thread->do_post_task_switch_extension = TRUE;
1286
1287        if ( _ISR_Is_in_progress() && _Thread_Is_executing( the_thread ) )
1288          _ISR_Signals_to_thread_executing = TRUE;
1289      }
1290      _Thread_Enable_dispatch();
1291      return 0;
1292  }
1293
1294  return POSIX_BOTTOM_REACHED();
1295}
1296
1297/*
1298 *  3.4.1 Schedule Alarm, P1003.1b-1993, p. 79
1299 */
1300
1301Watchdog_Control _POSIX_signals_Alarm_timer;
1302
1303unsigned int alarm(
1304  unsigned int seconds
1305)
1306{
1307  unsigned int      remaining = 0;
1308  Watchdog_Control *the_timer;
1309
1310  the_timer = &_POSIX_signals_Alarm_timer;
1311
1312  switch ( _Watchdog_Remove( the_timer ) ) {
1313    case WATCHDOG_INACTIVE:
1314    case WATCHDOG_BEING_INSERTED:
1315      break;
1316 
1317    case WATCHDOG_ACTIVE:
1318    case WATCHDOG_REMOVE_IT:
1319      remaining = the_timer->initial -
1320                  (the_timer->stop_time - the_timer->start_time);
1321      break;
1322  }
1323
1324  _Watchdog_Insert_seconds( the_timer, seconds );
1325
1326  return remaining;
1327}
1328
1329/*
1330 *  3.4.2 Suspend Process Execution, P1003.1b-1993, p. 81
1331 */
1332
1333int pause( void )
1334{
1335  sigset_t  all_signals;
1336  int       status;
1337 
1338  (void) sigfillset( &all_signals );
1339 
1340  status = sigtimedwait( &all_signals, NULL, NULL );
1341 
1342  return status;
1343}
Note: See TracBrowser for help on using the repository browser.