source: rtems/cpukit/posix/src/condwaitsupp.c @ 5222488

5
Last change on this file since 5222488 was 5222488, checked in by Sebastian Huber <sebastian.huber@…>, on 09/26/17 at 05:49:17

posix: Implement self-contained POSIX condvar

POSIX condition variables are now available in all configurations and no
longer depend on --enable-posix.

Update #2514.
Update #3113.

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