1 " |
1 " |
2 COPYRIGHT (c) 1993 by Claus Gittinger |
2 COPYRIGHT (c) 1993 by Claus Gittinger |
3 All Rights Reserved |
3 All Rights Reserved |
4 |
4 |
5 This software is furnished under a license and may be used |
5 This software is furnished under a license and may be used |
6 only in accordance with the terms of that license and with the |
6 only in accordance with the terms of that license and with the |
7 inclusion of the above copyright notice. This software may not |
7 inclusion of the above copyright notice. This software may not |
8 be provided or otherwise made available to, or used by, any |
8 be provided or otherwise made available to, or used by, any |
9 other person. No title to or ownership of the software is |
9 other person. No title to or ownership of the software is |
10 hereby transferred. |
10 hereby transferred. |
11 " |
11 " |
12 |
12 |
13 LinkedList subclass:#Semaphore |
13 LinkedList subclass:#Semaphore |
14 instanceVariableNames:'count waitingProcesses' |
14 instanceVariableNames:'count waitingProcesses' |
15 "/ instanceVariableNames:'count' |
15 "/ instanceVariableNames:'count' |
16 classVariableNames:'' |
16 classVariableNames:'' |
17 poolDictionaries:'' |
17 poolDictionaries:'' |
18 category:'Kernel-Processes'! |
18 category:'Kernel-Processes'! |
19 |
19 |
20 Semaphore comment:' |
20 Semaphore comment:' |
21 COPYRIGHT (c) 1993 by Claus Gittinger |
21 COPYRIGHT (c) 1993 by Claus Gittinger |
22 All Rights Reserved |
22 All Rights Reserved |
23 |
23 |
24 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.11 1994-08-05 00:59:40 claus Exp $ |
24 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.12 1994-10-10 00:28:02 claus Exp $ |
25 '! |
25 '! |
26 |
26 |
27 !Semaphore class methodsFor:'documentation'! |
27 !Semaphore class methodsFor:'documentation'! |
28 |
28 |
29 copyright |
29 copyright |
30 " |
30 " |
31 COPYRIGHT (c) 1993 by Claus Gittinger |
31 COPYRIGHT (c) 1993 by Claus Gittinger |
32 All Rights Reserved |
32 All Rights Reserved |
33 |
33 |
34 This software is furnished under a license and may be used |
34 This software is furnished under a license and may be used |
35 only in accordance with the terms of that license and with the |
35 only in accordance with the terms of that license and with the |
36 inclusion of the above copyright notice. This software may not |
36 inclusion of the above copyright notice. This software may not |
37 be provided or otherwise made available to, or used by, any |
37 be provided or otherwise made available to, or used by, any |
40 " |
40 " |
41 ! |
41 ! |
42 |
42 |
43 version |
43 version |
44 " |
44 " |
45 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.11 1994-08-05 00:59:40 claus Exp $ |
45 $Header: /cvs/stx/stx/libbasic/Semaphore.st,v 1.12 1994-10-10 00:28:02 claus Exp $ |
46 " |
46 " |
47 ! |
47 ! |
48 |
48 |
49 documentation |
49 documentation |
50 " |
50 " |
51 Semaphores are used to synchronize processes providing a nonBusy wait |
51 Semaphores are used to synchronize processes providing a nonBusy wait |
52 mechanism. A process can wait for the availability of some resource by |
52 mechanism. A process can wait for the availability of some resource by |
53 performing a Semaphore>>wait, which will suspend the process until the |
53 performing a Semaphore>>wait, which will suspend the process until the |
54 resource becomes available. Signalling is done by (another process performing) |
54 resource becomes available. Signalling is done by (another process performing) |
55 Semaphore>>signal. |
55 Semaphore>>signal. |
56 If the resource has been alrady available before the wait, no suspending is |
56 If the resource has been already available before the wait, no suspending is |
57 done, but the resource immediately allocated. |
57 done, but the resource immediately allocated. |
58 There are also semaphores for mutual access to a critical region |
58 There are also semaphores for mutual access to a critical region |
59 (Semaphore>>forMutualExclusion and Semaphore>>critical:). |
59 (Semaphore>>forMutualExclusion and Semaphore>>critical:). |
60 |
60 |
|
61 You can also attach semaphores to external events (such as I/O arrival or |
|
62 timer events. This is done by telling the Processor to signal the semaphore. |
|
63 See 'Processor>>signal:afterSeconds:', 'Processor>>signal:onInput:' etc. |
|
64 |
61 See examples in doc/coding. |
65 See examples in doc/coding. |
62 " |
66 " |
63 ! ! |
67 ! ! |
64 |
68 |
65 !Semaphore class methodsFor:'instance creation'! |
69 !Semaphore class methodsFor:'instance creation'! |
94 |
98 |
95 wait |
99 wait |
96 "wait for the semaphore" |
100 "wait for the semaphore" |
97 |
101 |
98 |current wasBlocked| |
102 |current wasBlocked| |
|
103 |
|
104 " |
|
105 this works only since interrupts are only serviced at |
|
106 message send and method-return time .... |
|
107 If you add a message send into the ifTrue:-block, things will |
|
108 go mad ... (especially be careful when adding a debugPrint-here) |
|
109 " |
|
110 count ~~ 0 ifTrue:[ |
|
111 count := count - 1. |
|
112 ^ self |
|
113 ]. |
|
114 |
|
115 wasBlocked := OperatingSystem blockInterrupts. |
|
116 |
|
117 current := Processor activeProcess. |
|
118 waitingProcesses isNil ifTrue:[ |
|
119 waitingProcesses := OrderedCollection with:current |
|
120 ] ifFalse:[ |
|
121 waitingProcesses add:current |
|
122 ]. |
|
123 "/ self add:current. |
99 |
124 |
100 " |
125 " |
101 need a while-loop here, since more than one process may |
126 need a while-loop here, since more than one process may |
102 wait for it and another one may also wake up. |
127 wait for it and another one may also wake up. |
103 Thus, the count is not always non-zero after returning from |
128 Thus, the count is not always non-zero after returning from |
104 suspend. |
129 suspend. |
105 " |
130 " |
106 |
131 [count == 0] whileTrue:[ |
107 " |
132 " |
108 this works only due to interrupts being serviced at message send |
133 for some more descriptive info in processMonitor ... |
109 and method-return time only .... |
134 (notice that state could already be #ioWait or #timeWait) |
|
135 " |
|
136 current setStateTo:#wait if:#active. |
|
137 Processor suspend:current |
|
138 ]. |
|
139 count := count - 1. |
|
140 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
|
141 ! |
|
142 |
|
143 waitWithTimeout:seconds |
|
144 "wait for the semaphore, but abort the wait after some time. |
|
145 return true if semaphore triggered normal, false if we return |
|
146 due to a timeout. With zero timeout, this can be used to poll |
|
147 a semaphore (which is not the intend of semaphores, though)." |
|
148 |
|
149 |current timeoutOccured wasBlocked unblock now endTime| |
|
150 |
|
151 " |
|
152 this works only since interrupts are only serviced at |
|
153 message send and method-return time .... |
|
154 If you add a message send into the ifTrue:-block, things will |
|
155 go mad ... (especially be careful when adding a debugPrint-here) |
110 " |
156 " |
111 count ~~ 0 ifTrue:[ |
157 count ~~ 0 ifTrue:[ |
112 count := count - 1. |
158 count := count - 1. |
113 ^ self |
159 ^ true |
|
160 ]. |
|
161 |
|
162 " |
|
163 with zero-timeout, this is a poll |
|
164 " |
|
165 seconds = 0 ifTrue:[ |
|
166 ^ false |
114 ]. |
167 ]. |
115 |
168 |
116 wasBlocked := OperatingSystem blockInterrupts. |
169 wasBlocked := OperatingSystem blockInterrupts. |
|
170 |
|
171 " |
|
172 calculate the end-time |
|
173 " |
|
174 now := OperatingSystem getMillisecondTime. |
|
175 endTime := OperatingSystem millisecondTimeAdd:now and:(seconds * 1000). |
|
176 |
|
177 current := Processor activeProcess. |
|
178 waitingProcesses isNil ifTrue:[ |
|
179 waitingProcesses := OrderedCollection with:current |
|
180 ] ifFalse:[ |
|
181 waitingProcesses add:current |
|
182 ]. |
|
183 "/ self add:current. |
|
184 |
|
185 unblock := [timeoutOccured := true. Processor resume:current]. |
|
186 Processor addTimedBlock:unblock for:current atMilliseconds:endTime. |
|
187 |
|
188 " |
|
189 need a while-loop here, since more than one process may |
|
190 wait for it and another one may also wake up. |
|
191 Thus, the count is not always non-zero after returning from |
|
192 suspend. |
|
193 " |
117 [count == 0] whileTrue:[ |
194 [count == 0] whileTrue:[ |
118 "/ (count == 0) ifTrue:[ |
195 " |
119 current := Processor activeProcess. |
196 for some more descriptive info in processMonitor ... |
120 waitingProcesses isNil ifTrue:[ |
197 (notice that state could already be #ioWait or #timeWait) |
121 waitingProcesses := OrderedCollection with:current |
198 " |
122 ] ifFalse:[ |
199 current setStateTo:#wait if:#active. |
123 waitingProcesses add:current |
200 |
124 ]. |
201 timeoutOccured := false. |
125 "/ self add:current. |
202 Processor suspend:current. |
126 " |
203 |
127 for some more info in processMonitor ... |
204 timeoutOccured ifTrue:[ |
128 " |
205 waitingProcesses remove:current ifAbsent:[]. |
129 current state == #active ifTrue:[ |
206 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
130 current state:#wait. |
207 ^ false |
131 ]. |
208 ]. |
132 Processor suspend:current |
209 ]. |
133 "/ ]. |
210 Processor removeTimedBlock:unblock. |
134 ]. |
|
135 count := count - 1. |
211 count := count - 1. |
136 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
212 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
|
213 ^ true |
137 ! |
214 ! |
138 |
215 |
139 signalOnce |
216 signalOnce |
140 "wakeup waiters - but only once. |
217 "wakeup waiters - but only once. |
141 I.e. if the receiver has already been signalled, this |
218 I.e. if the semaphore has already been signalled, this |
142 is ignored." |
219 is ignored." |
143 |
220 |
144 |wasBlocked| |
221 |wasBlocked| |
145 |
222 |
146 wasBlocked := OperatingSystem blockInterrupts. |
|
147 count == 0 ifTrue:[ |
223 count == 0 ifTrue:[ |
148 self signal |
224 wasBlocked := OperatingSystem blockInterrupts. |
149 ]. |
225 count == 0 ifTrue:[ |
150 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
226 self signal |
|
227 ]. |
|
228 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
|
229 ] |
151 ! |
230 ! |
152 |
231 |
153 signal |
232 signal |
154 "waking up (first) waiter" |
233 "waking up (first) waiter" |
155 |
234 |
156 |p wasBlocked| |
235 |p wasBlocked| |
157 |
236 |
158 wasBlocked := OperatingSystem blockInterrupts. |
237 wasBlocked := OperatingSystem blockInterrupts. |
159 count := count + 1. |
238 count := count + 1. |
160 (waitingProcesses notNil and:[waitingProcesses notEmpty]) ifTrue:[ |
239 (waitingProcesses notNil and:[waitingProcesses notEmpty]) ifTrue:[ |
161 p := waitingProcesses removeFirst. |
240 p := waitingProcesses removeFirst. |
162 "/ self isEmpty ifFalse:[ |
241 "/ self isEmpty ifFalse:[ |
163 "/ p := self removeFirst. |
242 "/ p := self removeFirst. |
164 |
243 |
165 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
244 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
166 p resume. |
245 p resume. |
167 ^ self |
246 ^ self |
168 ]. |
247 ]. |
169 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
248 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
170 ! |
249 ! |
171 |
250 |
172 critical:aBlock |
251 critical:aBlock |