source: rtems/cpukit/posix/src/psignalunblockthread.c @ 0e16fa45

5
Last change on this file since 0e16fa45 was 93306058, checked in by Sebastian Huber <sebastian.huber@…>, on 05/27/16 at 12:43:19

score: _CORE_mutex_Check_dispatch_for_seize()

Move the safety check performed by
_CORE_mutex_Check_dispatch_for_seize() out of the performance critical
path and generalize it. Blocking on a thread queue with an unexpected
thread dispatch disabled level is illegal in all system states.

Add the expected thread dispatch disable level (which may be 1 or 2
depending on the operation) to Thread_queue_Context and use it in
_Thread_queue_Enqueue_critical().

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief POSIX Signals Thread Unlock
5 * @ingroup POSIX_SIGNALS
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2007.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <errno.h>
22#include <pthread.h>
23#include <signal.h>
24
25#include <rtems/system.h>
26#include <rtems/score/isr.h>
27#include <rtems/score/threadimpl.h>
28#include <rtems/score/threadqimpl.h>
29#include <rtems/score/watchdogimpl.h>
30#include <rtems/score/wkspace.h>
31#include <rtems/seterr.h>
32#include <rtems/posix/threadsup.h>
33#include <rtems/posix/psignalimpl.h>
34#include <rtems/posix/pthreadimpl.h>
35#include <stdio.h>
36
37static void _POSIX_signals_Check_signal(
38  POSIX_API_Control  *api,
39  int                 signo,
40  bool                is_global
41)
42{
43  siginfo_t siginfo_struct;
44  sigset_t  saved_signals_unblocked;
45
46  if ( ! _POSIX_signals_Clear_signals( api, signo, &siginfo_struct,
47                                       is_global, true, true ) )
48    return;
49
50  /*
51   *  Since we made a union of these, only one test is necessary but this is
52   *  safer.
53   */
54  #if defined(RTEMS_DEBUG)
55    assert( _POSIX_signals_Vectors[ signo ].sa_handler ||
56            _POSIX_signals_Vectors[ signo ].sa_sigaction );
57  #endif
58
59  /*
60   *  Just to prevent sending a signal which is currently being ignored.
61   */
62  if ( _POSIX_signals_Vectors[ signo ].sa_handler == SIG_IGN )
63    return;
64
65  /*
66   *  Block the signals requested in sa_mask
67   */
68  saved_signals_unblocked = api->signals_unblocked;
69  api->signals_unblocked &= ~_POSIX_signals_Vectors[ signo ].sa_mask;
70
71  /*
72   *  Here, the signal handler function executes
73   */
74  switch ( _POSIX_signals_Vectors[ signo ].sa_flags ) {
75    case SA_SIGINFO:
76      (*_POSIX_signals_Vectors[ signo ].sa_sigaction)(
77        signo,
78        &siginfo_struct,
79        NULL        /* context is undefined per 1003.1b-1993, p. 66 */
80      );
81      break;
82    default:
83      (*_POSIX_signals_Vectors[ signo ].sa_handler)( signo );
84      break;
85  }
86
87  /*
88   *  Restore the previous set of unblocked signals
89   */
90  api->signals_unblocked = saved_signals_unblocked;
91}
92
93static void _POSIX_signals_Action_handler(
94  Thread_Control   *executing,
95  Thread_Action    *action,
96  ISR_lock_Context *lock_context
97)
98{
99  POSIX_API_Control *api;
100  int                signo;
101  uint32_t           hold_errno;
102
103  (void) action;
104  _Thread_State_release( executing, lock_context );
105
106  api = executing->API_Extensions[ THREAD_API_POSIX ];
107
108  /*
109   *  We need to ensure that if the signal handler executes a call
110   *  which overwrites the unblocking status, we restore it.
111   */
112  hold_errno = executing->Wait.return_code;
113
114  /*
115   * api may be NULL in case of a thread close in progress
116   */
117  if ( !api )
118    return;
119
120  /*
121   *  In case the executing thread is blocked or about to block on something
122   *  that uses the thread wait information, then this is a kernel bug.
123   */
124  _Assert(
125    ( _Thread_Wait_flags_get( executing )
126      & ( THREAD_WAIT_STATE_BLOCKED | THREAD_WAIT_STATE_INTEND_TO_BLOCK ) ) == 0
127  );
128
129  /*
130   *  If we invoke any user code, there is the possibility that
131   *  a new signal has been posted that we should process so we
132   *  restart the loop if a signal handler was invoked.
133   *
134   *  The first thing done is to check there are any signals to be
135   *  processed at all.  No point in doing this loop otherwise.
136   */
137  while (1) {
138    Thread_queue_Context queue_context;
139
140    _Thread_queue_Context_initialize( &queue_context );
141    _POSIX_signals_Acquire( &queue_context );
142      if ( !(api->signals_unblocked &
143            (api->signals_pending | _POSIX_signals_Pending)) ) {
144       _POSIX_signals_Release( &queue_context );
145       break;
146     }
147    _POSIX_signals_Release( &queue_context );
148
149    for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) {
150      _POSIX_signals_Check_signal( api, signo, false );
151      _POSIX_signals_Check_signal( api, signo, true );
152    }
153    /* Unfortunately - nothing like __SIGFIRSTNOTRT in newlib signal .h */
154
155    for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) {
156      _POSIX_signals_Check_signal( api, signo, false );
157      _POSIX_signals_Check_signal( api, signo, true );
158    }
159  }
160
161  executing->Wait.return_code = hold_errno;
162}
163
164static bool _POSIX_signals_Unblock_thread_done(
165  Thread_Control    *the_thread,
166  POSIX_API_Control *api,
167  bool               status
168)
169{
170  ISR_lock_Context lock_context;
171
172  _Thread_State_acquire( the_thread, &lock_context );
173  _Thread_Add_post_switch_action(
174    the_thread,
175    &api->Signal_action,
176    _POSIX_signals_Action_handler
177  );
178  _Thread_State_release( the_thread, &lock_context );
179
180  return status;
181}
182
183bool _POSIX_signals_Unblock_thread(
184  Thread_Control  *the_thread,
185  int              signo,
186  siginfo_t       *info
187)
188{
189  POSIX_API_Control  *api;
190  sigset_t            mask;
191  siginfo_t          *the_info = NULL;
192
193  api = the_thread->API_Extensions[ THREAD_API_POSIX ];
194
195  mask = signo_to_mask( signo );
196
197  /*
198   *  Is the thread is specifically waiting for a signal?
199   */
200
201  if ( _States_Is_interruptible_signal( the_thread->current_state ) ) {
202
203    if ( (the_thread->Wait.option & mask) || (api->signals_unblocked & mask) ) {
204      the_thread->Wait.return_code = STATUS_INTERRUPTED;
205
206      the_info = (siginfo_t *) the_thread->Wait.return_argument;
207
208      if ( !info ) {
209        the_info->si_signo = signo;
210        the_info->si_code = SI_USER;
211        the_info->si_value.sival_int = 0;
212      } else {
213        *the_info = *info;
214      }
215
216      _Thread_queue_Extract_with_proxy( the_thread );
217      return _POSIX_signals_Unblock_thread_done( the_thread, api, true );
218    }
219
220    /*
221     *  This should only be reached via pthread_kill().
222     */
223
224    return _POSIX_signals_Unblock_thread_done( the_thread, api, false );
225  }
226
227  /*
228   *  Thread is not waiting due to a sigwait.
229   */
230  if ( api->signals_unblocked & mask ) {
231
232    /*
233     *  The thread is interested in this signal.  We are going
234     *  to post it.  We have a few broad cases:
235     *    + If it is blocked on an interruptible signal, THEN
236     *        we unblock the thread.
237     *    + If it is in the ready state AND
238     *      we are sending from an ISR AND
239     *      it is the interrupted thread AND
240     *      it is not blocked, THEN
241     *        we need to dispatch at the end of this ISR.
242     *    + Any other combination, do nothing.
243     */
244
245    if ( _States_Is_interruptible_by_signal( the_thread->current_state ) ) {
246      the_thread->Wait.return_code = STATUS_INTERRUPTED;
247      _Thread_queue_Extract_with_proxy( the_thread );
248    }
249  }
250  return _POSIX_signals_Unblock_thread_done( the_thread, api, false );
251}
Note: See TracBrowser for help on using the repository browser.