source: rtems/cpukit/posix/src/sigtimedwait.c @ e2735012

5
Last change on this file since e2735012 was e2735012, checked in by Sebastian Huber <sebastian.huber@…>, on 06/24/15 at 09:05:39

score: Introduce Thread_queue_Queue

Separate the thread queue heads and lock from the operations. This
enables the support for light weight objects which only support one
queuing discipline.

  • Property mode set to 100644
File size: 4.4 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief Wait for Queued Signals
5 *  @ingroup POSIXAPI
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2008.
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 <pthread.h>
22#include <signal.h>
23#include <errno.h>
24
25#include <rtems/posix/pthreadimpl.h>
26#include <rtems/posix/psignalimpl.h>
27#include <rtems/score/threadqimpl.h>
28#include <rtems/seterr.h>
29#include <rtems/posix/time.h>
30#include <rtems/score/isr.h>
31
32static int _POSIX_signals_Get_lowest(
33  sigset_t   set
34)
35{
36  int signo;
37
38  for ( signo = SIGRTMIN ; signo <= SIGRTMAX ; signo++ ) {
39    if ( set & signo_to_mask( signo ) ) {
40      goto found_it;
41    }
42  }
43
44  /*
45   *  We assume SIGHUP == 1 and is the first non-real-time signal.
46   */
47
48  #if (SIGHUP != 1)
49    #error "Assumption that SIGHUP==1 violated!!"
50  #endif
51  for ( signo = SIGHUP ; signo <= __SIGLASTNOTRT ; signo++ ) {
52    if ( set & signo_to_mask( signo ) ) {
53      goto found_it;
54    }
55  }
56
57  /*
58   *  This is structured this way to eliminate the need to have
59   *  a return 0.  This routine will NOT be called unless a signal
60   *  is pending in the set passed in.
61   */
62found_it:
63  return signo;
64}
65
66/**
67 *  3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76
68 */
69int sigtimedwait(
70  const sigset_t         *__restrict set,
71  siginfo_t              *__restrict info,
72  const struct timespec  *__restrict timeout
73)
74{
75  Thread_Control    *executing;
76  POSIX_API_Control *api;
77  Watchdog_Interval  interval;
78  siginfo_t          signal_information;
79  siginfo_t         *the_info;
80  int                signo;
81  ISR_lock_Context   lock_context;
82
83  /*
84   *  Error check parameters before disabling interrupts.
85   */
86  if ( !set )
87    rtems_set_errno_and_return_minus_one( EINVAL );
88
89  /*  NOTE: This is very specifically a RELATIVE not ABSOLUTE time
90   *        in the Open Group specification.
91   */
92
93  interval = 0;
94  if ( timeout ) {
95
96    if ( !_Timespec_Is_valid( timeout ) )
97      rtems_set_errno_and_return_minus_one( EINVAL );
98
99    interval = _Timespec_To_ticks( timeout );
100
101    if ( !interval )
102      rtems_set_errno_and_return_minus_one( EINVAL );
103  }
104
105  /*
106   *  Initialize local variables.
107   */
108
109  the_info = ( info ) ? info : &signal_information;
110
111  executing = _Thread_Get_executing();
112  api = executing->API_Extensions[ THREAD_API_POSIX ];
113
114  /*
115   *  What if they are already pending?
116   */
117
118  /* API signals pending? */
119
120  _POSIX_signals_Acquire( &lock_context );
121  if ( *set & api->signals_pending ) {
122    /* XXX real info later */
123    the_info->si_signo = _POSIX_signals_Get_lowest( api->signals_pending );
124    _POSIX_signals_Clear_signals(
125      api,
126      the_info->si_signo,
127      the_info,
128      false,
129      false,
130      false
131    );
132    _POSIX_signals_Release( &lock_context );
133
134    the_info->si_code = SI_USER;
135    the_info->si_value.sival_int = 0;
136    return the_info->si_signo;
137  }
138
139  /* Process pending signals? */
140
141  if ( *set & _POSIX_signals_Pending ) {
142    signo = _POSIX_signals_Get_lowest( _POSIX_signals_Pending );
143    _POSIX_signals_Clear_signals( api, signo, the_info, true, false, false );
144    _POSIX_signals_Release( &lock_context );
145
146    the_info->si_signo = signo;
147    the_info->si_code = SI_USER;
148    the_info->si_value.sival_int = 0;
149    return signo;
150  }
151
152  the_info->si_signo = -1;
153
154  _Thread_Disable_dispatch();
155    executing->Wait.return_code     = EINTR;
156    executing->Wait.option          = *set;
157    executing->Wait.return_argument = the_info;
158    _Thread_queue_Enqueue_critical(
159      &_POSIX_signals_Wait_queue.Queue,
160      _POSIX_signals_Wait_queue.operations,
161      executing,
162      STATES_WAITING_FOR_SIGNAL | STATES_INTERRUPTIBLE_BY_SIGNAL,
163      interval,
164      EAGAIN,
165      &lock_context
166    );
167  _Thread_Enable_dispatch();
168
169  /*
170   * When the thread is set free by a signal, it is need to eliminate
171   * the signal.
172   */
173
174  _POSIX_signals_Clear_signals(
175    api,
176    the_info->si_signo,
177    the_info,
178    false,
179    false,
180    true
181  );
182
183  /* Set errno only if return code is not EINTR or
184   * if EINTR was caused by a signal being caught, which
185   * was not in our set.
186   */
187
188  if ( (executing->Wait.return_code != EINTR)
189       || !(*set & signo_to_mask( the_info->si_signo )) ) {
190    errno = executing->Wait.return_code;
191    return -1;
192  }
193
194  return the_info->si_signo;
195}
Note: See TracBrowser for help on using the repository browser.