ProcSched.st
changeset 159 514c749165c3
parent 144 dcea1d2b93bc
child 161 ed36169f354d
equal deleted inserted replaced
158:be947d4e7fb2 159:514c749165c3
     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
    53 "
    53 "
    54 !
    54 !
    55 
    55 
    56 version
    56 version
    57 "
    57 "
    58 $Header: /cvs/stx/stx/libbasic/Attic/ProcSched.st,v 1.20 1994-08-23 23:11:00 claus Exp $
    58 $Header: /cvs/stx/stx/libbasic/Attic/ProcSched.st,v 1.21 1994-10-10 00:27:28 claus Exp $
    59 "
    59 "
    60 !
    60 !
    61 
    61 
    62 documentation
    62 documentation
    63 "
    63 "
    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
   302      (warning: low level entry, no administration done)"
   271      (warning: low level entry, no administration done)"
   303 
   272 
   304 %{  /* NOCONTEXT */
   273 %{  /* NOCONTEXT */
   305 
   274 
   306     if (_isSmallInteger(id)) {
   275     if (_isSmallInteger(id)) {
   307         __threadDestroy(_intVal(id));
   276 	__threadDestroy(_intVal(id));
   308     }
   277     }
   309 %}
   278 %}
   310 ! !
   279 ! !
   311 
   280 
   312 !ProcessorScheduler methodsFor:'primitive process primitives'!
   281 !ProcessorScheduler methodsFor:'primitive process primitives'!
   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
   454 
   421 
   455 initialize
   422 initialize
   456     "initialize the one-and-only ProcessorScheduler"
   423     "initialize the one-and-only ProcessorScheduler"
   457 
   424 
   458     |nPrios l p|
   425     |nPrios l p|
       
   426 
       
   427     KnownProcesses isNil ifTrue:[
       
   428 	KnownProcesses := WeakArray new:10.
       
   429 	KnownProcesses watcher:self class.
       
   430 	KnownProcessIds := OrderedCollection new.
       
   431     ].
   459 
   432 
   460     nPrios := SchedulingPriority.
   433     nPrios := SchedulingPriority.
   461     quiescentProcessLists := Array new:nPrios.
   434     quiescentProcessLists := Array new:nPrios.
   462 
   435 
   463     readFds := Array with:nil.
   436     readFds := Array with:nil.
   479      for a runnable process.
   452      for a runnable process.
   480     "
   453     "
   481 
   454 
   482     currentPriority := SchedulingPriority.
   455     currentPriority := SchedulingPriority.
   483     p := Process new.
   456     p := Process new.
   484     p setId:0.
   457     p setId:0 state:#run.
       
   458     p setPriority:currentPriority.
   485     p name:'scheduler'.
   459     p name:'scheduler'.
   486     p state:#run.
       
   487     p setPriority:currentPriority.
       
   488 
   460 
   489     l := LinkedList new.
   461     l := LinkedList new.
   490     l add:p.
   462     l add:p.
   491     scheduler := activeProcess := p.
   463     scheduler := activeProcess := p.
   492 
   464 
   494 
   466 
   495     ObjectMemory ioInterruptHandler:self.
   467     ObjectMemory ioInterruptHandler:self.
   496     ObjectMemory timerInterruptHandler:self.
   468     ObjectMemory timerInterruptHandler:self.
   497 !
   469 !
   498 
   470 
   499 reInitialize
   471 reinitialize
   500     "all previous stuff is obsolete - each object should reinstall itself
   472     "all previous processes are dead - each object should reinstall its
   501      upon restart."
   473      process(s) upon restart - especially, windowgroups have to."
   502 
   474 
   503     KnownProcesses := WeakArray new:5.
   475     KnownProcesses do:[:p |
   504     KnownProcesses watcher:self class.
   476 	p notNil ifTrue:[
   505     KnownProcessIds := OrderedCollection new.
   477 	    "how, exactly should this be done ?"
       
   478 
       
   479 	    'process restart not implemented' errorPrintNL.
       
   480 	    p setId:nil state:#dead 
       
   481 	].
       
   482 	scheduler setId:nil state:#dead 
       
   483     ].
       
   484 
       
   485     "
       
   486      now, start from scratch
       
   487     "
       
   488     KnownProcesses := nil.
   506     self initialize
   489     self initialize
   507 ! !
   490 ! !
   508 
   491 
   509 !ProcessorScheduler methodsFor:'private'!
   492 !ProcessorScheduler methodsFor:'private'!
   510 
   493 
   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 
   645 
   583 
   646     "
   584     "
   647      debugging consistency checks - will be removed later
   585      debugging consistency checks - will be removed later
   648     "
   586     "
   649     l isNil ifTrue:[
   587     l isNil ifTrue:[
   650         wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   588 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   651         'oops - nil runnable list' errorPrintNL.
   589 	'oops - nil runnable list' errorPrintNL.
   652         ^ self
   590 	^ self
   653     ].
   591     ].
   654     l isEmpty ifTrue:[
   592     l isEmpty ifTrue:[
   655         wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   593 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   656         'oops - empty runnable list' errorPrintNL.
   594 	'oops - empty runnable list' errorPrintNL.
   657         ^ self
   595 	^ self
   658     ].
   596     ].
   659 
   597 
   660     l size == 1 ifTrue:[
   598     l size == 1 ifTrue:[
   661         "
   599 	"
   662          the running one is the only one
   600 	 the running one is the only one
   663         "
   601 	"
   664         wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   602 	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
   665         ^ self
   603 	^ self
   666     ].
   604     ].
   667 
   605 
   668     "
   606     "
   669      bring running process to the end
   607      bring running process to the end
   670     "
   608     "
   688 
   626 
   689     "
   627     "
   690      some debugging stuff
   628      some debugging stuff
   691     "
   629     "
   692     aProcess isNil ifTrue:[
   630     aProcess isNil ifTrue:[
   693         MiniDebugger enterWithMessage:'nil suspend'.
   631 	MiniDebugger enterWithMessage:'nil suspend'.
   694         ^ self
   632 	^ self
   695     ].
   633     ].
   696     aProcess id isNil ifTrue:[
   634     aProcess id isNil ifTrue:[
   697         MiniDebugger enterWithMessage:'bad suspend: already dead'.
   635 	MiniDebugger enterWithMessage:'bad suspend: already dead'.
   698 	self reschedule.
   636 	self threadSwitch:scheduler.
   699         ^ self
   637 	^ self
   700     ].
   638     ].
   701     aProcess == scheduler ifTrue:[
   639     aProcess == scheduler ifTrue:[
   702         MiniDebugger enterWithMessage:'scheduler should never be suspended'.
   640 	'scheduler should never be suspended' printNL.
   703         ^ self
   641 	"/ MiniDebugger enterWithMessage:'scheduler should never be suspended'.
       
   642 	^ self
   704     ].
   643     ].
   705 
   644 
   706     wasBlocked := OperatingSystem blockInterrupts.
   645     wasBlocked := OperatingSystem blockInterrupts.
   707 
   646 
   708     pri := aProcess priority.
   647     pri := aProcess priority.
   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'!
   981     "Processor currentPriority"
   932     "Processor currentPriority"
   982 !
   933 !
   983 
   934 
   984 activePriority
   935 activePriority
   985     "return the priority of the currently running process.
   936     "return the priority of the currently running process.
   986      GNU-ST compatibility; this is the same as currentPriority"
   937      GNU-ST & ST-80 compatibility; this is the same as currentPriority"
   987 
   938 
   988     ^ currentPriority
   939     ^ currentPriority
   989 !
   940 !
   990 
   941 
   991 activeProcess
   942 activeProcess
  1003 
   954 
  1004     |l p maxPri "{ Class: SmallInteger }" |
   955     |l p maxPri "{ Class: SmallInteger }" |
  1005 
   956 
  1006     maxPri := self highestPriority.
   957     maxPri := self highestPriority.
  1007     maxPri to:1 by:-1 do:[:prio |
   958     maxPri to:1 by:-1 do:[:prio |
  1008         l := quiescentProcessLists at:prio.
   959 	l := quiescentProcessLists at:prio.
  1009         l notNil ifTrue:[
   960 	l notNil ifTrue:[
  1010             l isEmpty ifTrue:[
   961 	    l isEmpty ifTrue:[
  1011                 "
   962 		"
  1012                  on the fly clear out empty lists
   963 		 on the fly clear out empty lists
  1013                 "
   964 		"
  1014                 quiescentProcessLists at:prio put:nil
   965 		quiescentProcessLists at:prio put:nil
  1015             ] ifFalse:[    
   966 	    ] ifFalse:[    
  1016                 p := l first.
   967 		p := l first.
  1017                 "
   968 		"
  1018                  if it got corrupted somehow
   969 		 if it got corrupted somehow
  1019                 "
   970 		"
  1020                 p id isNil ifTrue:[
   971 		p id isNil ifTrue:[
  1021                     'process with nil id removed' printNL.
   972 		    'process with nil id removed' printNL.
  1022                     l removeFirst.
   973 		    l removeFirst.
  1023                     ^ nil.
   974 		    ^ nil.
  1024                 ].
   975 		].
  1025                 ^ p
   976 		^ p
  1026             ].
   977 	    ].
  1027         ]
   978 	]
  1028     ].
   979     ].
  1029     ^ nil
   980     ^ nil
  1030 ! !
   981 ! !
  1031 
   982 
  1032 !ProcessorScheduler methodsFor:'dispatching'!
   983 !ProcessorScheduler methodsFor:'dispatching'!
  1040 
   991 
  1041     "I made this an extra call to dispatch; this allows recompilation
   992     "I made this an extra call to dispatch; this allows recompilation
  1042      of the dispatch-handling code in the running system.
   993      of the dispatch-handling code in the running system.
  1043     "
   994     "
  1044     [true] whileTrue:[
   995     [true] whileTrue:[
  1045         self dispatch
   996 	self dispatch
  1046     ]
   997     ]
  1047 !
   998 !
  1048 
   999 
  1049 dispatch
  1000 dispatch
  1050      "It handles timeouts and switches to the highest prio runnable process"
  1001      "It handles timeouts and switches to the highest prio runnable process"
  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.
  1111  this will all change, when timeouts are removed and all is process driven
  1062  this will all change, when timeouts are removed and all is process driven
  1112 "
  1063 "
  1113 
  1064 
  1114 "
  1065 "
  1115     pri < TimingPriority ifTrue:[
  1066     pri < TimingPriority ifTrue:[
  1116         anyTimeouts ifTrue:[
  1067 	anyTimeouts ifTrue:[
  1117             millis := self timeToNextTimeout.
  1068 	    millis := self timeToNextTimeout.
  1118             millis == 0 ifTrue:[^ self].
  1069 	    millis == 0 ifTrue:[^ self].
  1119         ]
  1070 	]
  1120     ].
  1071     ].
  1121 "
  1072 "
  1122 
  1073 
  1123     "
  1074     "
  1124      if the process to run has a lower than UserInterruptPriority,
  1075      if the process to run has a lower than UserInterruptPriority,
  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"
  1195      If there where many, the list should be kept sorted ... keeping deltas
  1146      If there where many, the list should be kept sorted ... keeping deltas
  1196      to next (as in Unix kernel)"
  1147      to next (as in Unix kernel)"
  1197 
  1148 
  1198     n := timeouts size.
  1149     n := timeouts size.
  1199     1 to:n do:[:index |
  1150     1 to:n do:[:index |
  1200         aTime := timeouts at:index.
  1151 	aTime := timeouts at:index.
  1201         aTime notNil ifTrue:[
  1152 	aTime notNil ifTrue:[
  1202             minDelta isNil ifTrue:[
  1153 	    minDelta isNil ifTrue:[
  1203                 now := OperatingSystem getMillisecondTime.
  1154 		now := OperatingSystem getMillisecondTime.
  1204                 (OperatingSystem millisecondTime:aTime isAfter:now) ifFalse:[^ 0].
  1155 		(OperatingSystem millisecondTime:aTime isAfter:now) ifFalse:[^ 0].
  1205                 minDelta := OperatingSystem millisecondTimeDeltaBetween:aTime and:now.
  1156 		minDelta := OperatingSystem millisecondTimeDeltaBetween:aTime and:now.
  1206             ] ifFalse:[
  1157 	    ] ifFalse:[
  1207                 (OperatingSystem millisecondTime:aTime isAfter:now) ifFalse:[^ 0].
  1158 		(OperatingSystem millisecondTime:aTime isAfter:now) ifFalse:[^ 0].
  1208                 minDelta := minDelta min:(OperatingSystem millisecondTimeDeltaBetween:aTime and:now)
  1159 		minDelta := minDelta min:(OperatingSystem millisecondTimeDeltaBetween:aTime and:now)
  1209             ]
  1160 	    ]
  1210         ]
  1161 	]
  1211     ].
  1162     ].
  1212 
  1163 
  1213     ^ minDelta
  1164     ^ minDelta
  1214 !
  1165 !
  1215 
  1166 
  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
  1380 
  1274 
  1381     |idx wasBlocked|
  1275     |idx wasBlocked|
  1382 
  1276 
  1383     wasBlocked := OperatingSystem blockInterrupts.
  1277     wasBlocked := OperatingSystem blockInterrupts.
  1384     (readFds includes:aFileDescriptor) ifFalse:[
  1278     (readFds includes:aFileDescriptor) ifFalse:[
  1385         idx := readFds indexOf:nil.
  1279 	idx := readFds indexOf:nil.
  1386         idx ~~ 0 ifTrue:[
  1280 	idx ~~ 0 ifTrue:[
  1387             readFds at:idx put:aFileDescriptor.
  1281 	    readFds at:idx put:aFileDescriptor.
  1388             readSemaphores at:idx put:aSemaphore.
  1282 	    readSemaphores at:idx put:aSemaphore.
  1389             readChecks at:idx put:aBlock
  1283 	    readChecks at:idx put:aBlock
  1390         ] ifFalse:[
  1284 	] ifFalse:[
  1391             readFds := readFds copyWith:aFileDescriptor.
  1285 	    readFds := readFds copyWith:aFileDescriptor.
  1392             readSemaphores := readSemaphores copyWith:aSemaphore.
  1286 	    readSemaphores := readSemaphores copyWith:aSemaphore.
  1393             readChecks := readChecks copyWith:aBlock.
  1287 	    readChecks := readChecks copyWith:aBlock.
  1394         ]
  1288 	]
  1395     ].
  1289     ].
  1396     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  1290     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  1397 !
  1291 !
  1398 
  1292 
  1399 signal:aSemaphore onOutput:aFileDescriptor
  1293 signal:aSemaphore onOutput:aFileDescriptor
  1402 
  1296 
  1403     |idx wasBlocked|
  1297     |idx wasBlocked|
  1404 
  1298 
  1405     wasBlocked := OperatingSystem blockInterrupts.
  1299     wasBlocked := OperatingSystem blockInterrupts.
  1406     (writeFds includes:aFileDescriptor) ifFalse:[
  1300     (writeFds includes:aFileDescriptor) ifFalse:[
  1407         idx := writeFds indexOf:nil.
  1301 	idx := writeFds indexOf:nil.
  1408         idx ~~ 0 ifTrue:[
  1302 	idx ~~ 0 ifTrue:[
  1409             writeFds at:idx put:aFileDescriptor.
  1303 	    writeFds at:idx put:aFileDescriptor.
  1410             writeSemaphores at:idx put:aSemaphore.
  1304 	    writeSemaphores at:idx put:aSemaphore.
  1411         ] ifFalse:[
  1305 	] ifFalse:[
  1412             writeFds := writeFds copyWith:aFileDescriptor.
  1306 	    writeFds := writeFds copyWith:aFileDescriptor.
  1413             writeSemaphores := writeSemaphores copyWith:aSemaphore.
  1307 	    writeSemaphores := writeSemaphores copyWith:aSemaphore.
  1414         ]
  1308 	]
  1415     ].
  1309     ].
  1416     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  1310     wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
  1417 !
  1311 !
  1418 
  1312 
  1419 signal:aSemaphore afterSeconds:seconds
  1313 signal:aSemaphore afterSeconds:seconds
  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 ! !