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

5
Last change on this file since e0bb60b was e0bb60b, checked in by Sebastian Huber <sebastian.huber@…>, on 05/27/16 at 08:17:28

posix: Avoid use of internal mutex methods

Avoid use of internal mutex methods for condition variables.

  • Property mode set to 100644
File size: 3.4 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
30int _POSIX_Condition_variables_Wait_support(
31  pthread_cond_t            *cond,
32  pthread_mutex_t           *mutex,
33  Watchdog_Interval          timeout,
34  bool                       already_timedout
35)
36{
37  POSIX_Condition_variables_Control *the_cond;
38  Thread_queue_Context               queue_context;
39  int                                error;
40  int                                mutex_error;
41  Per_CPU_Control                   *cpu_self;
42  Thread_Control                    *executing;
43
44  if ( mutex == NULL ) {
45    return EINVAL;
46  }
47
48  the_cond = _POSIX_Condition_variables_Get( cond, &queue_context );
49
50  if ( the_cond == NULL ) {
51    return EINVAL;
52  }
53
54  _POSIX_Condition_variables_Acquire_critical( the_cond, &queue_context );
55
56  if (
57    the_cond->mutex != POSIX_CONDITION_VARIABLES_NO_MUTEX
58      && the_cond->mutex != *mutex
59  ) {
60    _POSIX_Condition_variables_Release( the_cond, &queue_context );
61    return EINVAL;
62  }
63
64  the_cond->mutex = *mutex;
65
66  cpu_self = _Thread_Dispatch_disable_critical( &queue_context.Lock_context );
67  executing = _Per_CPU_Get_executing( cpu_self );
68
69  if ( !already_timedout ) {
70    _Thread_queue_Context_set_expected_level( &queue_context, 2 );
71    _Thread_queue_Enqueue_critical(
72      &the_cond->Wait_queue.Queue,
73      POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
74      executing,
75      STATES_WAITING_FOR_CONDITION_VARIABLE,
76      timeout,
77      &queue_context
78    );
79  } else {
80    _POSIX_Condition_variables_Release( the_cond, &queue_context );
81    executing->Wait.return_code = STATUS_TIMEOUT;
82  }
83
84  mutex_error = pthread_mutex_unlock( mutex );
85  if ( mutex_error != 0 ) {
86    /*
87     *  Historically, we ignored the unlock status since the behavior
88     *  is undefined by POSIX. But GNU/Linux returns EPERM in this
89     *  case, so we follow their lead.
90     */
91    _Assert( mutex_error == EINVAL || mutex_error == EPERM );
92    _Thread_queue_Extract( executing );
93    _Thread_Dispatch_enable( cpu_self );
94    return EPERM;
95  }
96
97  /*
98   *  Switch ourself out because we blocked as a result of the
99   *  _Thread_queue_Enqueue_critical().
100   */
101
102  _Thread_Dispatch_enable( cpu_self );
103
104  error = _POSIX_Get_error_after_wait( executing );
105
106  /*
107   *  If the thread is interrupted, while in the thread queue, by
108   *  a POSIX signal, then pthread_cond_wait returns spuriously,
109   *  according to the POSIX standard. It means that pthread_cond_wait
110   *  returns a success status, except for the fact that it was not
111   *  woken up a pthread_cond_signal() or a pthread_cond_broadcast().
112   */
113
114  if ( error == EINTR ) {
115    error = 0;
116  }
117
118  /*
119   *  When we get here the dispatch disable level is 0.
120   */
121
122  mutex_error = pthread_mutex_lock( mutex );
123  if ( mutex_error != 0 ) {
124    _Assert( mutex_error == EINVAL );
125    return EINVAL;
126  }
127
128  return error;
129}
Note: See TracBrowser for help on using the repository browser.