source: rtems/cpukit/posix/src/psignal.c @ 82f490f

4.104.114.84.95
Last change on this file since 82f490f was 82f490f, checked in by Joel Sherrill <joel.sherrill@…>, on 04/12/99 at 20:24:56

Patch from Ralf Corsepius <corsepiu@…> to correct the
--enable-tests problem a better way.

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