URL
https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk
Subversion Repositories openrisc_me
Compare Revisions
- This comparison shows the changes necessary to convert path
/openrisc/trunk/rtos/ecos-2.0/packages/kernel/v2_0/src/sync
- from Rev 27 to Rev 174
- ↔ Reverse comparison
Rev 27 → Rev 174
/mqueue.cxx
0,0 → 1,65
//========================================================================== |
// |
// sync/mqueue.cxx |
// |
// Mqueue message queue non-inline implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): jlarmour |
// Contributors: |
// Date: 2001-10-12 |
// Purpose: Non-inlined implementation of mqueue message queue. |
// Description: This file contains the non-inlined instantiations of the |
// mqueue message queue implementation functions. |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#ifdef CYGIMP_KERNEL_SYNCH_MQUEUE_NOT_INLINE |
|
#define CYGPRI_KERNEL_SYNCH_MQUEUE_INLINE |
#include <cyg/kernel/mqueue.hxx> |
#include <cyg/kernel/mqueue.inl> |
|
#endif |
|
// ------------------------------------------------------------------------- |
// EOF sync/mqueue.cxx |
/mutex.cxx
0,0 → 1,863
//========================================================================== |
// |
// sync/mutex.cxx |
// |
// Mutex and condition variable implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg, jlarmour |
// Date: 1999-02-17 |
// Purpose: Mutex implementation |
// Description: This file contains the implementations of the mutex |
// and condition variable classes. |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/ktypes.h> // base kernel types |
#include <cyg/infra/cyg_trac.h> // tracing macros |
#include <cyg/infra/cyg_ass.h> // assertion macros |
#include <cyg/kernel/instrmnt.h> // instrumentation |
|
#include <cyg/kernel/mutex.hxx> // our header |
|
#include <cyg/kernel/thread.inl> // thread inlines |
#include <cyg/kernel/sched.inl> // scheduler inlines |
#include <cyg/kernel/clock.inl> // clock inlines |
|
// ------------------------------------------------------------------------- |
// Mutex protocol test macros. |
// If the dynamic protocol option is enabled, then these generate appropriate |
// tests on the protocol field. If there is no dynamic choice then they simply |
// result in empty statements. |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
|
#define IF_PROTOCOL_INHERIT if( protocol == INHERIT ) |
#define IF_PROTOCOL_CEILING if( protocol == CEILING ) |
#define IF_PROTOCOL_ACTIVE if( protocol != NONE ) |
|
#else |
|
#define IF_PROTOCOL_INHERIT |
#define IF_PROTOCOL_CEILING |
#define IF_PROTOCOL_ACTIVE |
|
#endif |
|
// ------------------------------------------------------------------------- |
// Constructor |
|
Cyg_Mutex::Cyg_Mutex() |
{ |
CYG_REPORT_FUNCTION(); |
|
locked = false; |
owner = NULL; |
|
#if defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT) && \ |
defined(CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC) |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_INHERIT |
protocol = INHERIT; |
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_CEILING |
protocol = CEILING; |
ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY; |
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_NONE |
protocol = NONE; |
#endif |
|
#else // not (DYNAMIC and DEFAULT defined) |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY |
|
// if there is a default priority ceiling defined, use that to initialize |
// the ceiling. |
ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY; |
|
#else |
|
// Otherwise set it to zero. |
ceiling = 0; |
|
#endif |
#endif |
|
#endif // DYNAMIC and DEFAULT defined |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Construct with defined protocol |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
|
Cyg_Mutex::Cyg_Mutex( cyg_protcol protocol_arg ) |
{ |
CYG_REPORT_FUNCTION(); |
|
locked = false; |
owner = NULL; |
|
protocol = protocol_arg; |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY |
|
// if there is a default priority ceiling defined, use that to initialize |
// the ceiling. |
ceiling = CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DEFAULT_PRIORITY; |
|
#else |
|
// Otherwise set it to zero. |
ceiling = 0; |
|
#endif |
#endif |
|
CYG_REPORT_RETURN(); |
} |
|
#endif |
|
// ------------------------------------------------------------------------- |
// Destructor |
|
Cyg_Mutex::~Cyg_Mutex() |
{ |
CYG_REPORT_FUNCTION(); |
|
CYG_ASSERT( owner == NULL, "Deleting mutex with owner"); |
CYG_ASSERT( queue.empty(), "Deleting mutex with waiting threads"); |
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
|
#ifdef CYGDBG_USE_ASSERTS |
|
cyg_bool |
Cyg_Mutex::check_this( cyg_assert_class_zeal zeal) const |
{ |
// CYG_REPORT_FUNCTION(); |
|
// check that we have a non-NULL pointer first |
if( this == NULL ) return false; |
|
switch( zeal ) |
{ |
case cyg_system_test: |
case cyg_extreme: |
case cyg_thorough: |
case cyg_quick: |
case cyg_trivial: |
if( locked && owner == NULL ) return false; |
if( !locked && owner != NULL ) return false; |
case cyg_none: |
default: |
break; |
}; |
|
return true; |
} |
|
#endif |
|
// ------------------------------------------------------------------------- |
// Lock and/or wait |
|
cyg_bool |
Cyg_Mutex::lock(void) |
{ |
CYG_REPORT_FUNCTYPE("returning %d"); |
|
cyg_bool result = true; |
Cyg_Thread *self = Cyg_Thread::self(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
CYG_INSTRUMENT_MUTEX(LOCK, this, 0); |
|
// Loop while the mutex is locked, sleeping each time around |
// the loop. This copes with the possibility of a higher priority |
// thread grabbing the mutex between the wakeup in unlock() and |
// this thread actually starting. |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
|
IF_PROTOCOL_ACTIVE |
self->count_mutex(); |
|
#endif |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
|
IF_PROTOCOL_CEILING |
self->set_priority_ceiling(ceiling); |
|
#endif |
|
while( locked && result ) |
{ |
CYG_ASSERT( self != owner, "Locking mutex I already own"); |
|
self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
self->sleep(); |
|
queue.enqueue( self ); |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
|
IF_PROTOCOL_INHERIT |
owner->inherit_priority(self); |
|
#endif |
|
CYG_INSTRUMENT_MUTEX(WAIT, this, 0); |
|
// Allow other threads to run |
Cyg_Scheduler::reschedule(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
|
} |
|
if( result ) |
{ |
locked = true; |
owner = self; |
|
CYG_INSTRUMENT_MUTEX(LOCKED, this, 0); |
} |
else |
{ |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
|
IF_PROTOCOL_ACTIVE |
self->uncount_mutex(); |
|
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
|
IF_PROTOCOL_INHERIT |
self->disinherit_priority(); |
|
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
|
IF_PROTOCOL_CEILING |
self->clear_priority_ceiling(); |
|
#endif |
} |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
CYG_REPORT_RETVAL(result); |
|
return result; |
} |
|
// ------------------------------------------------------------------------- |
// Try to lock and return success |
|
cyg_bool |
Cyg_Mutex::trylock(void) |
{ |
CYG_REPORT_FUNCTYPE("returning %d"); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
cyg_bool result = true; |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
// If the mutex is not locked, grab it |
// for ourself. Otherwise return failure. |
if( !locked ) |
{ |
Cyg_Thread *self = Cyg_Thread::self(); |
|
locked = true; |
owner = self; |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
|
IF_PROTOCOL_ACTIVE |
self->count_mutex(); |
|
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
|
IF_PROTOCOL_CEILING |
self->set_priority_ceiling(ceiling); |
|
#endif |
|
} |
else result = false; |
|
CYG_INSTRUMENT_MUTEX(TRY, this, result); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETVAL(result); |
return result; |
} |
|
// ------------------------------------------------------------------------- |
// unlock |
|
void |
Cyg_Mutex::unlock(void) |
{ |
CYG_REPORT_FUNCTION(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_MUTEX(UNLOCK, this, 0); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERT( locked, "Unlock mutex that is not locked"); |
CYG_ASSERT( owner == Cyg_Thread::self(), "Unlock mutex I do not own"); |
|
if( !queue.empty() ) { |
|
// The queue is non-empty, so grab the next |
// thread from it and wake it up. |
|
Cyg_Thread *thread = queue.dequeue(); |
|
CYG_ASSERTCLASS( thread, "Bad thread pointer"); |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
|
// Give the owner-to-be a chance to inherit from the remaining |
// queue or the relinquishing thread: |
|
IF_PROTOCOL_INHERIT |
thread->relay_priority(owner, &queue); |
|
#endif |
|
thread->set_wake_reason( Cyg_Thread::DONE ); |
|
thread->wake(); |
|
CYG_INSTRUMENT_MUTEX(WAKE, this, thread); |
|
} |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL |
|
IF_PROTOCOL_ACTIVE |
owner->uncount_mutex(); |
|
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_INHERIT |
|
IF_PROTOCOL_INHERIT |
owner->disinherit_priority(); |
|
#endif |
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
|
IF_PROTOCOL_CEILING |
owner->clear_priority_ceiling(); |
|
#endif |
|
locked = false; |
owner = NULL; |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Release all waiting threads. |
|
void Cyg_Mutex::release() |
{ |
CYG_REPORT_FUNCTION(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_MUTEX(RELEASE, this, 0); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
while( !queue.empty() ) |
{ |
// The queue is non-empty, so grab each |
// thread from it and release it. |
|
Cyg_Thread *thread = queue.dequeue(); |
|
CYG_ASSERTCLASS( thread, "Bad thread pointer"); |
|
thread->release(); |
|
CYG_INSTRUMENT_MUTEX(RELEASED, this, thread); |
|
} |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Set ceiling priority for priority ceiling protocol |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_CEILING |
|
void Cyg_Mutex::set_ceiling( cyg_priority priority ) |
{ |
CYG_REPORT_FUNCTION(); |
|
// CYG_ASSERT( priority >= CYG_THREAD_MAX_PRIORITY, "Priority out of range"); |
// CYG_ASSERT( priority <= CYG_THREAD_MIN_PRIORITY, "Priority out of range"); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
ceiling = priority; |
|
// Unlock the scheduler |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETURN(); |
} |
|
#endif |
|
// ------------------------------------------------------------------------- |
// Set priority inversion protocol |
|
#ifdef CYGSEM_KERNEL_SYNCH_MUTEX_PRIORITY_INVERSION_PROTOCOL_DYNAMIC |
void Cyg_Mutex::set_protocol( cyg_protcol new_protocol ) |
{ |
CYG_REPORT_FUNCTION(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
protocol = new_protocol; |
|
// Unlock the scheduler |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETURN(); |
} |
|
#endif |
|
|
//========================================================================== |
// Condition variables |
|
Cyg_Condition_Variable::Cyg_Condition_Variable( |
Cyg_Mutex &mx // linked mutex |
) |
{ |
CYG_REPORT_FUNCTION(); |
|
mutex = &mx; |
|
CYG_ASSERTCLASS( mutex, "Invalid mutex argument"); |
|
CYG_REPORT_RETURN(); |
} |
|
Cyg_Condition_Variable::Cyg_Condition_Variable() |
{ |
CYG_REPORT_FUNCTION(); |
|
mutex = NULL; |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Destructor |
|
Cyg_Condition_Variable::~Cyg_Condition_Variable() |
{ |
CYG_REPORT_FUNCTION(); |
|
CYG_ASSERT( queue.empty(), "Deleting condvar with waiting threads"); |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
|
#ifdef CYGDBG_USE_ASSERTS |
|
cyg_bool |
Cyg_Condition_Variable::check_this( cyg_assert_class_zeal zeal) const |
{ |
bool result = true; |
|
CYG_REPORT_FUNCTYPE("returning %d"); |
CYG_REPORT_FUNCARG1("zeal = %d", zeal); |
|
// check that we have a non-NULL pointer first |
if( this == NULL ) |
result = false; |
else { |
|
switch( zeal ) |
{ |
case cyg_system_test: |
case cyg_extreme: |
case cyg_thorough: |
if( mutex != NULL && !mutex->check_this(zeal) ) |
result = false; |
case cyg_quick: |
case cyg_trivial: |
case cyg_none: |
default: |
break; |
} |
} |
|
CYG_REPORT_RETVAL(result); |
return result; |
} |
|
#endif |
|
// ------------------------------------------------------------------------- |
// Wait for condition to be true |
// Note: if this function is entered with the scheduler locked (e.g. to |
// suspend DSR processing) then there is no need to take the lock. Also |
// in this case, exit with the scheduler locked, which allows this function |
// to be used in a totally thread-safe manner. |
|
cyg_bool |
Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx ) |
{ |
CYG_REPORT_FUNCTION(); |
|
cyg_bool result = true; |
Cyg_Thread *self = Cyg_Thread::self(); |
|
Cyg_Scheduler::lock(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
CYG_ASSERTCLASS( self, "Bad self thread"); |
|
CYG_INSTRUMENT_CONDVAR(WAIT, this, 0); |
|
mx->unlock(); |
|
self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
self->sleep(); |
|
queue.enqueue( self ); |
|
// Avoid calling ASRs during the following unlock. |
self->set_asr_inhibit(); |
|
// Unlock the scheduler and switch threads |
Cyg_Scheduler::unlock_reschedule(); |
|
// Allow ASRs again |
self->clear_asr_inhibit(); |
|
CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::DESTRUCT: // which, the cv or the mutex? |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
|
// When we awake, we must re-acquire the mutex. Note that while |
// it is essential to release the mutex and queue on the CV |
// atomically relative to other threads, to avoid races, it is not |
// necessary for us to re-acquire the mutex in the same atomic |
// action. Hence we can do it after unlocking the scheduler. |
// We need to loop here in case the thread is released while waiting |
// for the mutex. It is essential that we exit this function with the |
// mutex claimed. |
|
while ( !mx->lock() ) |
continue; |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
CYG_ASSERT( mx->owner == self, "Not mutex owner"); |
|
CYG_REPORT_RETURN(); |
|
return result; |
} |
|
// ------------------------------------------------------------------------- |
// Wake one thread |
|
void |
Cyg_Condition_Variable::signal(void) |
{ |
CYG_REPORT_FUNCTION(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CONDVAR(SIGNAL, this, 0); |
|
if( !queue.empty() ) |
{ |
// The queue is non-empty, so grab the next |
// thread from it and wake it up. |
|
Cyg_Thread *thread = queue.dequeue(); |
|
CYG_ASSERTCLASS( thread, "Bad thread pointer"); |
|
thread->set_wake_reason( Cyg_Thread::DONE ); |
|
thread->wake(); |
|
CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); |
|
} |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Set cond true, wake all threads |
|
void |
Cyg_Condition_Variable::broadcast(void) |
{ |
CYG_REPORT_FUNCTION(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CONDVAR(BROADCAST, this, 0); |
|
// Grab all the threads from the queue and let them |
// go. |
|
while( !queue.empty() ) |
{ |
Cyg_Thread *thread = queue.dequeue(); |
|
CYG_ASSERTCLASS( thread, "Bad thread pointer"); |
|
thread->set_wake_reason( Cyg_Thread::DONE ); |
|
thread->wake(); |
|
CYG_INSTRUMENT_CONDVAR(WAKE, this, thread); |
} |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Optional timed wait on a CV |
|
#if defined(CYGMFN_KERNEL_SYNCH_CONDVAR_TIMED_WAIT) |
|
cyg_bool |
Cyg_Condition_Variable::wait_inner( Cyg_Mutex *mx, cyg_tick_count timeout ) |
{ |
CYG_REPORT_FUNCTYPE("returning %d"); |
CYG_REPORT_FUNCARG1("timeout = %d", timeout); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
|
cyg_bool result = true; |
|
Cyg_Thread *self = Cyg_Thread::self(); |
|
CYG_ASSERTCLASS( self, "Bad self thread"); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CONDVAR(TIMED_WAIT, this, 0 ); |
|
mx->unlock(); |
|
// The ordering of sleep() and set_timer() here are |
// important. If the timeout is in the past, the thread |
// will be woken up immediately and will not sleep. |
|
self->sleep(); |
|
// Set the timer and sleep reason |
self->set_timer( timeout, Cyg_Thread::TIMEOUT ); |
|
// Only enqueue if the timeout has not already fired. |
if( self->get_wake_reason() == Cyg_Thread::NONE ) |
queue.enqueue( self ); |
|
// Avoid calling ASRs during the following unlock. |
self->set_asr_inhibit(); |
|
// Unlock the scheduler and switch threads |
Cyg_Scheduler::unlock_reschedule(); |
|
// Allow ASRs again |
self->clear_asr_inhibit(); |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
|
self->clear_timer(); |
|
CYG_INSTRUMENT_CONDVAR(WOKE, this, self->get_wake_reason()); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::TIMEOUT: |
case Cyg_Thread::DESTRUCT: // which, the cv or the mutex? |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
|
|
// When we awake, we must re-acquire the mutex. Note that while |
// it is essential to release the mutex and queue on the CV |
// atomically relative to other threads, to avoid races, it is not |
// necessary for us to re-acquire the mutex in the same atomic |
// action. Hence we can do it after unlocking the scheduler. |
|
while ( !mx->lock() ) |
continue; |
|
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERTCLASS( mx, "Corrupt mutex"); |
|
CYG_REPORT_RETVAL(result); |
|
return result; |
} |
|
#endif |
|
|
// ------------------------------------------------------------------------- |
// EOF sync/mutex.cxx |
/mbox.cxx
0,0 → 1,170
//========================================================================== |
// |
// mbox.cxx |
// |
// Mbox mbox template class implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 1998-02-11 |
// Purpose: Mbox implementation |
// Description: This file contains the implementations of the mbox class |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/ktypes.h> // base kernel types |
#include <cyg/infra/cyg_trac.h> // tracing macros |
#include <cyg/infra/cyg_ass.h> // assertion macros |
#include <cyg/kernel/instrmnt.h> // instrumentation |
|
#include <cyg/kernel/thread.inl> // Cyg_Thread inlines |
|
#include <cyg/kernel/mbox.hxx> // our own header |
|
#ifndef CYGIMP_MBOXT_INLINE // force inlining |
#define CYGIMP_MBOXT_INLINE // of implementation |
#endif |
|
#ifdef CYGIMP_MBOX_USE_MBOXT_PLAIN |
#include <cyg/kernel/mboxt.inl> // mbox template implementation |
#else |
#include <cyg/kernel/mboxt2.inl> // mbox template implementation |
#endif |
|
// ------------------------------------------------------------------------- |
// This module exists to cause exactly one instance of these functions to |
// exist; this is just like a vanilla class, except we use the template |
// class to acquire an implementation. The template functions are inlined |
// in each of these methods. |
|
|
// ------------------------------------------------------------------------- |
// Constructor |
|
Cyg_Mbox::Cyg_Mbox() |
{ |
} |
|
// ------------------------------------------------------------------------- |
// Destructor |
|
Cyg_Mbox::~Cyg_Mbox() |
{ |
} |
|
// ------------------------------------------------------------------------- |
// debugging/assert function |
|
#ifdef CYGDBG_USE_ASSERTS |
cyg_bool |
Cyg_Mbox::check_this(cyg_assert_class_zeal zeal) const |
{ |
return m.check_this(zeal); |
} |
#endif |
|
// ------------------------------------------------------------------------- |
// now the members themselves: |
|
void * |
Cyg_Mbox::get() |
{ |
void * p; |
if ( ! m.get( p ) ) |
return NULL; |
return p; |
} |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
void * |
Cyg_Mbox::get( cyg_tick_count timeout ) |
{ |
void * p; |
if ( ! m.get( p, timeout ) ) |
return NULL; |
return p; |
} |
#endif |
|
void * |
Cyg_Mbox::tryget() |
{ |
void * p; |
if ( ! m.tryget( p ) ) |
return NULL; |
return p; |
} |
|
#ifdef CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
cyg_bool |
Cyg_Mbox::put( void *item ) |
{ |
return m.put( item ); |
} |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
cyg_bool |
Cyg_Mbox::put( void *item, cyg_tick_count timeout ) |
{ |
return m.put( item, timeout ); |
} |
#endif |
#endif // CYGMFN_KERNEL_SYNCH_MBOXT_PUT_CAN_WAIT |
|
cyg_bool |
Cyg_Mbox::tryput( void *item ) |
{ |
return m.tryput( item ); |
} |
|
void * |
Cyg_Mbox::peek_item() // Get next item to be returned |
{ |
void *p; |
if ( ! m.peek_item( p ) ) |
return NULL; |
return p; |
} |
|
// ------------------------------------------------------------------------- |
// EOF mbox.cxx |
/cnt_sem.cxx
0,0 → 1,281
//========================================================================== |
// |
// sync/cnt_sem.cxx |
// |
// Counting semaphore implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 1997-09-24 |
// Purpose: Cyg_Counting_Semaphore implementation |
// Description: This file contains the implementations of the counting semaphore |
// class. |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/ktypes.h> // base kernel types |
#include <cyg/infra/cyg_trac.h> // tracing macros |
#include <cyg/infra/cyg_ass.h> // assertion macros |
#include <cyg/kernel/instrmnt.h> // instrumentation |
|
#include <cyg/kernel/thread.inl> // Cyg_Thread inlines |
|
#include <cyg/kernel/sema.hxx> // our header |
|
#include <cyg/kernel/sched.inl> // scheduler inlines |
|
// ------------------------------------------------------------------------- |
// Constructor |
|
Cyg_Counting_Semaphore::Cyg_Counting_Semaphore( |
cyg_count32 init_count // Initial count value |
) |
{ |
count = init_count; |
} |
|
// ------------------------------------------------------------------------- |
// Destructor |
|
Cyg_Counting_Semaphore::~Cyg_Counting_Semaphore() |
{ |
CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads"); |
} |
|
// ------------------------------------------------------------------------- |
// Wait until the count can be decremented without it becoming |
// negative. |
|
cyg_bool Cyg_Counting_Semaphore::wait() |
{ |
cyg_bool result = true; |
Cyg_Thread *self = Cyg_Thread::self(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CNTSEM( CLAIM, this, count ); |
|
while( count == 0 && result ) |
{ |
self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
self->sleep(); |
|
queue.enqueue( self ); |
|
CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 ); |
|
// Allow other threads to run |
Cyg_Scheduler::reschedule(); |
|
CYG_INSTRUMENT_CNTSEM( WOKE, this, count ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
} |
|
if( result ) count--; |
|
// Unlock the scheduler |
Cyg_Scheduler::unlock(); |
|
return result; |
} |
|
// ------------------------------------------------------------------------- |
// Wait until the count can be decremented without it becoming |
// negative. |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
cyg_bool |
Cyg_Counting_Semaphore::wait( cyg_tick_count timeout ) |
{ |
cyg_bool result = true; |
Cyg_Thread *self = Cyg_Thread::self(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CNTSEM( CLAIM, this, count ); |
|
// Set the timer _once_ outside the loop. |
self->set_timer( timeout, Cyg_Thread::TIMEOUT ); |
|
// If the timeout is in the past, the wake reason will have been |
// set to something other than NONE already. Set the result false |
// to force an immediate return. |
|
if( self->get_wake_reason() != Cyg_Thread::NONE ) |
result = false; |
|
while ( 0 == count && result ) { |
|
// must reset the sleep reason every time |
self->set_sleep_reason( Cyg_Thread::TIMEOUT ); |
|
self->sleep(); |
|
queue.enqueue( self ); |
|
CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 ); |
|
// Allow other threads to run |
Cyg_Scheduler::reschedule(); |
|
CYG_INSTRUMENT_CNTSEM( WOKE, this, count ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::TIMEOUT: |
result = false; |
CYG_INSTRUMENT_CNTSEM( TIMEOUT, this, count); |
break; |
|
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
} |
|
// Clear the timeout. It is irrelevant whether the alarm has |
// actually gone off or not. |
self->clear_timer(); |
|
if ( result ) count--; |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
return result; |
} |
|
#endif // CYGFUN_KERNEL_THREADS_TIMER |
|
// ------------------------------------------------------------------------- |
// Try to decrement, but fail if not possible |
|
cyg_bool Cyg_Counting_Semaphore::trywait() |
{ |
cyg_bool result = true; |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
if( count > 0 ) count--; |
else result = false; |
|
CYG_INSTRUMENT_CNTSEM( TRY, this, result ); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
return result; |
} |
|
// ------------------------------------------------------------------------- |
// Increment count |
|
void Cyg_Counting_Semaphore::post() |
{ |
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CNTSEM( POST, this, 0 ); |
|
count++; |
|
if( !queue.empty() ) { |
|
// The queue is non-empty, so grab the next |
// thread from it and wake it up. The waiter |
// will decrement the count when he is awakened. |
|
Cyg_Thread *thread = queue.dequeue(); |
|
thread->set_wake_reason( Cyg_Thread::DONE ); |
|
thread->wake(); |
|
CYG_INSTRUMENT_CNTSEM( WAKE, this, thread ); |
} |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
} |
|
// ------------------------------------------------------------------------- |
// Get current count value |
|
cyg_count32 Cyg_Counting_Semaphore::peek() const |
{ |
// This is a single read of the value of count. |
// This is already atomic, hence there is no need |
// to lock the scheduler. |
|
return count; |
} |
|
// ------------------------------------------------------------------------- |
// EOF sync/cnt_sem.cxx |
/flag.cxx
0,0 → 1,418
//========================================================================== |
// |
// flag.cxx |
// |
// Flag class implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): hmt |
// Contributors: hmt |
// Date: 1998-02-11 |
// Purpose: Flag implementation |
// Description: This file contains the implementations of the flag class |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/ktypes.h> // base kernel types |
#include <cyg/infra/cyg_trac.h> // tracing macros |
#include <cyg/infra/cyg_ass.h> // assertion macros |
#include <cyg/kernel/instrmnt.h> // instrumentation |
|
#include <cyg/kernel/thread.inl> // thread inlines |
|
#include <cyg/kernel/flag.hxx> // our own header |
|
#include <cyg/kernel/sched.inl> // scheduler inlines |
#include <cyg/kernel/clock.inl> // clock inlines |
|
// ------------------------------------------------------------------------- |
// Constructor |
|
Cyg_Flag::Cyg_Flag( Cyg_FlagValue init ) |
{ |
CYG_REPORT_FUNCTION(); |
value = init; |
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Destructor |
|
Cyg_Flag::~Cyg_Flag() |
{ |
CYG_REPORT_FUNCTION(); |
#if 0 |
CYG_ASSERT( queue.empty(), "Deleting flag with threads waiting"); |
#endif |
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
while ( ! queue.empty() ) { |
Cyg_Thread *thread = queue.dequeue(); |
thread->set_wake_reason( Cyg_Thread::DESTRUCT ); |
thread->wake(); |
} |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// debugging/assert function |
|
#ifdef CYGDBG_USE_ASSERTS |
cyg_bool |
Cyg_Flag::check_this(cyg_assert_class_zeal zeal) const |
{ |
CYG_REPORT_FUNCTION(); |
|
if ( Cyg_Thread::DESTRUCT == Cyg_Thread::self()->get_wake_reason() ) |
// then the whole thing is invalid, and we know it. |
// so return OK, since this check should NOT make an error. |
return true; |
|
// check that we have a non-NULL pointer first |
if( this == NULL ) { |
CYG_REPORT_RETVAL( false ); |
return false; |
} |
|
// there ain't a lot to check here. |
CYG_REPORT_RETVAL( true ); |
return true; |
} |
#endif |
|
// ------------------------------------------------------------------------- |
// now the members themselves: |
|
// clear some bits in the value (all of them by default) by ANDing with the |
// argument. This cannot make a wait condition become true, so there's not |
// much to it. |
void |
Cyg_Flag::maskbits( Cyg_FlagValue arg ) |
{ |
CYG_REPORT_FUNCTION(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
value &= arg; |
// no need to wake anyone up; no waiter can become valid in |
// consequence of this operation. |
|
// Unlock scheduler and allow other threads to run |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETURN(); |
} |
|
|
// ------------------------------------------------------------------------- |
// set some bits in the value (all of them by default) and wake up any |
// affected waiting threads; we do the decision making here so as to get |
// atomicity wrt the other threads waking up - the value might have changed |
// by the time they get to run. |
|
void |
Cyg_Flag::setbits( Cyg_FlagValue arg ) |
{ |
CYG_REPORT_FUNCTION(); |
CYG_ASSERTCLASS( this, "Bad this pointer"); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
// OR in the argument to get a new flag value. |
value |= arg; |
|
// anyone waiting? |
if ( !(queue.empty()) ) { |
FlagWaitInfo *p; |
Cyg_Thread *thread; |
Cyg_ThreadQueue holding; |
|
do { |
thread = queue.dequeue(); |
p = (FlagWaitInfo *)(thread->get_wait_info()); |
|
CYG_ASSERT( (p->allmask == 0) != (p->anymask == 0), |
"Both masks set" ); |
CYG_ASSERT( 0 == p->value_out, "Thread already awoken?" ); |
|
if ( ((p->allmask != 0) && (p->allmask & value) == p->allmask) || |
((p->anymask & value) != 0 ) ) { |
// success! awaken the thread |
thread->set_wake_reason( Cyg_Thread::DONE ); |
thread->wake(); |
// return the successful value to it |
p->value_out = value; |
// do we clear the value; is this the end? |
if ( p->do_clear ) { |
// we can break here but need to preserve ordering |
value = 0; |
// so let it cycle the whole queue regardless |
} |
} |
else { |
// preserve the entry on the holding queue |
holding.enqueue( thread ); |
} |
} while ( !(queue.empty()) ); |
|
// Now re-queue the unaffected threads back into the flag queue |
while ( !(holding.empty()) ) { |
queue.enqueue( holding.dequeue() ); |
} |
} |
// Unlock scheduler and allow other threads to run |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Wait for a match on our pattern, according to the flags given. |
// Return the matching value. |
Cyg_FlagValue |
Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode ) |
{ |
CYG_REPORT_FUNCTION(); |
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" ); |
|
Cyg_FlagValue result; |
|
// Prevent preemption so that we compare atomically |
Cyg_Scheduler::lock(); |
|
// try the current value |
result = poll( pattern, mode ); |
|
if ( 0 != result ) { |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETVAL( result ); |
return result; // all done |
} |
|
// we have to wait until we are awoken |
Cyg_Thread *self = Cyg_Thread::self(); |
|
FlagWaitInfo saveme; |
saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern; |
saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0; |
saveme.do_clear = (0 != (Cyg_Flag::CLR & mode)); |
|
self->set_wait_info( (CYG_ADDRWORD)&saveme ); |
|
result = true; // just being used as an early-out flag now |
// this loop allows us to deal correctly with spurious wakeups |
while ( result && (0 == saveme.value_out) ) { |
self->set_sleep_reason( Cyg_Thread::WAIT ); |
self->sleep(); |
// keep track of myself on the queue of waiting threads |
queue.enqueue( self ); |
|
// Allow other threads to run |
Cyg_Scheduler::reschedule(); |
|
CYG_ASSERT( ((CYG_ADDRWORD)&saveme) == |
Cyg_Thread::self()->get_wait_info(), |
"Wait info lost" ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
} |
|
CYG_ASSERT( (false == result) ^ (0 != saveme.value_out), |
"Break out but also good result!" ); |
|
// Unlock scheduler and allow other threads to run |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETVAL( saveme.value_out ); |
return saveme.value_out; |
} |
|
// ------------------------------------------------------------------------- |
// Wait for a match on our pattern, with a timeout. |
// Return the matching value, or zero if timed out. |
// (zero cannot match any pattern). |
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
Cyg_FlagValue |
Cyg_Flag::wait( Cyg_FlagValue pattern, WaitMode mode, |
cyg_tick_count abs_timeout ) |
{ |
CYG_REPORT_FUNCTION(); |
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" ); |
|
Cyg_FlagValue result; |
|
// Prevent preemption so that we compare atomically |
Cyg_Scheduler::lock(); |
|
// try the current value |
result = poll( pattern, mode ); |
|
if ( 0 != result ) { |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETVAL( result ); |
return result; // all done |
} |
|
// we have to wait until we are awoken |
Cyg_Thread *self = Cyg_Thread::self(); |
|
FlagWaitInfo saveme; |
saveme.allmask = (Cyg_Flag::OR & mode) ? 0 : pattern; |
saveme.anymask = (Cyg_Flag::OR & mode) ? pattern : 0; |
saveme.do_clear = (0 != (Cyg_Flag::CLR & mode)); |
|
self->set_wait_info( (CYG_ADDRWORD)&saveme ); |
|
// Set the timer _once_ outside the loop. |
self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); |
|
// If the timeout was in the past, it will have changed the value |
// of wake_reason, so avoid going into the loop. |
if( self->get_wake_reason() != Cyg_Thread::NONE ) |
result = false; |
else result = true; |
|
// Result is just being used as an early-out flag now. This loop |
// allows us to deal correctly with spurious wakeups. |
|
while ( result && (0 == saveme.value_out) ) { |
self->set_sleep_reason( Cyg_Thread::TIMEOUT ); |
self->sleep(); |
// keep track of myself on the queue of waiting threads |
queue.enqueue( self ); |
|
// Allow other threads to run |
Cyg_Scheduler::reschedule(); |
|
CYG_ASSERT( ((CYG_ADDRWORD)&saveme) == |
Cyg_Thread::self()->get_wait_info(), |
"Wait info lost" ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::TIMEOUT: |
result = false; |
break; |
|
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
} |
|
CYG_ASSERT( (false == result) ^ (0 != saveme.value_out), |
"Break out but also good result!" ); |
|
// clear the timer; if it actually fired, no worries. |
self->clear_timer(); |
|
// Unlock scheduler and allow other threads to run |
Cyg_Scheduler::unlock(); |
// in this version, value_out might be zero meaning timed out. |
CYG_REPORT_RETVAL( saveme.value_out ); |
return saveme.value_out; |
} |
#endif // CYGFUN_KERNEL_THREADS_TIMER |
|
// ------------------------------------------------------------------------- |
// Test for a match on our pattern, according to the flags given. |
// Return the matching value if success, else zero. |
Cyg_FlagValue |
Cyg_Flag::poll( Cyg_FlagValue pattern, WaitMode mode ) |
{ |
CYG_REPORT_FUNCTION(); |
CYG_ASSERTCLASS( this, "Bad this pointer"); |
CYG_ASSERT( Cyg_Flag::MASK >= mode, "Bad mode" ); |
|
// Prevent preemption so that we compare atomically |
Cyg_Scheduler::lock(); |
|
Cyg_FlagValue result = 0; |
|
if ( Cyg_Flag::OR & mode ) { |
if ( 0 != (value & pattern) ) |
result = value; |
} |
else { // Cyg_Flag::AND - all must be set |
if ( (pattern != 0) && (pattern == (value & pattern)) ) |
result = value; |
} |
|
// result != 0 <=> test passed |
if ( result && (Cyg_Flag::CLR & mode) ) |
value = 0; |
|
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETVAL( result ); |
return result; |
} |
|
|
// ------------------------------------------------------------------------- |
// EOF flag.cxx |
/cnt_sem2.cxx
0,0 → 1,295
//========================================================================== |
// |
// sync/cnt_sem2.cxx |
// |
// Counting semaphore implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 1997-09-24 |
// Purpose: Cyg_Counting_Semaphore implementation |
// Description: This file contains the implementations of the counting semaphore |
// class. |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/ktypes.h> // base kernel types |
#include <cyg/infra/cyg_trac.h> // tracing macros |
#include <cyg/infra/cyg_ass.h> // assertion macros |
#include <cyg/kernel/instrmnt.h> // instrumentation |
|
#include <cyg/kernel/thread.inl> // Cyg_Thread inlines |
|
#include <cyg/kernel/sema2.hxx> // our header |
|
#include <cyg/kernel/sched.inl> // scheduler inlines |
|
// ------------------------------------------------------------------------- |
// Constructor |
|
Cyg_Counting_Semaphore2::Cyg_Counting_Semaphore2( |
cyg_count32 init_count // Initial count value |
) |
{ |
count = init_count; |
} |
|
// ------------------------------------------------------------------------- |
// Destructor |
|
Cyg_Counting_Semaphore2::~Cyg_Counting_Semaphore2() |
{ |
CYG_REPORT_FUNCTION(); |
#if 0 |
CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads"); |
#endif |
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
while ( ! queue.empty() ) { |
Cyg_Thread *thread = queue.dequeue(); |
thread->set_wake_reason( Cyg_Thread::DESTRUCT ); |
thread->wake(); |
} |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Wait until the count can be decremented without it becoming |
// negative. |
|
cyg_bool Cyg_Counting_Semaphore2::wait() |
{ |
CYG_REPORT_FUNCTION(); |
Cyg_Thread *self = Cyg_Thread::self(); |
cyg_bool result = true; |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CNTSEM( CLAIM, this, count ); |
|
if ( 0 < count ) { |
count--; |
Cyg_Scheduler::unlock(); |
} |
else { |
self->set_sleep_reason( Cyg_Thread::WAIT ); |
self->sleep(); |
queue.enqueue( self ); |
|
CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 ); |
|
Cyg_Scheduler::unlock(); |
|
CYG_INSTRUMENT_CNTSEM( WOKE, this, count ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
} |
|
CYG_REPORT_RETVAL( result ); |
return result; |
} |
|
// ------------------------------------------------------------------------- |
// Wait until the count can be decremented without it becoming |
// negative. |
|
#ifdef CYGFUN_KERNEL_THREADS_TIMER |
|
cyg_bool |
Cyg_Counting_Semaphore2::wait( cyg_tick_count abs_timeout ) |
{ |
CYG_REPORT_FUNCTION(); |
Cyg_Thread *self = Cyg_Thread::self(); |
cyg_bool result = true; |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CNTSEM( CLAIM, this, count ); |
|
if ( 0 < count ) { |
count--; |
Cyg_Scheduler::unlock(); |
} |
else { |
|
// Put thread in sleep state before setting timer since if the |
// timeout is in the past, it will be re-awoken |
// immediately. If this happens then wake_reason will not be |
// NONE. |
|
self->sleep(); |
|
self->set_timer( abs_timeout, Cyg_Thread::TIMEOUT ); |
|
// only enqueue if the timeout did not already happen |
if( Cyg_Thread::NONE == self->get_wake_reason() ) |
queue.enqueue( self ); |
|
CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 ); |
|
|
Cyg_Scheduler::unlock(); |
|
// Clear the timeout. It is irrelevant whether the alarm has |
// actually gone off or not. |
self->clear_timer(); |
|
CYG_INSTRUMENT_CNTSEM( WOKE, this, count ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::TIMEOUT: |
result = false; |
CYG_INSTRUMENT_CNTSEM( TIMEOUT, this, count); |
break; |
|
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
} |
|
CYG_REPORT_RETVAL( result ); |
return result; |
} |
|
#endif // CYGFUN_KERNEL_THREADS_TIMER |
|
// ------------------------------------------------------------------------- |
// Try to decrement, but fail if not possible |
|
cyg_bool Cyg_Counting_Semaphore2::trywait() |
{ |
CYG_REPORT_FUNCTION(); |
cyg_bool result = true; |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
if( 0 < count ) count--; |
else result = false; |
|
CYG_INSTRUMENT_CNTSEM( TRY, this, result ); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
CYG_REPORT_RETVAL( result ); |
return result; |
} |
|
// ------------------------------------------------------------------------- |
// Increment count |
|
void Cyg_Counting_Semaphore2::post() |
{ |
CYG_REPORT_FUNCTION(); |
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_CNTSEM( POST, this, 0 ); |
|
if( queue.empty() ) { |
count++; |
} |
else { |
// The queue is non-empty, so grab the next |
// thread from it and wake it up. The waiter |
// won't decrement the count when he is awakened, |
// for we never incremented it in the first place |
|
Cyg_Thread *thread = queue.dequeue(); |
|
thread->set_wake_reason( Cyg_Thread::DONE ); |
|
thread->wake(); |
|
CYG_INSTRUMENT_CNTSEM( WAKE, this, thread ); |
} |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
CYG_REPORT_RETURN(); |
} |
|
// ------------------------------------------------------------------------- |
// Get current count value |
|
cyg_count32 Cyg_Counting_Semaphore2::peek() const |
{ |
// This is a single read of the value of count. |
// This is already atomic, hence there is no need |
// to lock the scheduler. |
|
return count; |
} |
|
// ------------------------------------------------------------------------- |
// EOF sync/cnt_sem2.cxx |
/bin_sem.cxx
0,0 → 1,197
//========================================================================== |
// |
// sync/bin_sem.cxx |
// |
// Binary semaphore implementation |
// |
//========================================================================== |
//####ECOSGPLCOPYRIGHTBEGIN#### |
// ------------------------------------------- |
// This file is part of eCos, the Embedded Configurable Operating System. |
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
// |
// eCos is free software; you can redistribute it and/or modify it under |
// the terms of the GNU General Public License as published by the Free |
// Software Foundation; either version 2 or (at your option) any later version. |
// |
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
// WARRANTY; without even the implied warranty of MERCHANTABILITY or |
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
// for more details. |
// |
// You should have received a copy of the GNU General Public License along |
// with eCos; if not, write to the Free Software Foundation, Inc., |
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
// |
// As a special exception, if other files instantiate templates or use macros |
// or inline functions from this file, or you compile this file and link it |
// with other works to produce a work based on this file, this file does not |
// by itself cause the resulting work to be covered by the GNU General Public |
// License. However the source code for this file must still be made available |
// in accordance with section (3) of the GNU General Public License. |
// |
// This exception does not invalidate any other reasons why a work based on |
// this file might be covered by the GNU General Public License. |
// |
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
// at http://sources.redhat.com/ecos/ecos-license/ |
// ------------------------------------------- |
//####ECOSGPLCOPYRIGHTEND#### |
//========================================================================== |
//#####DESCRIPTIONBEGIN#### |
// |
// Author(s): nickg |
// Contributors: nickg |
// Date: 1997-09-24 |
// Purpose: Cyg_Binary_Semaphore implementation |
// Description: This file contains the implementations of the binary semaphore |
// class. |
// |
//####DESCRIPTIONEND#### |
// |
//========================================================================== |
|
#include <pkgconf/kernel.h> |
|
#include <cyg/kernel/ktypes.h> // base kernel types |
#include <cyg/infra/cyg_trac.h> // tracing macros |
#include <cyg/infra/cyg_ass.h> // assertion macros |
#include <cyg/kernel/instrmnt.h> // instrumentation |
|
#include <cyg/kernel/thread.inl> // Cyg_Thread inlines |
|
#include <cyg/kernel/sema.hxx> // our header |
|
#include <cyg/kernel/sched.inl> // scheduler inlines |
|
// ------------------------------------------------------------------------- |
|
Cyg_Binary_Semaphore::Cyg_Binary_Semaphore ( |
cyg_bool init_state |
) |
{ |
state = init_state; |
} |
|
// ------------------------------------------------------------------------- |
|
Cyg_Binary_Semaphore::~Cyg_Binary_Semaphore ( ) |
{ |
} |
|
// ------------------------------------------------------------------------- |
|
cyg_bool Cyg_Binary_Semaphore::wait() |
{ |
cyg_bool result = true; |
Cyg_Thread *self = Cyg_Thread::self(); |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_BINSEM( CLAIM, this, state ); |
|
while( !state && result ) |
{ |
self->set_sleep_reason( Cyg_Thread::WAIT ); |
|
self->sleep(); |
|
queue.enqueue( self ); |
|
CYG_INSTRUMENT_BINSEM( WAIT, this, 0 ); |
|
// Allow other threads to run |
Cyg_Scheduler::reschedule(); |
|
CYG_INSTRUMENT_BINSEM( WOKE, this, state ); |
|
switch( self->get_wake_reason() ) |
{ |
case Cyg_Thread::DESTRUCT: |
case Cyg_Thread::BREAK: |
result = false; |
break; |
|
case Cyg_Thread::EXIT: |
self->exit(); |
break; |
|
default: |
break; |
} |
|
} |
|
if( result ) state = false; |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
return result; |
} |
|
// ------------------------------------------------------------------------- |
|
cyg_bool Cyg_Binary_Semaphore::trywait() |
{ |
cyg_bool result = true; |
|
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
if( state ) state = false; |
else result = false; |
|
CYG_INSTRUMENT_BINSEM( TRY, this, result ); |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
return result; |
} |
|
// ------------------------------------------------------------------------- |
|
void Cyg_Binary_Semaphore::post() |
{ |
// Prevent preemption |
Cyg_Scheduler::lock(); |
|
CYG_INSTRUMENT_BINSEM( POST, this, 0 ); |
|
state = true; |
|
if( !queue.empty() ) { |
|
// The queue is non-empty, so grab the next |
// thread from it and wake it up. The waiter |
// will clear the flag. |
|
Cyg_Thread *thread = queue.dequeue(); |
|
thread->set_wake_reason( Cyg_Thread::DONE ); |
|
thread->wake(); |
|
CYG_INSTRUMENT_BINSEM( WAKE, this, thread ); |
} |
|
// Unlock the scheduler and maybe switch threads |
Cyg_Scheduler::unlock(); |
|
} |
|
// ------------------------------------------------------------------------- |
|
cyg_bool Cyg_Binary_Semaphore::posted() |
{ |
// This is a single read of the value of state. |
// This is already atomic, hence there is no need |
// to lock the scheduler. |
|
return state; |
} |
|
// ------------------------------------------------------------------------- |
// EOF sync/bin_sem.cxx |