comparison packages/kernel/current/src/sync/cnt_sem.cxx @ 0:3111d98ba7b3 ecos-v1_1-release

Initial commit of eCos version 1.1
author jlarmour
date Tue, 11 May 1999 11:16:07 +0000
parents
children 443894e2e912
comparison
equal deleted inserted replaced
-1:000000000000 0:3111d98ba7b3
1 //==========================================================================
2 //
3 // sync/cnt_sem.cxx
4 //
5 // Counting semaphore implementation
6 //
7 //==========================================================================
8 //####COPYRIGHTBEGIN####
9 //
10 // -------------------------------------------
11 // The contents of this file are subject to the Cygnus eCos Public License
12 // Version 1.0 (the "License"); you may not use this file except in
13 // compliance with the License. You may obtain a copy of the License at
14 // http://sourceware.cygnus.com/ecos
15 //
16 // Software distributed under the License is distributed on an "AS IS"
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
18 // License for the specific language governing rights and limitations under
19 // the License.
20 //
21 // The Original Code is eCos - Embedded Cygnus Operating System, released
22 // September 30, 1998.
23 //
24 // The Initial Developer of the Original Code is Cygnus. Portions created
25 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved.
26 // -------------------------------------------
27 //
28 //####COPYRIGHTEND####
29 //==========================================================================
30 //#####DESCRIPTIONBEGIN####
31 //
32 // Author(s): nickg
33 // Contributors: nickg
34 // Date: 1997-09-24
35 // Purpose: Cyg_Counting_Semaphore implementation
36 // Description: This file contains the implementations of the counting semaphore
37 // class.
38 //
39 //####DESCRIPTIONEND####
40 //
41 //==========================================================================
42
43 #include <pkgconf/kernel.h>
44
45 #include <cyg/kernel/ktypes.h> // base kernel types
46 #include <cyg/infra/cyg_trac.h> // tracing macros
47 #include <cyg/infra/cyg_ass.h> // assertion macros
48 #include <cyg/kernel/instrmnt.h> // instrumentation
49
50 #include <cyg/kernel/thread.inl> // Cyg_Thread inlines
51
52 #include <cyg/kernel/sema.hxx> // our header
53
54 #include <cyg/kernel/sched.inl> // scheduler inlines
55
56 // -------------------------------------------------------------------------
57 // Constructor
58
59 Cyg_Counting_Semaphore::Cyg_Counting_Semaphore(
60 cyg_count32 init_count // Initial count value
61 )
62 {
63 count = init_count;
64 }
65
66 // -------------------------------------------------------------------------
67 // Destructor
68
69 Cyg_Counting_Semaphore::~Cyg_Counting_Semaphore()
70 {
71 CYG_ASSERT( queue.empty(), "Destroying semaphore with waiting threads");
72 }
73
74 // -------------------------------------------------------------------------
75 // Wait until the count can be decremented without it becoming
76 // negative.
77
78 cyg_bool Cyg_Counting_Semaphore::wait()
79 {
80 cyg_bool result = true;
81 Cyg_Thread *self = Cyg_Thread::self();
82
83 // Prevent preemption
84 Cyg_Scheduler::lock();
85
86 CYG_INSTRUMENT_CNTSEM( CLAIM, this, count );
87
88 while( count == 0 && result )
89 {
90 self->set_sleep_reason( Cyg_Thread::WAIT );
91
92 self->sleep();
93
94 queue.enqueue( self );
95
96 CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 );
97
98 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1, "Called with non-zero scheduler lock");
99
100 Cyg_Scheduler::unlock();
101 Cyg_Scheduler::lock();
102
103 CYG_INSTRUMENT_CNTSEM( WOKE, this, count );
104
105 switch( self->get_wake_reason() )
106 {
107 case Cyg_Thread::DESTRUCT:
108 case Cyg_Thread::BREAK:
109 result = false;
110 break;
111
112 case Cyg_Thread::EXIT:
113 self->exit();
114 break;
115
116 default:
117 break;
118 }
119 }
120
121 if( result ) count--;
122
123 // Unlock the scheduler
124 Cyg_Scheduler::unlock();
125
126 return result;
127 }
128
129 // -------------------------------------------------------------------------
130 // Wait until the count can be decremented without it becoming
131 // negative.
132
133 #ifdef CYGFUN_KERNEL_THREADS_TIMER
134
135 cyg_bool
136 Cyg_Counting_Semaphore::wait( cyg_tick_count timeout )
137 {
138 cyg_bool result = true;
139 Cyg_Thread *self = Cyg_Thread::self();
140
141 // Prevent preemption
142 Cyg_Scheduler::lock();
143
144 CYG_INSTRUMENT_CNTSEM( CLAIM, this, count );
145
146 // Set the timer _once_ outside the loop.
147 self->set_timer( timeout, Cyg_Thread::TIMEOUT );
148
149 // If the timeout is in the past, the wake reason will have been
150 // set to something other than NONE already. Set the result false
151 // to force an immediate return.
152
153 if( self->get_wake_reason() != Cyg_Thread::NONE )
154 result = false;
155
156 while ( 0 == count && result ) {
157
158 // must reset the sleep reason every time
159 self->set_sleep_reason( Cyg_Thread::TIMEOUT );
160
161 self->sleep();
162
163 queue.enqueue( self );
164
165 CYG_INSTRUMENT_CNTSEM( WAIT, this, 0 );
166
167 CYG_ASSERT( Cyg_Scheduler::get_sched_lock() == 1,
168 "Called with non-zero scheduler lock");
169
170 Cyg_Scheduler::unlock();
171 Cyg_Scheduler::lock();
172
173 CYG_INSTRUMENT_CNTSEM( WOKE, this, count );
174
175 switch( self->get_wake_reason() )
176 {
177 case Cyg_Thread::TIMEOUT:
178 result = false;
179 CYG_INSTRUMENT_CNTSEM( TIMEOUT, this, count);
180 break;
181
182 case Cyg_Thread::DESTRUCT:
183 case Cyg_Thread::BREAK:
184 result = false;
185 break;
186
187 case Cyg_Thread::EXIT:
188 self->exit();
189 break;
190
191 default:
192 break;
193 }
194 }
195
196 // Clear the timeout. It is irrelevant whether the alarm has
197 // actually gone off or not.
198 self->clear_timer();
199
200 if ( result ) count--;
201
202 // Unlock the scheduler and maybe switch threads
203 Cyg_Scheduler::unlock();
204
205 return result;
206 }
207
208 #endif // CYGFUN_KERNEL_THREADS_TIMER
209
210 // -------------------------------------------------------------------------
211 // Try to decrement, but fail if not possible
212
213 cyg_bool Cyg_Counting_Semaphore::trywait()
214 {
215 cyg_bool result = true;
216
217 // Prevent preemption
218 Cyg_Scheduler::lock();
219
220 if( count > 0 ) count--;
221 else result = false;
222
223 CYG_INSTRUMENT_CNTSEM( TRY, this, result );
224
225 // Unlock the scheduler and maybe switch threads
226 Cyg_Scheduler::unlock();
227
228 return result;
229 }
230
231 // -------------------------------------------------------------------------
232 // Increment count
233
234 void Cyg_Counting_Semaphore::post()
235 {
236 // Prevent preemption
237 Cyg_Scheduler::lock();
238
239 CYG_INSTRUMENT_CNTSEM( POST, this, 0 );
240
241 count++;
242
243 if( !queue.empty() ) {
244
245 // The queue is non-empty, so grab the next
246 // thread from it and wake it up. The waiter
247 // will decrement the count when he is awakened.
248
249 Cyg_Thread *thread = queue.dequeue();
250
251 thread->set_wake_reason( Cyg_Thread::DONE );
252
253 thread->wake();
254
255 CYG_INSTRUMENT_CNTSEM( WAKE, this, thread );
256 }
257
258 // Unlock the scheduler and maybe switch threads
259 Cyg_Scheduler::unlock();
260 }
261
262 // -------------------------------------------------------------------------
263 // Get current count value
264
265 cyg_count32 Cyg_Counting_Semaphore::peek()
266 {
267 // This is a single read of the value of count.
268 // This is already atomic, hence there is no need
269 // to lock the scheduler.
270
271 return count;
272 }
273
274 // -------------------------------------------------------------------------
275 // EOF sync/cnt_sem.cxx