[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] | 58 | int _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 | */ |
---|
| 321 | process_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 | |
---|
| 332 | post_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 | } |
---|