source: rtems/cpukit/posix/src/cond.c @ 9093c3c

4.104.114.84.95
Last change on this file since 9093c3c was 9093c3c, checked in by Joel Sherrill <joel.sherrill@…>, on 09/17/96 at 21:29:51

Corrected implementation of timed wait on condition variables. First
the timeout is given as a wall-time not an interval as was previously
implemented. Second, the interpretation of ETIMEDOUT behavior was
incorrect as all possible error cases needed to be checked before
this error was returned. This caused problems when the wall-time
specified was in the past.

  • Property mode set to 100644
File size: 11.1 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <pthread.h>
6#include <errno.h>
7
8#include <rtems/system.h>
9#include <rtems/score/object.h>
10#include <rtems/score/states.h>
11#include <rtems/score/watchdog.h>
12#include <rtems/posix/cond.h>
13#include <rtems/posix/time.h>
14#include <rtems/posix/mutex.h>
15
16/*
17 *  TEMPORARY
18 */
19
20void _POSIX_Condition_variables_MP_Send_process_packet (
21  POSIX_Condition_variables_MP_Remote_operations  operation,
22  Objects_Id                        condition_variables_id,
23  Objects_Name                      name,
24  Objects_Id                        proxy_id
25)
26{
27  (void) POSIX_MP_NOT_IMPLEMENTED();
28}
29
30void _POSIX_Condition_variables_MP_Send_extract_proxy(
31  Thread_Control *the_thread
32)
33{
34  (void) POSIX_MP_NOT_IMPLEMENTED();
35}
36
37/*
38 *  END OF TEMPORARY
39 */
40
41/*PAGE
42 *
43 *  The default condition variable attributes structure.
44 */
45 
46const pthread_condattr_t _POSIX_Condition_variables_Default_attributes = {
47  TRUE,                      /* is_initialized */
48  PTHREAD_PROCESS_PRIVATE    /* process_shared */
49};
50 
51/*PAGE
52 *
53 *  _POSIX_Condition_variables_Manager_initialization
54 *
55 *  This routine initializes all condition variable manager related data
56 *  structures.
57 *
58 *  Input parameters:
59 *    maximum_condition_variables - maximum configured condition_variables
60 *
61 *  Output parameters:  NONE
62 */
63 
64void _POSIX_Condition_variables_Manager_initialization(
65  unsigned32 maximum_condition_variables
66)
67{
68  _Objects_Initialize_information(
69    &_POSIX_Condition_variables_Information,
70    OBJECTS_POSIX_CONDITION_VARIABLES,
71    TRUE,
72    maximum_condition_variables,
73    sizeof( POSIX_Condition_variables_Control ),
74    FALSE,
75    0,
76    FALSE
77  );
78}
79
80/*PAGE
81 *
82 *  11.4.1 Condition Variable Initialization Attributes,
83 *            P1003.1c/Draft 10, p. 96
84 */
85 
86int pthread_condattr_init(
87  pthread_condattr_t *attr
88)
89{
90  if ( !attr )
91    return EINVAL;
92
93  *attr = _POSIX_Condition_variables_Default_attributes;
94  return 0;
95}
96 
97/*PAGE
98 *
99 *  11.4.1 Condition Variable Initialization Attributes,
100 *            P1003.1c/Draft 10, p. 96
101 */
102 
103int pthread_condattr_destroy(
104  pthread_condattr_t *attr
105)
106{
107  if ( !attr || attr->is_initialized == FALSE )
108    return EINVAL;
109
110  attr->is_initialized = FALSE;
111  return 0;
112}
113 
114/*PAGE
115 *
116 *  11.4.1 Condition Variable Initialization Attributes,
117 *            P1003.1c/Draft 10, p. 96
118 */
119 
120int pthread_condattr_getpshared(
121  const pthread_condattr_t *attr,
122  int                      *pshared
123)
124{
125  if ( !attr )
126    return EINVAL;
127
128  *pshared = attr->process_shared;
129  return 0;
130}
131 
132/*PAGE
133 *
134 *  11.4.1 Condition Variable Initialization Attributes,
135 *            P1003.1c/Draft 10, p. 96
136 */
137 
138int pthread_condattr_setpshared(
139  pthread_condattr_t *attr,
140  int                 pshared
141)
142{
143  if ( !attr )
144    return EINVAL;
145
146  switch ( pshared ) {
147    case PTHREAD_PROCESS_SHARED:
148    case PTHREAD_PROCESS_PRIVATE:
149      attr->process_shared = pshared;
150      return 0;
151
152    default:
153      return EINVAL;
154  }
155}
156 
157/*PAGE
158 *
159 *  11.4.2 Initializing and Destroying a Condition Variable,
160 *         P1003.1c/Draft 10, p. 87
161 */
162 
163int pthread_cond_init(
164  pthread_cond_t           *cond,
165  const pthread_condattr_t *attr
166)
167{
168  POSIX_Condition_variables_Control   *the_cond;
169  const pthread_condattr_t            *the_attr;
170 
171  if ( attr ) the_attr = attr;
172  else        the_attr = &_POSIX_Condition_variables_Default_attributes;
173 
174  /*
175   *  XXX: Be careful about attributes when global!!!
176   */
177 
178  if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED )
179    return POSIX_MP_NOT_IMPLEMENTED();
180 
181  if ( !the_attr->is_initialized )
182    return EINVAL;
183 
184  _Thread_Disable_dispatch();
185 
186  the_cond = _POSIX_Condition_variables_Allocate();
187 
188  if ( !the_cond ) {
189    _Thread_Enable_dispatch();
190    return ENOMEM;
191  }
192 
193  if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED &&
194     !( _Objects_MP_Allocate_and_open( &_POSIX_Condition_variables_Information,
195                0, the_cond->Object.id, FALSE ) ) ) {
196    _POSIX_Condition_variables_Free( the_cond );
197    _Thread_Enable_dispatch();
198    return EAGAIN;
199  }
200 
201  the_cond->process_shared  = the_attr->process_shared;
202
203  the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX;
204
205/* XXX some more initialization might need to go here */
206  _Thread_queue_Initialize(
207    &the_cond->Wait_queue,
208    OBJECTS_POSIX_CONDITION_VARIABLES,
209    THREAD_QUEUE_DISCIPLINE_FIFO,
210    STATES_WAITING_FOR_CONDITION_VARIABLE,
211    _POSIX_Condition_variables_MP_Send_extract_proxy,
212    ETIMEDOUT
213  );
214
215  _Objects_Open(
216    &_POSIX_Condition_variables_Information,
217    &the_cond->Object,
218    0
219  );
220 
221  *cond = the_cond->Object.id;
222 
223  if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED )
224    _POSIX_Condition_variables_MP_Send_process_packet(
225      POSIX_CONDITION_VARIABLES_MP_ANNOUNCE_CREATE,
226      the_cond->Object.id,
227      0,                         /* Name not used */
228      0                          /* Not used */
229    );
230 
231  _Thread_Enable_dispatch();
232
233  return 0;
234}
235 
236/*PAGE
237 *
238 *  11.4.2 Initializing and Destroying a Condition Variable,
239 *         P1003.1c/Draft 10, p. 87
240 */
241 
242int pthread_cond_destroy(
243  pthread_cond_t           *cond
244)
245{
246  register POSIX_Condition_variables_Control *the_cond;
247  Objects_Locations                           location;
248 
249  the_cond = _POSIX_Condition_variables_Get( cond, &location );
250  switch ( location ) {
251    case OBJECTS_ERROR:
252      return EINVAL;
253    case OBJECTS_REMOTE:
254      _Thread_Dispatch();
255      return POSIX_MP_NOT_IMPLEMENTED();
256      return EINVAL;
257    case OBJECTS_LOCAL:
258 
259      if ( _Thread_queue_First( &the_cond->Wait_queue ) ) {
260        _Thread_Enable_dispatch();
261        return EBUSY;
262      }
263 
264      _Objects_Close(
265        &_POSIX_Condition_variables_Information,
266        &the_cond->Object
267      );
268 
269      _POSIX_Condition_variables_Free( the_cond );
270 
271      if ( the_cond->process_shared == PTHREAD_PROCESS_SHARED ) {
272 
273        _Objects_MP_Close(
274          &_POSIX_Condition_variables_Information,
275          the_cond->Object.id
276        );
277 
278        _POSIX_Condition_variables_MP_Send_process_packet(
279          POSIX_CONDITION_VARIABLES_MP_ANNOUNCE_DELETE,
280          the_cond->Object.id,
281          0,                         /* Not used */
282          0                          /* Not used */
283        );
284      }
285      _Thread_Enable_dispatch();
286      return 0;
287  }
288  return POSIX_BOTTOM_REACHED();
289}
290 
291/*PAGE
292 *
293 *  _POSIX_Condition_variables_Signal_support
294 *
295 *  A support routine which implements guts of the broadcast and single task
296 *  wake up version of the "signal" operation.
297 */
298 
299int _POSIX_Condition_variables_Signal_support(
300  pthread_cond_t            *cond,
301  boolean                    is_broadcast
302)
303{
304  register POSIX_Condition_variables_Control *the_cond;
305  Objects_Locations                           location;
306  Thread_Control                             *the_thread;
307 
308  the_cond = _POSIX_Condition_variables_Get( cond, &location );
309  switch ( location ) {
310    case OBJECTS_ERROR:
311      return EINVAL;
312    case OBJECTS_REMOTE:
313      _Thread_Dispatch();
314      return POSIX_MP_NOT_IMPLEMENTED();
315      return EINVAL;
316    case OBJECTS_LOCAL:
317 
318      do {
319        the_thread = _Thread_queue_Dequeue( &the_cond->Wait_queue );
320        if ( !the_thread )
321          the_cond->Mutex = POSIX_CONDITION_VARIABLES_NO_MUTEX;
322      } while ( is_broadcast && the_thread );
323
324      _Thread_Enable_dispatch();
325
326      return 0;
327  }
328  return POSIX_BOTTOM_REACHED();
329}
330
331/*PAGE
332 *
333 *  11.4.3 Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101
334 */
335 
336int pthread_cond_signal(
337  pthread_cond_t   *cond
338)
339{
340  return _POSIX_Condition_variables_Signal_support( cond, FALSE );
341}
342 
343/*PAGE
344 *
345 *  11.4.3 Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101
346 */
347 
348int pthread_cond_broadcast(
349  pthread_cond_t   *cond
350)
351{
352  return _POSIX_Condition_variables_Signal_support( cond, TRUE );
353}
354 
355/*PAGE
356 *
357 *  _POSIX_Condition_variables_Wait_support
358 *
359 *  A support routine which implements guts of the blocking, non-blocking, and
360 *  timed wait version of condition variable wait routines.
361 */
362 
363int _POSIX_Condition_variables_Wait_support(
364  pthread_cond_t            *cond,
365  pthread_mutex_t           *mutex,
366  Watchdog_Interval          timeout,
367  boolean                    already_timedout
368)
369{
370  register POSIX_Condition_variables_Control *the_cond;
371  Objects_Locations                           location;
372  int                                         status;
373  int                                         mutex_status;
374 
375  if ( !_POSIX_Mutex_Get( mutex, &location ) ) {
376     return EINVAL;
377  }
378
379  _Thread_Unnest_dispatch();
380
381  the_cond = _POSIX_Condition_variables_Get( cond, &location );
382  switch ( location ) {
383    case OBJECTS_ERROR:
384      return EINVAL;
385    case OBJECTS_REMOTE:
386      _Thread_Dispatch();
387      return POSIX_MP_NOT_IMPLEMENTED();
388      return EINVAL;
389    case OBJECTS_LOCAL:
390 
391      if ( the_cond->Mutex && ( the_cond->Mutex != *mutex ) ) {
392        _Thread_Enable_dispatch();
393        return EINVAL;
394      }
395 
396      (void) pthread_mutex_unlock( mutex );
397/* XXX ignore this for now  since behavior is undefined
398      if ( mutex_status ) {
399        _Thread_Enable_dispatch();
400        return EINVAL;
401      }
402*/
403
404      if ( !already_timedout ) {
405        the_cond->Mutex = *mutex;
406 
407        _Thread_queue_Enter_critical_section( &the_cond->Wait_queue );
408        _Thread_Executing->Wait.return_code = 0;
409        _Thread_Executing->Wait.queue       = &the_cond->Wait_queue;
410        _Thread_Executing->Wait.id          = *cond;
411
412        _Thread_queue_Enqueue( &the_cond->Wait_queue, timeout );
413
414        _Thread_Enable_dispatch();
415
416        /*
417         *  Switch ourself out because we blocked as a result of the
418         *  _Thread_queue_Enqueue.
419         */
420
421        status = _Thread_Executing->Wait.return_code;
422        if ( status && status != ETIMEDOUT )
423          return status;
424
425      }
426      else
427        status = ETIMEDOUT;
428
429      mutex_status = pthread_mutex_lock( mutex );
430      if ( mutex_status )
431        return EINVAL;
432   
433      return status;
434  }
435  return POSIX_BOTTOM_REACHED();
436}
437
438/*PAGE
439 *
440 *  11.4.4 Waiting on a Condition, P1003.1c/Draft 10, p. 105
441 */
442 
443int pthread_cond_wait(
444  pthread_cond_t     *cond,
445  pthread_mutex_t    *mutex
446)
447{
448  return _POSIX_Condition_variables_Wait_support(
449    cond,
450    mutex,
451    THREAD_QUEUE_WAIT_FOREVER,
452    FALSE
453  );
454}
455 
456/*PAGE
457 *
458 *  11.4.4 Waiting on a Condition, P1003.1c/Draft 10, p. 105
459 */
460 
461int pthread_cond_timedwait(
462  pthread_cond_t        *cond,
463  pthread_mutex_t       *mutex,
464  const struct timespec *abstime
465)
466{
467  Watchdog_Interval timeout;
468  struct timespec   current_time;
469  struct timespec   difference;
470  boolean           already_timedout = FALSE;
471
472  if ( !abstime )
473    return EINVAL;
474
475  /*
476   *  The abstime is a walltime.  We turn it into an interval.
477   */
478
479  (void) clock_gettime( CLOCK_REALTIME, &current_time );
480
481  /* XXX probably some error checking should go here */
482
483  _POSIX_Timespec_subtract( &current_time, abstime, &difference );
484
485  if ( ( difference.tv_sec < 0 ) || ( ( difference.tv_sec == 0 ) &&
486       ( difference.tv_nsec < 0 ) ) )
487    already_timedout = TRUE;   
488
489  timeout = _POSIX_Timespec_to_interval( &difference );
490
491  return _POSIX_Condition_variables_Wait_support(
492    cond,
493    mutex,
494    timeout,
495    already_timedout
496  );
497}
Note: See TracBrowser for help on using the repository browser.