source: rtems/cpukit/posix/src/killinfo.c @ dba7398

4.104.115
Last change on this file since dba7398 was dba7398, checked in by Joel Sherrill <joel.sherrill@…>, on 06/15/09 at 16:33:11

2009-06-15 Joel Sherrill <joel.sherrill@…>

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