[comp.os.os2.programmer] Preemptive multitasking

klimas@iccgcc.decnet.ab.com (12/14/90)

Can someone clarify what happens under OS/2's preemptive multitasking
when another task needs service and what the relevance of the 30hz 
time slice interval is.

Is one correct in assuming that OS/2 will within a matter
of ? milliseconds suspend the currently executing task and hand over
control to the new task requesting service without waiting for the completion
of the 30hz time slice?

Any guess on roughly what ? milliseconds can correspond to?

db3l@ibm.com (David Bolen) (12/15/90)

In article <2426.27678d77@iccgcc.decnet.ab.com> klimas@iccgcc.decnet.ab.com writes:

>Can someone clarify what happens under OS/2's preemptive multitasking
>when another task needs service and what the relevance of the 30hz 
>time slice interval is.
>
>Is one correct in assuming that OS/2 will within a matter
>of ? milliseconds suspend the currently executing task and hand over
>control to the new task requesting service without waiting for the completion
>of the 30hz time slice?
>
>Any guess on roughly what ? milliseconds can correspond to?

Well, the only thing I remember seeing documented was a maximum of 1ms
latency from a thread becoming ready to run, until it actually begins
execution, provided according to the scheduler it has the right (priority)
to run next.  I think this was in Letwin's book for OS/2 1.1, so it may or
may not hold true anymore.  But it's certainly less than the 31.25ms (32Hz)
period between scheduler interrupts.

At least to my understanding, here's what's going on with OS/2's scheduling.
Every 31.25ms, the system timer fires, triggering the scheduler to run.  So
time resolution for system functions (such as DosSleep()) is about 32ms.
No matter what else is going on with the system, the scheduler is going to
get control (even if for a tiny amount of time) 32 times a second.

Each time the timer fires, the scheduler will decide whether it needs to
switch the CPU to some other thread than the one executing when the timer
went off.  If some new thread is ready to run, and has a higher priority
than the currently running thread, then the scheduler will immediately set
the CPU to switch to that thread, pausing the currently running thread.

If all runnable threads have the same priority, then the scheduler handles
them in a round-robin fashion.  It cycles through each thread, allowing it
(if it wants) to execute for some maximum amount of time, as set by the
TIMESLICE parameter in CONFIG.SYS.  The default value (for OS/2 1.2), is
documented online at 248ms, about 1/4s or 7 timer ticks.  So once a thread
is scheduled, even though the scheduler will get control of the CPU
momentarily every 32ms, it will allow the same thread to keep control for
7 of those ticks.  Then it will proceed on to a different thread at the
same priority level.

To help prevent threads from starving for the CPU, if a thread has a
priority in the normal class (rather than idle, fixed-high, or time-critical),
and it doesn't get the CPU at all for a set amount of time (set by the
MAXWAIT parameter in CONFIG.SYS, which on my system defaulted to 3 seconds),
then it has its priority delta incremented within the normal class, which
will make it available to the scheduler before other normal class threads.
There is also a boost added to threads that are the current foreground
application, to help them remain responsive to the user.

Now all this is based on the assumption that your system is mostly CPU
bound, and that there aren't threads in a blocked state or waiting for I/O.
Since having parts of the system blocked or I/O bound at any given time is
more normal, that changes the picture somewhat, and is where the 1ms latency
mentioned above comes in.

Again, according to my understanding, if you have a thread that is blocked
on some condition, such as a semaphore, in order for that condition to
clear (making the thread executable), some other thread on the system will
have to release the resource via an OS/2 system request.  So what is done
is that the OS/2 functions that control such resources - the DosSemClear
function in this case, will trigger rescheduling threads when called if
necessary.  Thus, if you have a time-critical thread that is blocked in
a semaphore request, some other thread (whatever priority) is going to have
to clear that semaphore to enable the time-critical thread to run.  When
that other thread clears the semaphore, it never gets control back from
the DosSemClear function.  Instead the execution of that function triggers
the scheduler which decides to give control to the higher-priority thread
instead.  And the 1ms latency is from the point where DosSemClear cleared
the semaphore, making the time-critical thread executable, to when that
thread got control of the CPU.  Since this is triggered by some other thread
issuing the system call, it does not have to fall on one of the timer
boundaries, and in this case, the thread originating the call does not get
to use any of the remaining time in it's current timeslice.

I can't guarantee any of the above is canon, but is what I have gleaned from
documentation and articles over the past few years.  I do know that the
scheduler has undergone internal changes in each OS/2 version (for example,
the "aging" of threads is more accurate in 1.3 than either 1.1 or 1.2), but
conceptually I think the above is what is happening.

-- David
--
/-----------------------------------------------------------------------\
 \                             David Bolen                             /
  |    Laboratory Automation, IBM Thomas J. Watson Research Center    |
 /              P.O. Box 218, Yorktown Heights, NY  10598              \
| - - - - - - - - - - - -  M i t h r a n d i r  - - - - - - - - - - - - |
| Internet : db3l@ibm.com                    | Bitnet : db3l@yktvmv     |
| Usenet   : uunet!bywater!arnor!larios!db3l | Phone  : (914) 945-1940  |
\-----------------------------------------------------------------------/

oleg@ibm.com (12/15/90)

> Each time the timer fires, the scheduler will decide whether it needs to
> switch the CPU to some other thread than the one executing when the timer
> went off.  If some new thread is ready to run, and has a higher priority
> than the currently running thread, then the scheduler will immediately set
> the CPU to switch to that thread, pausing the currently running thread.

According to an article "Measure Your Machine's Activity ..." in November 90
issue of Microsoft System Journal, the scheduler can cut right into the middle
of a thread's time slice and steal the CPU away. This happens if a thread
makes a system call, and there is another thread with a higher priority ready
to be dispatched.

Oleg Vishnepolsky
IBM T. J. Watson Research Center