source: rtems/cpukit/posix/src/mutex.c @ a0b94685

4.104.114.84.95
Last change on this file since a0b94685 was a0b94685, checked in by Joel Sherrill <joel.sherrill@…>, on 05/14/99 at 14:43:53

Removed check for initialized ID at request of Rosimildo DaSilva?
<rdasilva@…> who encountered random failures in his
port of omniORB2.

  • Property mode set to 100644
File size: 16.7 KB
Line 
1/*
2 *  $Id$
3 */
4
5#include <assert.h>
6#include <errno.h>
7#include <pthread.h>
8
9#include <rtems/system.h>
10#include <rtems/score/coremutex.h>
11#include <rtems/score/watchdog.h>
12#if defined(RTEMS_MULTIPROCESSING)
13#include <rtems/score/mpci.h>
14#endif
15#include <rtems/posix/mutex.h>
16#include <rtems/posix/priority.h>
17#include <rtems/posix/time.h>
18
19/*
20 *  TEMPORARY
21 */
22
23#if defined(RTEMS_MULTIPROCESSING)
24void _POSIX_Mutex_MP_Send_process_packet (
25  POSIX_Mutex_MP_Remote_operations  operation,
26  Objects_Id                        mutex_id,
27  Objects_Name                      name,
28  Objects_Id                        proxy_id
29)
30{
31  (void) POSIX_MP_NOT_IMPLEMENTED();
32}
33
34void _POSIX_Mutex_MP_Send_object_was_deleted (
35  Thread_Control *the_proxy
36)
37{
38  (void) POSIX_MP_NOT_IMPLEMENTED();
39}
40
41int _POSIX_Mutex_MP_Send_request_packet (
42  POSIX_Mutex_MP_Remote_operations  operation,
43  Objects_Id                        mutex_id,
44  boolean                           wait,  /* XXX options */
45  Watchdog_Interval                 timeout
46)
47{
48  return POSIX_MP_NOT_IMPLEMENTED();
49}
50
51void POSIX_Threads_mutex_MP_support(
52  Thread_Control *the_thread,
53  Objects_Id      id
54)
55{
56  (void) POSIX_MP_NOT_IMPLEMENTED();   /* XXX: should never get here */
57}
58#endif
59
60/*
61 *  END OF TEMPORARY
62 */
63
64/*PAGE
65 * 
66 *  The default mutex attributes structure.
67 */
68
69const pthread_mutexattr_t _POSIX_Mutex_Default_attributes = {
70  TRUE,                                    /* is_initialized */
71  PTHREAD_PROCESS_PRIVATE,                 /* process_shared */
72  POSIX_SCHEDULER_MAXIMUM_PRIORITY,        /* prio_ceiling   */
73  PTHREAD_PRIO_NONE,                       /* protocol       */
74  FALSE                                    /* recursive      */
75};
76
77/*PAGE
78 *
79 *  _POSIX_Mutex_From_core_mutex_status
80 */
81
82int _POSIX_Mutex_From_core_mutex_status(
83  CORE_mutex_Status  status
84)
85{
86  switch ( status ) {
87    case CORE_MUTEX_STATUS_SUCCESSFUL:
88      return 0;
89    case CORE_MUTEX_STATUS_UNSATISFIED_NOWAIT:
90      return EBUSY;
91    case CORE_MUTEX_STATUS_NESTING_NOT_ALLOWED:
92      return EDEADLK;
93    case CORE_MUTEX_STATUS_NOT_OWNER_OF_RESOURCE:
94      return EPERM;
95    case CORE_MUTEX_WAS_DELETED:
96      return EINVAL;
97    case CORE_MUTEX_TIMEOUT:
98      return EAGAIN;
99    case CORE_MUTEX_STATUS_CEILING_VIOLATED:
100      return EINVAL;
101    default:
102      break;
103  }
104  assert( 0 );
105  return 0;
106}
107
108/*PAGE
109 *
110 *  _POSIX_Mutex_Manager_initialization
111 *
112 *  This routine initializes all mutex manager related data structures.
113 *
114 *  Input parameters:
115 *    maximum_mutexes - maximum configured mutexes
116 *
117 *  Output parameters:  NONE
118 */
119 
120void _POSIX_Mutex_Manager_initialization(
121  unsigned32 maximum_mutexes
122)
123{
124  _Objects_Initialize_information(
125    &_POSIX_Mutex_Information,
126    OBJECTS_POSIX_MUTEXES,
127    TRUE,
128    maximum_mutexes,
129    sizeof( POSIX_Mutex_Control ),
130    FALSE,
131    0,
132    FALSE
133  );
134}
135
136/*PAGE
137 *
138 *  11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81
139 */
140
141int pthread_mutexattr_init(
142  pthread_mutexattr_t *attr
143)
144{
145  if ( !attr )
146    return EINVAL;
147
148  *attr = _POSIX_Mutex_Default_attributes;
149  return 0;
150}
151
152/*PAGE
153 *
154 *  11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81
155 */
156
157int pthread_mutexattr_destroy(
158  pthread_mutexattr_t *attr
159)
160{
161  if ( !attr || !attr->is_initialized )
162    return EINVAL;
163
164  attr->is_initialized = FALSE;
165  return 0;
166}
167
168/*PAGE
169 *
170 *  11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81
171 */
172
173int pthread_mutexattr_getpshared(
174  const pthread_mutexattr_t *attr,
175  int                       *pshared
176)
177{
178  if ( !attr || !attr->is_initialized || !pshared )
179    return EINVAL;
180
181  *pshared = attr->process_shared;
182  return 0;
183}
184
185/*PAGE
186 *
187 *  11.3.1 Mutex Initialization Attributes, P1003.1c/Draft 10, p. 81
188 */
189
190int pthread_mutexattr_setpshared(
191  pthread_mutexattr_t *attr,
192  int                  pshared
193)
194{
195  if ( !attr || !attr->is_initialized )
196    return EINVAL;
197
198  switch ( pshared ) {
199    case PTHREAD_PROCESS_SHARED:
200    case PTHREAD_PROCESS_PRIVATE:
201      attr->process_shared = pshared;
202      return 0;
203
204    default:
205      return EINVAL;
206  }
207}
208
209/*PAGE
210 *
211 *  11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87
212 *
213 *  NOTE:  XXX Could be optimized so all the attribute error checking
214 *             is not performed when attr is NULL.
215 */
216
217int pthread_mutex_init(
218  pthread_mutex_t           *mutex,
219  const pthread_mutexattr_t *attr
220)
221{
222  POSIX_Mutex_Control          *the_mutex;
223  CORE_mutex_Attributes        *the_mutex_attr;
224  const pthread_mutexattr_t    *the_attr;
225  CORE_mutex_Disciplines        the_discipline;
226  register POSIX_Mutex_Control *mutex_in_use;
227  Objects_Locations             location;
228
229  if ( attr ) the_attr = attr;
230  else        the_attr = &_POSIX_Mutex_Default_attributes;
231
232  /* Check for NULL mutex */
233
234  if ( !mutex )
235    return EINVAL;
236
237  /*
238   *  This code should eventually be removed. 
239   *
240   *  Although the POSIX specification says:
241   *
242   *  "Attempting to initialize an already initialized mutex results
243   *  in undefined behavior."
244   *
245   *  Trying to keep the caller from doing the create when *mutex
246   *  is actually a valid ID causes grief.  All it takes is the wrong
247   *  value in an uninitialized variable to make this fail.  As best
248   *  I can tell, RTEMS was the only pthread implementation to choose
249   *  this option for "undefined behavior" and doing so has created
250   *  portability problems.  In particular, Rosimildo DaSilva
251   *  <rdasilva@connecttel.com> saw seemingly random failures in the
252   *  RTEMS port of omniORB2 when this code was enabled.
253   *
254   *  Joel Sherrill <joel@OARcorp.com>     14 May 1999
255   */
256
257 
258#if 0
259  /* avoid infinite recursion on call to this routine in _POSIX_Mutex_Get */
260
261  if ( *mutex != PTHREAD_MUTEX_INITIALIZER ) {
262
263    /* EBUSY if *mutex is a valid id */
264
265    mutex_in_use = _POSIX_Mutex_Get( mutex, &location );
266    switch ( location ) {
267      case OBJECTS_REMOTE:
268      case OBJECTS_ERROR:
269        break;
270      case OBJECTS_LOCAL:
271        _Thread_Enable_dispatch();
272        return EBUSY;
273    }
274  }
275#endif
276 
277  if ( !the_attr->is_initialized )
278    return EINVAL;
279
280  /*
281   *  XXX: Be careful about attributes when global!!!
282   */
283
284  assert( the_attr->process_shared == PTHREAD_PROCESS_PRIVATE );
285
286#if defined(RTEMS_MULTIPROCESSING)
287  if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED )
288    return POSIX_MP_NOT_IMPLEMENTED();
289#endif
290 
291  /*
292   *  Determine the discipline of the mutex
293   */
294 
295  switch ( the_attr->protocol ) {
296    case PTHREAD_PRIO_NONE:
297      the_discipline = CORE_MUTEX_DISCIPLINES_FIFO;
298      break;
299    case PTHREAD_PRIO_INHERIT:
300      the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_INHERIT;
301      break;
302    case PTHREAD_PRIO_PROTECT:
303      the_discipline = CORE_MUTEX_DISCIPLINES_PRIORITY_CEILING;
304      break;
305    default:
306      return EINVAL;
307  }
308
309  if ( !_POSIX_Priority_Is_valid( the_attr->prio_ceiling ) )
310    return EINVAL;
311
312  _Thread_Disable_dispatch();
313
314  the_mutex = _POSIX_Mutex_Allocate();
315 
316  if ( !the_mutex ) {
317    _Thread_Enable_dispatch();
318    return EAGAIN;
319  }
320
321#if defined(RTEMS_MULTIPROCESSING)
322  if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED &&
323       !( _Objects_MP_Allocate_and_open( &_POSIX_Mutex_Information, 0,
324                            the_mutex->Object.id, FALSE ) ) ) {
325    _POSIX_Mutex_Free( the_mutex );
326    _Thread_Enable_dispatch();
327    return EAGAIN;
328  }
329#endif
330
331  the_mutex->process_shared = the_attr->process_shared;
332
333  the_mutex_attr = &the_mutex->Mutex.Attributes;
334
335  the_mutex_attr->allow_nesting = the_attr->recursive;
336  the_mutex_attr->priority_ceiling =
337    _POSIX_Priority_To_core( the_attr->prio_ceiling );
338  the_mutex_attr->discipline = the_discipline;
339
340  /*
341   *  Must be initialized to unlocked.
342   */
343
344  _CORE_mutex_Initialize(
345    &the_mutex->Mutex,
346    OBJECTS_POSIX_MUTEXES,
347    the_mutex_attr,
348    CORE_MUTEX_UNLOCKED,
349    NULL                      /* proxy_extract_callout */
350  );
351
352  _Objects_Open( &_POSIX_Mutex_Information, &the_mutex->Object, 0 );
353
354  *mutex = the_mutex->Object.id;
355
356#if defined(RTEMS_MULTIPROCESSING)
357  if ( the_attr->process_shared == PTHREAD_PROCESS_SHARED )
358    _POSIX_Mutex_MP_Send_process_packet(
359      POSIX_MUTEX_MP_ANNOUNCE_CREATE,
360      the_mutex->Object.id,
361      0,                         /* Name not used */
362      0                          /* Not used */
363    );
364#endif
365
366  _Thread_Enable_dispatch();
367  return 0;
368}
369
370/*PAGE
371 *
372 *  11.3.2 Initializing and Destroying a Mutex, P1003.1c/Draft 10, p. 87
373 */
374
375int pthread_mutex_destroy(
376  pthread_mutex_t           *mutex
377)
378{
379  register POSIX_Mutex_Control *the_mutex;
380  Objects_Locations             location;
381 
382  the_mutex = _POSIX_Mutex_Get( mutex, &location );
383  switch ( location ) {
384    case OBJECTS_REMOTE:
385#if defined(RTEMS_MULTIPROCESSING)
386      _Thread_Dispatch();
387      return POSIX_MP_NOT_IMPLEMENTED();
388      return EINVAL;
389#endif
390    case OBJECTS_ERROR:
391      return EINVAL;
392    case OBJECTS_LOCAL:
393       /*
394        * XXX: There is an error for the mutex being locked
395        *  or being in use by a condition variable.
396        */
397
398      if ( _CORE_mutex_Is_locked( &the_mutex->Mutex ) ) {
399        _Thread_Enable_dispatch();
400        return EBUSY;
401      }
402 
403      _Objects_Close( &_POSIX_Mutex_Information, &the_mutex->Object );
404 
405      _CORE_mutex_Flush(
406        &the_mutex->Mutex,
407#if defined(RTEMS_MULTIPROCESSING)
408        _POSIX_Mutex_MP_Send_object_was_deleted,
409#else
410        NULL,
411#endif
412        EINVAL
413      );
414 
415      _POSIX_Mutex_Free( the_mutex );
416 
417#if defined(RTEMS_MULTIPROCESSING)
418      if ( the_mutex->process_shared == PTHREAD_PROCESS_SHARED ) {
419 
420        _Objects_MP_Close( &_POSIX_Mutex_Information, the_mutex->Object.id );
421 
422        _POSIX_Mutex_MP_Send_process_packet(
423          POSIX_MUTEX_MP_ANNOUNCE_DELETE,
424          the_mutex->Object.id,
425          0,                         /* Not used */
426          0                          /* Not used */
427        );
428      }
429#endif
430      _Thread_Enable_dispatch();
431      return 0;
432  }
433  return POSIX_BOTTOM_REACHED();
434}
435
436/*PAGE
437 *
438 *  _POSIX_Mutex_Lock_support
439 *
440 *  A support routine which implements guts of the blocking, non-blocking, and
441 *  timed wait version of mutex lock.
442 */
443
444int _POSIX_Mutex_Lock_support(
445  pthread_mutex_t           *mutex,
446  boolean                    blocking,
447  Watchdog_Interval          timeout
448)
449{
450  register POSIX_Mutex_Control *the_mutex;
451  Objects_Locations             location;
452 
453  the_mutex = _POSIX_Mutex_Get( mutex, &location );
454  switch ( location ) {
455    case OBJECTS_REMOTE:
456#if defined(RTEMS_MULTIPROCESSING)
457      return _POSIX_Mutex_MP_Send_request_packet(
458          POSIX_MUTEX_MP_OBTAIN_REQUEST,
459          *mutex,
460          0,   /* must define the option set */
461          WATCHDOG_NO_TIMEOUT
462      );
463#endif
464    case OBJECTS_ERROR:
465      return EINVAL;
466    case OBJECTS_LOCAL:
467      _CORE_mutex_Seize(
468        &the_mutex->Mutex,
469        the_mutex->Object.id,
470        blocking,
471        timeout
472      );
473      _Thread_Enable_dispatch();
474      return _POSIX_Mutex_From_core_mutex_status(
475        (CORE_mutex_Status) _Thread_Executing->Wait.return_code
476      );
477  }
478  return POSIX_BOTTOM_REACHED();
479}
480
481/*PAGE
482 *
483 *  11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93
484 *       
485 *  NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29
486 */
487
488int pthread_mutex_lock(
489  pthread_mutex_t           *mutex
490)
491{
492  return _POSIX_Mutex_Lock_support( mutex, TRUE, THREAD_QUEUE_WAIT_FOREVER );
493}
494
495/*PAGE
496 *
497 *  11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93
498 *       
499 *  NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29
500 */
501
502int pthread_mutex_trylock(
503  pthread_mutex_t           *mutex
504)
505{
506  return _POSIX_Mutex_Lock_support( mutex, FALSE, THREAD_QUEUE_WAIT_FOREVER );
507}
508
509/*PAGE
510 *
511 *  11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93
512 *       
513 *  NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29
514 */
515
516int pthread_mutex_unlock(
517  pthread_mutex_t           *mutex
518)
519{
520  register POSIX_Mutex_Control *the_mutex;
521  Objects_Locations             location;
522  CORE_mutex_Status             status;
523 
524  the_mutex = _POSIX_Mutex_Get( mutex, &location );
525  switch ( location ) {
526    case OBJECTS_REMOTE:
527#if defined(RTEMS_MULTIPROCESSING)
528      return _POSIX_Mutex_MP_Send_request_packet(
529          POSIX_MUTEX_MP_RELEASE_REQUEST,
530          *mutex,
531          0,                    /* Not used */
532          MPCI_DEFAULT_TIMEOUT
533      );
534#endif
535    case OBJECTS_ERROR:
536      return EINVAL;
537    case OBJECTS_LOCAL:
538      status = _CORE_mutex_Surrender(
539        &the_mutex->Mutex,
540        the_mutex->Object.id,
541#if defined(RTEMS_MULTIPROCESSING)
542        POSIX_Threads_mutex_MP_support
543#else
544        NULL
545#endif
546      );
547      _Thread_Enable_dispatch();
548      return _POSIX_Mutex_From_core_mutex_status( status );
549      break;
550  }
551  return POSIX_BOTTOM_REACHED();
552}
553
554/*PAGE
555 *
556 *  11.3.3 Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93
557 *       
558 *  NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29
559 */
560
561int pthread_mutex_timedlock(
562  pthread_mutex_t       *mutex,
563  const struct timespec *timeout
564)
565{
566  return _POSIX_Mutex_Lock_support(
567    mutex,
568    TRUE,
569    _POSIX_Timespec_to_interval( timeout )
570  );
571}
572
573/*PAGE
574 *
575 *  13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128
576 */
577 
578int pthread_mutexattr_setprotocol(
579  pthread_mutexattr_t   *attr,
580  int                    protocol
581)
582{
583  if ( !attr || !attr->is_initialized )
584    return EINVAL;
585
586  switch ( protocol ) {
587    case PTHREAD_PRIO_NONE:
588    case PTHREAD_PRIO_INHERIT:
589    case PTHREAD_PRIO_PROTECT:
590      attr->protocol = protocol;
591      return 0;
592 
593    default:
594      return EINVAL;
595  }
596}
597
598/*PAGE
599 *
600 *  13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128
601 */
602 
603int pthread_mutexattr_getprotocol(
604  const pthread_mutexattr_t   *attr,
605  int                         *protocol
606)
607{
608  if ( !attr || !attr->is_initialized || !protocol )
609    return EINVAL;
610
611  *protocol = attr->protocol;
612  return 0;
613}
614
615/*PAGE
616 *
617 *  13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128
618 */
619 
620int pthread_mutexattr_setprioceiling(
621  pthread_mutexattr_t   *attr,
622  int                    prioceiling
623)
624{
625  if ( !attr || !attr->is_initialized )
626    return EINVAL;
627
628  if ( !_POSIX_Priority_Is_valid( prioceiling ) )
629    return EINVAL;
630
631  attr->prio_ceiling = prioceiling;
632  return 0;
633}
634
635/*PAGE
636 *
637 *  13.6.1 Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128
638 */
639 
640int pthread_mutexattr_getprioceiling(
641  const pthread_mutexattr_t   *attr,
642  int                         *prioceiling
643)
644{
645  if ( !attr || !attr->is_initialized || !prioceiling )
646    return EINVAL;
647
648  *prioceiling = attr->prio_ceiling;
649  return 0;
650}
651
652/*PAGE
653 *
654 *  13.6.2 Change the Priority Ceiling of a Mutex, P1003.1c/Draft 10, p. 131
655 */
656
657int pthread_mutex_setprioceiling(
658  pthread_mutex_t   *mutex,
659  int                prioceiling,
660  int               *old_ceiling
661)
662{
663  register POSIX_Mutex_Control *the_mutex;
664  Objects_Locations             location;
665  Priority_Control              the_priority;
666  int                           status;
667
668  if ( !old_ceiling )
669    return EINVAL;
670
671  if ( !_POSIX_Priority_Is_valid( prioceiling ) )
672    return EINVAL;
673
674  the_priority = _POSIX_Priority_To_core( prioceiling );
675
676  /*
677   *  Must acquire the mutex before we can change it's ceiling
678   */
679
680  status = pthread_mutex_lock( mutex );
681  if ( status )
682    return status;
683
684  the_mutex = _POSIX_Mutex_Get( mutex, &location );
685  switch ( location ) {
686    case OBJECTS_REMOTE:
687#if defined(RTEMS_MULTIPROCESSING)
688      /*  XXX It feels questionable to set the ceiling on a remote mutex. */
689      return EINVAL;
690#endif
691    case OBJECTS_ERROR:
692      return EINVAL;        /* impossible to get here */
693    case OBJECTS_LOCAL:
694      *old_ceiling = _POSIX_Priority_From_core(
695        the_mutex->Mutex.Attributes.priority_ceiling
696      );
697      the_mutex->Mutex.Attributes.priority_ceiling = the_priority;
698      _CORE_mutex_Surrender(
699        &the_mutex->Mutex,
700        the_mutex->Object.id,
701#if defined(RTEMS_MULTIPROCESSING)
702        POSIX_Threads_mutex_MP_support
703#else
704        NULL
705#endif
706      );
707      _Thread_Enable_dispatch();
708      return 0;
709  }
710  return POSIX_BOTTOM_REACHED();
711}
712 
713/*PAGE
714 *
715 *  13.6.2 Change the Priority Ceiling of a Mutex, P1003.1c/Draft 10, p. 131
716 */
717
718int pthread_mutex_getprioceiling(
719  pthread_mutex_t   *mutex,
720  int               *prioceiling
721)
722{
723  register POSIX_Mutex_Control *the_mutex;
724  Objects_Locations             location;
725
726  if ( !prioceiling )
727    return EINVAL;
728
729  the_mutex = _POSIX_Mutex_Get( mutex, &location );
730  switch ( location ) {
731    case OBJECTS_REMOTE:
732#if defined(RTEMS_MULTIPROCESSING)
733      return POSIX_MP_NOT_IMPLEMENTED();   /* XXX feels questionable */
734#endif
735    case OBJECTS_ERROR:
736      return EINVAL;
737    case OBJECTS_LOCAL:
738      *prioceiling = _POSIX_Priority_From_core(
739        the_mutex->Mutex.Attributes.priority_ceiling
740      );
741      _Thread_Enable_dispatch();
742      return 0;
743  }
744  return POSIX_BOTTOM_REACHED();
745}
Note: See TracBrowser for help on using the repository browser.