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

4.104.114.84.95
Last change on this file since 07a3253d was 07a3253d, checked in by Joel Sherrill <joel.sherrill@…>, on 11/23/98 at 19:07:58

Added base version of file system infrastructure. This includes a major
overhaul of the RTEMS system call interface. This base file system is
the "In-Memory File System" aka IMFS.

The design and implementation was done by the following people:

+ Joel Sherrill (joel@…)
+ Jennifer Averett (jennifer@…)
+ Steve "Mr Mount" Salitasc (salitasc@…)
+ Kerwin Wade (wade@…)

PROBLEMS
========

+ It is VERY likely that merging this will break the UNIX port. This

can/will be fixed.

+ There is likely some reentrancy/mutual exclusion needed.

+ Eventually, there should be a "mini-IMFS" description table to

eliminate links, symlinks, etc to save memory. All you need to
have "classic RTEMS" functionality is technically directories
and device IO. All the rest could be left out to save memory.

  • Property mode set to 100644
File size: 31.0 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 && _Thread_Do_post_task_switch_extension )
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 *  _kill_r
1226 *
1227 *  This is the Newlib dependent reentrant version of kill().
1228 */
1229
1230#if defined(RTEMS_NEWLIB)
1231
1232#include <reent.h>
1233
1234int _kill_r(
1235  struct _reent *ptr,
1236  pid_t          pid,
1237  int            sig
1238)
1239{
1240  return kill( pid, sig );
1241}
1242#endif
1243
1244/*
1245 *  3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78
1246 */
1247
1248int sigqueue(
1249  pid_t               pid,
1250  int                 signo,
1251  const union sigval  value
1252)
1253{
1254  return killinfo( pid, signo, &value );
1255}
1256
1257/*
1258 *  3.3.10 Send a Signal to a Thread, P1003.1c/D10, p. 43
1259 */
1260
1261int pthread_kill(
1262  pthread_t   thread,
1263  int         sig
1264)
1265{
1266  POSIX_API_Control  *api;
1267  Thread_Control     *the_thread;
1268  Objects_Locations  location;
1269
1270  if ( sig && !is_valid_signo(sig) )
1271    set_errno_and_return_minus_one( EINVAL );
1272
1273  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO )
1274    set_errno_and_return_minus_one( ENOSYS );
1275
1276  /*
1277   *  RTEMS does not support sending  a siginfo signal to a specific thread.
1278   */
1279
1280  the_thread = _POSIX_Threads_Get( thread, &location );
1281  switch ( location ) {
1282    case OBJECTS_ERROR:
1283    case OBJECTS_REMOTE:
1284      set_errno_and_return_minus_one( ESRCH );
1285    case OBJECTS_LOCAL:
1286      /*
1287       *  If sig == 0 then just validate arguments
1288       */
1289
1290      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1291
1292      if ( sig ) {
1293
1294        if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) {
1295          _Thread_Enable_dispatch();
1296          return 0;
1297        }
1298
1299        /* XXX critical section */
1300
1301        api->signals_pending |= signo_to_mask( sig );
1302
1303        (void) _POSIX_signals_Unblock_thread( the_thread, sig, NULL );
1304
1305        the_thread->do_post_task_switch_extension = TRUE;
1306
1307        if ( _ISR_Is_in_progress() && _Thread_Is_executing( the_thread ) )
1308          _ISR_Signals_to_thread_executing = TRUE;
1309      }
1310      _Thread_Enable_dispatch();
1311      return 0;
1312  }
1313
1314  return POSIX_BOTTOM_REACHED();
1315}
1316
1317/*
1318 *  3.4.1 Schedule Alarm, P1003.1b-1993, p. 79
1319 */
1320
1321Watchdog_Control _POSIX_signals_Alarm_timer;
1322
1323unsigned int alarm(
1324  unsigned int seconds
1325)
1326{
1327  unsigned int      remaining = 0;
1328  Watchdog_Control *the_timer;
1329
1330  the_timer = &_POSIX_signals_Alarm_timer;
1331
1332  switch ( _Watchdog_Remove( the_timer ) ) {
1333    case WATCHDOG_INACTIVE:
1334    case WATCHDOG_BEING_INSERTED:
1335      break;
1336 
1337    case WATCHDOG_ACTIVE:
1338    case WATCHDOG_REMOVE_IT:
1339      remaining = the_timer->initial -
1340                  (the_timer->stop_time - the_timer->start_time);
1341      break;
1342  }
1343
1344  _Watchdog_Insert_seconds( the_timer, seconds );
1345
1346  return remaining;
1347}
1348
1349/*
1350 *  3.4.2 Suspend Process Execution, P1003.1b-1993, p. 81
1351 */
1352
1353int pause( void )
1354{
1355  sigset_t  all_signals;
1356  int       status;
1357 
1358  (void) sigfillset( &all_signals );
1359 
1360  status = sigtimedwait( &all_signals, NULL, NULL );
1361 
1362  return status;
1363}
Note: See TracBrowser for help on using the repository browser.