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 Object subclass:#ProcessorScheduler |
13 Object subclass:#ProcessorScheduler |
14 instanceVariableNames:'quiescentProcessLists scheduler |
14 instanceVariableNames:'quiescentProcessLists scheduler |
15 zombie |
15 zombie |
16 activeProcess currentPriority |
16 activeProcess currentPriority |
17 readFds readSemaphores readChecks |
17 readFds readSemaphores readChecks |
18 writeFds writeSemaphores |
18 writeFds writeSemaphores |
19 timeouts timeoutActions timeoutProcesses timeoutSemaphores |
19 timeouts timeoutActions timeoutProcesses timeoutSemaphores |
20 idleActions anyTimeouts dispatching' |
20 idleActions anyTimeouts dispatching' |
21 classVariableNames:'KnownProcesses KnownProcessIds |
21 classVariableNames:'KnownProcesses KnownProcessIds |
22 PureEventDriven |
22 PureEventDriven |
23 UserSchedulingPriority |
23 UserSchedulingPriority |
24 UserInterruptPriority |
24 UserInterruptPriority |
25 TimingPriority |
25 TimingPriority |
26 SchedulingPriority' |
26 SchedulingPriority' |
27 poolDictionaries:'' |
27 poolDictionaries:'' |
28 category:'Kernel-Processes' |
28 category:'Kernel-Processes' |
29 ! |
29 ! |
30 |
30 |
31 ProcessorScheduler comment:' |
31 ProcessorScheduler comment:' |
32 COPYRIGHT (c) 1993 by Claus Gittinger |
32 COPYRIGHT (c) 1993 by Claus Gittinger |
33 All Rights Reserved |
33 All Rights Reserved |
34 |
34 |
35 $Header: /cvs/stx/stx/libbasic/Attic/ProcSched.st,v 1.20 1994-08-23 23:11:00 claus Exp $ |
35 $Header: /cvs/stx/stx/libbasic/Attic/ProcSched.st,v 1.21 1994-10-10 00:27:28 claus Exp $ |
36 '! |
36 '! |
37 |
37 |
38 Smalltalk at:#Processor put:nil! |
38 Smalltalk at:#Processor put:nil! |
39 |
39 |
40 !ProcessorScheduler class methodsFor:'documentation'! |
40 !ProcessorScheduler class methodsFor:'documentation'! |
41 |
41 |
42 copyright |
42 copyright |
43 " |
43 " |
44 COPYRIGHT (c) 1993 by Claus Gittinger |
44 COPYRIGHT (c) 1993 by Claus Gittinger |
45 All Rights Reserved |
45 All Rights Reserved |
46 |
46 |
47 This software is furnished under a license and may be used |
47 This software is furnished under a license and may be used |
48 only in accordance with the terms of that license and with the |
48 only in accordance with the terms of that license and with the |
49 inclusion of the above copyright notice. This software may not |
49 inclusion of the above copyright notice. This software may not |
50 be provided or otherwise made available to, or used by, any |
50 be provided or otherwise made available to, or used by, any |
65 'Processor'. It is responsible for scheduling among the smalltalk |
65 'Processor'. It is responsible for scheduling among the smalltalk |
66 processes (threads; not to confuse with heavy weight unix processes). |
66 processes (threads; not to confuse with heavy weight unix processes). |
67 |
67 |
68 Scheduling is fully done in smalltalk (the always runnable scheduler- |
68 Scheduling is fully done in smalltalk (the always runnable scheduler- |
69 process, running at highest priority does this). |
69 process, running at highest priority does this). |
70 The main primitive support is used in threadSwitch, which passes |
70 The main primitive to support this is found in threadSwitch, which passes |
71 control to another process (usually selected by the scheduler). |
71 control to another process (usually selected by the scheduler). |
72 Thus it is possible to modify the schedulers policy. |
72 Thus it is possible to modify the schedulers policy and implementation |
|
73 at the smalltalk level. |
73 (To answer a frequently asked question: |
74 (To answer a frequently asked question: |
74 dont add preemtive round-robin here; this can be implemented without |
75 dont add preemptive round-robin here; this can be implemented without |
75 any need to change the scheduler. See goodies/timeslicing.st for how |
76 any need to change the scheduler. See goodies/timeslicing.st for how |
76 this is done in a very elegant way). |
77 this is done in a very elegant way). |
77 |
78 |
78 Notice: Smalltalk/X can (still) be compiled & configured without |
79 Notice: Smalltalk/X can (still) be compiled & configured without |
79 process support. This non-process mode is called 'pureEventDriven' mode |
80 process support. This non-process mode is called 'pureEventDriven' mode |
86 |
87 |
87 This pure-event mode may not be supported in the future. |
88 This pure-event mode may not be supported in the future. |
88 |
89 |
89 class variables: |
90 class variables: |
90 |
91 |
91 KnownProcesses <Collection> all known processes |
92 KnownProcesses <Collection> all known processes |
92 KnownProcessIds <Collection> and their IDs |
93 KnownProcessIds <Collection> and their IDs |
93 PureEventDriven <Boolean> true, if no process support |
94 PureEventDriven <Boolean> true, if no process support |
94 is available |
95 is available |
95 UserSchedulingPriority <Integer> the priority at which normal |
96 UserSchedulingPriority <Integer> the priority at which normal |
96 user interfaces run |
97 user interfaces run |
97 UserInterruptPriority the priority at which user- |
98 UserInterruptPriority the priority at which user- |
98 interrupts (Cntl-C) processing |
99 interrupts (Cntl-C) processing |
99 takes place. Processes with |
100 takes place. Processes with |
100 a greater or equal priority are |
101 a greater or equal priority are |
101 not interruptable. |
102 not interruptable. |
102 TimingPriority the priority used for timing. |
103 TimingPriority the priority used for timing. |
103 Processes with a greater or |
104 Processes with a greater or |
104 equal priority are not interrupted |
105 equal priority are not interrupted |
105 by timers. |
106 by timers. |
106 SchedulingPriority The priority of the scheduler (must |
107 SchedulingPriority The priority of the scheduler (must |
107 me higher than any other). |
108 me higher than any other). |
108 |
109 |
109 |
110 |
110 most interresting methods: |
111 most interresting methods: |
111 |
112 |
112 Processor>>suspend: (see also Process>>suspend) |
113 Processor>>suspend: (see also Process>>suspend) |
113 Processor>>resume: (see also Process>>resume) |
114 Processor>>resume: (see also Process>>resume) |
114 Processor>>terminate: (see also Process>>terminate) |
115 Processor>>terminate: (see also Process>>terminate) |
115 Processor>>yield |
116 Processor>>yield |
116 Processor>>changePriority:for: (see also Process>>priority: |
117 Processor>>changePriority:for: (see also Process>>priority: |
117 |
118 |
118 Processor>>signal:afterSeconds: (see also Delay>>forSeconds:) |
119 Processor>>signal:afterSeconds: (see also Delay>>forSeconds:) |
119 Processor>>signal:afterMilliseconds: (see also Delay>>forMilliseconds:) |
120 Processor>>signal:afterMilliseconds: (see also Delay>>forMilliseconds:) |
120 Processor>>signal:onInput: (see also ExternalStream>>readWait) |
121 Processor>>signal:onInput: (see also ExternalStream>>readWait) |
121 Processor>>signal:onOutput: (see also ExternalStream>>writeWait) |
122 Processor>>signal:onOutput: (see also ExternalStream>>writeWait) |
122 Processor>>disableSemaphore: |
123 Processor>>disableSemaphore: |
123 " |
124 " |
124 ! ! |
125 ! ! |
125 |
126 |
126 !ProcessorScheduler class methodsFor:'initialization'! |
127 !ProcessorScheduler class methodsFor:'initialization'! |
127 |
128 |
132 UserSchedulingPriority := 8. |
133 UserSchedulingPriority := 8. |
133 UserInterruptPriority := 24. |
134 UserInterruptPriority := 24. |
134 TimingPriority := 16. |
135 TimingPriority := 16. |
135 SchedulingPriority := 31. |
136 SchedulingPriority := 31. |
136 |
137 |
137 KnownProcesses isNil ifTrue:[ |
|
138 KnownProcesses := WeakArray new:10. |
|
139 KnownProcesses watcher:self. |
|
140 KnownProcessIds := OrderedCollection new. |
|
141 |
|
142 "want to get informed when returning from snapshot" |
|
143 ObjectMemory addDependent:self |
|
144 ]. |
|
145 |
|
146 Processor isNil ifTrue:[ |
138 Processor isNil ifTrue:[ |
147 "create the one and only processor" |
139 "create the one and only processor" |
148 |
140 |
149 Processor := self new. |
141 Processor := self basicNew initialize. |
150 ]. |
142 ]. |
151 |
143 |
152 " |
144 " |
153 allow configurations without processes |
145 allow configurations without processes |
154 " |
146 " |
155 PureEventDriven := self threadsAvailable not. |
147 PureEventDriven := self threadsAvailable not. |
156 PureEventDriven ifTrue:[ |
148 PureEventDriven ifTrue:[ |
157 'no process support - running event driven' errorPrintNL |
149 'no process support - running event driven' errorPrintNL |
158 ]. |
150 ]. |
159 ! |
|
160 |
|
161 update:something |
|
162 "being a dependent of the ObjectMemory, this is the notification |
|
163 that something happened" |
|
164 |
|
165 something == #restarted ifTrue:[ |
|
166 self reinstallProcesses |
|
167 ] |
|
168 ! |
|
169 |
|
170 reinstallProcesses |
|
171 "recreate all processes after a snapShot load. |
|
172 This is currently not implemented (and might never be). |
|
173 All we could do is to restart the processes. Time will show." |
|
174 |
|
175 KnownProcesses do:[:p | |
|
176 p notNil ifTrue:[ |
|
177 "how, exactly should this be done ?" |
|
178 |
|
179 p id ~~ 0 ifTrue:[ |
|
180 'process restart not implemented' errorPrintNL |
|
181 ] |
|
182 ] |
|
183 ] |
|
184 ! ! |
151 ! ! |
185 |
152 |
186 !ProcessorScheduler class methodsFor:'instance creation'! |
153 !ProcessorScheduler class methodsFor:'instance creation'! |
187 |
154 |
188 new |
155 new |
189 "there is (currently) only one processor ..." |
156 "there is (currently) only one processor ..." |
190 |
157 |
191 Processor isNil ifTrue:[ |
158 self error:'only one processor is allowed in the system' |
192 Processor := self basicNew initialize |
|
193 ]. |
|
194 ^ Processor. |
|
195 ! ! |
159 ! ! |
196 |
160 |
197 !ProcessorScheduler class methodsFor:'instance release'! |
161 !ProcessorScheduler class methodsFor:'instance release'! |
198 |
162 |
199 informDispose |
163 informDispose |
200 "some Process has been collected - terminate the underlying thread" |
164 "some Process has been garbage collected |
|
165 - terminate the underlying thread. Usually this does not happen, |
|
166 but the thread terminates itself by using #terminate." |
201 |
167 |
202 |id sz "{ Class: SmallInteger }"| |
168 |id sz "{ Class: SmallInteger }"| |
203 |
169 |
204 sz := KnownProcessIds size. |
170 sz := KnownProcessIds size. |
205 1 to:sz do:[:index | |
171 1 to:sz do:[:index | |
206 (KnownProcesses at:index) isNil ifTrue:[ |
172 (KnownProcesses at:index) isNil ifTrue:[ |
207 id := KnownProcessIds at:index. |
173 id := KnownProcessIds at:index. |
208 id notNil ifTrue:[ |
174 id notNil ifTrue:[ |
209 Transcript showCr:('terminate thread ', |
175 'PROCESSOR: terminating thread ' errorPrint. |
210 id printString, |
176 id errorPrint. |
211 ' (no longer refd)'). |
177 ' (no longer refd)' errorPrintNL. |
212 self threadDestroy:id. |
178 |
213 KnownProcessIds at:index put:nil. |
179 self threadDestroy:id. |
214 ] |
180 KnownProcessIds at:index put:nil. |
215 ] |
181 ] |
|
182 ] |
216 ] |
183 ] |
217 ! ! |
184 ! ! |
218 |
185 |
219 !ProcessorScheduler class methodsFor:'queries'! |
186 !ProcessorScheduler class methodsFor:'queries'! |
220 |
187 |
268 "make the process evaluate an interrupt" |
235 "make the process evaluate an interrupt" |
269 |
236 |
270 %{ /* NOCONTEXT */ |
237 %{ /* NOCONTEXT */ |
271 |
238 |
272 if (_isSmallInteger(id)) { |
239 if (_isSmallInteger(id)) { |
273 __threadInterrupt(_intVal(id)); |
240 __threadInterrupt(_intVal(id)); |
274 } |
241 } |
275 %} |
242 %} |
276 ! |
243 ! |
277 |
244 |
278 threadCreate:aBlock |
245 threadCreate:aProcess |
279 "physical creation of a process executing aBlock. |
246 "physical creation of a process. |
280 (warning: low level entry, no administration done). |
247 (warning: low level entry, no administration done). |
281 This may return nil, if process could not be created." |
248 This may return nil, if process could not be created." |
282 |
249 |
283 %{ /* NOCONTEXT */ |
250 %{ /* NOCONTEXT */ |
284 int tid; |
251 int tid; |
285 extern int __threadCreate(); |
252 extern int __threadCreate(); |
286 |
253 |
287 tid = __threadCreate(aBlock, 0 /* stackSize no longer needed */); |
254 tid = __threadCreate(aProcess, 0 /* stackSize no longer needed */); |
288 if (tid != 0) { |
255 if (tid != 0) { |
289 RETURN ( _MKSMALLINT(tid)); |
256 RETURN ( _MKSMALLINT(tid)); |
290 } |
257 } |
291 %} |
258 %} |
292 . |
259 . |
293 " |
260 " |
294 arrive here, if creation of process in VM failed. |
261 arrive here, if creation of process in VM failed. |
295 (no memory for process) |
262 This may happen, if the VM does not support more processes, |
|
263 or if it ran out of memory, when allocating internal data |
|
264 structures. |
296 " |
265 " |
297 ^ ObjectMemory allocationFailureSignal raise. |
266 ^ ObjectMemory allocationFailureSignal raise. |
298 ! |
267 ! |
299 |
268 |
300 threadDestroy:id |
269 threadDestroy:id |
315 "continue execution in aProcess. |
284 "continue execution in aProcess. |
316 (warning: low level entry, no administration is done here)" |
285 (warning: low level entry, no administration is done here)" |
317 |
286 |
318 |id pri ok oldProcess oldPri p singleStep wasBlocked| |
287 |id pri ok oldProcess oldPri p singleStep wasBlocked| |
319 |
288 |
320 aProcess isNil ifTrue:[^ self]. |
289 (aProcess isNil or:[aProcess == activeProcess]) ifTrue:[^ self]. |
321 aProcess == activeProcess ifTrue:[^ self]. |
|
322 |
290 |
323 wasBlocked := OperatingSystem blockInterrupts. |
291 wasBlocked := OperatingSystem blockInterrupts. |
324 |
292 |
325 oldProcess := activeProcess. |
293 oldProcess := activeProcess. |
326 oldPri := currentPriority. |
294 oldPri := currentPriority. |
327 |
295 |
328 id := aProcess id. |
296 id := aProcess id. |
329 pri := aProcess priority. |
297 pri := aProcess priority. |
330 singleStep := aProcess isSingleStepping. |
298 singleStep := aProcess isSingleStepping. |
331 aProcess state:#active. |
299 aProcess state:#active. |
332 oldProcess state == #active ifTrue:[ |
300 oldProcess setStateTo:#run if:#active. |
333 oldProcess state:#run. |
|
334 ]. |
|
335 |
301 |
336 "no interrupts now - activeProcess has already been changed |
302 "no interrupts now - activeProcess has already been changed |
337 (dont add any message sends here)" |
303 (dont add any message sends here)" |
338 activeProcess := aProcess. |
304 activeProcess := aProcess. |
339 currentPriority := pri. |
305 currentPriority := pri. |
340 %{ |
306 %{ |
341 extern OBJ __threadSwitch(), __threadSwitchWithSingleStep(); |
307 extern OBJ __threadSwitch(), __threadSwitchWithSingleStep(); |
342 |
308 |
343 if (singleStep == true) |
309 if (singleStep == true) |
344 ok = __threadSwitchWithSingleStep(__context, _intVal(id)); |
310 ok = __threadSwitchWithSingleStep(__context, _intVal(id)); |
345 else |
311 else |
346 ok = __threadSwitch(__context, _intVal(id)); |
312 ok = __threadSwitch(__context, _intVal(id)); |
347 %}. |
313 %}. |
348 "time passes ... |
314 "time passes ... |
349 ... here again" |
315 ... here again" |
350 |
316 |
351 ok ifFalse:[ |
317 ok ifFalse:[ |
352 " |
318 " |
353 switch failed for some reason - |
319 switch failed for some reason - |
354 destroy the bad process |
320 destroy the bad process |
355 " |
321 " |
356 p := activeProcess. |
322 p := activeProcess. |
357 activeProcess := oldProcess. |
323 activeProcess := oldProcess. |
358 currentPriority := oldPri. |
324 currentPriority := oldPri. |
359 p id ~~ 0 ifTrue:[ |
325 p id ~~ 0 ifTrue:[ |
360 p state:#suspended. |
326 'process switch failed' errorPrintNL. |
361 p terminate. |
327 p state:#suspended. |
362 ] |
328 self terminateNoSignal:p. |
|
329 ] |
363 ]. |
330 ]. |
364 zombie notNil ifTrue:[ |
331 zombie notNil ifTrue:[ |
365 self class threadDestroy:zombie. |
332 self class threadDestroy:zombie. |
366 zombie := nil |
333 zombie := nil |
367 ]. |
334 ]. |
368 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
335 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
369 ! |
336 ! |
370 |
337 |
371 scheduleForInterrupt:aProcess |
338 scheduleForInterrupt:aProcess |
518 |
501 |
519 wasBlocked := OperatingSystem blockInterrupts. |
502 wasBlocked := OperatingSystem blockInterrupts. |
520 index := 1. |
503 index := 1. |
521 sz := KnownProcessIds size. |
504 sz := KnownProcessIds size. |
522 [index <= sz] whileTrue:[ |
505 [index <= sz] whileTrue:[ |
523 (KnownProcesses at:index) isNil ifTrue:[ |
506 (KnownProcesses at:index) isNil ifTrue:[ |
524 oldId := KnownProcessIds at:index. |
507 oldId := KnownProcessIds at:index. |
525 oldId notNil ifTrue:[ |
508 oldId notNil ifTrue:[ |
526 self class threadDestroy:oldId. |
509 self class threadDestroy:oldId. |
527 ]. |
510 ]. |
528 KnownProcesses at:index put:aProcess. |
511 KnownProcesses at:index put:aProcess. |
529 KnownProcessIds at:index put:aProcess id. |
512 KnownProcessIds at:index put:aProcess id. |
530 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
513 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
531 ^ self |
514 ^ self |
532 ]. |
515 ]. |
533 index := index + 1 |
516 index := index + 1 |
534 ]. |
517 ]. |
535 |
518 |
536 KnownProcessIds grow:index. |
519 KnownProcessIds grow:index. |
537 KnownProcessIds at:index put:aProcess id. |
520 KnownProcessIds at:index put:aProcess id. |
538 |
521 |
539 oldSize := KnownProcesses size. |
522 oldSize := KnownProcesses size. |
540 (index > oldSize) ifTrue:[ |
523 (index > oldSize) ifTrue:[ |
541 newShadow := WeakArray new:(oldSize * 2). |
524 newShadow := WeakArray new:(oldSize * 2). |
542 newShadow watcher:self class. |
525 newShadow watcher:self class. |
543 newShadow replaceFrom:1 with:KnownProcesses. |
526 newShadow replaceFrom:1 with:KnownProcesses. |
544 KnownProcesses := newShadow |
527 KnownProcesses := newShadow |
545 ]. |
528 ]. |
546 KnownProcesses at:index put:aProcess. |
529 KnownProcesses at:index put:aProcess. |
547 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
530 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
548 ! |
531 ! |
549 |
532 |
553 |index wasBlocked| |
536 |index wasBlocked| |
554 |
537 |
555 wasBlocked := OperatingSystem blockInterrupts. |
538 wasBlocked := OperatingSystem blockInterrupts. |
556 index := KnownProcesses identityIndexOf:aProcess. |
539 index := KnownProcesses identityIndexOf:aProcess. |
557 index ~~ 0 ifTrue:[ |
540 index ~~ 0 ifTrue:[ |
558 KnownProcessIds at:index put:nil. |
541 KnownProcessIds at:index put:nil. |
559 KnownProcesses at:index put:nil. |
542 KnownProcesses at:index put:nil. |
560 ]. |
543 ]. |
561 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
544 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
562 ! ! |
545 ! ! |
563 |
546 |
564 !ProcessorScheduler methodsFor:'process creation'! |
547 !ProcessorScheduler methodsFor:'process creation'! |
565 |
548 |
566 newProcessFor:aBlock |
549 newProcessFor:aProcess |
567 "create a new process executing aBlock. |
550 "create a physical (VM-) process for aProcess. |
568 Return a process (or nil if fail). The new process is not scheduled. |
551 Return true if ok, false if something went wrong. |
569 To start it running, it needs a Process>>resume." |
552 The process is not scheduled; to start it running, it needs a Process>>resume." |
570 |
553 |
571 |id p| |
554 |id| |
572 |
555 |
573 id := self class threadCreate:aBlock. |
556 id := self class threadCreate:aProcess. |
574 id isNil ifTrue:[ |
557 id isNil ifTrue:[^ false]. |
575 " |
558 |
576 this may happen, if the VM does not support more processes, |
559 aProcess setId:id state:#light. "meaning: has no stack yet" |
577 or if it ran out of memory, when allocating internal data |
560 self remember:aProcess. |
578 structures |
561 ^ true |
579 " |
|
580 self error:'cannot create new Process'. |
|
581 ^ nil |
|
582 ]. |
|
583 p := Process new. |
|
584 p setId:id. |
|
585 p startBlock:aBlock. |
|
586 p state:#light. "meaning: has no stack yet" |
|
587 p setPriority:currentPriority. |
|
588 " |
|
589 give it a user-friendly name |
|
590 " |
|
591 activeProcess name notNil ifTrue:[ |
|
592 p name:(activeProcess name , ' (sub)') |
|
593 ]. |
|
594 self remember:p. |
|
595 ^ p |
|
596 ! ! |
562 ! ! |
597 |
563 |
598 !ProcessorScheduler methodsFor:'scheduling'! |
564 !ProcessorScheduler methodsFor:'scheduling'! |
599 |
565 |
600 reschedule |
566 reschedule |
601 "switch to the highest prio runnable process |
567 "switch to the highest prio runnable process. |
602 The scheduler itself is always runnable, so there is always a switch. |
568 The scheduler itself is always runnable, so we can do an unconditional switch |
603 (if you want to implement your own scheduler stuff, uncomment below)" |
569 to that one. This method is a historical left-over and will vanish." |
604 |
570 |
605 ^ self threadSwitch:scheduler |
571 ^ self threadSwitch:scheduler |
606 |
|
607 "/ |l p maxPri "{ Class: SmallInteger }"| |
|
608 "/ |
|
609 "/ maxPri := SchedulingPriority. |
|
610 "/ maxPri to:1 by:-1 do:[:prio | |
|
611 "/ l := quiescentProcessLists at:prio. |
|
612 "/ l notNil ifTrue:[ |
|
613 "/ p := l first. |
|
614 "/ p notNil ifTrue:[ |
|
615 "/ activeProcess state == #active ifTrue:[ |
|
616 "/ activeProcess state:#run. |
|
617 "/ ]. |
|
618 "/ ^ self threadSwitch:p |
|
619 "/ ]. |
|
620 "/ quiescentProcessLists at:prio put:nil |
|
621 "/ ] |
|
622 "/ ]. |
|
623 "/ " |
|
624 "/ no process to run - this 'cannot' happen |
|
625 "/ (well, not quite: it may happen if the scheduler process is |
|
626 "/ suspended - which btw. should be avoided, since noone is there |
|
627 "/ to schedule processes then) |
|
628 "/ " |
|
629 "/ |
|
630 "/ MiniDebugger enterWithMessage:'fatal dispatcher should never be suspended'. |
|
631 "/ |
|
632 "/ "try to repair by just resuming ..." |
|
633 "/ activeProcess resume |
|
634 ! |
572 ! |
635 |
573 |
636 yield |
574 yield |
637 "move the currently running process to the end of the currentList |
575 "move the currently running process to the end of the currentList |
638 and reschedule to the first in the list, thus switching to the |
576 and reschedule to the first in the list, thus switching to the |
710 |
649 |
711 " |
650 " |
712 debugging consisteny checks - will be removed later |
651 debugging consisteny checks - will be removed later |
713 " |
652 " |
714 l isNil ifTrue:[ |
653 l isNil ifTrue:[ |
715 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
654 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
716 |
655 |
717 'bad suspend: empty run list' printNL. |
656 'bad suspend: empty run list' printNL. |
718 "/ MiniDebugger enterWithMessage:'bad suspend: empty run list'. |
657 "/ MiniDebugger enterWithMessage:'bad suspend: empty run list'. |
719 self reschedule. |
658 self threadSwitch:scheduler. |
720 ^ self |
659 ^ self |
721 ]. |
660 ]. |
722 |
661 |
723 l remove:aProcess ifAbsent:[ |
662 l remove:aProcess ifAbsent:[ |
724 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
663 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
725 MiniDebugger enterWithMessage:'bad suspend: not on run list'. |
664 'bad suspend: not on run list' printNL. |
726 ^ self |
665 "/ MiniDebugger enterWithMessage:'bad suspend: not on run list'. |
|
666 self threadSwitch:scheduler. |
|
667 ^ self |
727 ]. |
668 ]. |
728 |
669 |
729 l isEmpty ifTrue:[ |
670 l isEmpty ifTrue:[ |
730 quiescentProcessLists at:pri put:nil. |
671 quiescentProcessLists at:pri put:nil. |
731 l := nil |
672 l := nil |
732 ]. |
673 ]. |
733 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
674 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
734 |
675 |
735 " |
676 " |
736 this is a bit of a kludge: allow someone else to |
677 this is a bit of a kludge: allow someone else to |
737 set the state to something like ioWait etc. |
678 set the state to something like #ioWait etc. |
738 In this case, do not set to suspend. |
679 In this case, do not set to #suspend. |
739 All of this to enhance the output of the process monitor ... |
680 All of this to enhance the output of the process monitor ... |
740 " |
681 " |
741 s := aProcess state. |
682 aProcess setStateTo:#suspended if:#active or:#run. |
742 ((s == #active) or:[s == #run]) ifTrue:[ |
683 |
743 aProcess state:#suspended. |
|
744 ]. |
|
745 (aProcess == activeProcess) ifTrue:[ |
684 (aProcess == activeProcess) ifTrue:[ |
746 "we can immediately switch sometimes" |
685 "we can immediately switch sometimes" |
747 l notNil ifTrue:[ |
686 l notNil ifTrue:[ |
748 p := l first |
687 p := l first |
749 ] ifFalse:[ |
688 ] ifFalse:[ |
750 p := scheduler |
689 p := scheduler |
751 ]. |
690 ]. |
752 self threadSwitch:p |
691 self threadSwitch:p |
753 "/ self reschedule |
|
754 ]. |
692 ]. |
755 ! |
693 ! |
756 |
694 |
757 resume:aProcess |
695 resume:aProcess |
758 "set aProcess runnable - |
696 "set aProcess runnable - |
770 |
708 |
771 pri := aProcess priority. |
709 pri := aProcess priority. |
772 |
710 |
773 l := quiescentProcessLists at:pri. |
711 l := quiescentProcessLists at:pri. |
774 l isNil ifTrue:[ |
712 l isNil ifTrue:[ |
775 l := LinkedList new. |
713 l := LinkedList new. |
776 quiescentProcessLists at:pri put:l |
714 quiescentProcessLists at:pri put:l |
777 ] ifFalse:[ |
715 ] ifFalse:[ |
778 "if already running, ignore" |
716 "if already running, ignore" |
779 (l includes:aProcess) ifTrue:[ |
717 (l includes:aProcess) ifTrue:[ |
780 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
718 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
781 ^ self |
719 ^ self |
782 ] |
720 ] |
783 ]. |
721 ]. |
784 l addLast:aProcess. |
722 l addLast:aProcess. |
785 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
723 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
786 |
724 |
787 (pri > currentPriority) ifTrue:[ |
725 (pri > currentPriority) ifTrue:[ |
788 " |
726 " |
789 its prio is higher; immediately transfer control to it |
727 its prio is higher; immediately transfer control to it |
790 " |
728 " |
791 self threadSwitch:aProcess |
729 self threadSwitch:aProcess |
792 ] ifFalse:[ |
730 ] ifFalse:[ |
793 " |
731 " |
794 its prio is lower; it will have to wait for a while ... |
732 its prio is lower; it will have to wait for a while ... |
795 " |
733 " |
796 aProcess state:#run |
734 aProcess state:#run |
797 ] |
735 ] |
798 ! |
736 ! |
799 |
737 |
800 resumeForSingleSend:aProcess |
738 resumeForSingleSend:aProcess |
801 "like resume, but let the process execute a single send only. |
739 "like resume, but let the process execute a single send only. |
814 |
752 |
815 pri := aProcess priority. |
753 pri := aProcess priority. |
816 |
754 |
817 l := quiescentProcessLists at:pri. |
755 l := quiescentProcessLists at:pri. |
818 l isNil ifTrue:[ |
756 l isNil ifTrue:[ |
819 l := LinkedList new. |
757 l := LinkedList new. |
820 quiescentProcessLists at:pri put:l |
758 quiescentProcessLists at:pri put:l |
821 ] ifFalse:[ |
759 ] ifFalse:[ |
822 "if already running, ignore" |
760 "if already running, ignore" |
823 (l includes:aProcess) ifTrue:[ |
761 (l includes:aProcess) ifTrue:[ |
824 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
762 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
825 ^ self |
763 ^ self |
826 ] |
764 ] |
827 ]. |
765 ]. |
828 l addLast:aProcess. |
766 l addLast:aProcess. |
829 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
767 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
830 |
768 |
831 (pri > currentPriority) ifTrue:[ |
769 (pri > currentPriority) ifTrue:[ |
832 " |
770 " |
833 its prio is higher; immediately transfer control to it |
771 its prio is higher; immediately transfer control to it |
834 " |
772 " |
835 "/ activeProcess state:#run. |
773 "/ activeProcess state:#run. |
836 self threadSwitch:aProcess |
774 self threadSwitch:aProcess |
837 ] ifFalse:[ |
775 ] ifFalse:[ |
838 " |
776 " |
839 its prio is lower; it will have to wait for a while ... |
777 its prio is lower; it will have to wait for a while ... |
840 " |
778 " |
841 aProcess state:#suspended |
779 aProcess state:#suspended |
842 ] |
780 ] |
843 ! |
781 ! |
844 |
782 |
845 terminate:aProcess |
783 terminateNoSignal:aProcess |
846 "terminate aProcess. If its not the current process, its simply |
784 "hard terminate aProcess without sending the terminate signal, thus |
847 removed from its list and destroyed. Otherwise, a switch is forced |
785 no unwind blocks or exitAction are performed in the process.. |
848 and the process is destroyed by the next running process." |
786 If its not the current process, it is simply removed from its list |
|
787 and physically destroyed. Otherwise (since we can't take away the chair |
|
788 we are sitting on), a switch is forced and the process |
|
789 will be physically destroyed by the next running process. |
|
790 (see zombie handling)" |
849 |
791 |
850 |pri id l wasBlocked| |
792 |pri id l wasBlocked| |
851 |
793 |
852 aProcess isNil ifTrue:[^ self]. |
794 aProcess isNil ifTrue:[^ self]. |
853 id := aProcess id. |
795 id := aProcess id. |
854 id isNil ifTrue:[^ self]. "already dead" |
796 id isNil ifTrue:[^ self]. "already dead" |
855 |
797 |
856 aProcess setId:nil. |
798 aProcess setId:nil state:#dead. |
857 aProcess startBlock:nil. |
799 "/ aProcess setStartBlock:nil. |
858 |
800 |
859 wasBlocked := OperatingSystem blockInterrupts. |
801 wasBlocked := OperatingSystem blockInterrupts. |
860 |
802 |
861 "remove the process from the runnable list" |
803 "remove the process from the runnable list" |
862 |
804 |
863 pri := aProcess priority. |
805 pri := aProcess priority. |
864 l := quiescentProcessLists at:pri. |
806 l := quiescentProcessLists at:pri. |
865 (l notNil and:[l includes:aProcess]) ifTrue:[ |
807 (l notNil and:[l includes:aProcess]) ifTrue:[ |
866 l remove:aProcess. |
808 l remove:aProcess. |
867 l isEmpty ifTrue:[quiescentProcessLists at:pri put:nil]. |
809 l isEmpty ifTrue:[quiescentProcessLists at:pri put:nil]. |
868 ]. |
810 ]. |
869 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
811 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
870 |
812 |
871 aProcess exitAction notNil ifTrue:[ |
|
872 aProcess exitAction value. |
|
873 aProcess exitAction:nil |
|
874 ]. |
|
875 |
|
876 aProcess state:#dead. |
|
877 aProcess == activeProcess ifTrue:[ |
813 aProcess == activeProcess ifTrue:[ |
878 " |
814 " |
879 hard case - its the currently running process |
815 hard case - its the currently running process |
880 we must have the next active process destroy this one |
816 we must have the next active process destroy this one |
881 (we cannot destroy the chair we are sitting on ... :-) |
817 (we cannot destroy the chair we are sitting on ... :-) |
882 " |
818 " |
883 zombie := id. |
819 zombie := id. |
884 self unRemember:aProcess. |
820 self unRemember:aProcess. |
885 self threadSwitch:scheduler. |
821 self threadSwitch:scheduler. |
886 "/ self reschedule. |
822 "not reached" |
887 ^ self |
823 ^ self |
888 ]. |
824 ]. |
889 self class threadDestroy:id. |
825 self class threadDestroy:id. |
890 self unRemember:aProcess. |
826 self unRemember:aProcess. |
891 ^ self |
827 ^ self |
892 ! |
828 ! |
893 |
829 |
|
830 terminateActiveNoSignal |
|
831 "hard terminate the active process, without sending any |
|
832 terminate signal thus no unwind blocks are evaluated." |
|
833 |
|
834 self terminateNoSignal:activeProcess |
|
835 ! |
|
836 |
894 processTermination |
837 processTermination |
895 "current process finished its startup block without termination, |
838 "sent by VM if the current process finished its startup block |
896 lay him to rest now." |
839 without proper process termination, lay him to rest now. |
897 |
840 This can only happen, if something went wrong in Block>>newProcess, |
898 self terminate:activeProcess. |
841 since the block defined there always terminates itself." |
|
842 |
|
843 self terminateNoSignal:activeProcess. |
899 self threadSwitch:scheduler |
844 self threadSwitch:scheduler |
900 "/ self reschedule |
845 ! |
|
846 |
|
847 terminate:aProcess |
|
848 "terminate aProcess. This is deon by sending aProcess the terminateSignal, |
|
849 which will evaluate any unwind blocks and finally do a hard terminate." |
|
850 |
|
851 aProcess terminate |
901 ! |
852 ! |
902 |
853 |
903 terminateActive |
854 terminateActive |
904 "terminate the current process |
855 "terminate the current process (i.e. the currently running process kills itself). |
905 (i.e. the currently running process kills itself)" |
856 The active process is sent the terminateSignal so it will evaluate any |
906 |
857 unwind blocks." |
907 self terminate:activeProcess |
858 |
|
859 activeProcess terminate |
908 ! |
860 ! |
909 |
861 |
910 interruptActive |
862 interruptActive |
911 "interrupt the current process (i.e. myself)" |
863 "interrupt the current process (i.e. myself)" |
912 |
864 |
924 " |
876 " |
925 check for valid argument |
877 check for valid argument |
926 " |
878 " |
927 newPrio := prio. |
879 newPrio := prio. |
928 newPrio < 1 ifTrue:[ |
880 newPrio < 1 ifTrue:[ |
929 newPrio := 1. |
881 newPrio := 1. |
930 ] ifFalse:[ |
882 ] ifFalse:[ |
931 newPrio >= SchedulingPriority ifTrue:[ |
883 newPrio >= SchedulingPriority ifTrue:[ |
932 newPrio := SchedulingPriority - 1 |
884 newPrio := SchedulingPriority - 1 |
933 ] |
885 ] |
934 ]. |
886 ]. |
935 |
887 |
936 wasBlocked := OperatingSystem blockInterrupts. |
888 wasBlocked := OperatingSystem blockInterrupts. |
937 |
889 |
938 aProcess setPriority:newPrio. |
890 aProcess setPriority:newPrio. |
939 |
891 |
940 oldList := quiescentProcessLists at:oldPrio. |
892 oldList := quiescentProcessLists at:oldPrio. |
941 (oldList isNil or:[(oldList includes:aProcess) not]) ifTrue:[ |
893 (oldList isNil or:[(oldList includes:aProcess) not]) ifTrue:[ |
942 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
894 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
943 ^ self |
895 ^ self |
944 ]. |
896 ]. |
945 |
897 |
946 oldList remove:aProcess. |
898 oldList remove:aProcess. |
947 oldList isEmpty ifTrue:[quiescentProcessLists at:oldPrio put:nil]. |
899 oldList isEmpty ifTrue:[quiescentProcessLists at:oldPrio put:nil]. |
948 |
900 |
949 newList := quiescentProcessLists at:newPrio. |
901 newList := quiescentProcessLists at:newPrio. |
950 newList isNil ifTrue:[ |
902 newList isNil ifTrue:[ |
951 newList := LinkedList new. |
903 newList := LinkedList new. |
952 quiescentProcessLists at:newPrio put:newList |
904 quiescentProcessLists at:newPrio put:newList |
953 ]. |
905 ]. |
954 newList addLast:aProcess. |
906 newList addLast:aProcess. |
955 |
907 |
956 "if its the current process lowering its prio |
908 "if its the current process lowering its prio |
957 or another one raising, we have to reschedule" |
909 or another one raising, we have to reschedule" |
958 |
910 |
959 aProcess == activeProcess ifTrue:[ |
911 aProcess == activeProcess ifTrue:[ |
960 currentPriority := newPrio. |
912 currentPriority := newPrio. |
961 newPrio < oldPrio ifTrue:[ |
913 newPrio < oldPrio ifTrue:[ |
962 self threadSwitch:scheduler. |
914 self threadSwitch:scheduler. |
963 "/ self reschedule. |
915 ] |
964 ] |
|
965 ] ifFalse:[ |
916 ] ifFalse:[ |
966 newPrio > currentPriority ifTrue:[ |
917 newPrio > currentPriority ifTrue:[ |
967 "/ activeProcess state:#run. |
918 "/ activeProcess state:#run. |
968 self threadSwitch:aProcess. |
919 self threadSwitch:aProcess. |
969 ] |
920 ] |
970 ]. |
921 ]. |
971 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
922 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
972 ! ! |
923 ! ! |
973 |
924 |
974 !ProcessorScheduler methodsFor:'accessing'! |
925 !ProcessorScheduler methodsFor:'accessing'! |
1055 |
1006 |
1056 " |
1007 " |
1057 handle all timeout actions |
1008 handle all timeout actions |
1058 " |
1009 " |
1059 anyTimeouts ifTrue:[ |
1010 anyTimeouts ifTrue:[ |
1060 self evaluateTimeouts |
1011 self evaluateTimeouts |
1061 ]. |
1012 ]. |
1062 |
1013 |
1063 "first do a quick check using checkActions - this is needed for |
1014 "first do a quick check using checkActions - this is needed for |
1064 devices like X-connection, where some events might be in the event |
1015 devices like X-connection, where some events might be in the event |
1065 queue, so a select does not always help |
1016 queue, so a select does not always help |
1066 " |
1017 " |
1067 any := false. |
1018 any := false. |
1068 nActions := readChecks size. |
1019 nActions := readChecks size. |
1069 1 to:nActions do:[:index | |
1020 1 to:nActions do:[:index | |
1070 |checkBlock sema action| |
1021 |checkBlock sema action| |
1071 |
1022 |
1072 checkBlock := readChecks at:index. |
1023 checkBlock := readChecks at:index. |
1073 (checkBlock notNil and:[checkBlock value]) ifTrue:[ |
1024 (checkBlock notNil and:[checkBlock value]) ifTrue:[ |
1074 sema := readSemaphores at:index. |
1025 sema := readSemaphores at:index. |
1075 sema notNil ifTrue:[ |
1026 sema notNil ifTrue:[ |
1076 sema signalOnce. |
1027 sema signalOnce. |
1077 ]. |
1028 ]. |
1078 any := true. |
1029 any := true. |
1079 ] |
1030 ] |
1080 ]. |
1031 ]. |
1081 |
1032 |
1082 "now, someone might be runnable:" |
1033 "now, someone might be runnable:" |
1083 |
1034 |
1084 p := self highestPriorityRunnableProcess. |
1035 p := self highestPriorityRunnableProcess. |
1085 p isNil ifTrue:[ |
1036 p isNil ifTrue:[ |
1086 "no one runnable, hard wait for event or timeout" |
1037 "no one runnable, hard wait for event or timeout" |
1087 |
1038 |
1088 self waitForEventOrTimeout. |
1039 self waitForEventOrTimeout. |
1089 ^ self |
1040 ^ self |
1090 ]. |
1041 ]. |
1091 |
1042 |
1092 pri := p priority. |
1043 pri := p priority. |
1093 |
1044 |
1094 "want to give control to another process p. |
1045 "want to give control to another process p. |
1127 or by installing a poll-interrupt after 50ms (if the OS does not). |
1078 or by installing a poll-interrupt after 50ms (if the OS does not). |
1128 " |
1079 " |
1129 pri < UserInterruptPriority ifTrue:[ |
1080 pri < UserInterruptPriority ifTrue:[ |
1130 |
1081 |
1131 "comment out this if above is uncommented" |
1082 "comment out this if above is uncommented" |
1132 anyTimeouts ifTrue:[ |
1083 anyTimeouts ifTrue:[ |
1133 millis := self timeToNextTimeout. |
1084 millis := self timeToNextTimeout. |
1134 millis == 0 ifTrue:[^ self]. |
1085 millis == 0 ifTrue:[^ self]. |
1135 ]. |
1086 ]. |
1136 "---" |
1087 "---" |
1137 |
1088 |
1138 OperatingSystem supportsIOInterrupts ifTrue:[ |
1089 OperatingSystem supportsIOInterrupts ifTrue:[ |
1139 readFds do:[:fd | |
1090 readFds do:[:fd | |
1140 fd notNil ifTrue:[ |
1091 fd notNil ifTrue:[ |
1141 OperatingSystem enableIOInterruptsOn:fd |
1092 OperatingSystem enableIOInterruptsOn:fd |
1142 ]. |
1093 ]. |
1143 ]. |
1094 ]. |
1144 ] ifFalse:[ |
1095 ] ifFalse:[ |
1145 millis notNil ifTrue:[ |
1096 millis notNil ifTrue:[ |
1146 millis := millis min:50 |
1097 millis := millis min:50 |
1147 ] ifFalse:[ |
1098 ] ifFalse:[ |
1148 millis := 50 |
1099 millis := 50 |
1149 ] |
1100 ] |
1150 ] |
1101 ] |
1151 ]. |
1102 ]. |
1152 |
1103 |
1153 millis notNil ifTrue:[ |
1104 millis notNil ifTrue:[ |
1154 "schedule a clock interrupt after millis milliseconds" |
1105 "schedule a clock interrupt after millis milliseconds" |
1155 OperatingSystem enableTimer:millis rounded. |
1106 OperatingSystem enableTimer:millis rounded. |
1156 ]. |
1107 ]. |
1157 |
1108 |
1158 "now let the process run - will come back here by reschedule |
1109 "now let the process run - will come back here by reschedule |
1159 from ioInterrupt or timerInterrupt ... (running at max+1)" |
1110 from ioInterrupt or timerInterrupt ... (running at max+1)" |
1160 |
1111 |
1162 self threadSwitch:p. |
1113 self threadSwitch:p. |
1163 |
1114 |
1164 "... when we arrive here, we are back on stage" |
1115 "... when we arrive here, we are back on stage" |
1165 |
1116 |
1166 millis notNil ifTrue:[ |
1117 millis notNil ifTrue:[ |
1167 OperatingSystem disableTimer. |
1118 OperatingSystem disableTimer. |
1168 self checkForInputWithTimeout:0. |
1119 self checkForInputWithTimeout:0. |
1169 ] |
1120 ] |
1170 ! ! |
1121 ! ! |
1171 |
1122 |
1172 !ProcessorScheduler methodsFor:'waiting'! |
1123 !ProcessorScheduler methodsFor:'waiting'! |
1173 |
1124 |
1174 ioInterrupt |
1125 ioInterrupt |
1175 "data arrived while waiting - reschedule to bring dispatcher into play" |
1126 "data arrived while waiting - switch to scheduler process which will decide |
|
1127 what to do now." |
1176 |
1128 |
1177 self threadSwitch:scheduler |
1129 self threadSwitch:scheduler |
1178 "/ self reschedule |
|
1179 ! |
1130 ! |
1180 |
1131 |
1181 timerInterrupt |
1132 timerInterrupt |
1182 "timer expired while waiting - reschedule to bring dispatcher into play" |
1133 "timer expired while waiting - switch to scheduler process which will decide |
|
1134 what to do now." |
1183 |
1135 |
1184 self threadSwitch:scheduler |
1136 self threadSwitch:scheduler |
1185 "/ self reschedule |
|
1186 ! |
1137 ! |
1187 |
1138 |
1188 timeToNextTimeout |
1139 timeToNextTimeout |
1189 "return the delta-T (in millis) to next timeout, or nil if |
1140 "return the delta-T (in millis) to next timeout, or nil if |
1190 there is none" |
1141 there is none" |
1222 |
1173 |
1223 |millis limit doingGC| |
1174 |millis limit doingGC| |
1224 |
1175 |
1225 doingGC := true. |
1176 doingGC := true. |
1226 [doingGC] whileTrue:[ |
1177 [doingGC] whileTrue:[ |
1227 anyTimeouts ifTrue:[ |
1178 anyTimeouts ifTrue:[ |
1228 millis := self timeToNextTimeout. |
1179 millis := self timeToNextTimeout. |
1229 (millis notNil and:[millis <= 0]) ifTrue:[ |
1180 (millis notNil and:[millis <= 0]) ifTrue:[ |
1230 ^ self "oops - hurry up checking" |
1181 ^ self "oops - hurry up checking" |
1231 ]. |
1182 ]. |
1232 ]. |
1183 ]. |
1233 |
1184 |
1234 "if its worth doing, collect a bit of garbage" |
1185 "if its worth doing, collect a bit of garbage" |
1235 limit := ObjectMemory incrementalGCLimit. |
1186 limit := ObjectMemory incrementalGCLimit. |
1236 doingGC := limit notNil and:[ObjectMemory oldSpaceAllocatedSinceLastGC > limit]. |
1187 doingGC := limit notNil and:[ObjectMemory oldSpaceAllocatedSinceLastGC > limit]. |
1237 doingGC ifTrue:[ |
1188 doingGC ifTrue:[ |
1238 ObjectMemory gcStep. |
1189 ObjectMemory gcStep. |
1239 ]. |
1190 ]. |
1240 |
1191 |
1241 "then do idle actions" |
1192 "then do idle actions" |
1242 (idleActions size ~~ 0) ifTrue:[ |
1193 (idleActions size ~~ 0) ifTrue:[ |
1243 idleActions do:[:aBlock | |
1194 idleActions do:[:aBlock | |
1244 aBlock value. |
1195 aBlock value. |
1245 ]. |
1196 ]. |
1246 ^ self "go back checking" |
1197 ^ self "go back checking" |
1247 ]. |
1198 ]. |
1248 |
1199 |
1249 doingGC ifTrue:[ |
1200 doingGC ifTrue:[ |
1250 (self checkForInputWithTimeout:0) ifTrue:[ |
1201 (self checkForInputWithTimeout:0) ifTrue:[ |
1251 ^ self "go back checking" |
1202 ^ self "go back checking" |
1252 ] |
1203 ] |
1253 ] |
1204 ] |
1254 ]. |
1205 ]. |
1255 |
1206 |
1256 (self checkForInputWithTimeout:0) ifTrue:[ |
1207 (self checkForInputWithTimeout:0) ifTrue:[ |
1257 ^ self "go back checking" |
1208 ^ self "go back checking" |
1258 ]. |
1209 ]. |
1259 |
1210 |
1260 "no, really nothing to do - simply wait" |
1211 "no, really nothing to do - simply wait" |
1261 |
1212 |
1262 OperatingSystem supportsSelect ifFalse:[ |
1213 OperatingSystem supportsSelect ifFalse:[ |
1263 "SCO instant ShitStation has a bug here, |
1214 "SCO instant ShitStation has a bug here, |
1264 waiting always 1 sec in the select - therefore we delay a bit and |
1215 waiting always 1 sec in the select - therefore we delay a bit and |
1265 return - effectively polling in 50ms cycles |
1216 return - effectively polling in 50ms cycles |
1266 " |
1217 " |
1267 OperatingSystem millisecondDelay:50. |
1218 OperatingSystem millisecondDelay:50. |
1268 ^ self |
1219 ^ self |
1269 ]. |
1220 ]. |
1270 |
1221 |
1271 millis isNil ifTrue:[ |
1222 millis isNil ifTrue:[ |
1272 millis := 9999. |
1223 millis := 9999. |
1273 ] ifFalse:[ |
1224 ] ifFalse:[ |
1274 millis := millis rounded |
1225 millis := millis rounded |
1275 ]. |
1226 ]. |
1276 self checkForInputWithTimeout:millis |
1227 self checkForInputWithTimeout:millis |
1277 ! |
1228 ! |
1278 |
1229 |
1279 checkForInputWithTimeout:millis |
1230 checkForInputWithTimeout:millis |
1281 hard wait for either input to arrive or a timeout to occur." |
1232 hard wait for either input to arrive or a timeout to occur." |
1282 |
1233 |
1283 |fd index sema action| |
1234 |fd index sema action| |
1284 |
1235 |
1285 fd := OperatingSystem |
1236 fd := OperatingSystem |
1286 selectOnAnyReadable:readFds |
1237 selectOnAnyReadable:readFds |
1287 writable:writeFds |
1238 writable:writeFds |
1288 exception:nil |
1239 exception:nil |
1289 withTimeOut:millis. |
1240 withTimeOut:millis. |
1290 fd notNil ifTrue:[ |
1241 fd notNil ifTrue:[ |
1291 index := readFds indexOf:fd. |
1242 index := readFds indexOf:fd. |
1292 index ~~ 0 ifTrue:[ |
1243 index ~~ 0 ifTrue:[ |
1293 sema := readSemaphores at:index. |
1244 sema := readSemaphores at:index. |
1294 sema notNil ifTrue:[ |
1245 sema notNil ifTrue:[ |
1295 sema signalOnce. |
1246 sema signalOnce. |
1296 ^ true |
1247 ^ true |
1297 ] ifFalse:[ |
1248 ] ifFalse:[ |
1298 action := readChecks at:index. |
1249 action := readChecks at:index. |
1299 action notNil ifTrue:[ |
1250 action notNil ifTrue:[ |
1300 action value. |
1251 action value. |
1301 ^ true |
1252 ^ true |
1302 ] |
1253 ] |
1303 ] |
1254 ] |
1304 ] |
1255 ] |
1305 ]. |
1256 ]. |
1306 ^ false |
1257 ^ false |
1307 ! |
|
1308 |
|
1309 evaluateTimeouts |
|
1310 "walk through timeouts and evaluate blocks or signal semas that need to be .." |
|
1311 |
|
1312 |sema now aTime block blocksToEvaluate |
|
1313 processes n "{ Class: SmallInteger }"| |
|
1314 |
|
1315 anyTimeouts ifFalse:[ ^ self]. |
|
1316 |
|
1317 "have to collect the blocks first, then evaluate them. This avoids |
|
1318 problems due to newly inserted blocks." |
|
1319 |
|
1320 now := OperatingSystem getMillisecondTime. |
|
1321 blocksToEvaluate := nil. |
|
1322 n := timeouts size. |
|
1323 anyTimeouts := false. |
|
1324 1 to:n do:[:index | |
|
1325 aTime := timeouts at:index. |
|
1326 aTime notNil ifTrue:[ |
|
1327 (OperatingSystem millisecondTime:aTime isAfter:now) ifFalse:[ |
|
1328 "this one should be triggered" |
|
1329 |
|
1330 sema := timeoutSemaphores at:index. |
|
1331 sema notNil ifTrue:[ |
|
1332 sema signalOnce. |
|
1333 timeoutSemaphores at:index put:nil |
|
1334 ] ifFalse:[ |
|
1335 "to support pure-events" |
|
1336 block := timeoutActions at:index. |
|
1337 block notNil ifTrue:[ |
|
1338 blocksToEvaluate isNil ifTrue:[ |
|
1339 blocksToEvaluate := OrderedCollection new:10. |
|
1340 processes := OrderedCollection new:10. |
|
1341 ]. |
|
1342 blocksToEvaluate add:block. |
|
1343 processes add:(timeoutProcesses at:index). |
|
1344 timeoutActions at:index put:nil. |
|
1345 timeoutProcesses at:index put:nil. |
|
1346 ] |
|
1347 ]. |
|
1348 timeouts at:index put:nil. |
|
1349 ] ifTrue:[ |
|
1350 anyTimeouts := true |
|
1351 ] |
|
1352 ] |
|
1353 ]. |
|
1354 |
|
1355 blocksToEvaluate notNil ifTrue:[ |
|
1356 1 to:blocksToEvaluate size do:[:index | |
|
1357 PureEventDriven ifTrue:[ |
|
1358 (blocksToEvaluate at:index) value |
|
1359 ] ifFalse:[ |
|
1360 (processes at:index) interruptWith:(blocksToEvaluate at:index) |
|
1361 ] |
|
1362 ] |
|
1363 ] |
|
1364 ! ! |
1258 ! ! |
1365 |
1259 |
1366 !ProcessorScheduler methodsFor:'semaphore signalling'! |
1260 !ProcessorScheduler methodsFor:'semaphore signalling'! |
1367 |
1261 |
1368 signal:aSemaphore onInput:aFileDescriptor |
1262 signal:aSemaphore onInput:aFileDescriptor |
1440 |index wasBlocked| |
1334 |index wasBlocked| |
1441 |
1335 |
1442 wasBlocked := OperatingSystem blockInterrupts. |
1336 wasBlocked := OperatingSystem blockInterrupts. |
1443 index := timeoutSemaphores identityIndexOf:aSemaphore. |
1337 index := timeoutSemaphores identityIndexOf:aSemaphore. |
1444 index ~~ 0 ifTrue:[ |
1338 index ~~ 0 ifTrue:[ |
1445 timeouts at:index put:aMillisecondTime |
1339 timeouts at:index put:aMillisecondTime |
1446 ] ifFalse:[ |
1340 ] ifFalse:[ |
1447 index := timeouts indexOf:nil. |
1341 index := timeouts indexOf:nil. |
1448 index ~~ 0 ifTrue:[ |
1342 index ~~ 0 ifTrue:[ |
1449 timeoutSemaphores at:index put:aSemaphore. |
1343 timeoutSemaphores at:index put:aSemaphore. |
1450 timeouts at:index put:aMillisecondTime. |
1344 timeouts at:index put:aMillisecondTime. |
1451 timeoutActions at:index put:nil. |
1345 timeoutActions at:index put:nil. |
1452 timeoutProcesses at:index put:nil |
1346 timeoutProcesses at:index put:nil |
1453 ] ifFalse:[ |
1347 ] ifFalse:[ |
1454 timeoutSemaphores := timeoutSemaphores copyWith:aSemaphore. |
1348 timeoutSemaphores := timeoutSemaphores copyWith:aSemaphore. |
1455 timeouts := timeouts copyWith:aMillisecondTime. |
1349 timeouts := timeouts copyWith:aMillisecondTime. |
1456 timeoutActions := timeoutActions copyWith:nil. |
1350 timeoutActions := timeoutActions copyWith:nil. |
1457 timeoutProcesses := timeoutProcesses copyWith:nil |
1351 timeoutProcesses := timeoutProcesses copyWith:nil |
1458 ]. |
1352 ]. |
1459 ]. |
1353 ]. |
1460 anyTimeouts := true. |
1354 anyTimeouts := true. |
1461 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1355 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1462 ! |
1356 ! |
1463 |
1357 |
1467 |idx wasBlocked| |
1361 |idx wasBlocked| |
1468 |
1362 |
1469 wasBlocked := OperatingSystem blockInterrupts. |
1363 wasBlocked := OperatingSystem blockInterrupts. |
1470 idx := readSemaphores identityIndexOf:aSemaphore. |
1364 idx := readSemaphores identityIndexOf:aSemaphore. |
1471 idx ~~ 0 ifTrue:[ |
1365 idx ~~ 0 ifTrue:[ |
1472 readFds at:idx put:nil. |
1366 readFds at:idx put:nil. |
1473 readSemaphores at:idx put:nil. |
1367 readSemaphores at:idx put:nil. |
1474 readChecks at:idx put:nil |
1368 readChecks at:idx put:nil |
|
1369 ]. |
|
1370 idx := writeSemaphores identityIndexOf:aSemaphore. |
|
1371 idx ~~ 0 ifTrue:[ |
|
1372 writeFds at:idx put:nil. |
|
1373 writeSemaphores at:idx put:nil. |
1475 ]. |
1374 ]. |
1476 idx := timeoutSemaphores identityIndexOf:aSemaphore. |
1375 idx := timeoutSemaphores identityIndexOf:aSemaphore. |
1477 idx ~~ 0 ifTrue:[ |
1376 idx ~~ 0 ifTrue:[ |
1478 timeouts at:idx put:nil. |
1377 timeouts at:idx put:nil. |
1479 timeoutSemaphores at:idx put:nil. |
1378 timeoutSemaphores at:idx put:nil. |
1480 timeoutActions at:idx put:nil. |
1379 timeoutActions at:idx put:nil. |
1481 timeoutProcesses at:idx put:nil. |
1380 timeoutProcesses at:idx put:nil. |
1482 ]. |
1381 ]. |
1483 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1382 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1484 ! ! |
1383 ! ! |
1485 |
1384 |
1486 !ProcessorScheduler methodsFor:'background processing'! |
1385 !ProcessorScheduler methodsFor:'background processing'! |
1488 addIdleBlock:aBlock |
1387 addIdleBlock:aBlock |
1489 "add the argument, aBlock to the list of idle-actions. |
1388 "add the argument, aBlock to the list of idle-actions. |
1490 Idle blocks are evaluated whenever no other process is runnable, |
1389 Idle blocks are evaluated whenever no other process is runnable, |
1491 and no events are pending. |
1390 and no events are pending. |
1492 Use of idle blocks is not recommended, use a low priority processes |
1391 Use of idle blocks is not recommended, use a low priority processes |
1493 instead, which has the same effect. They have been implemented to support |
1392 instead, which has the same effect. Idle blcoks are still included |
1494 background actions in pure-event systems, where no processes are |
1393 to support background actions in pure-event systems, where no processes |
1495 available. |
1394 are available. |
1496 Support for idle-blocks may vanish." |
1395 Support for idle-blocks may vanish." |
1497 |
1396 |
1498 |wasBlocked| |
1397 |wasBlocked| |
1499 |
1398 |
1500 wasBlocked := OperatingSystem blockInterrupts. |
1399 wasBlocked := OperatingSystem blockInterrupts. |
1501 idleActions isNil ifTrue:[ |
1400 idleActions isNil ifTrue:[ |
1502 idleActions := OrderedCollection new |
1401 idleActions := OrderedCollection new |
1503 ]. |
1402 ]. |
1504 idleActions add:aBlock. |
1403 idleActions add:aBlock. |
1505 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1404 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1506 ! |
1405 ! |
1507 |
1406 |
1518 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1417 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1519 ! ! |
1418 ! ! |
1520 |
1419 |
1521 !ProcessorScheduler methodsFor:'I/O event actions'! |
1420 !ProcessorScheduler methodsFor:'I/O event actions'! |
1522 |
1421 |
1523 enableIOAction:aBlock on:aFileDescriptor |
1422 enableIOAction:aBlock onInput:aFileDescriptor |
1524 "half-obsolete event support: arrange for aBlock to be |
1423 "half-obsolete event support: arrange for aBlock to be |
1525 evaluated when input on aFileDescriptor arrives. |
1424 evaluated when input on aFileDescriptor arrives. |
1526 This is a leftover support for pure-event systems and may vanish." |
1425 This is a leftover support for pure-event systems and may vanish." |
1527 |
1426 |
1528 |idx wasBlocked| |
1427 |idx wasBlocked| |
1529 |
1428 |
1530 wasBlocked := OperatingSystem blockInterrupts. |
1429 wasBlocked := OperatingSystem blockInterrupts. |
1531 (readFds includes:aFileDescriptor) ifFalse:[ |
1430 (readFds includes:aFileDescriptor) ifFalse:[ |
1532 idx := readFds indexOf:nil. |
1431 idx := readFds indexOf:nil. |
1533 idx ~~ 0 ifTrue:[ |
1432 idx ~~ 0 ifTrue:[ |
1534 readFds at:idx put:aFileDescriptor. |
1433 readFds at:idx put:aFileDescriptor. |
1535 readChecks at:idx put:aBlock. |
1434 readChecks at:idx put:aBlock. |
1536 readSemaphores at:idx put:nil |
1435 readSemaphores at:idx put:nil |
1537 ] ifFalse:[ |
1436 ] ifFalse:[ |
1538 readFds := readFds copyWith:aFileDescriptor. |
1437 readFds := readFds copyWith:aFileDescriptor. |
1539 readChecks := readChecks copyWith:aBlock. |
1438 readChecks := readChecks copyWith:aBlock. |
1540 readSemaphores := readSemaphores copyWith:nil. |
1439 readSemaphores := readSemaphores copyWith:nil. |
1541 ] |
1440 ] |
1542 ]. |
1441 ]. |
1543 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1442 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1544 ! |
1443 ! |
1545 |
1444 |
1546 disableFd:aFileDescriptor |
1445 disableFd:aFileDescriptor |
1550 |idx wasBlocked| |
1449 |idx wasBlocked| |
1551 |
1450 |
1552 wasBlocked := OperatingSystem blockInterrupts. |
1451 wasBlocked := OperatingSystem blockInterrupts. |
1553 idx := readFds indexOf:aFileDescriptor. |
1452 idx := readFds indexOf:aFileDescriptor. |
1554 idx ~~ 0 ifTrue:[ |
1453 idx ~~ 0 ifTrue:[ |
1555 readFds at:idx put:nil. |
1454 readFds at:idx put:nil. |
1556 readChecks at:idx put:nil. |
1455 readChecks at:idx put:nil. |
1557 readSemaphores at:idx put:nil |
1456 readSemaphores at:idx put:nil |
1558 ]. |
1457 ]. |
1559 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1458 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1560 ! ! |
1459 ! ! |
1561 |
1460 |
1562 !ProcessorScheduler methodsFor:'timed block'! |
1461 !ProcessorScheduler methodsFor:'timeout handling'! |
1563 |
1462 |
1564 addTimedBlock:aBlock afterSeconds:delta |
1463 addTimedBlock:aBlock afterSeconds:delta |
1565 "add the argument, aBlock to the list of time-scheduled-blocks. |
1464 "add the argument, aBlock to the list of time-scheduled-blocks. |
1566 to be evaluated after delta seconds. The process which installs this timed |
1465 to be evaluated after delta seconds. The process which installs this timed |
1567 block will be interrupted for execution of the block. |
1466 block will be interrupted for execution of the block. |
1568 (if it is running, the interrupt will occur in whatever method it is |
1467 (if it is running, the interrupt will occur in whatever method it is |
1569 executing; if it is suspended, it will be resumed for the execution). |
1468 executing; if it is suspended, it will be resumed). |
1570 The block will be removed from the timed-block list after evaluation |
1469 The block will be removed from the timed-block list after evaluation |
1571 (i.e. it will trigger only once)." |
1470 (i.e. it will trigger only once)." |
1572 |
1471 |
1573 self addTimedBlock:aBlock for:activeProcess afterMilliseconds:(delta * 1000) rounded |
1472 self addTimedBlock:aBlock for:activeProcess afterMilliseconds:(delta * 1000) rounded |
1574 ! |
1473 ! |
1576 addTimedBlock:aBlock for:aProcess afterSeconds:delta |
1475 addTimedBlock:aBlock for:aProcess afterSeconds:delta |
1577 "add the argument, aBlock to the list of time-scheduled-blocks. |
1476 "add the argument, aBlock to the list of time-scheduled-blocks. |
1578 to be evaluated after delta seconds. aProcess will be interrupted for |
1477 to be evaluated after delta seconds. aProcess will be interrupted for |
1579 execution of the block. |
1478 execution of the block. |
1580 (if it is running, the interrupt will occur in whatever method it is |
1479 (if it is running, the interrupt will occur in whatever method it is |
1581 executing; if it is suspended, it will be resumed for the execution). |
1480 executing; if it is suspended, it will be resumed). |
|
1481 If aProcess is nil, the block will be evaluated by the scheduler itself |
|
1482 (which is dangerous - the block should not raise any error conditions). |
1582 The block will be removed from the timed-block list after evaluation |
1483 The block will be removed from the timed-block list after evaluation |
1583 (i.e. it will trigger only once)." |
1484 (i.e. it will trigger only once)." |
1584 |
1485 |
1585 self addTimedBlock:aBlock for:aProcess afterMilliseconds:(delta * 1000) rounded |
1486 self addTimedBlock:aBlock for:aProcess afterMilliseconds:(delta * 1000) rounded |
1586 ! |
1487 ! |
1588 addTimedBlock:aBlock afterMilliseconds:delta |
1489 addTimedBlock:aBlock afterMilliseconds:delta |
1589 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1490 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1590 evaluated after delta milliseconds. The process which installs this timed |
1491 evaluated after delta milliseconds. The process which installs this timed |
1591 block will be interrupted for execution of the block. |
1492 block will be interrupted for execution of the block. |
1592 (if it is running, the interrupt will occur in whatever method it is |
1493 (if it is running, the interrupt will occur in whatever method it is |
1593 executing; if it is suspended, it will be resumed for the execution). |
1494 executing; if it is suspended, it will be resumed). |
1594 The block will be removed from the timed-block list after evaluation |
1495 The block will be removed from the timed-block list after evaluation |
1595 (i.e. it will trigger only once)." |
1496 (i.e. it will trigger only once)." |
1596 |
1497 |
1597 ^ self addTimedBlock:aBlock for:activeProcess afterMilliseconds:delta |
1498 ^ self addTimedBlock:aBlock for:activeProcess afterMilliseconds:delta |
1598 ! |
1499 ! |
1599 |
1500 |
1600 addTimedBlock:aBlock for:aProcess afterMilliseconds:delta |
1501 addTimedBlock:aBlock for:aProcess afterMilliseconds:delta |
1601 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1502 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1602 evaluated after delta milliseconds. aProcess will be interrupted for |
1503 evaluated after delta milliseconds. The process specified by the argument, |
1603 execution of the block. |
1504 aProcess will be interrupted for execution of the block. |
1604 (if it is running, the interrupt will occur in whatever method it is |
1505 (if it is running, the interrupt will occur in whatever method it is |
1605 executing; if it is suspended, it will be resumed for the execution). |
1506 executing; if it is suspended, it will be resumed). |
|
1507 If aProcess is nil, the block will be evaluated by the scheduler itself |
|
1508 (which is dangerous - the block should not raise any error conditions). |
1606 The block will be removed from the timed-block list after evaluation |
1509 The block will be removed from the timed-block list after evaluation |
1607 (i.e. it will trigger only once)." |
1510 (i.e. it will trigger only once)." |
1608 |
1511 |
1609 |now then wasBlocked| |
1512 |now then wasBlocked| |
1610 |
1513 |
1619 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1522 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1620 evaluated when the millisecondClock value passes aMillisecondTime. |
1523 evaluated when the millisecondClock value passes aMillisecondTime. |
1621 The process which installs this timed block will be interrupted for |
1524 The process which installs this timed block will be interrupted for |
1622 execution of the block. |
1525 execution of the block. |
1623 (if it is running, the interrupt will occur in whatever method it is |
1526 (if it is running, the interrupt will occur in whatever method it is |
1624 executing; if it is suspended, it will be resumed for the execution). |
1527 executing; if it is suspended, it will be resumed). |
1625 The block will be removed from the timed-block list after evaluation |
1528 The block will be removed from the timed-block list after evaluation |
1626 (i.e. it will trigger only once)." |
1529 (i.e. it will trigger only once)." |
1627 |
1530 |
1628 self addTimedBlock:aBlock for:activeProcess atMilliseconds:aMillisecondTime |
1531 self addTimedBlock:aBlock for:activeProcess atMilliseconds:aMillisecondTime |
1629 ! |
1532 ! |
1630 |
1533 |
1631 addTimedBlock:aBlock for:aProcess atMilliseconds:aMillisecondTime |
1534 addTimedBlock:aBlock for:aProcess atMilliseconds:aMillisecondTime |
1632 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1535 "add the argument, aBlock to the list of time-scheduled-blocks; to be |
1633 evaluated by aProcess when the millisecondClock value passes |
1536 evaluated by aProcess when the millisecondClock value passes |
1634 aMillisecondTime. |
1537 aMillisecondTime. The process specified by the argument, |
1635 aProcess will be interrupted for execution of the block. |
1538 aProcess will be interrupted for execution of the block. If |
|
1539 aProcess is nil, the block will be evaluated by the scheduler itself |
|
1540 (which is dangerous - the block should not raise any error conditions). |
1636 (if it is running, the interrupt will occur in whatever method it is |
1541 (if it is running, the interrupt will occur in whatever method it is |
1637 executing; if it is suspended, it will be resumed for the execution). |
1542 executing; if it is suspended, it will be resumed). |
1638 The block will be removed from the timed-block list after evaluation |
1543 The block will be removed from the timed-block list after evaluation |
1639 (i.e. it will trigger only once)." |
1544 (i.e. it will trigger only once)." |
1640 |
1545 |
1641 |index wasBlocked| |
1546 |index wasBlocked| |
1642 |
1547 |
1643 wasBlocked := OperatingSystem blockInterrupts. |
1548 wasBlocked := OperatingSystem blockInterrupts. |
1644 index := timeoutActions identityIndexOf:aBlock. |
1549 index := timeoutActions identityIndexOf:aBlock. |
1645 index ~~ 0 ifTrue:[ |
1550 index ~~ 0 ifTrue:[ |
1646 timeouts at:index put:aMillisecondTime |
1551 timeouts at:index put:aMillisecondTime |
1647 ] ifFalse:[ |
1552 ] ifFalse:[ |
1648 index := timeouts indexOf:nil. |
1553 index := timeouts indexOf:nil. |
1649 index ~~ 0 ifTrue:[ |
1554 index ~~ 0 ifTrue:[ |
1650 timeouts at:index put:aMillisecondTime. |
1555 timeouts at:index put:aMillisecondTime. |
1651 timeoutActions at:index put:aBlock. |
1556 timeoutActions at:index put:aBlock. |
1652 timeoutSemaphores at:index put:nil. |
1557 timeoutSemaphores at:index put:nil. |
1653 timeoutProcesses at:index put:aProcess |
1558 timeoutProcesses at:index put:aProcess |
1654 ] ifFalse:[ |
1559 ] ifFalse:[ |
1655 timeouts := timeouts copyWith:aMillisecondTime. |
1560 timeouts := timeouts copyWith:aMillisecondTime. |
1656 timeoutActions := timeoutActions copyWith:aBlock. |
1561 timeoutActions := timeoutActions copyWith:aBlock. |
1657 timeoutSemaphores := timeoutSemaphores copyWith:nil. |
1562 timeoutSemaphores := timeoutSemaphores copyWith:nil. |
1658 timeoutProcesses := timeoutProcesses copyWith:aProcess. |
1563 timeoutProcesses := timeoutProcesses copyWith:aProcess. |
1659 ]. |
1564 ]. |
1660 ]. |
1565 ]. |
1661 anyTimeouts := true. |
1566 anyTimeouts := true. |
1662 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1567 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1663 ! |
1568 ! |
1664 |
1569 |
1668 |index wasBlocked| |
1573 |index wasBlocked| |
1669 |
1574 |
1670 wasBlocked := OperatingSystem blockInterrupts. |
1575 wasBlocked := OperatingSystem blockInterrupts. |
1671 index := timeoutActions identityIndexOf:aBlock. |
1576 index := timeoutActions identityIndexOf:aBlock. |
1672 (index ~~ 0) ifTrue:[ |
1577 (index ~~ 0) ifTrue:[ |
1673 timeouts at:index put:nil. |
1578 timeouts at:index put:nil. |
1674 timeoutActions at:index put:nil. |
1579 timeoutActions at:index put:nil. |
1675 timeoutSemaphores at:index put:nil. |
1580 timeoutSemaphores at:index put:nil. |
1676 timeoutProcesses at:index put:nil. |
1581 timeoutProcesses at:index put:nil. |
1677 ]. |
1582 ]. |
1678 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1583 wasBlocked ifFalse:[OperatingSystem unblockInterrupts]. |
1679 ! ! |
1584 ! |
|
1585 |
|
1586 evaluateTimeouts |
|
1587 "walk through timeouts and evaluate blocks or signal semas that need to be .." |
|
1588 |
|
1589 |sema now aTime block blocksToEvaluate |
|
1590 processes n "{ Class: SmallInteger }"| |
|
1591 |
|
1592 anyTimeouts ifFalse:[ ^ self]. |
|
1593 |
|
1594 "have to collect the blocks first, then evaluate them. This avoids |
|
1595 problems due to newly inserted blocks." |
|
1596 |
|
1597 now := OperatingSystem getMillisecondTime. |
|
1598 blocksToEvaluate := nil. |
|
1599 n := timeouts size. |
|
1600 anyTimeouts := false. |
|
1601 1 to:n do:[:index | |
|
1602 aTime := timeouts at:index. |
|
1603 aTime notNil ifTrue:[ |
|
1604 (OperatingSystem millisecondTime:aTime isAfter:now) ifFalse:[ |
|
1605 "this one should be triggered" |
|
1606 |
|
1607 sema := timeoutSemaphores at:index. |
|
1608 sema notNil ifTrue:[ |
|
1609 sema signalOnce. |
|
1610 timeoutSemaphores at:index put:nil |
|
1611 ] ifFalse:[ |
|
1612 "to support pure-events" |
|
1613 block := timeoutActions at:index. |
|
1614 block notNil ifTrue:[ |
|
1615 blocksToEvaluate isNil ifTrue:[ |
|
1616 blocksToEvaluate := OrderedCollection new:10. |
|
1617 processes := OrderedCollection new:10. |
|
1618 ]. |
|
1619 blocksToEvaluate add:block. |
|
1620 processes add:(timeoutProcesses at:index). |
|
1621 timeoutActions at:index put:nil. |
|
1622 timeoutProcesses at:index put:nil. |
|
1623 ] |
|
1624 ]. |
|
1625 timeouts at:index put:nil. |
|
1626 ] ifTrue:[ |
|
1627 anyTimeouts := true |
|
1628 ] |
|
1629 ] |
|
1630 ]. |
|
1631 |
|
1632 blocksToEvaluate notNil ifTrue:[ |
|
1633 blocksToEvaluate keysAndValuesDo:[:index :block | |
|
1634 |p| |
|
1635 |
|
1636 p := processes at:index. |
|
1637 (p isNil or:[PureEventDriven]) ifTrue:[ |
|
1638 block value |
|
1639 ] ifFalse:[ |
|
1640 p interruptWith:block |
|
1641 ] |
|
1642 ] |
|
1643 ] |
|
1644 ! ! |