source: rtems/cpukit/posix/src/psignal.c @ 108ef35

4.104.114.84.95
Last change on this file since 108ef35 was 108ef35, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 15, 1996 at 7:55:39 PM

initial modifications to support sigtimedwait.

  • Property mode set to 100644
File size: 29.3 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  int                signo;
779 
780  the_info = ( info ) ? info : &signal_information;
781
782  the_thread = _Thread_Executing;
783
784  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
785
786  /*
787   *  What if they are already pending?
788   */
789
790  /* API signals pending? */
791
792  if ( *set & api->signals_pending ) {
793    /* XXX real info later */
794    the_info->si_signo = _POSIX_signals_Get_highest( api->signals_pending );
795    the_info->si_code = SI_USER;
796    the_info->si_value.sival_int = 0;
797    return the_info->si_signo;
798  }
799
800  /* Process pending signals? */
801
802#warning "Mark fix me"
803  if ( *set & _POSIX_signals_Pending) {
804    signo = _POSIX_signals_Get_highest( _POSIX_signals_Pending );
805    if ( !info || ( _POSIX_signals_Vectors[ signo ].sa_flags == SA_SIGINFO ) ) {
806      the_info->si_signo = signo;
807      the_info->si_code = SI_USER;
808      the_info->si_value.sival_int = 0;
809    } else {
810#warning "_POSIX_signals_Siginfo is an array of chains.... "
811#if 0
812      *the_info = *_POSIX_signals_Siginfo[ signo ];
813#endif
814    }
815  }
816
817  interval = 0;
818  if ( timeout ) {
819
820    if (timeout->tv_nsec < 0 || timeout->tv_nsec >= TOD_NANOSECONDS_PER_SECOND)
821      set_errno_and_return_minus_one( EINVAL );
822
823    interval = _POSIX_Timespec_to_interval( timeout );
824  }
825
826  the_info->si_signo = -1;
827
828  _Thread_Disable_dispatch();
829    the_thread->Wait.queue           = &_POSIX_signals_Wait_queue;
830    the_thread->Wait.return_code     = EINTR;
831    the_thread->Wait.option          = *set;
832    the_thread->Wait.return_argument = (void *) the_info;
833    _Thread_queue_Enter_critical_section( &_POSIX_signals_Wait_queue ); 
834    _Thread_queue_Enqueue( &_POSIX_signals_Wait_queue, interval ); 
835  _Thread_Enable_dispatch();
836
837  errno = _Thread_Executing->Wait.return_code;
838  return the_info->si_signo;
839}
840
841/*
842 *  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
843 *
844 *  NOTE: P1003.1c/D10, p. 39 adds sigwait().
845 */
846
847int sigwait(
848  const sigset_t  *set,
849  int             *sig
850)
851{
852  int status;
853
854  status = sigtimedwait( set, NULL, NULL );
855
856  if ( status != -1 ) {
857    if ( sig )
858      *sig = status;
859    return 0;
860  }
861
862  return errno;
863}
864
865/*PAGE
866 *
867 *  3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68
868 *
869 *  NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS.
870 */
871
872#define _POSIX_signals_Is_interested( _api, _mask ) \
873  ( ~(_api)->signals_blocked & (_mask) )
874         
875int killinfo(
876  pid_t               pid,
877  int                 sig,
878  const union sigval *value
879)
880{
881  sigset_t                     mask;
882  POSIX_API_Control           *api;
883  unsigned32                   the_class;
884  unsigned32                   index;
885  unsigned32                   maximum;
886  Objects_Information         *the_info;
887  Objects_Control            **object_table;
888  Thread_Control              *the_thread;
889  Thread_Control              *interested_thread;
890  Priority_Control             interested_priority;
891  Chain_Control               *the_chain;
892  Chain_Node                  *the_node;
893  siginfo_t                    siginfo_struct;
894  siginfo_t                   *siginfo;
895  POSIX_signals_Siginfo_node  *psiginfo;
896 
897  /*
898   *  Only supported for the "calling process" (i.e. this node).
899   */
900 
901  if( pid != getpid() )
902    set_errno_and_return_minus_one( ESRCH );
903
904  /*
905   *  If the signal is being ignored, then we are out of here.
906   */
907
908  if ( !sig || _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN )
909    return 0;
910
911  /*
912   *  P1003.1c/Draft 10, p. 33 says that certain signals should always
913   *  be directed to the executing thread such as those caused by hardware
914   *  faults.
915   */
916
917  switch ( sig ) {
918    case SIGFPE:
919    case SIGILL:
920    case SIGSEGV:
921      return pthread_kill( pthread_self(), sig );
922    default:
923      break;
924  }
925
926  mask = signo_to_mask( sig );
927
928  /*
929   *  Build up a siginfo structure
930   */
931
932  siginfo = &siginfo_struct;
933  siginfo->si_signo = sig;
934  siginfo->si_code = SI_USER;
935  if ( !value ) {
936    siginfo->si_value.sival_int = 0;
937  } else {
938    siginfo->si_value = *value;
939  }
940
941  _Thread_Disable_dispatch();
942
943  /*
944   *  Is the currently executing thread interested?  If so then it will
945   *  get it an execute it as soon as the dispatcher executes.
946   */
947
948  the_thread = _Thread_Executing;
949
950  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
951  if ( _POSIX_signals_Is_interested( api, mask ) ) {
952    goto process_it;
953  }
954
955  /*
956   *  Is an interested thread waiting for this signal (sigwait())?
957   */
958
959  /* XXX violation of visibility -- need to define thread queue support */
960
961  for( index=0 ;
962       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
963       index++ ) {
964
965    the_chain = &_POSIX_signals_Wait_queue.Queues.Priority[ index ];
966 
967    for ( the_node = the_chain->first ;
968          !_Chain_Is_tail( the_chain, the_node ) ;
969          the_node = the_node->next ) {
970
971      the_thread = (Thread_Control *)the_node;
972      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
973
974      if ((the_thread->Wait.option & mask) || (~api->signals_blocked & mask)) {
975        goto process_it;
976      }
977
978    }
979  }
980
981  /*
982   *  Is any other thread interested?  The highest priority interested
983   *  thread is selected.  In the event of a tie, then the following
984   *  additional criteria is used:
985   *
986   *    + ready thread over blocked
987   *    + blocked on call interruptible by signal (can return EINTR)
988   *    + blocked on call not interruptible by signal
989   *
990   *  This looks at every thread in the system regardless of the creating API.
991   *
992   *  NOTES:
993   *
994   *    + rtems internal threads do not receive signals.
995   */
996
997  interested_thread = NULL;
998  interested_priority = PRIORITY_MAXIMUM + 1;
999
1000  for ( the_class = OBJECTS_CLASSES_FIRST_THREAD_CLASS;
1001        the_class <= OBJECTS_CLASSES_LAST_THREAD_CLASS;
1002        the_class++ ) {
1003
1004    if ( the_class == OBJECTS_INTERNAL_THREADS )
1005      continue;
1006
1007    the_info = _Objects_Information_table[ the_class ];
1008
1009    if ( !the_info )                        /* manager not installed */
1010      continue;
1011
1012    maximum = the_info->maximum;
1013    object_table = the_info->local_table;
1014
1015    assert( object_table );                 /* always at least 1 entry */
1016
1017    for ( index = 1 ; index <= maximum ; index++ ) {
1018      the_thread = (Thread_Control *) object_table[ index ];
1019
1020      if ( !the_thread )
1021        continue;
1022
1023      /*
1024       *  If this thread is of lower priority than the interested thread,
1025       *  go on to the next thread.
1026       */
1027
1028      if ( the_thread->current_priority > interested_priority )
1029        continue;
1030
1031      /*
1032       *  If this thread is not interested, then go on to the next thread.
1033       */
1034
1035      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1036
1037      if ( !api || !_POSIX_signals_Is_interested( api, mask ) )
1038        continue;
1039
1040      /*
1041       *  Now we know the thread under connsideration is interested.
1042       *  If the thread under consideration is of higher priority, then
1043       *  it becomes the interested thread.
1044       */
1045
1046      if ( the_thread->current_priority < interested_priority ) {
1047        interested_thread   = the_thread;
1048        interested_priority = the_thread->current_priority;
1049        continue;
1050      }
1051
1052      /*
1053       *  Now the thread and the interested thread have the same priority.
1054       *  If the interested thread is ready, then we don't need to send it
1055       *  to a blocked thread.
1056       */
1057
1058      if ( _States_Is_ready( interested_thread->current_state ) )
1059        continue;
1060
1061      /*
1062       *  Now the interested thread is blocked.
1063       *  If the thread we are considering is not, the it becomes the
1064       *  interested thread.
1065       */
1066
1067      if ( _States_Is_ready( the_thread->current_state ) ) {
1068        interested_thread   = the_thread;
1069        interested_priority = the_thread->current_priority;
1070        continue;
1071      }
1072
1073      /*
1074       *  Now we know both threads are blocked.
1075       *  If the interested thread is interruptible, then just use it.
1076       */
1077
1078      /* XXX need a new states macro */
1079      if ( interested_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL )
1080        continue;
1081
1082      /*
1083       *  Now both threads are blocked and the interested thread is not
1084       *  interruptible.
1085       *  If the thread under consideration is interruptible by a signal,
1086       *  then it becomes the interested thread.
1087       */
1088
1089      /* XXX need a new states macro */
1090      if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) {
1091        interested_thread   = the_thread;
1092        interested_priority = the_thread->current_priority;
1093      }
1094    }
1095  }
1096
1097  if ( interested_thread ) {
1098    the_thread = interested_thread;
1099    goto process_it;
1100  }
1101
1102  /*
1103   *  OK so no threads were interested right now.  It will be left on the
1104   *  global pending until a thread receives it.  The global set of threads
1105   *  can change interest in this signal in one of the following ways:
1106   *
1107   *    + a thread is created with the signal unblocked,
1108   *    + pthread_sigmask() unblocks the signal,
1109   *    + sigprocmask() unblocks the signal, OR
1110   *    + sigaction() which changes the handler to SIG_IGN.
1111   */
1112
1113  the_thread = NULL;
1114  goto post_process_signal;
1115
1116  /*
1117   *  We found a thread which was interested, so now we mark that this
1118   *  thread needs to do the post context switch extension so it can
1119   *  evaluate the signals pending.
1120   */
1121
1122process_it:
1123 
1124  the_thread->do_post_task_switch_extension = TRUE;
1125
1126  /*
1127   *  Returns TRUE if the signal was synchronously given to a thread
1128   *  blocked waiting for the signal.
1129   */
1130
1131  if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) {
1132    _Thread_Enable_dispatch();
1133    return 0;
1134  }
1135
1136post_process_signal:
1137
1138  /*
1139   *  We may have woken up a thread but we definitely need to post the
1140   *  signal to the process wide information set.
1141   */
1142
1143  _POSIX_signals_Set_process_signals( mask );
1144
1145  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) {
1146
1147    psiginfo = (POSIX_signals_Siginfo_node *)
1148               _Chain_Get( &_POSIX_signals_Inactive_siginfo );
1149    if ( !psiginfo )
1150      set_errno_and_return_minus_one( EAGAIN );
1151
1152    psiginfo->Info = *siginfo;
1153
1154    _Chain_Append( &_POSIX_signals_Siginfo[ sig ], &psiginfo->Node );
1155  }
1156
1157  _Thread_Enable_dispatch();
1158  return 0;
1159}
1160
1161/*PAGE
1162 *
1163 *  3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68
1164 *
1165 *  NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS.
1166 */
1167
1168int kill(
1169  pid_t pid,
1170  int   sig
1171)
1172{
1173  return killinfo( pid, sig, NULL );
1174}
1175
1176/*
1177 *  3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78
1178 */
1179
1180int sigqueue(
1181  pid_t               pid,
1182  int                 signo,
1183  const union sigval  value
1184)
1185{
1186  return killinfo( pid, signo, &value );
1187}
1188
1189/*
1190 *  3.3.10 Send a Signal to a Thread, P1003.1c/D10, p. 43
1191 */
1192
1193int pthread_kill(
1194  pthread_t   thread,
1195  int         sig
1196)
1197{
1198  POSIX_API_Control  *api;
1199  Thread_Control     *the_thread;
1200  Objects_Locations  location;
1201
1202  if ( sig && !is_valid_signo(sig) )
1203    set_errno_and_return_minus_one( EINVAL );
1204
1205  if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN )
1206    return 0;
1207
1208  /*
1209   *  RTEMS does not support sending  a siginfo signal to a specific thread.
1210   */
1211
1212  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO )
1213    return ENOSYS;
1214
1215  the_thread = _POSIX_Threads_Get( thread, &location );
1216  switch ( location ) {
1217    case OBJECTS_ERROR:
1218    case OBJECTS_REMOTE:
1219      return ESRCH;
1220    case OBJECTS_LOCAL:
1221      /*
1222       *  If sig == 0 then just validate arguments
1223       */
1224
1225      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
1226
1227      if ( sig ) {
1228
1229        /* XXX critical section */
1230
1231        api->signals_pending |= signo_to_mask( sig );
1232
1233        (void) _POSIX_signals_Unblock_thread( the_thread, sig, NULL );
1234    }
1235    _Thread_Enable_dispatch();
1236    return 0;
1237  }
1238
1239  return POSIX_BOTTOM_REACHED();
1240}
1241
1242/*
1243 *  3.4.1 Schedule Alarm, P1003.1b-1993, p. 79
1244 */
1245
1246Watchdog_Control _POSIX_signals_Alarm_timer;
1247
1248unsigned int alarm(
1249  unsigned int seconds
1250)
1251{
1252  unsigned int      remaining = 0;
1253  Watchdog_Control *the_timer;
1254
1255  the_timer = &_POSIX_signals_Alarm_timer;
1256
1257  switch ( _Watchdog_Remove( the_timer ) ) {
1258    case WATCHDOG_INACTIVE:
1259    case WATCHDOG_BEING_INSERTED:
1260      break;
1261 
1262    case WATCHDOG_ACTIVE:
1263    case WATCHDOG_REMOVE_IT:
1264      remaining = the_timer->initial - 
1265                  (the_timer->stop_time - the_timer->start_time);
1266      break;
1267  }
1268
1269  _Watchdog_Insert_seconds( the_timer, seconds );
1270
1271  return remaining;
1272}
1273
1274/*
1275 *  3.4.2 Suspend Process Execution, P1003.1b-1993, p. 81
1276 */
1277
1278int pause( void )
1279{
1280  sigset_t  all_signals;
1281  int       status;
1282 
1283  (void) sigfillset( &all_signals );
1284 
1285  status = sigtimedwait( &all_signals, NULL, NULL );
1286 
1287  return status;
1288}
Note: See TracBrowser for help on using the repository browser.