source: rtems/cpukit/posix/src/condwaitsupp.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.8 KB
Line 
1/**
2 * @file
3 *
4 * @brief POSIX Condition Variables Wait Support
5 * @ingroup POSIX_COND_VARS
6 */
7
8/*
9 *  COPYRIGHT (c) 1989-2014.
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 <rtems/posix/condimpl.h>
22#include <rtems/posix/posixapi.h>
23#include <rtems/score/assert.h>
24#include <rtems/score/statesimpl.h>
25#include <rtems/score/status.h>
26#include <rtems/score/threaddispatch.h>
27
28THREAD_QUEUE_OBJECT_ASSERT( POSIX_Condition_variables_Control, Wait_queue );
29
30static void _POSIX_Condition_variables_Enqueue_callout(
31  Thread_queue_Queue   *queue,
32  Thread_Control       *the_thread,
33  Thread_queue_Context *queue_context
34)
35{
36  POSIX_Condition_variables_Control *the_cond;
37  int                                mutex_error;
38
39  the_cond = POSIX_CONDITION_VARIABLE_OF_THREAD_QUEUE_QUEUE( queue );
40
41  mutex_error = pthread_mutex_unlock( &the_cond->mutex );
42  if ( mutex_error != 0 ) {
43    /*
44     *  Historically, we ignored the unlock status since the behavior
45     *  is undefined by POSIX. But GNU/Linux returns EPERM in this
46     *  case, so we follow their lead.
47     */
48    _Assert( mutex_error == EINVAL || mutex_error == EPERM );
49    _Thread_queue_Extract( the_thread );
50    the_thread->Wait.return_code= STATUS_NOT_OWNER;
51  }
52}
53
54int _POSIX_Condition_variables_Wait_support(
55  pthread_cond_t            *cond,
56  pthread_mutex_t           *mutex,
57  const struct timespec     *abstime
58)
59{
60  POSIX_Condition_variables_Control *the_cond;
61  Thread_queue_Context               queue_context;
62  int                                error;
63  int                                mutex_error;
64  Thread_Control                    *executing;
65  Watchdog_Interval                  timeout;
66  bool                               already_timedout;
67  TOD_Absolute_timeout_conversion_results  status;
68
69  if ( mutex == NULL ) {
70    return EINVAL;
71  }
72
73  the_cond = _POSIX_Condition_variables_Get( cond, &queue_context );
74
75  if ( the_cond == NULL ) {
76    return EINVAL;
77  }
78
79  already_timedout = false;
80
81  if ( abstime != NULL ) {
82    /*
83     *  POSIX requires that blocking calls with timeouts that take
84     *  an absolute timeout must ignore issues with the absolute
85     *  time provided if the operation would otherwise succeed.
86     *  So we check the abstime provided, and hold on to whether it
87     *  is valid or not.  If it isn't correct and in the future,
88     *  then we do a polling operation and convert the UNSATISFIED
89     *  status into the appropriate error.
90     */
91    _Assert( the_cond->clock );
92    status = _TOD_Absolute_timeout_to_ticks(abstime, the_cond->clock, &timeout);
93    if ( status == TOD_ABSOLUTE_TIMEOUT_INVALID )
94      return EINVAL;
95
96    if ( status == TOD_ABSOLUTE_TIMEOUT_IS_IN_PAST ||
97        status == TOD_ABSOLUTE_TIMEOUT_IS_NOW ) {
98      already_timedout = true;
99    } else {
100      _Thread_queue_Context_set_relative_timeout( &queue_context, timeout );
101    }
102  } else {
103    _Thread_queue_Context_set_no_timeout( &queue_context );
104  }
105
106  _POSIX_Condition_variables_Acquire_critical( the_cond, &queue_context );
107
108  if (
109    the_cond->mutex != POSIX_CONDITION_VARIABLES_NO_MUTEX
110      && the_cond->mutex != *mutex
111  ) {
112    _POSIX_Condition_variables_Release( the_cond, &queue_context );
113    return EINVAL;
114  }
115
116  the_cond->mutex = *mutex;
117  executing = _Thread_Executing;
118
119  if ( !already_timedout ) {
120    _Thread_queue_Context_set_thread_state(
121      &queue_context,
122      STATES_WAITING_FOR_CONDITION_VARIABLE
123    );
124    _Thread_queue_Context_set_enqueue_callout(
125      &queue_context,
126      _POSIX_Condition_variables_Enqueue_callout
127    );
128    _Thread_queue_Enqueue(
129      &the_cond->Wait_queue.Queue,
130      POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
131      executing,
132      &queue_context
133    );
134    error = _POSIX_Get_error_after_wait( executing );
135  } else {
136    _POSIX_Condition_variables_Release( the_cond, &queue_context );
137
138    mutex_error = pthread_mutex_unlock( &the_cond->mutex );
139    if ( mutex_error != 0 ) {
140      error = EPERM;
141    } else {
142      error = ETIMEDOUT;
143    }
144  }
145
146  /*
147   *  If the thread is interrupted, while in the thread queue, by
148   *  a POSIX signal, then pthread_cond_wait returns spuriously,
149   *  according to the POSIX standard. It means that pthread_cond_wait
150   *  returns a success status, except for the fact that it was not
151   *  woken up a pthread_cond_signal() or a pthread_cond_broadcast().
152   */
153
154  if ( error == EINTR ) {
155    error = 0;
156  }
157
158  /*
159   *  When we get here the dispatch disable level is 0.
160   */
161
162  if ( error != EPERM ) {
163    mutex_error = pthread_mutex_lock( mutex );
164    if ( mutex_error != 0 ) {
165      _Assert( mutex_error == EINVAL );
166      error = EINVAL;
167    }
168  }
169
170  return error;
171}
Note: See TracBrowser for help on using the repository browser.