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

5
Last change on this file since f23d470 was f23d470, checked in by Gedare Bloom <gedare@…>, on 06/09/16 at 15:33:15

cpukit: Add and use Watchdog_Discipline.

Clock disciplines may be WATCHDOG_RELATIVE, WATCHDOG_ABSOLUTE,
or WATCHDOG_NO_TIMEOUT. A discipline of WATCHDOG_RELATIVE with
a timeout of WATCHDOG_NO_TIMEOUT is equivalent to a discipline
of WATCHDOG_NO_TIMEOUT.

updates #2732

  • Property mode set to 100644
File size: 3.5 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_Context_set_timeout( &queue_context, timeout );
72    _Thread_queue_Context_set_discipline( &queue_context, WATCHDOG_RELATIVE );
73    _Thread_queue_Enqueue_critical(
74      &the_cond->Wait_queue.Queue,
75      POSIX_CONDITION_VARIABLES_TQ_OPERATIONS,
76      executing,
77      STATES_WAITING_FOR_CONDITION_VARIABLE,
78      &queue_context
79    );
80  } else {
81    _POSIX_Condition_variables_Release( the_cond, &queue_context );
82    executing->Wait.return_code = STATUS_TIMEOUT;
83  }
84
85  mutex_error = pthread_mutex_unlock( mutex );
86  if ( mutex_error != 0 ) {
87    /*
88     *  Historically, we ignored the unlock status since the behavior
89     *  is undefined by POSIX. But GNU/Linux returns EPERM in this
90     *  case, so we follow their lead.
91     */
92    _Assert( mutex_error == EINVAL || mutex_error == EPERM );
93    _Thread_queue_Extract( executing );
94    _Thread_Dispatch_enable( cpu_self );
95    return EPERM;
96  }
97
98  /*
99   *  Switch ourself out because we blocked as a result of the
100   *  _Thread_queue_Enqueue_critical().
101   */
102
103  _Thread_Dispatch_enable( cpu_self );
104
105  error = _POSIX_Get_error_after_wait( executing );
106
107  /*
108   *  If the thread is interrupted, while in the thread queue, by
109   *  a POSIX signal, then pthread_cond_wait returns spuriously,
110   *  according to the POSIX standard. It means that pthread_cond_wait
111   *  returns a success status, except for the fact that it was not
112   *  woken up a pthread_cond_signal() or a pthread_cond_broadcast().
113   */
114
115  if ( error == EINTR ) {
116    error = 0;
117  }
118
119  /*
120   *  When we get here the dispatch disable level is 0.
121   */
122
123  mutex_error = pthread_mutex_lock( mutex );
124  if ( mutex_error != 0 ) {
125    _Assert( mutex_error == EINVAL );
126    return EINVAL;
127  }
128
129  return error;
130}
Note: See TracBrowser for help on using the repository browser.