]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/compat/posix/v2_0/src/mutex.cxx
Initial revision
[karo-tx-redboot.git] / packages / compat / posix / v2_0 / src / mutex.cxx
1 //==========================================================================
2 //
3 //      pthread.cxx
4 //
5 //      POSIX pthreads implementation
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):           nickg
44 // Contributors:        nickg, jlarmour, Wade Jensen
45 // Date:                2000-03-27
46 // Purpose:             POSIX pthread implementation
47 // Description:         This file contains the implementation of the POSIX pthread
48 //                      functions.
49 //              
50 //              
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <pkgconf/posix.h>
57
58 #include <cyg/infra/cyg_trac.h>        // tracing macros
59 #include <cyg/infra/cyg_ass.h>         // assertion macros
60
61 #include "pprivate.h"                  // POSIX private header
62
63 #include <cyg/kernel/thread.hxx>       // thread definitions
64 #include <cyg/kernel/mutex.hxx>        // mutex definitions
65 #include <cyg/kernel/clock.hxx>        // clock definitions
66 #include <cyg/kernel/sched.hxx>        // scheduler primitives
67 #include <pthread.h>
68
69 #include <cyg/kernel/thread.inl>       // thread inlines
70 #include <cyg/kernel/sched.inl>        // scheduler inlines
71
72 //-----------------------------------------------------------------------------
73 // new operator to allow us to construct mutex objects
74
75 inline void *operator new(size_t size,  cyg_uint8 *ptr) { return (void *)ptr; };
76
77 //=============================================================================
78 // Mutexes
79
80 //-----------------------------------------------------------------------------
81 // Mutex attributes manipulation functions
82
83 //-----------------------------------------------------------------------------
84 // Initialize attribute object
85
86 externC int pthread_mutexattr_init ( pthread_mutexattr_t *attr)
87 {
88     PTHREAD_ENTRY();
89     
90     PTHREAD_CHECK(attr);
91
92     attr->protocol      = PTHREAD_PRIO_NONE;
93 #ifdef _POSIX_THREAD_PRIO_PROTECT    
94     attr->prioceiling   = 0;
95 #endif
96     
97     PTHREAD_RETURN(0);
98 }
99
100 //-----------------------------------------------------------------------------
101 // Destroy attribute object
102
103 externC int pthread_mutexattr_destroy ( pthread_mutexattr_t *attr)
104 {
105     PTHREAD_ENTRY();
106     
107     PTHREAD_CHECK(attr);
108
109     // Nothing to do here...
110     
111     PTHREAD_RETURN(0);
112 }
113
114 //-----------------------------------------------------------------------------
115 // Optional functions depending on priority inversion protection options.
116
117 #if defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
118
119 // Set priority inversion protection protocol
120 externC int pthread_mutexattr_setprotocol ( pthread_mutexattr_t *attr,
121                                             int protocol)
122 {
123     PTHREAD_ENTRY();
124     
125     PTHREAD_CHECK(attr);
126
127     switch( protocol )
128     {
129     case PTHREAD_PRIO_NONE:
130 #if defined(_POSIX_THREAD_PRIO_INHERIT)        
131     case PTHREAD_PRIO_INHERIT:
132 #endif
133 #if defined(_POSIX_THREAD_PRIO_PROTECT)
134     case PTHREAD_PRIO_PROTECT:
135 #endif        
136         attr->protocol = protocol;
137         PTHREAD_RETURN(0);
138
139     default:
140         PTHREAD_RETURN(EINVAL);
141     }
142     
143     PTHREAD_RETURN(0);
144 }
145
146 // Get priority inversion protection protocol
147 externC int pthread_mutexattr_getprotocol ( pthread_mutexattr_t *attr,
148                                             int *protocol)
149 {
150     PTHREAD_ENTRY();
151     
152     PTHREAD_CHECK(attr);
153
154     if( protocol != NULL )
155         *protocol = attr->protocol;
156     
157     PTHREAD_RETURN(0);
158 }
159
160 #if defined(_POSIX_THREAD_PRIO_PROTECT)
161
162 // Set priority for priority ceiling protocol
163 externC int pthread_mutexattr_setprioceiling ( pthread_mutexattr_t *attr,
164                                                int prioceiling)
165 {
166     PTHREAD_ENTRY();
167     
168     PTHREAD_CHECK(attr);
169
170     
171     attr->prioceiling = prioceiling;
172     
173     PTHREAD_RETURN(0);
174 }
175
176 // Get priority for priority ceiling protocol
177 externC int pthread_mutexattr_getprioceiling ( pthread_mutexattr_t *attr,
178                                                int *prioceiling)
179 {
180     PTHREAD_ENTRY();
181     
182     PTHREAD_CHECK(attr);
183
184     if( prioceiling != NULL )
185         *prioceiling = attr->prioceiling;
186     
187     PTHREAD_RETURN(0);
188 }
189
190 // Set priority ceiling of given mutex, returning old ceiling.
191 externC int pthread_mutex_setprioceiling( pthread_mutex_t *mutex,
192                                           int prioceiling,
193                                           int *old_ceiling)
194 {
195     PTHREAD_ENTRY();
196     
197     PTHREAD_CHECK(mutex);
198
199     pthread_mutex_lock( mutex );
200
201     Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
202
203     if( old_ceiling != NULL )
204         *old_ceiling = mx->get_ceiling();
205     
206     mx->set_ceiling( prioceiling );
207     
208     pthread_mutex_unlock( mutex );
209
210     PTHREAD_RETURN(0);
211 }
212
213 // Get priority ceiling of given mutex
214 externC int pthread_mutex_getprioceiling( pthread_mutex_t *mutex,
215                                           int *prioceiling)
216 {
217     PTHREAD_ENTRY();
218     
219     PTHREAD_CHECK(mutex);
220
221     Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
222
223     if( prioceiling != NULL )
224         *prioceiling = mx->get_ceiling();
225         
226     PTHREAD_RETURN(0);
227 }
228
229 #endif // defined(_POSIX_THREAD_PRIO_PROTECT)
230
231 #endif // defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
232
233 //-----------------------------------------------------------------------------
234 // Mutex functions
235
236 //-----------------------------------------------------------------------------
237 // Initialize mutex. If mutex_attr is NULL, use default attributes.
238
239 externC int pthread_mutex_init (pthread_mutex_t *mutex,
240                                 const pthread_mutexattr_t *mutex_attr)
241 {
242     PTHREAD_ENTRY();
243
244     PTHREAD_CHECK( mutex );
245     
246     pthread_mutexattr_t use_attr;
247
248     // Set up the attributes we are going to use
249     if( mutex_attr == NULL )
250         pthread_mutexattr_init( &use_attr );
251     else use_attr = *mutex_attr;
252
253     // Now translate the POSIX protocol identifier into the eCos one.
254     Cyg_Mutex::cyg_protcol protocol;
255     
256     switch( use_attr.protocol )
257     {
258 #if defined(_POSIX_THREAD_PRIO_PROTECT)
259     case PTHREAD_PRIO_PROTECT:
260         protocol = Cyg_Mutex::CEILING;
261         break;
262 #endif
263 #if defined(_POSIX_THREAD_PRIO_INHERIT)
264     case PTHREAD_PRIO_INHERIT:
265         protocol = Cyg_Mutex::INHERIT;
266         break;
267 #endif        
268     case PTHREAD_PRIO_NONE:
269         protocol = Cyg_Mutex::NONE;
270         break;
271
272     default:
273         PTHREAD_RETURN(EINVAL);
274     }
275
276     Cyg_Mutex *mx = new((cyg_uint8 *)mutex) Cyg_Mutex(  protocol );
277
278     mx = mx; // silence compiler warning
279 #if defined(_POSIX_THREAD_PRIO_PROTECT)
280     if ( protocol == Cyg_Mutex::CEILING )
281         mx->set_ceiling( use_attr.prioceiling );
282 #endif
283     
284     PTHREAD_RETURN(0);
285 }
286
287 //-----------------------------------------------------------------------------
288 // Destroy mutex.
289
290 externC int pthread_mutex_destroy (pthread_mutex_t *mutex)
291 {
292     PTHREAD_ENTRY();
293
294     int err = ENOERR;
295     
296     PTHREAD_CHECK( mutex );
297
298     Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
299     
300     if( mx->get_owner() != NULL )
301         err = EBUSY;
302     else mx->~Cyg_Mutex();
303     
304     PTHREAD_RETURN(err);
305 }
306
307 //-----------------------------------------------------------------------------
308 // Lock mutex, waiting for it if necessary.
309
310 externC int pthread_mutex_lock (pthread_mutex_t *mutex)
311 {
312     PTHREAD_ENTRY();
313
314     PTHREAD_CHECK( mutex );
315
316     Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
317
318     if( mx->get_owner() == Cyg_Thread::self() )
319         PTHREAD_RETURN(EDEADLK);
320     
321     // Loop here until we acquire the mutex. Even if we are kicked out
322     // of the wait by a signal or release we must retry.
323     while( !mx->lock() )
324         continue;
325     
326     PTHREAD_RETURN(0);
327 }
328
329 //-----------------------------------------------------------------------------
330 // Try to lock mutex.
331
332 externC int pthread_mutex_trylock (pthread_mutex_t *mutex)
333 {
334     PTHREAD_ENTRY();
335
336     PTHREAD_CHECK( mutex );
337     
338     Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
339
340     if( mx->get_owner() == Cyg_Thread::self() )
341         PTHREAD_RETURN(EDEADLK);
342     
343     if( mx->trylock() )
344         PTHREAD_RETURN(0);
345
346     PTHREAD_RETURN(EBUSY);
347 }
348
349
350 //-----------------------------------------------------------------------------
351 // Unlock mutex.
352
353 externC int pthread_mutex_unlock (pthread_mutex_t *mutex)
354 {
355     PTHREAD_ENTRY();
356
357     PTHREAD_CHECK( mutex );
358     
359     Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
360
361     mx->unlock();
362     
363     PTHREAD_RETURN(0);
364 }
365
366
367 //=============================================================================
368 // Condition Variables
369
370 //-----------------------------------------------------------------------------
371 // Attribute manipulation functions
372 // We do not actually support any attributes at present, so these do nothing.
373
374 //-----------------------------------------------------------------------------
375 // Initialize condition variable attributes
376
377 externC int pthread_condattr_init (pthread_condattr_t *attr)
378 {
379     PTHREAD_ENTRY();
380     
381     PTHREAD_CHECK(attr);
382
383     // There are no condition variable attributes at present
384     
385     PTHREAD_RETURN(0);
386 }
387
388 //-----------------------------------------------------------------------------
389 // Destroy condition variable attributes
390
391 externC int pthread_condattr_destroy (pthread_condattr_t *attr)
392 {
393     PTHREAD_ENTRY();
394     
395     PTHREAD_CHECK(attr);
396
397     // nothing to do here...
398     
399     PTHREAD_RETURN(0);
400 }
401
402 //-----------------------------------------------------------------------------
403 // Condition variable functions
404
405 //-----------------------------------------------------------------------------
406 // Initialize condition variable.
407
408 externC int pthread_cond_init (pthread_cond_t *cond,
409                                const pthread_condattr_t *attr)
410 {
411     PTHREAD_ENTRY();
412
413     PTHREAD_CHECK( cond );
414
415     Cyg_Condition_Variable *cv =
416         new((cyg_uint8 *)cond) Cyg_Condition_Variable();
417
418     cv = cv;
419     
420     PTHREAD_RETURN(0);
421 }
422
423 //-----------------------------------------------------------------------------
424 // Destroy condition variable.
425
426 externC int pthread_cond_destroy (pthread_cond_t *cond)
427 {
428     PTHREAD_ENTRY();
429
430     PTHREAD_CHECK( cond );
431
432     ((Cyg_Condition_Variable *)cond)->~Cyg_Condition_Variable();
433     
434     PTHREAD_RETURN(0);
435 }
436
437 //-----------------------------------------------------------------------------
438 // Wake up one thread waiting for condition variable
439
440 externC int pthread_cond_signal (pthread_cond_t *cond)
441 {
442     PTHREAD_ENTRY();
443
444     PTHREAD_CHECK( cond );
445
446     ((Cyg_Condition_Variable *)cond)->signal();
447     
448     PTHREAD_RETURN(0);
449 }
450
451 //-----------------------------------------------------------------------------
452 // Wake up all threads waiting for condition variable
453
454 externC int pthread_cond_broadcast (pthread_cond_t *cond)
455 {
456     PTHREAD_ENTRY();
457
458     PTHREAD_CHECK( cond );
459
460     ((Cyg_Condition_Variable *)cond)->broadcast();
461     
462     PTHREAD_RETURN(0);
463 }
464
465 //-----------------------------------------------------------------------------
466 // Block on condition variable until signalled. The mutex is
467 // assumed to be locked before this call, will be unlocked
468 // during the wait, and will be re-locked on wakeup.
469
470 externC int pthread_cond_wait (pthread_cond_t *cond,
471                                pthread_mutex_t *mutex)
472 {
473     PTHREAD_ENTRY();
474
475     // check for cancellation first.
476     PTHREAD_TESTCANCEL();
477
478     PTHREAD_CHECK( cond );
479     PTHREAD_CHECK( mutex );    
480
481     ((Cyg_Condition_Variable *)cond)->wait( *(Cyg_Mutex *)mutex );
482     
483     // check if we were woken because we were being cancelled
484     PTHREAD_TESTCANCEL();
485
486     PTHREAD_RETURN(0);
487 }
488
489 //-----------------------------------------------------------------------------
490 // Block on condition variable until signalled, or the timeout expires.
491
492 externC int pthread_cond_timedwait (pthread_cond_t *cond,
493                                     pthread_mutex_t *mutex,
494                                     const struct timespec *abstime)
495 {
496     PTHREAD_ENTRY();
497
498     // check for cancellation first.
499     PTHREAD_TESTCANCEL();
500
501     PTHREAD_CHECK( cond );
502     PTHREAD_CHECK( mutex );    
503     PTHREAD_CHECK( abstime );    
504
505     // Only initialize the converters once or they will consume a huge
506     // amount or runtime.
507
508     static struct Cyg_Clock::converter ns_converter;
509     static struct Cyg_Clock::converter sec_converter;
510     static volatile cyg_atomic conv_init;
511     if (!conv_init)
512     {
513
514         // Try to avoid unnecessarily locking the scheduler when we are not
515         // initializing the converters.  Check the conv_init flag again to
516         // avoid race conditions.
517
518         struct Cyg_Clock::converter temp_ns_converter, temp_sec_converter;
519     
520         Cyg_Clock::real_time_clock
521             ->get_other_to_clock_converter( 1, &temp_ns_converter );
522         Cyg_Clock::real_time_clock
523             ->get_other_to_clock_converter( 1000000000, &temp_sec_converter );
524
525         Cyg_Scheduler::lock();
526         if (!conv_init)
527         {
528             ns_converter = temp_ns_converter;
529             sec_converter = temp_sec_converter;
530             conv_init=1;
531         }
532         Cyg_Scheduler::unlock();
533     }
534
535     cyg_tick_count ticks;
536     ticks = Cyg_Clock::convert( abstime->tv_sec, &sec_converter );
537     ticks += Cyg_Clock::convert( abstime->tv_nsec, &ns_converter );
538     
539     ((Cyg_Condition_Variable *)cond)->wait( *(Cyg_Mutex *)mutex, ticks );
540     
541     // check if we were woken because we were being cancelled
542     PTHREAD_TESTCANCEL();
543
544     if ( Cyg_Thread::self()->get_wake_reason() == Cyg_Thread::TIMEOUT )
545         PTHREAD_RETURN(ETIMEDOUT);
546     else
547         PTHREAD_RETURN(0);
548 }
549
550 // -------------------------------------------------------------------------
551 // EOF mutex.cxx