source: rtems/cpukit/posix/src/condwaitsupp.c @ 77fbbd6

5
Last change on this file since 77fbbd6 was c3105894, checked in by Sebastian Huber <sebastian.huber@…>, on 10/19/17 at 11:47:57

score: Move thread queue timeout handling

Update #3117.
Update #3182.

  • 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
28static void _POSIX_Condition_variables_Mutex_unlock(
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_Continue( the_thread, STATUS_NOT_OWNER );
48  }
49}
50
51static void _POSIX_Condition_variables_Enqueue_no_timeout(
52  Thread_queue_Queue   *queue,
53  Thread_Control       *the_thread,
54  Per_CPU_Control      *cpu_self,
55  Thread_queue_Context *queue_context
56)
57{
58  _POSIX_Condition_variables_Mutex_unlock( queue, the_thread, queue_context );
59}
60
61static void _POSIX_Condition_variables_Enqueue_with_timeout_monotonic(
62  Thread_queue_Queue   *queue,
63  Thread_Control       *the_thread,
64  Per_CPU_Control      *cpu_self,
65  Thread_queue_Context *queue_context
66)
67{
68  _Thread_queue_Add_timeout_monotonic_timespec(
69    queue,
70    the_thread,
71    cpu_self,
72    queue_context
73  );
74  _POSIX_Condition_variables_Mutex_unlock( queue, the_thread, queue_context );
75}
76
77static void _POSIX_Condition_variables_Enqueue_with_timeout_realtime(
78  Thread_queue_Queue   *queue,
79  Thread_Control       *the_thread,
80  Per_CPU_Control      *cpu_self,
81  Thread_queue_Context *queue_context
82)
83{
84  _Thread_queue_Add_timeout_realtime_timespec(
85    queue,
86    the_thread,
87    cpu_self,
88    queue_context
89  );
90  _POSIX_Condition_variables_Mutex_unlock( queue, the_thread, queue_context );
91}
92
93int _POSIX_Condition_variables_Wait_support(
94  pthread_cond_t            *cond,
95  pthread_mutex_t           *mutex,
96  const struct timespec     *abstime
97)
98{
99  POSIX_Condition_variables_Control *the_cond;
100  unsigned long                      flags;
101  Thread_queue_Context               queue_context;
102  int                                error;
103  Thread_Control                    *executing;
104
105  the_cond = _POSIX_Condition_variables_Get( cond );
106  POSIX_CONDITION_VARIABLES_VALIDATE_OBJECT( the_cond, flags );
107
108  _Thread_queue_Context_initialize( &queue_context );
109
110  if ( abstime != NULL ) {
111    _Thread_queue_Context_set_timeout_argument( &queue_context, abstime );
112
113    if ( _POSIX_Condition_variables_Get_clock( flags ) == CLOCK_MONOTONIC ) {
114      _Thread_queue_Context_set_enqueue_callout(
115        &queue_context,
116        _POSIX_Condition_variables_Enqueue_with_timeout_monotonic
117      );
118    } else {
119      _Thread_queue_Context_set_enqueue_callout(
120        &queue_context,
121        _POSIX_Condition_variables_Enqueue_with_timeout_realtime
122      );
123    }
124  } else {
125    _Thread_queue_Context_set_enqueue_callout(
126      &queue_context,
127      _POSIX_Condition_variables_Enqueue_no_timeout
128    );
129  }
130
131  executing = _POSIX_Condition_variables_Acquire( the_cond, &queue_context );
132
133  if (
134    the_cond->mutex != POSIX_CONDITION_VARIABLES_NO_MUTEX
135      && the_cond->mutex != mutex
136  ) {
137    _POSIX_Condition_variables_Release( the_cond, &queue_context );
138    return EINVAL;
139  }
140
141  the_cond->mutex = mutex;
142
143  _Thread_queue_Context_set_thread_state(
144    &queue_context,
145    STATES_WAITING_FOR_CONDITION_VARIABLE
146  );
147  _Thread_queue_Enqueue(
148    &the_cond->Queue.Queue,
149    POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
150    executing,
151    &queue_context
152  );
153  error = _POSIX_Get_error_after_wait( executing );
154
155  /*
156   *  If the thread is interrupted, while in the thread queue, by
157   *  a POSIX signal, then pthread_cond_wait returns spuriously,
158   *  according to the POSIX standard. It means that pthread_cond_wait
159   *  returns a success status, except for the fact that it was not
160   *  woken up a pthread_cond_signal() or a pthread_cond_broadcast().
161   */
162
163  if ( error == EINTR ) {
164    error = 0;
165  }
166
167  /*
168   *  When we get here the dispatch disable level is 0.
169   */
170
171  if ( error != EPERM ) {
172    int mutex_error;
173
174    mutex_error = pthread_mutex_lock( mutex );
175    if ( mutex_error != 0 ) {
176      _Assert( mutex_error == EINVAL );
177      error = EINVAL;
178    }
179  }
180
181  return error;
182}
Note: See TracBrowser for help on using the repository browser.