source: rtems/c/src/exec/posix/src/psignal.c @ 9e28da4

4.104.114.84.95
Last change on this file since 9e28da4 was 9e28da4, checked in by Mark Johannes <Mark.Johannes@…>, on 06/13/96 at 22:16:47

sigtimedwait passes initial test cases of timeout and simple satisfaction.

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