]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/kernel/v2_0/src/sync/bin_sem.cxx
Initial revision
[karo-tx-redboot.git] / packages / kernel / v2_0 / src / sync / bin_sem.cxx
1 //==========================================================================
2 //
3 //      sync/bin_sem.cxx
4 //
5 //      Binary semaphore 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
45 // Date:        1997-09-24
46 // Purpose:     Cyg_Binary_Semaphore implementation
47 // Description: This file contains the implementations of the binary semaphore
48 //              class.
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54 #include <pkgconf/kernel.h>
55
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
60
61 #include <cyg/kernel/thread.inl>           // Cyg_Thread inlines
62
63 #include <cyg/kernel/sema.hxx>             // our header
64
65 #include <cyg/kernel/sched.inl>            // scheduler inlines
66
67 // -------------------------------------------------------------------------
68
69 Cyg_Binary_Semaphore::Cyg_Binary_Semaphore (
70     cyg_bool    init_state
71 )
72 {
73     state       = init_state;
74 }
75
76 // -------------------------------------------------------------------------
77
78 Cyg_Binary_Semaphore::~Cyg_Binary_Semaphore ( )
79 {
80     CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
81 }
82
83 // -------------------------------------------------------------------------
84
85 cyg_bool Cyg_Binary_Semaphore::wait()
86 {
87     cyg_bool result = true;
88     Cyg_Thread *self = Cyg_Thread::self();
89     
90     // Prevent preemption
91     Cyg_Scheduler::lock();
92
93     CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
94         
95     while( !state && result )
96     {
97         self->set_sleep_reason( Cyg_Thread::WAIT );
98         
99         self->sleep();
100         
101         queue.enqueue( self );
102
103         CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
104
105         // Allow other threads to run
106         Cyg_Scheduler::reschedule();
107
108         CYG_INSTRUMENT_BINSEM( WOKE, this, state );
109
110         switch( self->get_wake_reason() )
111         {
112         case Cyg_Thread::DESTRUCT:
113         case Cyg_Thread::BREAK:
114             result = false;
115             break;
116             
117         case Cyg_Thread::EXIT:            
118             self->exit();
119             break;
120
121         default:
122             break;
123         }
124         
125     }
126
127     if( result ) state = false;
128
129     // Unlock the scheduler and maybe switch threads
130     Cyg_Scheduler::unlock();
131
132     return result;
133 }
134
135 // -------------------------------------------------------------------------
136 // Wait until the state can be set false or timeout
137
138 #ifdef CYGFUN_KERNEL_THREADS_TIMER
139
140 cyg_bool
141 Cyg_Binary_Semaphore::wait( cyg_tick_count timeout )
142 {
143     cyg_bool result = true;
144     Cyg_Thread *self = Cyg_Thread::self();
145     
146     // Prevent preemption
147     Cyg_Scheduler::lock();
148
149     CYG_INSTRUMENT_BINSEM( CLAIM, this, state );
150         
151     // Set the timer _once_ outside the loop.
152     self->set_timer( timeout, Cyg_Thread::TIMEOUT  );
153
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.
158     
159     if( self->get_wake_reason() != Cyg_Thread::NONE && !state )
160         result = false;
161             
162     while ( !state && result ) {
163
164         // must reset the sleep reason every time
165         self->set_sleep_reason( Cyg_Thread::TIMEOUT );
166
167         self->sleep();
168
169         queue.enqueue( self );
170
171         CYG_INSTRUMENT_BINSEM( WAIT, this, 0 );
172
173         // Allow other threads to run
174         Cyg_Scheduler::reschedule();
175
176         CYG_INSTRUMENT_BINSEM( WOKE, this, state );
177
178         switch( self->get_wake_reason() )
179         {
180         case Cyg_Thread::TIMEOUT:
181             result = false;
182             CYG_INSTRUMENT_BINSEM( TIMEOUT, this, state);
183             break;
184             
185         case Cyg_Thread::DESTRUCT:
186         case Cyg_Thread::BREAK:
187             result = false;
188             break;
189             
190         case Cyg_Thread::EXIT:            
191             self->exit();
192             break;
193
194         default:
195             break;
196         }
197     }
198
199     // Clear the timeout. It is irrelevant whether the alarm has
200     // actually gone off or not.
201     self->clear_timer();
202         
203     if( result ) state = false;
204
205     // Unlock the scheduler and maybe switch threads
206     Cyg_Scheduler::unlock();
207
208     return result;
209 }
210
211 #endif // CYGFUN_KERNEL_THREADS_TIMER
212
213 // -------------------------------------------------------------------------
214
215 cyg_bool Cyg_Binary_Semaphore::trywait()
216 {
217     cyg_bool result = true;
218     
219     // Prevent preemption
220     Cyg_Scheduler::lock();
221
222     if( state ) state = false;
223     else        result = false;
224     
225     CYG_INSTRUMENT_BINSEM( TRY, this, result );
226     
227     // Unlock the scheduler and maybe switch threads
228     Cyg_Scheduler::unlock();
229     
230     return result;
231 }
232
233 // -------------------------------------------------------------------------
234
235 void Cyg_Binary_Semaphore::post()
236 {
237     // Prevent preemption
238     Cyg_Scheduler::lock();
239
240     CYG_INSTRUMENT_BINSEM( POST, this, 0 );
241         
242     state = true;
243         
244     if( !queue.empty() ) {
245
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.
249
250         Cyg_Thread *thread = queue.dequeue();
251
252         thread->set_wake_reason( Cyg_Thread::DONE );
253         
254         thread->wake();
255
256         CYG_INSTRUMENT_BINSEM( WAKE, this, thread );
257     }
258     
259     // Unlock the scheduler and maybe switch threads
260     Cyg_Scheduler::unlock();
261     
262 }
263
264 // -------------------------------------------------------------------------
265
266 cyg_bool Cyg_Binary_Semaphore::posted()
267 {
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.
271     
272     return state;
273 }
274
275 // -------------------------------------------------------------------------
276 // EOF sync/bin_sem.cxx