source: rtems/cpukit/posix/src/killinfo.c @ 3899bc1a

5
Last change on this file since 3899bc1a was 3899bc1a, checked in by Sebastian Huber <sebastian.huber@…>, on 11/24/18 at 10:51:28

score: Optimize object lookup

Use the maximum ID for the ID to object translation. Using the maximum
ID gets rid of an additional load from the object information in
_Objects_Get(). In addition, object lookups fail for every ID in case
the object information is cleared to zero. This makes it a bit more
robust during system startup (see new tests in spconfig02).

The local table no longer needs a NULL pointer entry at array index
zero. Adjust all the object iteration loops accordingly.

Remove Objects_Information::minimum_id since it contains only redundant
information. Add _Objects_Get_minimum_id() to get the minimum ID.

Update #3621.

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