source: rtems/c/src/exec/posix/src/psignal.c @ aa48536

4.104.114.84.95
Last change on this file since aa48536 was aa48536, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 17, 1996 at 9:31:10 PM

Added code to insure that the post switch extension was executed and
to made signals sent to a particular thread from an ISR operated correctly.
This behavior was required by the exception detection/reporting code
in the gnat runtime.

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