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

5
Last change on this file since d7665823 was d7665823, checked in by Sebastian Huber <sebastian.huber@…>, on 06/24/15 at 13:43:19

score: Introduce Thread_queue_Heads

Move the storage for the thread queue heads to the threads. Each thread
provides a set of thread queue heads allocated from a dedicated memory
pool. In case a thread blocks on a queue, then it lends its heads to
the queue. In case the thread unblocks, then it takes a free set of
threads from the queue. Since a thread can block on at most one queue
this works. This mechanism is used in FreeBSD. The motivation for this
change is to reduce the memory demands of the synchronization objects.
On a 32-bit uni-processor configuration the Thread_queue_Control size is
now 8 bytes, compared to 64 bytes in RTEMS 4.10 (other changes reduced
the size as well).

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