eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'ProcessorScheduler':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: ProcessorScheduler


Inheritance:

   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

Description:


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:

copyright

COPYRIGHT (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.

scheduling

By 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).

Class protocol:

Signal constants
o  invalidProcessSignal

initialization
o  initialize
class setup: create the one-and-only instance of myself and
setup some priority values.

o  initializeVMMaxProcessId
for java locks, the VM may reserve some bits

instance creation
o  new
there is (currently) only one processor ...

instance release
o  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
o  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.

o  threadDestroy: id
physical destroy other process ...
(warning: low level entry, no administration done)

o  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).

o  threadsAvailable
return true, if the runtime system supports threads (i.e. processes);
false otherwise.

queries
o  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).

o  knownProcesses
return a collection of all (living) processes in the system

Usage example(s):

	ProcessorScheduler knownProcesses

o  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) **

o  maxNumberOfProcesses
return the limit on the number of processes;
the default is nil (i.e. unlimited).

o  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.

o  maxProcessId
Return a maximum allowed value of a Process id.

o  processDriven
turn on process driven mode

o  processWithID: id

o  pureEventDriven
turn on pure-event driven mode - no processes, single dispatch loop


Instance protocol:

I/O event actions
o  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
o  activePriority
return the priority of the currently running process.
GNU-ST & ST-80 compatibility; this is the same as currentPriority

o  activeProcess
return the currently running process

Usage example(s):

Processor activeProcess

o  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.

o  currentPriority
return the priority of the currently running process

Usage example(s):

Processor currentPriority

o  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.

o  interruptCounter
for statistics: counts the overall number of interrupts

Usage example(s):

     Processor interruptCounter

o  interruptedProcess
returns the process which was interrupted by the active one

o  maxProcessId

o  scheduler
return the scheduling process

o  timedActionCounter
for statistics: counts the overall number of timer actions

Usage example(s):

     Processor timedActionCounter

background processing
o  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.

o  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
o  dispatch
It handles timeouts and switches to the highest prio runnable process

o  dispatchLoop
central dispatch loop; the scheduler process is always staying in
this method, looping forever.

initialization
o  initialize
initialize the one-and-only ProcessorScheduler

o  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
o  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.

o  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
o  childSignalInterrupt
child changed state - switch to scheduler process which will decide
what to do now.

o  handleChildSignalInterrupt
child changed state - execute child termination blocks.
If child is no longer alive, remove action block.

o  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).

o  unmonitorPid: pid
remove a monitor for a child process.
Note: pid is a OS process id!

primitive process primitives
o  scheduleForInterrupt: aProcess
make aProcess evaluate its pushed interrupt block(s)

o  scheduleInterruptActionsOf: aProcess
make aProcess evaluate its pushed interrupt block(s)
when resumed.

o  threadSwitch: aProcess
continue execution in aProcess.
WARNING: this is a low level entry, no process administration is done here

priority constants
o  highIOPriority
not currently used - for ST80 compatibility only

o  highestPriority
return the highest priority value (normal) processes can have.

o  lowIOPriority
not currently used - for ST80 compatibility only

o  lowestPriority
return the lowest priority value

o  schedulingPriority
return the priority at which the scheduler runs.

o  systemBackgroundPriority
return the priority, at which background system processing
should take place.

Usage example(s):

     Processor systemBackgroundPriority

o  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.

o  timingPriority
return the priority, at which all timing takes place (messageTally,
delay etc.)

o  userBackgroundPriority
return the priority, at which background user (non-interactive) processing
should take place.

Usage example(s):

     Processor userBackgroundPriority

o  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.

o  userSchedulingPriority
return the priority, at which all normal user (interactive) processing
takes place

private
o  remember: aProcess
remember aProcess for later disposal (where the underlying
system resources have to be freed).

o  unRemember: aProcess
forget aProcess - dispose processing will not consider this one

process creation
o  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.

o  newProcessFor: aProcess withId: nilOrIdWant
private entry for Process restart - do not use in your program

