source: rtems/cpukit/posix/src/killinfo.c @ 811fae1

4.104.114.84.95
Last change on this file since 811fae1 was 0f4e074, checked in by Joel Sherrill <joel.sherrill@…>, on 04/15/99 at 18:57:02

Cleaned up.

  • Property mode set to 100644
File size: 8.6 KB
Line 
1/*
2 *  kill() support routine
3 *
4 *  COPYRIGHT (c) 1989-1998.
5 *  On-Line Applications Research Corporation (OAR).
6 *  Copyright assigned to U.S. Government, 1994.
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.OARcorp.com/rtems/license.html.
11 *
12 *  $Id$
13 */
14
15
16#include <pthread.h>
17#include <signal.h>
18#include <errno.h>
19#include <assert.h>
20
21#include <rtems/system.h>
22#include <rtems/posix/pthread.h>
23#include <rtems/posix/psignal.h>
24#include <rtems/posix/seterr.h>
25#include <rtems/score/isr.h>
26
27/*PAGE
28 *
29 *  3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68
30 *
31 *  NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS.
32 */
33
34#define _POSIX_signals_Is_interested( _api, _mask ) \
35  ( ~(_api)->signals_blocked & (_mask) )
36         
37int killinfo(
38  pid_t               pid,
39  int                 sig,
40  const union sigval *value
41)
42{
43  sigset_t                     mask;
44  POSIX_API_Control           *api;
45  unsigned32                   the_class;
46  unsigned32                   index;
47  unsigned32                   maximum;
48  Objects_Information         *the_info;
49  Objects_Control            **object_table;
50  Thread_Control              *the_thread;
51  Thread_Control              *interested_thread;
52  Priority_Control             interested_priority;
53  Chain_Control               *the_chain;
54  Chain_Node                  *the_node;
55  siginfo_t                    siginfo_struct;
56  siginfo_t                   *siginfo;
57  POSIX_signals_Siginfo_node  *psiginfo;
58 
59  /*
60   *  Only supported for the "calling process" (i.e. this node).
61   */
62 
63  if( pid != getpid() )
64    set_errno_and_return_minus_one( ESRCH );
65
66  /*
67   *  Validate the signal passed if not 0.
68   */
69 
70  if ( sig && !is_valid_signo(sig) ) {
71    set_errno_and_return_minus_one( EINVAL );
72  }
73
74  /*
75   *  If the signal is being ignored, then we are out of here.
76   */
77
78  if ( !sig || _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN ) {
79    return 0;
80  }
81
82  /*
83   *  P1003.1c/Draft 10, p. 33 says that certain signals should always
84   *  be directed to the executing thread such as those caused by hardware
85   *  faults.
86   */
87
88  switch ( sig ) {
89    case SIGFPE:
90    case SIGILL:
91    case SIGSEGV:
92      return pthread_kill( pthread_self(), sig );
93    default:
94      break;
95  }
96
97  mask = signo_to_mask( sig );
98
99  /*
100   *  Build up a siginfo structure
101   */
102
103  siginfo = &siginfo_struct;
104  siginfo->si_signo = sig;
105  siginfo->si_code = SI_USER;
106  if ( !value ) {
107    siginfo->si_value.sival_int = 0;
108  } else {
109    siginfo->si_value = *value;
110  }
111
112  _Thread_Disable_dispatch();
113
114  /*
115   *  Is the currently executing thread interested?  If so then it will
116   *  get it an execute it as soon as the dispatcher executes.
117   */
118
119  the_thread = _Thread_Executing;
120
121  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
122  if ( _POSIX_signals_Is_interested( api, mask ) ) {
123    goto process_it;
124  }
125
126  /*
127   *  Is an interested thread waiting for this signal (sigwait())?
128   */
129
130  /* XXX violation of visibility -- need to define thread queue support */
131
132  for( index=0 ;
133       index < TASK_QUEUE_DATA_NUMBER_OF_PRIORITY_HEADERS ;
134       index++ ) {
135
136    the_chain = &_POSIX_signals_Wait_queue.Queues.Priority[ index ];
137 
138    for ( the_node = the_chain->first ;
139          !_Chain_Is_tail( the_chain, the_node ) ;
140          the_node = the_node->next ) {
141
142      the_thread = (Thread_Control *)the_node;
143      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
144
145      if ((the_thread->Wait.option & mask) || (~api->signals_blocked & mask)) {
146        goto process_it;
147      }
148
149    }
150  }
151
152  /*
153   *  Is any other thread interested?  The highest priority interested
154   *  thread is selected.  In the event of a tie, then the following
155   *  additional criteria is used:
156   *
157   *    + ready thread over blocked
158   *    + blocked on call interruptible by signal (can return EINTR)
159   *    + blocked on call not interruptible by signal
160   *
161   *  This looks at every thread in the system regardless of the creating API.
162   *
163   *  NOTES:
164   *
165   *    + rtems internal threads do not receive signals.
166   */
167
168  interested_thread = NULL;
169  interested_priority = PRIORITY_MAXIMUM + 1;
170
171  for ( the_class = OBJECTS_CLASSES_FIRST_THREAD_CLASS;
172        the_class <= OBJECTS_CLASSES_LAST_THREAD_CLASS;
173        the_class++ ) {
174
175    if ( the_class == OBJECTS_INTERNAL_THREADS )
176      continue;
177
178    the_info = _Objects_Information_table[ the_class ];
179
180    if ( !the_info )                        /* manager not installed */
181      continue;
182
183    maximum = the_info->maximum;
184    object_table = the_info->local_table;
185
186    assert( object_table );                 /* always at least 1 entry */
187
188    for ( index = 1 ; index <= maximum ; index++ ) {
189      the_thread = (Thread_Control *) object_table[ index ];
190
191      if ( !the_thread )
192        continue;
193
194      /*
195       *  If this thread is of lower priority than the interested thread,
196       *  go on to the next thread.
197       */
198
199      if ( the_thread->current_priority > interested_priority )
200        continue;
201
202      /*
203       *  If this thread is not interested, then go on to the next thread.
204       */
205
206      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
207
208      if ( !api || !_POSIX_signals_Is_interested( api, mask ) )
209        continue;
210
211      /*
212       *  Now we know the thread under connsideration is interested.
213       *  If the thread under consideration is of higher priority, then
214       *  it becomes the interested thread.
215       */
216
217      if ( the_thread->current_priority < interested_priority ) {
218        interested_thread   = the_thread;
219        interested_priority = the_thread->current_priority;
220        continue;
221      }
222
223      /*
224       *  Now the thread and the interested thread have the same priority.
225       *  If the interested thread is ready, then we don't need to send it
226       *  to a blocked thread.
227       */
228
229      if ( _States_Is_ready( interested_thread->current_state ) )
230        continue;
231
232      /*
233       *  Now the interested thread is blocked.
234       *  If the thread we are considering is not, the it becomes the
235       *  interested thread.
236       */
237
238      if ( _States_Is_ready( the_thread->current_state ) ) {
239        interested_thread   = the_thread;
240        interested_priority = the_thread->current_priority;
241        continue;
242      }
243
244      /*
245       *  Now we know both threads are blocked.
246       *  If the interested thread is interruptible, then just use it.
247       */
248
249      /* XXX need a new states macro */
250      if ( interested_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL )
251        continue;
252
253      /*
254       *  Now both threads are blocked and the interested thread is not
255       *  interruptible.
256       *  If the thread under consideration is interruptible by a signal,
257       *  then it becomes the interested thread.
258       */
259
260      /* XXX need a new states macro */
261      if ( the_thread->current_state & STATES_INTERRUPTIBLE_BY_SIGNAL ) {
262        interested_thread   = the_thread;
263        interested_priority = the_thread->current_priority;
264      }
265    }
266  }
267
268  if ( interested_thread ) {
269    the_thread = interested_thread;
270    goto process_it;
271  }
272
273  /*
274   *  OK so no threads were interested right now.  It will be left on the
275   *  global pending until a thread receives it.  The global set of threads
276   *  can change interest in this signal in one of the following ways:
277   *
278   *    + a thread is created with the signal unblocked,
279   *    + pthread_sigmask() unblocks the signal,
280   *    + sigprocmask() unblocks the signal, OR
281   *    + sigaction() which changes the handler to SIG_IGN.
282   */
283
284  the_thread = NULL;
285  goto post_process_signal;
286
287  /*
288   *  We found a thread which was interested, so now we mark that this
289   *  thread needs to do the post context switch extension so it can
290   *  evaluate the signals pending.
291   */
292
293process_it:
294 
295  the_thread->do_post_task_switch_extension = TRUE;
296
297  /*
298   *  Returns TRUE if the signal was synchronously given to a thread
299   *  blocked waiting for the signal.
300   */
301
302  if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) {
303    _Thread_Enable_dispatch();
304    return 0;
305  }
306
307post_process_signal:
308
309  /*
310   *  We may have woken up a thread but we definitely need to post the
311   *  signal to the process wide information set.
312   */
313
314  _POSIX_signals_Set_process_signals( mask );
315
316  if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) {
317
318    psiginfo = (POSIX_signals_Siginfo_node *)
319               _Chain_Get( &_POSIX_signals_Inactive_siginfo );
320    if ( !psiginfo ) {
321      set_errno_and_return_minus_one( EAGAIN );
322    }
323
324    psiginfo->Info = *siginfo;
325
326    _Chain_Append( &_POSIX_signals_Siginfo[ sig ], &psiginfo->Node );
327  }
328
329  _Thread_Enable_dispatch();
330  return 0;
331}
Note: See TracBrowser for help on using the repository browser.