Chapter:Chapter 02 – Inside OS/2 Warp
Subsection: 01. Base Operating System Architecture
Topic: OS/2 Multitasking
Date Composed: 10-07-96 02:00:40 PM Date Modified: 01-15-99 11:10:35 AM
Introduction to Multitasking
At any given moment in time, a personal computer microprocessor can execute only one instruction in one task. However, by dividing the microprocessor time between multiple tasks, it is possible to give the impression to relatively slow human senses that they are running simultaneously. This technique is called multitasking.
DOS is intrinsically a single tasking operating system. This means that it can only perform one task, or job, at a time. If you wish to run an application program other than one which is currently running, you must terminate the current application and then start the second application. This limitation, as much as the limitation on memory usage, is due to the historical roots of DOS. The original Intel 8088 microprocessor did not have the hardware support required to effectively implement a multitasking, virtual memory, or memory isolated operating system.
OS/2 utilizes the built in multitasking capabilities of the Intel 80×86 family of microprocessors. These capabilities include the ability to address large amounts of real memory – up to 4 GB – and the ability to protect the system resources being used by one program from intrusion by another program. For this reason, the operating mode of the 80×86 microprocessors which provides for multitasking is known as protect mode.
The multitasking ability of OS/2 allows the system to perform more than one task at a time. You may have several different programs running at once, as well as multiple communications sessions. It is also possible to have one program performing several tasks simultaneously. The basic unit of program execution is the thread. Each program running under OS/2 must have at least one thread, but may have more than one if it has been so designed.
Processes and Threads
The minimal benefit of being able to switch from one program to another without terminating the first is something which everyone can appreciate. The real benefits of true multitasking become apparent when downloading several large files from a BBS, using FTP to transfer a file to the internet, spell checking a large document, and printing checks for accounts payable. The downloads, spell check, and check printing can be started and then you can work interactively with the word processor while the other tasks proceed in the background.
The benefits derived from using multiple threads in a single program are not so apparent, however. From the standpoint of the user, the primary benefit is that of faster perceived program response time. The programmer may provide one thread to allow for data input, another thread for updating the screen, and yet a third for performing calculations. In a spreadsheet environment, for example, as soon as a user has entered a number into a cell, the display can be updated with newly calculated values and while the user is entering additional data, the background thread can recalculate the rest of the spreadsheet. This results in a much faster perceived speed of operation because the user does not have to wait for the entire spreadsheet to recalculate before additional data is entered.
When each program is launched Warp creates a new process. Every process (program) has at least one thread. If the programmer of an OS/2 program decided that multiple threads were required, he or she could use special function calls within OS/2 to do so. In general, programs have only one thread unless the programmer has overtly designed the program for more.
OS/2 multitasking is managed by the task dispatcher. The dispatcher handles the dispatching of tasks with a set of algorithms which are designed to allow multiple tasks to run simultaneously with as little effect upon each other as possible, while still allowing high priority tasks swift access to the processor when needed. OS/2 is a dynamic, priority based, preemptive multitasking system with round-robin scheduling.
In OS/2 Warp, the dispatcher dynamically modifies a thread’s time slice based on trigger actions that may have occurred. For instance, if a thread encounters a page fault during its time slice, it is given an extra time slice to process the data contained in the faulted page. Applications doing disk I/O are also given extra time slices if the data they are reading is in the disk cache. When the TIMESLICE= parameter is used as in versions 1.x and 2.x of OS/2, none of these dynamic modifications of a threads allocated time will occur. Instead, each thread will be given the minimum time slice of X, and its time slice will not be allowed to go beyond value Y. See also the TIMESLICE document for more details about this CONFIG.SYS file parameter.
Priority Based Multitasking
A priority based multitasking operating system is one in which each task is assigned a priority. The priority of each task is determined by the programmer. If the programmer makes no overt choice, the operating system, OS/2 in this case, assigns a default priority, regular class, priority level 0.
In any priority based task scheduling operating system, the task with the highest priority which is capable of running, that is, not blocked, will get the CPU. All other tasks must wait until that task becomes blocked before they may have CPU time. A task becomes blocked when it must wait for input from a keyboard or mouse, for example, or for data to be read from a disk, or for a communications buffer to fill. There are many other reasons why a task might become blocked. If a task of a higher priority than the current running task becomes unblocked, then OS/2 will preempt the running task to give the CPU to the task with the higher priority.
OS/2 has four priority classes.
- Time critical (800)
A time critical task such as communications or networking will run in this priority class. Such programs need to have access to the CPU very quickly.
In communications, for example, when the data receive buffer fills up it is necessary to remove the data from it and store it in a less critical location until it can be processed by a lower priority task. When the receive buffer fills, the communications port hardware generates a hardware interrupt which is handled by the OS/2 device driver for that port. For an asynchronous communications port this is the COM.SYS device driver. The device driver sends a software interrupt to the application program which moves the data from the receive buffer and stores it in another location in memory.
The portion of the program which handles the communications buffer must be a very high priority so that it can get the data from the buffer before more data arrives and causes a receive buffer overrun. The rest of the communications prgram can run at a lower priority class. When overruns occur, the data must be resent which reduces the total data transfer rate.
Time critical tasks take a very small portion of the CPU’s time. Even after all time critical tasks receive all the CPU time they require, there is still plenty of time left for all the other tasks running on the computer.
- Server (400)
Server class programs are used by Warp Server, for example, to process requests for data by client workstations and to get the data requested ready to transfer across the network. Processing these types of tasks at the Server class ensures that administrative tasks such as creating new user IDs do not interfere with them.
- Regular/normal (200)
Regular, or normal class is the priority class at which most application programs run. This is also the default class at which OS/2 will run programs which do not overtly specify a priority class.
- Idle time (100)
A program which runs at idle class will only receive CPU time when all other programs at higher priorities have become blocked. In reality, for most average systems, this can be quite a large amount of time. To see this, start the OS/2 Pulse program applet which comes with OS/2. It is located in the Productivity folder. Most of the time the processor is doing very little, if anything, so there is lots of time for idle class programs to run.
The Pulse program itself runs at idle priority. It simply counts the CPU cycles which it receives as a consequence of the fact that no other process needs them, and displays the result as a graph indicating the amount of CPU time being used by all the other programs on the system. To perform this task accurately, it cannot run at regular class or higher because it would always receive some CPU cycles in the normal round-robin sequence of task dispatching. This would skew the results.
A good example of a productive application which should be run at idle class would be a math intensive calculation. There is an OS/2 program which calculates the common math constants Pi and e ( Euler’s constant) to any number of decimal places in increments of 500 places. Suppose I want to calculate Pi to 1,000,000 decimal places. At the same time, I want to do all my normal daily tasks like word processing, Lotus Notes, network communications, and asynchronous communications.
Since this calculation takes a couple days on even a fast system, I cannot afford to have it tie up my system. This program was written so that I can change the priority class, so I set it at idle class and start the calculation. Actually, this program was written so intelligently that I can change the priority class while it is calculating. With the Pi calculation going in the background in idle class, I can go do my regular daily work. Any CPU cycles not needed for my normal work are given by Warp to the Pi calculation.
Figure 1: The 4 priority classes of Warp each have 32 levels.
32 Priority levels per class
Figure 2.1.1, above, shows the four priority classes of OS/2 Warp. The boxes to the right of the priority class diagram represent threads of several processes which are running. Threads on the same line are at the same priority class and level. Threads shown with red rectangles are blocked; that is, they cannot run because they are waiting for some system activity, such as disk access to complete, or the printer to request more data. The threads indicated by yellow rectangles are capable of running, but are not currently running because another thread is. The one thread represented by a green rectangle is running. Only one thread can run at a time.
Each priority class under OS/2 has 32 priority levels numbered from 0 through 31. There are a total of 128 discrete priority levels at which tasks can run. This means that multiple tasks may run in regular class, for example, but one or more may still be at a higher priority level within the regular class. The numeric values for each priority class are given in Table 2.1.1.
|Time Critical||800 – 831|
|Server||400 – 431|
|Regular||200 – 231|
|Idle||100 – 131|
Table 2.1.1: Priority class numeric ranges.
Using PSTAT to determine the priority of a task
Warp has a utility called PSTAT which allows you to display or print a list of all the tasks and threads running on your system. PSTAT shows the process and thread IDs for each task as well as the priority level for each task. Figure 2.1.2 shows the output of PSTAT when run on the author’s system. The command below issued from the command prompt sends the output of the command to a file named C:\PSTAT.DAT. The /C parameter is used to display the current process and thread data. Other parameters allow display of memory, DLL, and semaphore information.
PSTAT /C > C:\PSTAT.DAT
Process and Thread Information
Process Process Session Process Thread
ID ID ID Name ID Priority Block ID State
002F 0000 13 C:\IBMLAN\SERVICES\ALERTER.EXE 01 0200 FFFE004C Block
002E 0000 13 C:\IBMLAN\SERVICES\TIMESRC.EXE 01 0200 FFFE004A Block
002D 0000 13 C:\IBMLAN\NETPROG\RNS1.EXE 01 0200 FFFE0048 Block
02 0200 06880096 Block
03 0200 068800C2 Block
04 0200 068800EE Block
002B 0000 13 C:\IBMLAN\SERVICES\NETLOGON.EXE 01 0200 FFFE0046 Block
02 0200 FFFD0072 Block
03 031F FFFE0045 Block
04 0200 040054FE Block
002A 0000 13 C:\IBMLAN\SERVICES\NETSERVR.EXE 01 0300 FFFE003E Block
02 0300 FFFE003C Block
03 0300 FDF2BB44 Block
04 0200 FDF254B8 Block
05 0300 FFFE003F Block
0029 0000 13 C:\IBMLAN\SERVICES\NETSERVR.EXE 01 0301 FFF78083 Block
02 0300 FFFE003D Block
03 0300 040054E6 Block
04 0300 FFFE0040 Block
05 0300 04004853 Block
06 0301 FFFE0041 Block
0026 0000 13 C:\MUGLIB\MUGLRQST.EXE 01 0200 040054C8 Block
02 0200 FE1ACE34 Block
0025 0000 13 C:\IBMLAN\SERVICES\MSRV.EXE 01 0200 040054BC Block
02 0200 FFFE0037 Block
0023 0000 13 C:\IBMLAN\SERVICES\WKSTAHLP.EXE 01 031E 2260BE6C Block
02 0200 225005FE Block
03 031E 2250210E Block
04 031E 2250061C Block
0022 0000 13 C:\IBMLAN\SERVICES\WKSTA.EXE 01 0300 FFFE003A Block
02 021F FFFD005B Block
03 0200 FFFE0033 Block
04 021F FFFD0060 Block
0018 0000 00 C:\OS2\EPWMUX.EXE 01 0200 FFFE0024 Block
0013 0000 00 C:\OS2\EPWMUX.EXE 01 0200 FFFE001F Block
0012 0000 00 C:\OS2\EPWPSI.EXE 01 0200 06880012 Block
0011 0000 00 C:\OS2\EPWMP.EXE 01 0200 FE03E834 Block
02 0200 FFFE0025 Block
03 0200 FFF78083 Block
000E 0000 00 C:\WAL\MEMMANIT.EXE 01 031F FFFE0016 Block
000C 0000 00 C:\IBMLAN\NETPROG\ATKINIT.EXE 01 0302 FFFE0013 Block
02 0200 FFFE0014 Block
000B 0000 00 C:\IBMCOM\VLANINIT.EXE 01 0200 FFFE0017 Block
000A 0000 00 C:\OS2\EPWROUT.EXE 01 0200 FFFE0020 Block
02 0200 FFFE001A Block
0009 0000 00 C:\OS2\SYSTEM\LOGDAEM.EXE 01 021F 04A00252 Block
0008 0000 00 C:\IBMLAN\NETPROG\LSDAEMON.EXE 01 0200 FFF78083 Block
0007 0000 00 C:\IBMCOM\PROTOCOL\LANDLL.EXE 01 030B 544F4B52 Block
0005 0000 00 C:\MPTN\BIN\CNTRL.EXE 01 0304 F2750002 Block
02 0304 F2750001 Block
03 0304 1450525A Block
04 0304 14505272 Block
05 0304 F2750001 Block
06 0304 F2750002 Block
07 0304 FFF78083 Block
08 0304 F2750008 Block
0004 0000 00 C:\IBMCOM\LANMSGEX.EXE 01 0200 FFFEF636 Block
000D 0001 01 C:\OS2\PMSHELL.EXE 01 0200 FDF20F24 Block
02 0300 FFCA000D Block
03 0300 FFFD001C Block
04 0300 FFFD001D Block
05 0300 04000E28 Block
06 0200 FE179B6C Block
07 0200 FE17BBF0 Block
08 041F FDF20F54 Block
09 0200 FFFE001B Block
0A 0200 FFFD0006 Block
0B 0300 FFFE001D Block
0C 0300 FFFE001E Block
0D 0300 FFFE001C Block
0E 0304 FFFD002A Block
0F 0304 04000E1A Block
10 0200 FFFD002C Block
11 0301 FDF25078 Block
12 0200 FDEDAD40 Block
13 0300 04000E36 Block
14 0300 FE03DB74 Block
15 0300 FDF254F8 Block
16 0401 FE1E037C Block
17 0401 FE1E0DA8 Block
00A0 000D 15 F:\IMPOS20\IMPOS.EXE 01 0200 FE1F16EC Block
02 0200 0688011A Block
0093 000D 1E E:\DESCRIBE\OS2\DESCRIBE.EXE 01 021F FE1E6E38 Block
02 0200 FE1E6BC8 Block
03 0200 FE1E6BF4 Block
04 021F FE1E1980 Block
05 0200 FE1E200C Block
06 0200 FE1E2A30 Block
008E 000D 1D (kernel) 01 0200 FE1E08D4 Block
0055 000D 1C E:\UTILITY\FILESTAR\FILESTAR.EXE 01 0200 FDEF5C30 Block
03 0200 FDEF5990 Block
04 0200 FDF0FACC Block
004B 000D 18 F:\NOTES\ILNOTES.EXE 01 0201 FE01ADF0 Block
004A 000D 1B F:\NOTES\QNC.EXE 01 0200 FDFE7F68 Block
0048 000D 1A E:\IBMAV\IBMAVTIM.EXE 01 0200 FFF78083 Block
0047 000D 11 E:\WPC200\WPC200.EXE 01 0200 FE1C2BEC Block
02 0200 FE1C29D0 Block
03 0200 FE1C2948 Block
04 0200 FE1C292C Block
0034 000D 13 C:\OS2\CMD.EXE 01 0200 FFCA0034 Block
00AA 0034 13 C:\OS2\PSTAT.EXE 01 031F 00000000 Running
0032 000D 04 F:\NOTES\QNC.EXE 01 0200 FE18C7B0 Block
0033 0032 04 F:\NOTES\ISERVER.EXE 01 0201 FFF78083 Block
02 0206 FFF78083 Block
03 0207 040054DA Block
04 0207 040054D4 Block
05 0201 FFF78083 Block
06 0205 FE1B71F0 Block
0045 0033 04 F:\NOTES\QNC.EXE 01 0206 FE1C4D88 Block
0046 0045 04 F:\NOTES\IADMINP.EXE 01 0201 FFF78083 Block
0041 0033 04 F:\NOTES\QNC.EXE 01 0206 FDEFDC70 Block
0042 0041 04 F:\NOTES\IAMGR.EXE 01 0201 FFF78083 Block
0043 0042 04 F:\NOTES\QNC.EXE 01 0201 FDEFDB64 Block
0044 0043 04 F:\NOTES\IAMGR.EXE 01 0201 FE136AAC Block
003C 0033 04 F:\NOTES\QNC.EXE 01 0206 FDFF3F70 Block
003D 003C 04 F:\NOTES\IUPDATE.EXE 01 0201 FFF78083 Block
003A 0033 04 F:\NOTES\QNC.EXE 01 0206 FE1B0D58 Block
003B 003A 04 F:\NOTES\IROUTER.EXE 01 0201 FFF78083 Block
0038 0033 04 F:\NOTES\QNC.EXE 01 0206 FE1C2864 Block
0039 0038 04 F:\NOTES\IREPLICA.EXE 01 0201 FFF78083 Block
001F 000D 19 E:\IBMAV\IBMAVSD.EXE 01 0200 FE040FCC Block
001C 000D 17 E:\UTILITY\GTU30\SENTRY.EXE 01 0200 FDF1B27C Block
02 0200 FFF78083 Block
03 0200 FFF78083 Block
04 0200 FFF78083 Block
05 0200 FFF78083 Block
001B 000D 16 E:\FAXWORKS\FAXWORKS.EXE 01 0200 FE10AECC Block
02 0300 FDEDA968 Block
03 0200 0688006A Block
04 0200 FFFE002F Block
05 031F 00BC09E4 Block
0019 000D 14 C:\IBMLAN\NETPROG\NETMSG.EXE 01 0200 FDFF1CC0 Block
02 0200 FFFE0039 Block
03 0200 FE126BCC Block
04 0200 FDFF1EE8 Block
0016 000D 12 C:\OS2\PMSHELL.EXE 01 0200 FE18CA20 Block
02 0300 FDEDA614 Block
03 030A FDEDA5FC Block
04 0300 FE18C7B4 Block
05 0300 FE17CE68 Block
06 0200 FDEDAD58 Block
07 0400 FE141FD8 Block
08 0200 FE122D34 Block
09 0200 FE122C30 Block
0B 0400 FE18C050 Block
0C 021F 43D82800 Ready
0D 0200 FFFE0026 Block
0E 0400 FE11FF54 Block
0014 000D 10 C:\OS2\PMSPOOL.EXE 01 0200 FFF78083 Block
02 0200 FE149BC4 Block
03 0200 4388000E Block
04 0200 FE18DFF0 Block
05 0200 FE150970 Block
06 0200 FE1509A8 Block
000F 000D 00 C:\OS2\SYSTEM\HARDERR.EXE 01 0300 04000E44 Block
02 0300 04001158 Block
03 0300 0400117C Block
Figure 2: The results of PSTAT on the Author’s system.
Altering Priority Levels
OS/2 does not provide for user access to priority levels. A programmer, however, may provide access to priority levels within a program and provide the user with controls in the program to manipulate them. There are also some third party utilities available which allow the user to view and alter the priority levels of other running programs. One such utility is CPU Monitor Plus, by BonAmi Software.
Extreme care should be taken when altering the priority level of a process or thread, as the action taken may have the opposite of the desired effect. Consider, for example, the print spooler process. This process manages the transfer of print data from application programs, to the hard drive, and from there to the printer.
When I ask most people what priority they think that the spooler process should run at, they tell me it should be a very low priority process. In fact, it should be a high priority process. The reason for this is that printing, being an essentially mechanical process, is very slow compared to the speed of the processors in today’s computers. As a result, when the spooler sends data to the printer, it must then wait for a computer’s eternity for the printer to print the data and request more from the spooler. When this request for more data is received by the spooler, it is important to respond and get the data to the printer as quickly as possible to prevent delays to an already slow process.
The spooler is blocked most of the time, either waiting for a print job or waiting for the printer to request more data for a running print job. While blocked, it gets no CPU time, and all five spooler threads have priority level 200, the base level of the Regular priority class. When a print job is spooling, however, one of the threads is boosted to priority level 400, the base level of Server (a.k.a. Fixed High) class. This provides a high enough priority to ensure that printing gets done quickly but, because the spooler is blocked most of the time waiting for the printer to request more data, it does not affect the performance of the rest of the system.
The Spooler object in the System Setup folder allows users to adjust the priority of the print spooler. You should be careful with this, however. Decreasing the priority will slow the print process significantly. Increasing the priority will have no noticable effects while small print jobs are printing because they complete so quickly, but can cause the rest of the system to slow considerably while very large print jobs are being printed. Another problem with increasing the priority too much is that the spooler priority becomes higher than that of other important tasks such as network functions. This can cause problems not only with the response time on the local workstation, but it can also create problems for networking tasks.
The default print spooler priority setting is perfect for most environments.
In any multitasking operating system, there are some tasks which are extremely important and which must obtain access to the processor as quickly as possible at specific times. Such a task would be a communications or networking program. These tasks, or really a small portion of these tasks, the portion responsible for the time critical part of the process, should be run at a high priority. For communications programs this is usually at some high level in the time critical class.
When a program with a higher priority than the currently running program or task becomes unblocked, OS/2 preempts the lower priority task and gives the CPU to the higher priority task.
Round-robin scheduling simply means that all tasks which are running at the same priority will receive time slices in a round-robin fashion, so that each can have some time. The Warp task dispatcher manages this and preempts any task which has taken the maximum time slice.
The priority level at which a task runs under OS/2 is dynamic; OS/2 can change the priority of a task depending upon its needs. There are three ways in which OS/2 uses it’s ability to dynamically alter the priority of applications, even while they are running.
It is possible that some tasks in a multitasking system might become starved for CPU time. Since most running tasks will be at regular priority, many will be at the same priority level. As these tasks run in round-robin fashion, the amount of time taken by the tasks which are not blocked may prevent one or more of the remaining tasks from obtaining CPU time within the amount of time specified in the MAXWAIT statement in CONFIG.SYS.
When a task becomes starved for CPU time in this manner, the OS/2 task scheduler boosts the priority of the starved task within its class by one priority level. This places this task at a higher priority level than the other tasks with which it was running. It will, therefore, receive a timeslice before those other programs. When it does receive a timeslice, it is allocated one minimum timeslice by the scheduler and then it is reduced to its base priority.
This dynamic priority scheduling allows each task to be sure it will receive at least some CPU time.
When running a program in a multitasking environment, especially one with which you will continually interact such as a word processing program, it is reasonable to expect that program to respond to user input quickly. One of the ways in which OS/2 ensures that this will happen is to provide the foreground task, that is the one with which the user is interacting and which has the keyboard focus, a boost in priority. In this case the boost is by a level of one within the task’s priority class.
Foreground I/O Boost
Setting PRIORITY_DISK_IO=YES in CONFIG.SYS provides a priority boost to I/O operations for the application running in the foreground. This ensures that a DOS program, or an OS/2 program which was not written with a separate thread for I/O operations will perform its I/O tasks and return control to the user as quickly as possible.