source: rtems/cpukit/posix/src/sigtimedwait.c @ 620b23e

5
Last change on this file since 620b23e was 620b23e, checked in by Sebastian Huber <sebastian.huber@…>, on 11/24/16 at 05:13:11

score: Optimize _Thread_queue_Enqueue()

Move thread state for _Thread_queue_Enqueue() to the thread queue
context. This reduces the parameter count of _Thread_queue_Enqueue()
from five to four (ARM for example has only four function parameter
registers). Since the thread state is used after several function calls
inside _Thread_queue_Enqueue() this parameter was saved on the stack
previously.

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