1 //==========================================================================
5 // Binary semaphore 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
46 // Purpose: Cyg_Binary_Semaphore implementation
47 // Description: This file contains the implementations of the binary semaphore
50 //####DESCRIPTIONEND####
52 //==========================================================================
54 #include <pkgconf/kernel.h>
56 #include <cyg/kernel/ktypes.h> // base kernel types
57 #include <cyg/infra/cyg_trac.h> // tracing macros
58 #include <cyg/infra/cyg_ass.h> // assertion macros
59 #include <cyg/kernel/instrmnt.h> // instrumentation
61 #include <cyg/kernel/thread.inl> // Cyg_Thread inlines
63 #include <cyg/kernel/sema.hxx> // our header
65 #include <cyg/kernel/sched.inl> // scheduler inlines
67 // -------------------------------------------------------------------------
69 Cyg_Binary_Semaphore::Cyg_Binary_Semaphore (
76 // -------------------------------------------------------------------------
78 Cyg_Binary_Semaphore::~Cyg_Binary_Semaphore ( )
80 CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
83 // -------------------------------------------------------------------------
85 cyg_bool Cyg_Binary_Semaphore::wait()
87 cyg_bool result = true;
88 Cyg_Thread *self = Cyg_Thread::self();
91 Cyg_Scheduler::lock();
93 CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
95 while( !state && result )
97 self->set_sleep_reason( Cyg_Thread::WAIT );
101 queue.enqueue( self );
103 CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
105 // Allow other threads to run
106 Cyg_Scheduler::reschedule();
108 CYG_INSTRUMENT_BINSEM( WOKE, this, state );
110 switch( self->get_wake_reason() )
112 case Cyg_Thread::DESTRUCT:
113 case Cyg_Thread::BREAK:
117 case Cyg_Thread::EXIT:
127 if( result ) state = false;
129 // Unlock the scheduler and maybe switch threads
130 Cyg_Scheduler::unlock();
135 // -------------------------------------------------------------------------
136 // Wait until the state can be set false or timeout
138 #ifdef CYGFUN_KERNEL_THREADS_TIMER
141 Cyg_Binary_Semaphore::wait( cyg_tick_count timeout )
143 cyg_bool result = true;
144 Cyg_Thread *self = Cyg_Thread::self();
146 // Prevent preemption
147 Cyg_Scheduler::lock();
149 CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
151 // Set the timer _once_ outside the loop.
152 self->set_timer( timeout, Cyg_Thread::TIMEOUT );
154 // If the timeout is in the past, the wake reason will have been
155 // set to something other than NONE already. If the semaphore is
156 // not available, set the result false to force an immediate
157 // return. If it is available, then go ahead and claim it.
159 if( self->get_wake_reason() != Cyg_Thread::NONE && !state )
162 while ( !state && result ) {
164 // must reset the sleep reason every time
165 self->set_sleep_reason( Cyg_Thread::TIMEOUT );
169 queue.enqueue( self );
171 CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
173 // Allow other threads to run
174 Cyg_Scheduler::reschedule();
176 CYG_INSTRUMENT_BINSEM( WOKE, this, state );
178 switch( self->get_wake_reason() )
180 case Cyg_Thread::TIMEOUT:
182 CYG_INSTRUMENT_BINSEM( TIMEOUT, this, state);
185 case Cyg_Thread::DESTRUCT:
186 case Cyg_Thread::BREAK:
190 case Cyg_Thread::EXIT:
199 // Clear the timeout. It is irrelevant whether the alarm has
200 // actually gone off or not.
203 if( result ) state = false;
205 // Unlock the scheduler and maybe switch threads
206 Cyg_Scheduler::unlock();
211 #endif // CYGFUN_KERNEL_THREADS_TIMER
213 // -------------------------------------------------------------------------
215 cyg_bool Cyg_Binary_Semaphore::trywait()
217 cyg_bool result = true;
219 // Prevent preemption
220 Cyg_Scheduler::lock();
222 if( state ) state = false;
225 CYG_INSTRUMENT_BINSEM( TRY, this, result );
227 // Unlock the scheduler and maybe switch threads
228 Cyg_Scheduler::unlock();
233 // -------------------------------------------------------------------------
235 void Cyg_Binary_Semaphore::post()
237 // Prevent preemption
238 Cyg_Scheduler::lock();
240 CYG_INSTRUMENT_BINSEM( POST, this, 0 );
244 if( !queue.empty() ) {
246 // The queue is non-empty, so grab the next
247 // thread from it and wake it up. The waiter
248 // will clear the flag.
250 Cyg_Thread *thread = queue.dequeue();
252 thread->set_wake_reason( Cyg_Thread::DONE );
256 CYG_INSTRUMENT_BINSEM( WAKE, this, thread );
259 // Unlock the scheduler and maybe switch threads
260 Cyg_Scheduler::unlock();
264 // -------------------------------------------------------------------------
266 cyg_bool Cyg_Binary_Semaphore::posted()
268 // This is a single read of the value of state.
269 // This is already atomic, hence there is no need
270 // to lock the scheduler.
275 // -------------------------------------------------------------------------
276 // EOF sync/bin_sem.cxx