Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  *  @file
0005  *
0006  *  @brief Wait for Queued Signals
0007  *  @ingroup POSIXAPI
0008  */
0009 
0010 /*
0011  *  COPYRIGHT (c) 1989-2008.
0012  *  On-Line Applications Research Corporation (OAR).
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <signal.h>
0041 
0042 #include <rtems/posix/pthreadimpl.h>
0043 #include <rtems/posix/psignalimpl.h>
0044 #include <rtems/posix/posixapi.h>
0045 #include <rtems/score/threadqimpl.h>
0046 #include <rtems/score/todimpl.h>
0047 #include <rtems/score/watchdogimpl.h>
0048 #include <rtems/score/isr.h>
0049 
0050 static int _POSIX_signals_Get_lowest(
0051   sigset_t   set
0052 )
0053 {
0054   int signo;
0055 
0056   for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) {
0057     if ( set & signo_to_mask( signo ) ) {
0058       goto found_it;
0059     }
0060   }
0061 
0062   /*
0063    *  We assume SIGHUP == 1 and is the first non-real-time signal.
0064    */
0065 
0066   #if (SIGHUP != 1)
0067     #error "Assumption that SIGHUP==1 violated!!"
0068   #endif
0069   for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) {
0070     if ( set & signo_to_mask( signo ) ) {
0071       goto found_it;
0072     }
0073   }
0074 
0075   /*
0076    *  This is structured this way to eliminate the need to have
0077    *  a return 0.  This routine will NOT be called unless a signal
0078    *  is pending in the set passed in.
0079    */
0080 found_it:
0081   return signo;
0082 }
0083 
0084 /**
0085  *  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
0086  */
0087 int sigtimedwait(
0088   const sigset_t         *__restrict set,
0089   siginfo_t              *__restrict info,
0090   const struct timespec  *__restrict timeout
0091 )
0092 {
0093   Thread_Control       *executing;
0094   POSIX_API_Control    *api;
0095   siginfo_t             signal_information;
0096   siginfo_t            *the_info;
0097   int                   signo;
0098   Thread_queue_Context  queue_context;
0099   int                   error;
0100 
0101   /*
0102    *  Error check parameters before disabling interrupts.
0103    */
0104   if ( !set )
0105     rtems_set_errno_and_return_minus_one( EINVAL );
0106 
0107   _Thread_queue_Context_initialize( &queue_context );
0108 
0109   /*  NOTE: This is very specifically a RELATIVE not ABSOLUTE time
0110    *        in the Open Group specification.
0111    */
0112 
0113   if ( timeout != NULL ) {
0114     _Thread_queue_Context_set_enqueue_timeout_monotonic_timespec(
0115       &queue_context,
0116       timeout,
0117       false
0118     );
0119   } else {
0120     _Thread_queue_Context_set_enqueue_do_nothing_extra( &queue_context );
0121   }
0122 
0123   /*
0124    *  Initialize local variables.
0125    */
0126 
0127   the_info = ( info ) ? info : &signal_information;
0128 
0129   executing = _Thread_Get_executing();
0130   api = executing->API_Extensions[ THREAD_API_POSIX ];
0131 
0132   /*
0133    *  What if they are already pending?
0134    */
0135 
0136   /* API signals pending? */
0137 
0138   _POSIX_signals_Acquire( &queue_context );
0139   if ( *set & api->signals_pending ) {
0140     /* XXX real info later */
0141     the_info->si_signo = _POSIX_signals_Get_lowest( api->signals_pending );
0142     _POSIX_signals_Clear_signals(
0143       api,
0144       the_info->si_signo,
0145       the_info,
0146       false,
0147       false,
0148       false
0149     );
0150     _POSIX_signals_Release( &queue_context );
0151 
0152     the_info->si_code = SI_USER;
0153     the_info->si_value.sival_int = 0;
0154     return the_info->si_signo;
0155   }
0156 
0157   /* Process pending signals? */
0158 
0159   if ( *set & _POSIX_signals_Pending ) {
0160     signo = _POSIX_signals_Get_lowest( _POSIX_signals_Pending );
0161     _POSIX_signals_Clear_signals( api, signo, the_info, true, false, false );
0162     _POSIX_signals_Release( &queue_context );
0163 
0164     the_info->si_signo = signo;
0165     the_info->si_code = SI_USER;
0166     the_info->si_value.sival_int = 0;
0167     return signo;
0168   }
0169 
0170   the_info->si_signo = -1;
0171 
0172   executing->Wait.option          = *set;
0173   executing->Wait.return_argument = the_info;
0174   _Thread_queue_Context_set_thread_state(
0175     &queue_context,
0176     STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL
0177   );
0178   _Thread_queue_Enqueue(
0179     &_POSIX_signals_Wait_queue.Queue,
0180     POSIX_SIGNALS_TQ_OPERATIONS,
0181     executing,
0182     &queue_context
0183   );
0184 
0185   /*
0186    * When the thread is set free by a signal, it is need to eliminate
0187    * the signal.
0188    */
0189 
0190   _POSIX_signals_Clear_signals(
0191     api,
0192     the_info->si_signo,
0193     the_info,
0194     false,
0195     false,
0196     true
0197   );
0198 
0199   /* Set errno only if return code is not EINTR or
0200    * if EINTR was caused by a signal being caught, which
0201    * was not in our set.
0202    */
0203 
0204   error = _POSIX_Get_error_after_wait( executing );
0205 
0206   if (
0207     error != EINTR
0208      || ( *set & signo_to_mask( the_info->si_signo ) ) == 0
0209   ) {
0210     if ( error == ETIMEDOUT ) {
0211       error = EAGAIN;
0212     }
0213 
0214     rtems_set_errno_and_return_minus_one( error );
0215   }
0216 
0217   return the_info->si_signo;
0218 }