Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:21

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup POSIXAPI
0007  *
0008  * @brief Send a Signal to a Process
0009  */
0010 
0011 /*
0012  *  kill() support routine
0013  *
0014  *  COPYRIGHT (c) 1989-2009.
0015  *  On-Line Applications Research Corporation (OAR).
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  */
0038 
0039 #ifdef HAVE_CONFIG_H
0040 #include "config.h"
0041 #endif
0042 
0043 #include <pthread.h>
0044 #include <signal.h>
0045 #include <errno.h>
0046 
0047 #include <rtems/posix/pthreadimpl.h>
0048 #include <rtems/posix/psignalimpl.h>
0049 #include <rtems/score/isr.h>
0050 #include <rtems/score/statesimpl.h>
0051 #include <rtems/seterr.h>
0052 
0053 /*
0054  *  If you enable this, then you get printk() feedback on each path
0055  *  and the input to the decision that lead to the decision.  Hopefully
0056  *  this will help in debugging the algorithm that distributes process
0057  *  signals to individual threads.
0058  */
0059 
0060 /* #define DEBUG_SIGNAL_PROCESSING */
0061 #if defined(DEBUG_SIGNAL_PROCESSING)
0062   #include <rtems/bspIo.h>
0063   #define DEBUG_STEP(_x) printk(_x)
0064 #else
0065   #define DEBUG_STEP(_x)
0066 #endif
0067 
0068 /*
0069  *  3.3.2 Send a Signal to a Process, P1003.1b-1993, p. 68
0070  *
0071  *  NOTE: Behavior of kill() depends on _POSIX_SAVED_IDS.
0072  */
0073 
0074 #define _POSIX_signals_Is_interested( _api, _mask ) \
0075   ( (_api)->signals_unblocked & (_mask) )
0076 
0077 int _POSIX_signals_Send(
0078   pid_t               pid,
0079   int                 sig,
0080   const union sigval *value
0081 )
0082 {
0083   sigset_t                     mask;
0084   POSIX_API_Control           *api;
0085   uint32_t                     the_api;
0086   uint32_t                     index;
0087   uint32_t                     maximum;
0088   Objects_Information         *the_info;
0089   Objects_Control            **object_table;
0090   Thread_Control              *the_thread;
0091   Thread_Control              *interested;
0092   Priority_Control             interested_priority;
0093   Chain_Node                  *the_node;
0094   siginfo_t                    siginfo_struct;
0095   siginfo_t                   *siginfo;
0096   POSIX_signals_Siginfo_node  *psiginfo;
0097   Thread_queue_Heads          *heads;
0098   Thread_queue_Context         queue_context;
0099   Per_CPU_Control             *cpu_self;
0100 
0101   /*
0102    *  Only supported for the "calling process" (i.e. this node).
0103    */
0104   if ( pid != getpid() )
0105     rtems_set_errno_and_return_minus_one( ESRCH );
0106 
0107   /*
0108    *  Validate the signal passed.
0109    */
0110   if ( !sig )
0111     rtems_set_errno_and_return_minus_one( EINVAL );
0112 
0113   if ( !is_valid_signo(sig) )
0114     rtems_set_errno_and_return_minus_one( EINVAL );
0115 
0116   /*
0117    *  If the signal is being ignored, then we are out of here.
0118    */
0119   if ( _POSIX_signals_Vectors[ sig ].sa_handler == SIG_IGN )
0120     return 0;
0121 
0122   /*
0123    *  P1003.1c/Draft 10, p. 33 says that certain signals should always
0124    *  be directed to the executing thread such as those caused by hardware
0125    *  faults.
0126    */
0127   if ( (sig == SIGFPE) || (sig == SIGILL) || (sig == SIGSEGV ) )
0128       return pthread_kill( pthread_self(), sig );
0129 
0130   mask = signo_to_mask( sig );
0131 
0132   /*
0133    *  Build up a siginfo structure
0134    */
0135   siginfo = &siginfo_struct;
0136   siginfo->si_signo = sig;
0137   siginfo->si_code = SI_USER;
0138   if ( !value ) {
0139     siginfo->si_value.sival_int = 0;
0140   } else {
0141     siginfo->si_value = *value;
0142   }
0143 
0144   /* FIXME: https://gitlab.rtems.org/rtems/rtos/rtems/-/issues/2690 */
0145   cpu_self = _Thread_Dispatch_disable();
0146 
0147   /*
0148    *  Is the currently executing thread interested?  If so then it will
0149    *  get it an execute it as soon as the dispatcher executes.
0150    */
0151   the_thread = _Per_CPU_Get_executing( cpu_self );
0152 
0153   api = the_thread->API_Extensions[ THREAD_API_POSIX ];
0154   if ( _POSIX_signals_Is_interested( api, mask ) ) {
0155     goto process_it;
0156   }
0157 
0158   /*
0159    *  Is an interested thread waiting for this signal (sigwait())?
0160    *
0161    *  There is no requirement on the order of threads pending on a sigwait().
0162    */
0163 
0164   /* XXX violation of visibility -- need to define thread queue support */
0165 
0166   heads = _POSIX_signals_Wait_queue.Queue.heads;
0167   if ( heads != NULL ) {
0168     Chain_Control *the_chain = &heads->Heads.Fifo;
0169 
0170     for ( the_node = _Chain_First( the_chain );
0171           !_Chain_Is_tail( the_chain, the_node ) ;
0172           the_node = the_node->next ) {
0173       Scheduler_Node *scheduler_node;
0174 
0175       scheduler_node = SCHEDULER_NODE_OF_WAIT_PRIORITY_NODE( the_node );
0176       the_thread = _Scheduler_Node_get_owner( scheduler_node );
0177       api = the_thread->API_Extensions[ THREAD_API_POSIX ];
0178 
0179       #if defined(DEBUG_SIGNAL_PROCESSING)
0180         printk( "Waiting Thread=%p option=0x%08x mask=0x%08x blocked=0x%08x\n",
0181           the_thread, the_thread->Wait.option, mask, ~api->signals_unblocked);
0182       #endif
0183 
0184       /*
0185        * Is this thread is actually blocked waiting for the signal?
0186        */
0187       if (the_thread->Wait.option & mask)
0188         goto process_it;
0189 
0190       /*
0191        * Is this thread is blocked waiting for another signal but has
0192        * not blocked this one?
0193        */
0194       if (api->signals_unblocked & mask)
0195         goto process_it;
0196     }
0197   }
0198 
0199   /*
0200    *  Is any other thread interested?  The highest priority interested
0201    *  thread is selected.  In the event of a tie, then the following
0202    *  additional criteria is used:
0203    *
0204    *    + ready thread over blocked
0205    *    + blocked on call interruptible by signal (can return EINTR)
0206    *    + blocked on call not interruptible by signal
0207    *
0208    *  This looks at every thread in the system regardless of the creating API.
0209    *
0210    *  NOTES:
0211    *
0212    *    + rtems internal threads do not receive signals.
0213    */
0214   interested = NULL;
0215   interested_priority = UINT64_MAX;
0216 
0217   for (the_api = OBJECTS_CLASSIC_API; the_api <= OBJECTS_APIS_LAST; the_api++) {
0218     _Assert( _Objects_Information_table[ the_api ] != NULL );
0219     the_info = _Objects_Information_table[ the_api ][ 1 ];
0220     if ( !the_info )
0221       continue;
0222 
0223     maximum = _Objects_Get_maximum_index( the_info );
0224     object_table = the_info->local_table;
0225 
0226     for ( index = 0 ; index < maximum ; ++index ) {
0227       the_thread = (Thread_Control *) object_table[ index ];
0228 
0229       if ( !the_thread )
0230         continue;
0231 
0232       #if defined(DEBUG_SIGNAL_PROCESSING)
0233         printk("\n 0x%08x/0x%08x %d/%d 0x%08x 1",
0234           the_thread->Object.id,
0235           ((interested) ? interested->Object.id : 0),
0236           _Thread_Get_priority( the_thread ), interested_priority,
0237           the_thread->current_state
0238         );
0239       #endif
0240 
0241       /*
0242        *  If this thread is of lower priority than the interested thread,
0243        *  go on to the next thread.
0244        */
0245       if ( _Thread_Get_priority( the_thread ) > interested_priority )
0246         continue;
0247       DEBUG_STEP("2");
0248 
0249       /*
0250        *  If this thread is not interested, then go on to the next thread.
0251        */
0252       api = the_thread->API_Extensions[ THREAD_API_POSIX ];
0253 
0254       #if defined(RTEMS_DEBUG)
0255         if ( !api )
0256           continue;
0257       #endif
0258 
0259       if ( !_POSIX_signals_Is_interested( api, mask ) )
0260         continue;
0261       DEBUG_STEP("3");
0262 
0263       /*
0264        *  Now we know the thread under consideration is interested.
0265        *  If the thread under consideration is of higher priority, then
0266        *  it becomes the interested thread.
0267        *
0268        *  NOTE: We initialized interested_priority to PRIORITY_MAXIMUM + 1
0269        *        so we never have to worry about deferencing a NULL
0270        *        interested thread.
0271        */
0272       if ( _Thread_Get_priority( the_thread ) < interested_priority ) {
0273         interested   = the_thread;
0274         interested_priority = _Thread_Get_priority( the_thread );
0275         continue;
0276       }
0277       DEBUG_STEP("4");
0278 
0279       /*
0280        *  Now the thread and the interested thread have the same priority.
0281        *  We have to sort through the combinations of blocked/not blocked
0282        *  and blocking interruptibutable by signal.
0283        *
0284        *  If the interested thread is ready, don't think about changing.
0285        */
0286 
0287       if ( interested && !_States_Is_ready( interested->current_state ) ) {
0288         /* preferred ready over blocked */
0289         DEBUG_STEP("5");
0290         if ( _States_Is_ready( the_thread->current_state ) ) {
0291           interested          = the_thread;
0292           interested_priority = _Thread_Get_priority( the_thread );
0293           continue;
0294         }
0295 
0296         DEBUG_STEP("6");
0297         /* prefer blocked/interruptible over blocked/not interruptible */
0298         if ( !_States_Is_interruptible_by_signal(interested->current_state) ) {
0299           DEBUG_STEP("7");
0300           if ( _States_Is_interruptible_by_signal(the_thread->current_state) ) {
0301             DEBUG_STEP("8");
0302             interested          = the_thread;
0303             interested_priority = _Thread_Get_priority( the_thread );
0304             continue;
0305           }
0306         }
0307       }
0308     }
0309   }
0310 
0311   if ( interested ) {
0312     the_thread = interested;
0313     goto process_it;
0314   }
0315 
0316   /*
0317    *  OK so no threads were interested right now.  It will be left on the
0318    *  global pending until a thread receives it.  The global set of threads
0319    *  can change interest in this signal in one of the following ways:
0320    *
0321    *    + a thread is created with the signal unblocked,
0322    *    + pthread_sigmask() unblocks the signal,
0323    *    + sigprocmask() unblocks the signal, OR
0324    *    + sigaction() which changes the handler to SIG_IGN.
0325    */
0326   goto post_process_signal;
0327 
0328   /*
0329    *  We found a thread which was interested, so now we mark that this
0330    *  thread needs to do the post context switch extension so it can
0331    *  evaluate the signals pending.
0332    */
0333 process_it:
0334 
0335   /*
0336    *  Returns true if the signal was synchronously given to a thread
0337    *  blocked waiting for the signal.
0338    */
0339   if ( _POSIX_signals_Unblock_thread( the_thread, sig, siginfo ) ) {
0340     _Thread_Dispatch_enable( cpu_self );
0341     return 0;
0342   }
0343 
0344 post_process_signal:
0345 
0346   /*
0347    *  We may have woken up a thread but we definitely need to post the
0348    *  signal to the process wide information set.
0349    */
0350   _POSIX_signals_Set_process_signals( mask );
0351 
0352   _Thread_queue_Context_initialize( &queue_context );
0353   _POSIX_signals_Acquire( &queue_context );
0354 
0355   if ( _POSIX_signals_Vectors[ sig ].sa_flags == SA_SIGINFO ) {
0356 
0357     psiginfo = (POSIX_signals_Siginfo_node *)
0358       _Chain_Get_unprotected( &_POSIX_signals_Inactive_siginfo );
0359     if ( !psiginfo ) {
0360       _POSIX_signals_Release( &queue_context );
0361       _Thread_Dispatch_enable( cpu_self );
0362       rtems_set_errno_and_return_minus_one( EAGAIN );
0363     }
0364 
0365     psiginfo->Info = *siginfo;
0366 
0367     _Chain_Append_unprotected(
0368       &_POSIX_signals_Siginfo[ sig ],
0369       &psiginfo->Node
0370     );
0371   }
0372 
0373   _POSIX_signals_Release( &queue_context );
0374   DEBUG_STEP("\n");
0375   _Thread_Dispatch_enable( cpu_self );
0376   return 0;
0377 }