1 //==========================================================================
5 // POSIX pthreads implementation
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.
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.
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
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.
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.
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.
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####
44 // Contributors: nickg, jlarmour, Wade Jensen
46 // Purpose: POSIX pthread implementation
47 // Description: This file contains the implementation of the POSIX pthread
52 //####DESCRIPTIONEND####
54 //==========================================================================
56 #include <pkgconf/posix.h>
58 #include <cyg/infra/cyg_trac.h> // tracing macros
59 #include <cyg/infra/cyg_ass.h> // assertion macros
61 #include "pprivate.h" // POSIX private header
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
69 #include <cyg/kernel/thread.inl> // thread inlines
70 #include <cyg/kernel/sched.inl> // scheduler inlines
72 //-----------------------------------------------------------------------------
73 // new operator to allow us to construct mutex objects
75 inline void *operator new(size_t size, cyg_uint8 *ptr) { return (void *)ptr; };
77 //=============================================================================
80 //-----------------------------------------------------------------------------
81 // Mutex attributes manipulation functions
83 //-----------------------------------------------------------------------------
84 // Initialize attribute object
86 externC int pthread_mutexattr_init ( pthread_mutexattr_t *attr)
92 attr->protocol = PTHREAD_PRIO_NONE;
93 #ifdef _POSIX_THREAD_PRIO_PROTECT
94 attr->prioceiling = 0;
100 //-----------------------------------------------------------------------------
101 // Destroy attribute object
103 externC int pthread_mutexattr_destroy ( pthread_mutexattr_t *attr)
109 // Nothing to do here...
114 //-----------------------------------------------------------------------------
115 // Optional functions depending on priority inversion protection options.
117 #if defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
119 // Set priority inversion protection protocol
120 externC int pthread_mutexattr_setprotocol ( pthread_mutexattr_t *attr,
129 case PTHREAD_PRIO_NONE:
130 #if defined(_POSIX_THREAD_PRIO_INHERIT)
131 case PTHREAD_PRIO_INHERIT:
133 #if defined(_POSIX_THREAD_PRIO_PROTECT)
134 case PTHREAD_PRIO_PROTECT:
136 attr->protocol = protocol;
140 PTHREAD_RETURN(EINVAL);
146 // Get priority inversion protection protocol
147 externC int pthread_mutexattr_getprotocol ( pthread_mutexattr_t *attr,
154 if( protocol != NULL )
155 *protocol = attr->protocol;
160 #if defined(_POSIX_THREAD_PRIO_PROTECT)
162 // Set priority for priority ceiling protocol
163 externC int pthread_mutexattr_setprioceiling ( pthread_mutexattr_t *attr,
171 attr->prioceiling = prioceiling;
176 // Get priority for priority ceiling protocol
177 externC int pthread_mutexattr_getprioceiling ( pthread_mutexattr_t *attr,
184 if( prioceiling != NULL )
185 *prioceiling = attr->prioceiling;
190 // Set priority ceiling of given mutex, returning old ceiling.
191 externC int pthread_mutex_setprioceiling( pthread_mutex_t *mutex,
197 PTHREAD_CHECK(mutex);
199 pthread_mutex_lock( mutex );
201 Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
203 if( old_ceiling != NULL )
204 *old_ceiling = mx->get_ceiling();
206 mx->set_ceiling( prioceiling );
208 pthread_mutex_unlock( mutex );
213 // Get priority ceiling of given mutex
214 externC int pthread_mutex_getprioceiling( pthread_mutex_t *mutex,
219 PTHREAD_CHECK(mutex);
221 Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
223 if( prioceiling != NULL )
224 *prioceiling = mx->get_ceiling();
229 #endif // defined(_POSIX_THREAD_PRIO_PROTECT)
231 #endif // defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT)
233 //-----------------------------------------------------------------------------
236 //-----------------------------------------------------------------------------
237 // Initialize mutex. If mutex_attr is NULL, use default attributes.
239 externC int pthread_mutex_init (pthread_mutex_t *mutex,
240 const pthread_mutexattr_t *mutex_attr)
244 PTHREAD_CHECK( mutex );
246 pthread_mutexattr_t use_attr;
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;
253 // Now translate the POSIX protocol identifier into the eCos one.
254 Cyg_Mutex::cyg_protcol protocol;
256 switch( use_attr.protocol )
258 #if defined(_POSIX_THREAD_PRIO_PROTECT)
259 case PTHREAD_PRIO_PROTECT:
260 protocol = Cyg_Mutex::CEILING;
263 #if defined(_POSIX_THREAD_PRIO_INHERIT)
264 case PTHREAD_PRIO_INHERIT:
265 protocol = Cyg_Mutex::INHERIT;
268 case PTHREAD_PRIO_NONE:
269 protocol = Cyg_Mutex::NONE;
273 PTHREAD_RETURN(EINVAL);
276 Cyg_Mutex *mx = new((cyg_uint8 *)mutex) Cyg_Mutex( protocol );
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 );
287 //-----------------------------------------------------------------------------
290 externC int pthread_mutex_destroy (pthread_mutex_t *mutex)
296 PTHREAD_CHECK( mutex );
298 Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
300 if( mx->get_owner() != NULL )
302 else mx->~Cyg_Mutex();
307 //-----------------------------------------------------------------------------
308 // Lock mutex, waiting for it if necessary.
310 externC int pthread_mutex_lock (pthread_mutex_t *mutex)
314 PTHREAD_CHECK( mutex );
316 Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
318 if( mx->get_owner() == Cyg_Thread::self() )
319 PTHREAD_RETURN(EDEADLK);
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.
329 //-----------------------------------------------------------------------------
330 // Try to lock mutex.
332 externC int pthread_mutex_trylock (pthread_mutex_t *mutex)
336 PTHREAD_CHECK( mutex );
338 Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
340 if( mx->get_owner() == Cyg_Thread::self() )
341 PTHREAD_RETURN(EDEADLK);
346 PTHREAD_RETURN(EBUSY);
350 //-----------------------------------------------------------------------------
353 externC int pthread_mutex_unlock (pthread_mutex_t *mutex)
357 PTHREAD_CHECK( mutex );
359 Cyg_Mutex *mx = (Cyg_Mutex *)mutex;
367 //=============================================================================
368 // Condition Variables
370 //-----------------------------------------------------------------------------
371 // Attribute manipulation functions
372 // We do not actually support any attributes at present, so these do nothing.
374 //-----------------------------------------------------------------------------
375 // Initialize condition variable attributes
377 externC int pthread_condattr_init (pthread_condattr_t *attr)
383 // There are no condition variable attributes at present
388 //-----------------------------------------------------------------------------
389 // Destroy condition variable attributes
391 externC int pthread_condattr_destroy (pthread_condattr_t *attr)
397 // nothing to do here...
402 //-----------------------------------------------------------------------------
403 // Condition variable functions
405 //-----------------------------------------------------------------------------
406 // Initialize condition variable.
408 externC int pthread_cond_init (pthread_cond_t *cond,
409 const pthread_condattr_t *attr)
413 PTHREAD_CHECK( cond );
415 Cyg_Condition_Variable *cv =
416 new((cyg_uint8 *)cond) Cyg_Condition_Variable();
423 //-----------------------------------------------------------------------------
424 // Destroy condition variable.
426 externC int pthread_cond_destroy (pthread_cond_t *cond)
430 PTHREAD_CHECK( cond );
432 ((Cyg_Condition_Variable *)cond)->~Cyg_Condition_Variable();
437 //-----------------------------------------------------------------------------
438 // Wake up one thread waiting for condition variable
440 externC int pthread_cond_signal (pthread_cond_t *cond)
444 PTHREAD_CHECK( cond );
446 ((Cyg_Condition_Variable *)cond)->signal();
451 //-----------------------------------------------------------------------------
452 // Wake up all threads waiting for condition variable
454 externC int pthread_cond_broadcast (pthread_cond_t *cond)
458 PTHREAD_CHECK( cond );
460 ((Cyg_Condition_Variable *)cond)->broadcast();
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.
470 externC int pthread_cond_wait (pthread_cond_t *cond,
471 pthread_mutex_t *mutex)
475 // check for cancellation first.
476 PTHREAD_TESTCANCEL();
478 PTHREAD_CHECK( cond );
479 PTHREAD_CHECK( mutex );
481 ((Cyg_Condition_Variable *)cond)->wait( *(Cyg_Mutex *)mutex );
483 // check if we were woken because we were being cancelled
484 PTHREAD_TESTCANCEL();
489 //-----------------------------------------------------------------------------
490 // Block on condition variable until signalled, or the timeout expires.
492 externC int pthread_cond_timedwait (pthread_cond_t *cond,
493 pthread_mutex_t *mutex,
494 const struct timespec *abstime)
498 // check for cancellation first.
499 PTHREAD_TESTCANCEL();
501 PTHREAD_CHECK( cond );
502 PTHREAD_CHECK( mutex );
503 PTHREAD_CHECK( abstime );
505 // Only initialize the converters once or they will consume a huge
506 // amount or runtime.
508 static struct Cyg_Clock::converter ns_converter;
509 static struct Cyg_Clock::converter sec_converter;
510 static volatile cyg_atomic conv_init;
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.
518 struct Cyg_Clock::converter temp_ns_converter, temp_sec_converter;
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 );
525 Cyg_Scheduler::lock();
528 ns_converter = temp_ns_converter;
529 sec_converter = temp_sec_converter;
532 Cyg_Scheduler::unlock();
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 );
539 ((Cyg_Condition_Variable *)cond)->wait( *(Cyg_Mutex *)mutex, ticks );
541 // check if we were woken because we were being cancelled
542 PTHREAD_TESTCANCEL();
544 if ( Cyg_Thread::self()->get_wake_reason() == Cyg_Thread::TIMEOUT )
545 PTHREAD_RETURN(ETIMEDOUT);
550 // -------------------------------------------------------------------------