|
Class: ProcessorScheduler
Object
|
+--ProcessorScheduler
- Package:
- stx:libbasic
- Category:
- Kernel-Processes
- Version:
- rev:
1.438
date: 2024/03/26 13:09:44
- user: cg
- file: ProcessorScheduler.st directory: libbasic
- module: stx stc-classLibrary: libbasic
This class has only one instance, which is bound to the global
'Processor' (well, on future multiprocessor systems, things may look
different ... ;-). It is responsible for scheduling among the Smalltalk
processes (threads; not to confuse with heavy weight unix processes).
Scheduling is fully done in Smalltalk (the always runnable scheduler-
process, running at highest priority does this).
See the 'scheduling' documentation.
The main VM primitive to support this is found in threadSwitch, which passes
control to another process (usually selected by the scheduler).
Thus it is possible to modify the scheduler's policy and implementation
at the Smalltalk level (if you are brave enough to do this).
Notice:
ST/X includes a timeslicer and reschedules running threads within the highest runnable
priority. This is done by the timeSlicer thread, which runs at high realtime prio.
Also notice, that ST/X supports dynamic priority ranges: a low prio (background) process
can be quaranteed to make progress, by giving it a range from low to a higher (usually user-) prios.
If it was suspended long enough, its prio will be dynamically increased, until it gets a slice to run
(and then drops back to its low background prio). So it will get a chance to do some work.
Final Notice:
Smalltalk/X used to support a mode (configured and compiled) without
process support. This non-process mode was called 'pureEventDriven' mode
and was useful to quickly port ST/X to systems, where these facilities
were either not needed (server applications), or were difficult to
implement (threads require some assembler support functions).
To allow pureEvent mode, kludges were built into some places in the
system, where either a process is forked, or a timeout is used instead
(for examples, see ProcessMonitor or MemoryMonitor).
Although still present in some places, support for this pure-event mode is no longer supported,
and will vanish over time from the code.
[instance variables:]
quiescentProcessLists - list of waiting processes
scheduler - the scheduler process itself
zombie - internal temporary (recently died process)
activeProcess - the current process
activeProcessId - the current processes id
currentPriority - the current processes priority
readFdArray - fd-sema-checkBlock triple-association
readSemaphoreArray (stupid historic 3-separate arrays for hi-speed-optimization reasons)
readCheckArray
writeFdArray - fd-sema-checkBlock triple-association
writeSemaphoreArray (stupid historic 3-separate arrays for hi-speed-optimization reasons)
writeCheckArray
timeoutArray - time-action-process-sema quadruple-association
timeoutActionArray (stupid historic 3-separate arrays for hi-speed-optimization reasons)
timeoutProcessArray
timeoutSemaphoreArray
idleActions - actions to be executed when idle
preWaitActions - actions to be executed BEFORE going into an OS-wait
anyTimeouts - flag if any timeouts are pending
dispatching - flag if dispatch process is running (i.e. NOT initializing)
interruptedProcess - the currently interrupted process.
useIOInterrupts - flag if the OS supports I/O interrupts and if they are used (to get me out of an OS wait)
gotIOInterrupt - flag if I came out of a wait due to an I/O interrupt
osChildExitActions - OS chid process actions
gotChildSignalInterrupt - flag if I came out of a wait due to an OS child interrupt
exitWhenNoMoreUserProcesses - flag which controls if ST/X should exit when the last process dies (for standalone apps)
suspendScheduler - internal use
timeSliceProcess - the timeSlicer process
supportDynamicPriorities - flag if dynamic priorities should be supported by the timeSlicer
scheduledProcesses - list of scheduled processes for the timeSlicers dynamic prio handling
[class variables:]
KnownProcesses <WeakArray> all known processes
KnownProcessIds <Array> and their IDs
PureEventDriven <Boolean> true, if no process support
is available
UserSchedulingPriority <Integer> the priority at which normal
user interfaces run
UserInterruptPriority the priority at which user-
interrupts (Cntl-C) processing
takes place. Processes with
a greater or equal priority are
not interruptable.
TimingPriority the priority used for timing.
Processes with a greater or
equal priority are not interrupted
by timers.
HighestPriority The highest allowed prio for processes
SchedulingPriority The priority of the scheduler (must
me higher than any other).
MaxNumberOfProcesses if non-nil, no more than this
number of processes are allowed
(for debugging)
TimeSliceInterval for preemptive priority scheduling only:
the time interval in millis, at which processes
are timesliced
TimeSlicingPriorityLimit for preemptive priority scheduling only:
processes are only timesliced, if running
at or below this priority.
EventPollingInterval for systems which do not support select on
a fileDescriptor: the polling interval in millis.
most interesting methods:
Processor>>suspend: (see also Process>>suspend)
Processor>>resume: (see also Process>>resume)
Processor>>terminate: (see also Process>>terminate)
Processor>>yield
Processor>>changePriority:for: (see also Process>>priority:
Processor>>signal:afterSeconds: (see also Delay>>forSeconds:)
Processor>>signal:afterMilliseconds: (see also Delay>>forMilliseconds:)
Processor>>signal:onInput: (see also ExternalStream>>readWait)
Processor>>signal:onOutput: (see also ExternalStream>>writeWait)
Processor>>disableSemaphore:
copyrightCOPYRIGHT (c) 1993 by Claus Gittinger
All Rights Reserved
This software is furnished under a license and may be used
only in accordance with the terms of that license and with the
inclusion of the above copyright notice. This software may not
be provided or otherwise made available to, or used by, any
other person. No title to or ownership of the software is
hereby transferred.
schedulingBy default, the scheduler does 'non preemptive priority scheduling';
this means, that the highest priority runnable process
is choosen and allowed to run, until it either gives back the CPU (via #yield),
or suspends (i.e. waiting for I/O, the time or a semaphore),
or a higher priority process becomes runnable..
A higher prio process may become runnable either by a programmatic action
(i.e. signalling a semaphore), by a timer or by IO availability.
If another process is runnable at the same priority, it will not
be given CPU-time, unless one of the above happens.
The consequence is, that a user process running at (say) priority 8,
may block other user processes at the same priority, if it does heavy
processing, or loops.
(the event handling which is responsible to care for userInterrupts,
is running at a much higher priority,
so that interrupting the process should always be possible).
The scheduler also supports 'timesliced priority scheduling', which is enabled
via the #startTimeSlicing message (and disabled by #stopTimeSlicing).
In this mode, the highest priority running process is suspended in regular intervals
(the TimeSliceInterval) IFF there is another runnable process with the same priority.
I.e. the top highest priority processes are timeshared.
In this mode, the other processes will also get a chance to make some progress - however,
lower priority process will only run, IFF all higher prio processes are waiting for an
event.
Timeslicing will not be done for processes running above TimeSlicingPriorityLimit, which
allows for critical processes to run unaffected to completion.
WARNING:
timesliced priority scheduling is an experimental feature. There is no warranty,
(at the moment), that the system runs reliable in this mode.
The problem is, that shared collections may now be easily modified by other
processes, running at the same time.
The class library has being investigated for such possible trouble spots
(we have eliminated many weak spots, and added critical regions at many places,
but cannot guarantee that all of them have been found so far ...)
We found that many existing public domain programs are not prepared for
being interrupted by a same-prio process and therefore may corrupt their
data. If in doubt, disable this fefature.
We think, that the timeSlicer is a useful add-on and that the system is fit enough
for it to be evaluated, therefore, its included.
However, use it at your own risk.
To demonstrate the effect of timeSlicing, do the following:
- disable timeSlicing (in the launchers misc-settings menu)
- open a workSpace
- in the workspace, evaluate:
[true] whileTrue:[1000 factorial]
now, (since the workSpace runs at the same prio as other window-processes),
other views do no longer react - all CPU is used up by the workSpace.
However, CTRL-C in the workspace is still possible to stop the endless loop,
since that is handled by the (higher prio) event dispatcher process.
Now, stop the factorial-loop, enable timeSlicing, and try again.
You will notice, that other windows react - although possibly a bit slower,
since the CPU is now divided equally among the runnable processes (timeSliced).
Signal constants
-
invalidProcessSignal
-
initialization
-
initialize
-
class setup: create the one-and-only instance of myself and
setup some priority values.
-
initializeVMMaxProcessId
-
for java locks, the VM may reserve some bits
instance creation
-
new
-
there is (currently) only one processor ...
instance release
-
update: anAspect with: aParameter from: changedObject
-
some Process has been garbage collected
- terminate the underlying thread.
Usually this does not happen; instead, the process terminates itself
by sending #terminate.
primitive process primitives
-
threadCreate: aProcess withId: id
-
physical creation of a process.
(warning: low level entry, no administration done).
This may raise an exception, if a VM process could not be created.
-
threadDestroy: id
-
physical destroy other process ...
(warning: low level entry, no administration done)
-
threadInterrupt: id
-
make the process evaluate an interrupt. This sets a flag in the VMs
threadSwitcher, to let the process perform a #interrupt when its set to
run the next time. The process itself can decide how to react on this
interrupt (currently, it looks for interruptBlocks to evaluate).
-
threadsAvailable
-
return true, if the runtime system supports threads (i.e. processes);
false otherwise.
queries
-
isPureEventDriven
-
this is temporary - (maybe not :-).
you can run ST/X either with or without processes.
Without, there is conceptionally a single process handling all
outside events and timeouts. This has some negative implications
(Debugger is ugly), but allows a fully portable ST/X without any
assembler support - i.e. quick portability.
The PureEvent flag will automatically be set if the runtime system
does not support threads - otherwise, it can be set manually
(from rc-file).
-
knownProcesses
-
return a collection of all (living) processes in the system
Usage example(s):
ProcessorScheduler knownProcesses
|
-
knownProcessesDo: aBlock
-
evaluate aBlock for each (living) processes in the system
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
maxNumberOfProcesses
-
return the limit on the number of processes;
the default is nil (i.e. unlimited).
-
maxNumberOfProcesses: aNumber
-
set the limit on the number of processes.
This helps if you have a program which (by error) creates countless
subprocesses. Without this limit, you may have a hard time to find
this error (and repairing it). If nil (the default), the number of
processes is unlimited.
-
maxProcessId
-
Return a maximum allowed value of a Process id.
-
processDriven
-
turn on process driven mode
-
processWithID: id
-
-
pureEventDriven
-
turn on pure-event driven mode - no processes, single dispatch loop
I/O event actions
-
enableIOAction: aBlock onInput: aFileDescriptor
-
obsolete event support: arrange for aBlock to be
evaluated when input on aFileDescriptor arrives.
This is a leftover support for pure-event systems and may vanish.
accessing
-
activePriority
-
return the priority of the currently running process.
GNU-ST & ST-80 compatibility; this is the same as currentPriority
-
activeProcess
-
return the currently running process
Usage example(s):
-
activeProcessId
-
return the currently running process's ID.
The same as returned by 'Processor activeProcess id';
added for to avoid another send in semaphores debugging support.
-
currentPriority
-
return the priority of the currently running process
Usage example(s):
Processor currentPriority
|
-
exitWhenNoMoreUserProcesses: aBoolean
-
set/clear the flag, which controls if the scheduler should exit and return
when the last user process finishes (and therefore exit the smalltalk system).
A userProcess is defined as a process with a non-zero processGroup.
This flag is typically set for standAlone operation, to terminate the (Unix-)
process, when the last thread terminates.
-
interruptCounter
-
for statistics: counts the overall number of interrupts
Usage example(s):
Processor interruptCounter
|
-
interruptedProcess
-
returns the process which was interrupted by the active one
-
maxProcessId
-
-
scheduler
-
return the scheduling process
-
timedActionCounter
-
for statistics: counts the overall number of timer actions
Usage example(s):
Processor timedActionCounter
|
background processing
-
addIdleBlock: aBlock
-
add the argument, aBlock to the list of idle-actions.
Idle blocks are evaluated whenever no other process is runnable,
and no events are pending.
Use of idle blocks is not recommended, use a low priority processes
instead, which has the same effect. Idle blocks are still included
to support background actions in pure-event systems, where no processes
are available.
ATTENTION: Support for idle-blocks may vanish.
-
removeIdleBlock: aBlock
-
remove the argument, aBlock from the list of idle-blocks.
ATTENTION: Support for idle-blocks may vanish - use low prio processes instead.
dispatching
-
dispatch
-
It handles timeouts and switches to the highest prio runnable process
-
dispatchLoop
-
central dispatch loop; the scheduler process is always staying in
this method, looping forever.
initialization
-
initialize
-
initialize the one-and-only ProcessorScheduler
-
reinitialize
-
all previous processes (except those marked as restartable) are made dead
- each object should reinstall its process(s) upon restart;
especially, windowgroups have to.
In contrast to ST-80, restartable processes are restarted at the beginning
NOT continued where left. This is a consequence of the portable implementation
of ST/X, since in order to continue a process, we needed to know the
internals of the machines (and C-compilers) stack layout.
This was not done, favouring portability for process continuation.
In praxis, this is not much of a problem, since in almost every case,
the computation state can be saved in some object, and processing be
restarted from scratch, reinitializing things from this saved state.
native thread support
-
vmResumeInterrupt: id
-
signal from VM to resume a thread after finish of an osWait or wrapCall-wait.
MUST be invoked with interrupts blocked.
This is only used with native threads.
-
vmSuspendInterrupt: whyCode
-
signal from VM to suspend a thread into a certain state.
Invoked before the VM switches to the scheduler process.
MUST be invoked with interrupts blocked.
This is only used with native threads.
os process handling
-
childSignalInterrupt
-
child changed state - switch to scheduler process which will decide
what to do now.
-
handleChildSignalInterrupt
-
child changed state - execute child termination blocks.
If child is no longer alive, remove action block.
-
monitor: aBlockReturningPid action: actionBlock
-
Helper for executing and waiting for OS processes.
aBlockReturningPid is evaluated and supposed to return
the process-id of an OS-process or nil.
To avoid race conditions, the OS-process must be started
within the block.
ActionBlock will be called with an OSProcessStatus as arg if the
status of the OS process changes (e.g. the process terminates).
The method returns the value from aBlockReturningPid (i.e. a pid or nil).
-
unmonitorPid: pid
-
remove a monitor for a child process.
Note: pid is a OS process id!
primitive process primitives
-
scheduleForInterrupt: aProcess
-
make aProcess evaluate its pushed interrupt block(s)
-
scheduleInterruptActionsOf: aProcess
-
make aProcess evaluate its pushed interrupt block(s)
when resumed.
-
threadSwitch: aProcess
-
continue execution in aProcess.
WARNING: this is a low level entry, no process administration is done here
priority constants
-
highIOPriority
-
not currently used - for ST80 compatibility only
-
highestPriority
-
return the highest priority value (normal) processes can have.
-
lowIOPriority
-
not currently used - for ST80 compatibility only
-
lowestPriority
-
return the lowest priority value
-
schedulingPriority
-
return the priority at which the scheduler runs.
-
systemBackgroundPriority
-
return the priority, at which background system processing
should take place.
Usage example(s):
Processor systemBackgroundPriority
|
-
timeSlicingPriorityLimit
-
return the priority, above which no timeslicing takes place
(i.e. processes running at a higher priority are not preempted).
This is only effective, if preemption is enabled.
-
timingPriority
-
return the priority, at which all timing takes place (messageTally,
delay etc.)
-
userBackgroundPriority
-
return the priority, at which background user (non-interactive) processing
should take place.
Usage example(s):
Processor userBackgroundPriority
|
-
userInterruptPriority
-
return the priority, at which the event scheduler runs - i.e.
all processes running at a lower priority are interruptable by Cntl-C
or the timer. Processes running at higher prio will not be interrupted.
-
userSchedulingPriority
-
return the priority, at which all normal user (interactive) processing
takes place
private
-
remember: aProcess
-
remember aProcess for later disposal (where the underlying
system resources have to be freed).
-
unRemember: aProcess
-
forget aProcess - dispose processing will not consider this one
process creation
-
newProcessFor: aProcess
-
create a physical (VM-) process for aProcess.
Raise an AllocationFailedError if something went wrong.
The process is not scheduled; to start it running, it needs a Process>>resume.
Once resumed, the process will later get control in its #start method.
-
newProcessFor: aProcess withId: nilOrIdWant
-
private entry for Process restart - do not use in your program
queries
-
activeProcessIsBackgroundProcess
-
return true if the active process is a background process,
running at a lower priority.
Usage example(s):
Processor activeProcessIsBackgroundProcess
|
-
activeProcessIsSystemProcess
-
return true if the active process is a system process,
which should not be suspended.
Usage example(s):
Processor activeProcessIsSystemProcess
|
-
anyScheduledWindowGroupAtAll
-
return true, if there is any window group with active topviews.
This is used to determine if we should stop scheduling
in standAlone applications.
Usage example(s):
Processor anyScheduledWindowGroupAtAll
|
-
anyUserProcessAtAll
-
return true, if there is any user process still running,
or waiting on a semaphore.
This is used to determine if we should stop scheduling
in standAlone applications.
A user process has a non-zero processGroup.
Should be called with interrupts blocked.
Usage example(s):
Processor anyUserProcessAtAll
|
-
highestPriorityRunnableProcess
-
return the highest prio runnable process
-
isDispatching
-
-
isPureEventDriven
-
this is temporary - (maybe not :-).
you can run ST/X either with or without processes.
Without, there is conceptionally a single process handling all
outside events and timeouts. This has some negative implications
(Debugger is ugly), but allows a fully portable ST/X without any
assembler support - i.e. quick portability.
The PureEvent flag will automatically be set if the runtime system
does not support threads - otherwise, it can be set manually
(from rc-file).
-
isTimeSlicing
-
return true, if in timeslicing mode
Usage example(s):
-
processWithId: anInteger
-
answer the process with id anInteger, or nil if there is none
Usage example(s):
Processor processWithId:4
Processor processWithId:4711
|
-
processesWithGroupId: anInteger
-
answer a collection of processes with processGroupId, anInteger
Usage example(s):
Processor processesWithGroupId:0
Processor processesWithGroupId:4711
|
scheduling
-
changePriority: prio for: aProcess
-
change the priority of aProcess
-
interruptActive
-
interrupt the current process
- this message is sent by the VM, when a process is about to be switched to,
and that process has the interrupted flag bit set.
Pass the interrupt to the process, which may do whatever it likes with it.
-
makeRunnable: aProcess
-
set aProcess runnable - but do not reschedule.
Answer:
the process, that has a higher priority than the current running process
nil if the current process should keep running.
NOTE: must not perform an operation inside that causes a reschedule.
-
processTermination
-
sent by VM if the current process finished its startup block
without proper process termination. Lay him to rest now.
This can only happen, if something went wrong in Block>>newProcess,
since the block defined there always terminates itself.
-
reschedule
-
switch to the highest prio runnable process.
The scheduler itself is always runnable, so we can do an unconditional switch
to that one. This method is provided as a hook for primitive C code,
to allow giving up the CPU.
-
resume: aProcess
-
set aProcess runnable -
if its prio is higher than the currently running prio, switch to it.
-
resumeForSingleSend: aProcess
-
like resume, but let the process execute a single send only.
This will be used by the debugger for single stepping.
-
suspend: aProcess
-
remove the argument, aProcess from the list of runnable processes.
If the process is the current one, reschedule.
Notice:
This method should only be called by Process>>suspend or
Process>>suspendWithState:
Usage example(s):
'Processor [warning]: bad suspend: process is not running' errorPrintCR.
|
Usage example(s):
MiniDebugger enterWithMessage:'bad suspend: process is not running'.
|
-
terminate: aProcess
-
terminate aProcess. This is done by sending aProcess the terminateSignal,
which will evaluate any unwind blocks and finally do a hard terminate.
-
terminateActive
-
terminate the current process (i.e. the running process kills itself).
The active process is sent the terminateSignal so it will evaluate any
unwind blocks and finally do a hard terminate.
This is sent for regular termination and by the VM, if the hard-stack limit
is reached. (i.e. a process did not repair things in a recursionInterrupt and
continued to grow its stack)
-
terminateActiveNoSignal
-
hard terminate the active process, without sending any
terminate signal thus no unwind blocks are evaluated.
-
terminateNoSignal: aProcess
-
hard terminate aProcess without sending the terminate signal, thus
no unwind blocks or exitAction are performed in the process..
If it's not the current process, it is simply removed from its list
and physically destroyed. Otherwise (since we can't take away the chair
we are sitting on), a switch is forced and the process
will be physically destroyed by the next running process.
(see zombie handling)
-
yield
-
move the currently running process to the end of the current list
and reschedule to the first in the list, thus switching to the
next same-prio-process.
scheduling-preemptive
-
recomputeDynamicPriorities
-
recompute dynamic priorities.
-
scheduledProcesses
-
return a collection of recently scheduled processes.
This is only non-empty, if the dynamic priority
scheduler is running
-
slice
-
Give other Processes at the current priority a chance to run.
-
startTimeSlicing
-
start preemptive scheduling (timeSlicing)
Usage example(s):
Processor stopTimeSlicing.
Processor startTimeSlicing.
|
-
stopTimeSlicing
-
stop preemptive scheduling (timeSlicing)
Usage example(s):
Processor stopTimeSlicing
|
-
supportDynamicPriorities
-
return true, if dynamic priorities are enabled
-
supportDynamicPriorities: aBoolean
-
enable/disable dynamic priorities
Usage example(s):
Processor supportDynamicPriorities:true
Processor supportDynamicPriorities:false
|
-
timeSlicingLoop
-
interval changed -> need a new delay
semaphore signalling
-
disableFd: aFileDescriptor doSignal: doSignal
-
disable triggering of a semaphore for aFileDescriptor..
If doSignal is true, the associated semaphore is signaled.
Answer a collection of semaphores that haven't been signaled.
-
disableSemaphore: aSemaphore
-
disable triggering of a semaphore
-
signal: aSemaphore
-
arrange for a semaphore to be triggered as soon as possible.
The actual signalling is performed slightly delayed, when the dispatcher
looks for a process to resume the next time. I.e. here, the current
process continues to execute, even if the semaphore signalling would
make a higher prio process runnable.
This is provided as entry for primitive-code (external functions)
which want to signal a semaphore AND make certain that they do not get
suspended (i.e. it is called by __STX_SignalSemaphore()).
Normal smalltalk code should always send an appropriate message directly
to the semaphore (i.e. aSemaphore signal).
-
signal: aSemaphore after: secondsOrTimeDuration
-
arrange for a semaphore to be triggered after aTimeDuration
-
signal: aSemaphore afterMilliseconds: millis
-
arrange for a semaphore to be triggered after some milliseconds
-
signal: aSemaphore afterSeconds: seconds
-
arrange for a semaphore to be triggered after some seconds
-
signal: aSemaphore atMilliseconds: aMillisecondTime
-
arrange for a semaphore to be triggered at a specific millisecond time.
If there is already a pending trigger time installed for that semaphore,
the time of the pending trigger is changed.
-
signal: aSemaphore onException: aFileDescriptor
-
arrange for a semaphore to be triggered when output on aFileDescriptor
is possible (i.e. can be written without blocking) or aBlock returns true.
The checkBlock will be evaluated by the scheduler from time to time
(i.e. every few milliseconds).
This checkBlock is required for poor windows, where a WaitForObject does
not know about sockets.
If aBlock is nil, the semaphore is removed from the set of semaphores, after being signaled.
-
signal: aSemaphore onInput: aFileDescriptor
-
arrange for a semaphore to be triggered when input on aFileDescriptor
arrives. This will only happen, if the OS supports selecting on fileDescriptors.
The semaphore is removed from the set of semaphores, after being signaled.
-
signal: aSemaphore onInput: aFileDescriptor orCheck: aBlock
-
arrange for a semaphore to be triggered when input on aFileDescriptor
arrives OR checkblock evaluates to true.
The checkBlock will be evaluated by the scheduler from time to time
(i.e. every few milliseconds).
(This is req'd for buffered input, where a select may not detect
data which has already been read into a buffer - as in Xlib.
Or on systems, where we cannot select on a displays eventQ, such as windows).
If aBlock is nil, the semaphore is removed from the set of semaphores, after being signaled.
-
signal: aSemaphore onInputStream: aStream
-
arrange for a semaphore to be triggered when input on aStream arrives.
This will do a select, if the OS supports selecting on that filedescriptor,
otherwise, it will be polled every few milliseconds (MSDOS).
-
signal: aSemaphore onOutput: aFileDescriptor
-
arrange for a semaphore to be triggered when output on aFileDescriptor
is possible without blocking.
The semaphore is removed from the set of semaphores, after being signaled.
-
signal: aSemaphore onOutput: aFileDescriptor orCheck: aBlock
-
arrange for a semaphore to be triggered when output on aFileDescriptor
is possible (i.e. can be written without blocking) or aBlock returns true.
The checkBlock will be evaluated by the scheduler from time to time
(i.e. every few milliseconds).
This checkBlock is required for poor windows, where a WaitForObject does
not know about sockets.
If aBlock is nil, the semaphore is removed from the set of semaphores, after being signaled.
-
signal: aSemaphore onOutputStream: aStream
-
arrange for a semaphore to be triggered when output on aStream is possible.
This will do a select, if the OS supports selecting on that filedescriptor,
otherwise, it will be polled every few milliseconds (MSDOS).
special configuration
-
useIOInterrupts: aBoolean
-
enable/disable the use of IO-interrupts.
If disabled, communication channels (socket, X-server connection etc.)
are polled in regular intervals.
If enabled, arrangements are made for data-availability to trigger an
interrupt.
Using IO interrupts reduces the idle CPU usage of ST/X by some percent
(typically 2-7%).
Notice:
some systems do not support IO-interrupts (or have a broken stdio-lib),
and this feature is always disabled;
Also notice:
we found that in some Xlib-implementations, interrupted reads are not
handled correctly (especially in multi-headed applications), and this
feature should be disabled to avoid a blocking XPending.
If this method is used to disable IO interrupts in multi-headed apps,
it should be invoked BEFORE the display event dispatcher processes are started.
timeout handling
-
addTimedBlock: aBlock after: timeDurationOrSeconds
-
add the argument, aBlock to the list of time-scheduled-blocks; to be
evaluated after timeDuration.
The process which installs this timed
block will later be interrupted for execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock afterMilliseconds: delta
-
add the argument, aBlock to the list of time-scheduled-blocks; to be
evaluated after delta milliseconds. The process which installs this timed
block will be interrupted for execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock afterSeconds: delta
-
add the argument, aBlock to the list of time-scheduled-blocks.
to be evaluated after delta seconds. The process which installs this timed
block will be interrupted for execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock atMilliseconds: aMillisecondTime
-
add the argument, aBlock to the list of time-scheduled-blocks; to be
evaluated when the millisecondClock value passes aMillisecondTime.
The process which installs this timed block will be interrupted for
execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock for: aProcess after: timeDurationOrSeconds
-
add the argument, aBlock to the list of time-scheduled-blocks.
to be evaluated after timeDuration. aProcess will be interrupted for
execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
If aProcess is nil, the block will be evaluated by the scheduler itself
(which is dangerous - the block should not raise any error conditions).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock for: aProcessOrNil afterMilliseconds: delta
-
add the argument, aBlock to the list of time-scheduled-blocks; to be
evaluated after delta milliseconds. The process specified by the argument,
aProcessOrNil will be interrupted for execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
If aProcessOrNil is nil, the block will be evaluated by the scheduler itself
(which is dangerous - the block should not raise any error conditions).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock for: aProcess afterSeconds: delta
-
add the argument, aBlock to the list of time-scheduled-blocks.
to be evaluated after delta seconds. aProcess will be interrupted for
execution of the block.
(if it is running, the interrupt will occur in whatever method it is
executing; if it is suspended, it will be resumed).
If aProcess is nil, the block will be evaluated by the scheduler itself
(which is dangerous - the block should not raise any error conditions).
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimedBlock: aBlock for: aProcessOrNil atMilliseconds: aMillisecondTime
-
add the argument, aBlock to the list of time-scheduled-blocks;
to be evaluated by aProcess when the millisecondClock value passes
aMillisecondTime.
If that block is already in the timeout list, its trigger-time is changed.
The process specified by the argument, aProcess
will be interrupted for execution of the block.
If aProcessOrNil is nil, the block will be evaluated by the scheduler itself
(which is dangerous: the block should not raise any error conditions).
If the process is active at trigger time, the interrupt will occur in
whatever method it is executing;
if suspended at trigger time, it will be resumed.
The block will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimeoutFunctionCall: anExternalFunction for: aProcess afterMilliseconds: delta with: argument
-
prepare for an external function to be called with a single argument
after some millisecond-Delay.
If aProcess is nil, the block will be evaluated by the scheduler itself,
otherwise, that process will be interrupted and the function is performed
in this processes context.
The callBack will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
addTimeoutFunctionCall: anExternalFunction for: aProcess atMilliseconds: milliTime with: argument
-
prepare for an external function to be called with a single argument
at some millisecond-time.
If aProcess is nil, the block will be evaluated by the scheduler itself,
otherwise, that process will be interrupted and the function is performed
in this processes context.
The callBack will be removed from the timed-block list after evaluation
(i.e. it will trigger only once).
Returns an ID, which can be used in #removeTimeoutWithID:
-
evaluateTimeouts
-
walk through timeouts and evaluate blocks or signal semas that need to be ..
-
removeTimedBlock: aBlock
-
remove the argument, aBlock from the list of time-scheduled blocks.
If aBlock is not found in the list, no error is raised.
-
removeTimeoutForSemaphore: aSemaphore
-
remove all the timeOuts that signals aSemaphore
from the list of time-scheduled actions.
If aSemaphore is not found in the list, no error is raised.
-
removeTimeoutWithID: anID
-
remove the timeOut with anID (as returned by #addTimedBlock)
from the list of time-scheduled-blocks.
DANGER: do not use.
Use #removeTimedBlock: or or #removeTimeoutForSemaphore: or #removeTimeoutWithID:object: instead, which are safe.
If you keep an outdated timeoutID and remove it later,
the wrong timeout which re-uses the same id may be removed!
** This is an obsolete interface - do not use it (it may vanish in future versions) **
-
removeTimeoutWithID: anID object: aBlockOrSemaphore
-
remove the timeOut with anID (as returned by #addTimedBlock)
from the list of time-scheduled-blocks.
If aBlockOrSempahore is not nil, check if the id is really for the block
or for the semphore.
-
timeoutHandlerProcess
-
-
timeoutHandlerProcessLoop
-
The timeoutHandlerProcess does nothing but wait.
It exists only, so that timeout blocks may be executed in its context
(i.e. it will always just wait forever, and perform timeout actions
for others in its interrupt handler).
-
timeoutList
-
return (a copy of) the list of current timeouts; only for debugging (i.e. for the monitor).
The info is a pair where the first element is the current time (in OS-milliseconds)
and the second element is a collection of timeouts which are valid at this time.
Usage example(s):
wait hooks
-
addPreWaitAction: aBlock
-
add the argument, aBlock to the list of preWait-actions.
These blocks are evaluated right before the CPU is given up for the OS-wait.
(i.e. the OS-wait for next event or timeout).
Systems with buffered output (i.e. Xlib) can install a flush-block here,
to force unflushed output to be sent out in regular intervals)
-
removePreWaitAction: aBlock
-
remove the argument, aBlock from the list of preWait-actions.
waiting
-
checkForEndOfDispatch
-
check if there are any processes at all
-
checkForIOWithTimeout: millis
-
this is called, when there is absolutely nothing to do;
hard wait for either input to arrive, or output to be possible
or a timeout to occur.
Answer true, if processes have possibly been woken up, false otherwise.
-
ioInterrupt
-
data arrived while waiting - switch to scheduler process which will decide
what to do now.
This method is called by the VM' interrupt handling mechanism.
Notice, that at the time of the message, we are still in the context
of whichever process is currently running.
-
removeCorruptedFds
-
this is sent when select returns an error due to some invalid
fileDescriptor. May happen, if someone does a readWait/writeWait on a
socket connection, which somehow got corrupted
(shutdown by partner, or closed by another thread, while being in a read/write-wait).
Without special care, all following selects would immediately return with
an #EBADF error, leading to high-frequency polling and a locked up system.
(you could still fix things by interrupting on the console and fixing the
readFdArray/writeFdArray in the debugger)
-
schedulerInterrupt
-
forced reschedule - switch to scheduler process which will decide
what to do now.
-
timeToNextTimeout
-
return the positive delta-T (in milliseconds) to the next timeout,
or nil if there is none
-
timerInterrupt
-
timer expired while waiting - switch to scheduler process which will decide
what to do now.
This method is called by the VM' interrupt handling mechanism.
Notice, that at the time of the message, we are still in the context
of whichever process is currently running.
-
waitForEventOrTimeout
-
entered when no process is runnable - wait for either input on
any file descriptors to arrive or a timeout to happen.
If it makes sense, do some background garbage collection.
The idle actions are a leftover from previous ST/X releases and will
vanish (installing a low-prio process has the same effect).
|