queries
o  activeProcessIsBackgroundProcess
return true if the active process is a background process,
running at a lower priority.

Usage example(s):

     Processor activeProcessIsBackgroundProcess

o  activeProcessIsSystemProcess
return true if the active process is a system process,
which should not be suspended.

Usage example(s):

     Processor activeProcessIsSystemProcess

o  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

o  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

o  highestPriorityRunnableProcess
return the highest prio runnable process

o  isDispatching

o  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).

o  isTimeSlicing
return true, if in timeslicing mode

Usage example(s):

     Processor isTimeSlicing

o  processWithId: anInteger
answer the process with id anInteger, or nil if there is none

Usage example(s):

	Processor processWithId:4
	Processor processWithId:4711

o  processesWithGroupId: anInteger
answer a collection of processes with processGroupId, anInteger

Usage example(s):

	Processor processesWithGroupId:0
	Processor processesWithGroupId:4711

scheduling
o  changePriority: prio for: aProcess
change the priority of aProcess

o  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.

o  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.

o  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.

o  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.

o  resume: aProcess
set aProcess runnable -
if its prio is higher than the currently running prio, switch to it.

o  resumeForSingleSend: aProcess
like resume, but let the process execute a single send only.
This will be used by the debugger for single stepping.

o  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'.

o  terminate: aProcess
terminate aProcess. This is done by sending aProcess the terminateSignal,
which will evaluate any unwind blocks and finally do a hard terminate.

o  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)

o  terminateActiveNoSignal
hard terminate the active process, without sending any
terminate signal thus no unwind blocks are evaluated.

o  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)

o  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
o  recomputeDynamicPriorities
recompute dynamic priorities.

o  scheduledProcesses
return a collection of recently scheduled processes.
This is only non-empty, if the dynamic priority
scheduler is running

o  slice
Give other Processes at the current priority a chance to run.

o  startTimeSlicing
start preemptive scheduling (timeSlicing)

Usage example(s):

     Processor stopTimeSlicing.
     Processor startTimeSlicing.

o  stopTimeSlicing
stop preemptive scheduling (timeSlicing)

Usage example(s):

     Processor stopTimeSlicing

o  supportDynamicPriorities
return true, if dynamic priorities are enabled

o  supportDynamicPriorities: aBoolean
enable/disable dynamic priorities

Usage example(s):

     Processor supportDynamicPriorities:true
     Processor supportDynamicPriorities:false

o  timeSlicingLoop
interval changed -> need a new delay

semaphore signalling
o  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.

o  disableSemaphore: aSemaphore
disable triggering of a semaphore

o  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).

o  signal: aSemaphore after: secondsOrTimeDuration
arrange for a semaphore to be triggered after aTimeDuration

o  signal: aSemaphore afterMilliseconds: millis
arrange for a semaphore to be triggered after some milliseconds

o  signal: aSemaphore afterSeconds: seconds
arrange for a semaphore to be triggered after some seconds

o  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.

o  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.

o  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.

o  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.

o  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).

o  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.

o  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.

o  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
o  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
o  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:

o  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:

o  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:

o  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:

o  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:

o  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:

o  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:

o  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:

o  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:

o  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:

o  evaluateTimeouts
walk through timeouts and evaluate blocks or signal semas that need to be ..

o  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.

o  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.

o  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) **

o  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.

o  timeoutHandlerProcess

o  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).

o  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):

     Processor timeoutList

wait hooks
o  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)

o  removePreWaitAction: aBlock
remove the argument, aBlock from the list of preWait-actions.

waiting
o  checkForEndOfDispatch
check if there are any processes at all

o  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.

o  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.

o  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)

o  schedulerInterrupt
forced reschedule - switch to scheduler process which will decide
what to do now.

o  timeToNextTimeout
return the positive delta-T (in milliseconds) to the next timeout,
or nil if there is none

o  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.

o  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).



ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Mon, 18 Nov 2024 04:41:06 GMT