
[Front][Next Chapter]Each domain has some memory that is private to it, but a domain can alsoaccess some shared or global memory. The private memory initially has thesame contents as that of the parent domain, but execution of the task canchange this without affecting the parent. This private memory is calledinstance memory and the data in it instance data since each instance of adomain has its own copy.At any time only one process of one task is actually executing. The systemkeeps an image in memory of the current registers of all other processes,which it uses to load the processor's registers when it dispatches thecorresponding process.The kernel consists of a number of cooperating modules. Each moduleprovides a complete and distinct set of services, and we thereforedescribe the kernel module by module.Figure 1-1 shows the internal structure ofthe core of the multitasking kernel, andFigure 1-5 on page 1-20 shows how the othermodules relate to it.
Core Modules
The core consists of six modules.
| Supervisor | Real Time Monitor |
| Memory Manager | Domain Manager |
| Module Manager | Exception Handler |
Figure 1-1
Core Modules
The modules which have functions you can call are
Real Time Monitor Module
The Real Time Monitor module (RTM) includes the dispatcher, and maintainsall lists of processes and their states. RTM also includes the queue andmutual-exclusion zone (mutex) functions. Queues are used to communicatebetween processes and to synchronize activities. Mutual-exclusion zonesgive exclusive use of a shared resource to one process at a time. Systemextensions may also use the RTM flag functions. Processes
Processes, or threads, are the active objects that execute code.Table 2-3 on page 2-3 lists the functionsyou call to create and manage processes. Initially, there is just oneprocess running. When the user tells the Task Manager to create a new task,or when a process calls X_PCreate, a new process is created. The newprocess is said to be the child of the process that called X_PCreate.
Each process has a set of attributes.
Any process that knows a queue's name can open it and then send messagesto or read messages from it, but the most common use of queues involvesjust one process reading from any one queue. The content of a message isentirely a matter for the applications reading and writing it.Although each queue's buffer will hold a fixed number of messages,processes that attempt to read an empty queue or write to a full oneare suspended, so the buffer capacity and sequence of events is hiddenfrom them. To writers, the queue appears to have an unlimited capacity.To readers it seems always to have a message. If a process does not wantto be suspended, it can make the read or write conditional on immediatesuccess. Also, you can read a message without removing it from the queue.This is called a non-destructive read.Figure 1-2 shows the various states a queuemay be in and the transitions between them. When you create a queue it isempty. Any number of processes may wait to read from an empty queue. Whena process at last writes a message to the queue, the process which hasbeen waiting longest is woken and reads the message.
Figure 1-2
Queues
A similar sequence of events takes place if processes try to write to a full queue. The writing processes are suspended. When a process reads from the queue, there will be space for one more message in the queue buffer. The message from one waiting process is immediately written into this space, and the writing process becomes ready to run again.Queues are thus a very convenient means to synchronize processes, as well as to pass information between processes. Mutual Exclusion Zones (Mutexes)
Mutual exclusion zones ensure that only one process at a time is performing some activity. This is one of the most common requirements when multiple processes may be running asynchronously with respect to one another.A mutual exclusion zone is not necessarily a physical entity such as a section of code. It can be any activity that consists of two or more actions that must be completed as a unit because they require exclusive access to a shared resource. Examples of such activities and resources include shared non-reentrant code, data base updating and printing.Mutual exclusion is achieved through the use of mutexes, a special type of queue. They have several features that enhance their usefulness.
Table 2-6 on page 2-5 lists the functions you call to create and use mutexes.
Figure 1-3
Mutex zones
A mutex comes into existence when an application calls X_MXCreate. The mutex is automatically given a unique name and a handle that is used to identify it in all subsequent calls.Applications call X_MXEnter to gain exclusive use of the zone. If the zone is currently Free, its state is changed to InUse and the application continues. If another process is in the zone, the second process goes into the queue. If the process calling X_MXEnter is already in the zone, its count is incremented.When ready to release the resource, the owning application calls X_MXExit. If another process is waiting to enter the zone, it becomes ready to run and is dispatched immediately if its priority is high enough.Note that for each call to X_MXEnter you must call X_MXExit once.Being in a mutex guarantees that no other process can enter the same mutex, but it gives no assurance that you will get the CPU time you may need. You can call the RTM Critical Region functions X_CritEnter and X_CritExit to do this.
Only one process can wait on any given flag.Before you can use a flag you must ask RTM to allocate one to you. There are a limited number of flags in the system, so use them sparingly. Each flag is identified only by its number.The process that is waiting for the event should call Z_FlagWait. If the flag is in its Off state, the process will sleep until the ISR calls Z_FlagSet or until an optional timeout expires. If the flag has already been set, the process continues immediately.If several interrupts occur before the process calls Z_FlagWait, the flag remains in its On state with a count of the number of "missed" interrupts. The flag stays in the On state until the corresponding number of Z_FlagWait calls has been made. An error code is returned both to the ISR and to the process that calls Z_FlagWait, to show that overrun has occurred.Figure 1-4
Flag states
Memory Manager Module
The Memory Manager module (MEM) and Domain Manager module (DOM) work together to allocate and map memory and descriptors so that each application can have the resources it needs. Many of the functions in MEM are needed only by other parts of the operating system.Table 2-7 on page 2-6 lists the functions in MEM.
Applications will not normally need to call MEM directly. If they need to allocate memory or descriptors, they should do so through higher level portable interfaces, such as XMS, VCPI and DPMI, which in turn call MEM. Domain Manager Module
A major capability of the operating system is its ability to run multiple DOS applications simultaneously. Each application sees a real mode 8086-like environment of its own, complete with an operating system, device drivers, keyboard, mouse, screen and so on. This environment is called a virtual machine, because it does not exist physically. The combination of a virtual machine and the application running in it is called a domain. Domains are created and managed by the Domain Manager (DOM).Table 2-8 on page 2-8 lists the functions you call to create and control domains.
When the kernel starts up, only one domain is created. It is normally the Task Manager which, in response to hot-key combinations pressed by the user, instructs DOM to create domains, delete them and switch selected domains to the foreground (that is, attach them to the keyboard, mouse and screen).DOM actually performs only the lower level functions needed to create virtual 8086 and virtual DOS machines. Higher level functions such as virtualizing a VGA are carried out by the VM module.A virtual machine is achieved by mapping the required physical memory into the first four megabytes of linear address space, setting traps to intercept I/O, then putting the processor into virtual 8086 mode. Virtual 8086 mode is practically indistinguishable from real mode as far as DOS applications are concerned. The required physical memory is a combination of unshared instance memory and shared global memory. The virtualization includes very sophisticated exception handling that can distinguish between the many sources of exceptions and interrupts. By trapping, for example, attempts to read from the screen memory, it allows applications to continue to run in the background. Each application "sees" a full screen. Only the foreground application's screen is visible to the user, but an application can force urgent messages to be displayed immediately, even if its domain is in the background, by calling the Virtual Machine module (VM); seepage 1-21 for a description of VM.
I/O Bitmaps
Each domain has its own I/O bitmap. The bitmap has a bit for each I/O port address. The bits corresponding to virtualized ports are set. This causes a General Exception whenever an application tries to read from or write to the port. The system recognizes that the exception was caused by an I/O operation, so it invokes the Virtual Machine module's I/O exception handlers, which make sure the port ownership rules are obeyed; see"Virtual Machine Module" onpage 1-21 for a description of the rules.
If you are writing system software that similarly needs to trap accesses to other I/O ports, you can call DOM functions to read, set and reset bits in the I/O bitmap of any domain. These functions' names all start Z_IOBitmap...See the description of Z_HandlerGenEx for a full explanation of exception and interrupt handling, including the use of installable handlers. Instancing
Before the Task Manager is loaded, only one domain exists. In itsinitialization, Task Manager must determine which memory areas shouldbe instanced. It uses several methods to do this, including making anINT 2FH with AX=4B05H to ask global programs to identify their instancedata. Programs that need to instance their data in a multitaskingenvironment must hook INT 2FH and process it appropriately. Any memoryowned by device drivers and other resident programs that they do notidentify as instanced is assumed to be global. Programs loaded afterthe Task Manager is running will be loaded into local memory, that is,instance memory within one domain only.The Task Manager informs DOM which addresses are to be instanced when ithas found them all.Memory instancing uses 80386 page tables for large areas andsoftware-controlled swapping for small ones. Each domain has its own pagetable for the first 4 MB of memory. These page tables point to globallyshared pages and unshared instanced pages. A context switch that includesa domain switch involves four steps to map memory.
Domain Screen Switching
Applications do not normally need to be aware of which domain owns the physical screen, and which domains are running in the background. Unless you are writing system software, you can skip this section.Global programs that need to be notified of domain screen switches should hook INT 2FH and be alert for the function Build Notification Chain (AX=4B01H), which will be the first indication they have that the Task Manager is active. This informs the kernel of the program's callback function's address, and informs the program of the kernel's service functions' address.While the Task Manager is active, programs can call Detect Switcher (INT 2FH / AX=4B02H) and then Hook Notification Chain to achieve the same thing.Programs can call the service functions to perform the following:
Figure 1-5
High Level Modules
Of the modules shown inFigure 1-5 only the Virtual Machine (VM) has an API that is unique to the multitasker, though the Task Manager's API is reduced when running on the multitasker. Other modules have no API, or behave the same whether running on the multitasker or raw single tasking DOS, with or without the Task Manager. Their descriptions are therefore not included in this manual.
Virtual Machine Module
The Virtual Machine module (VM) completes the virtualization of a PC from the application's perspective. Its major tasks are
While in Global Message Mode the Task Manager is disabled, so the user cannot avoid seeing the message. Serial and Parallel Ports
The standard ports known to the ROM BIOS are initially set up to use their default port numbers and IRQs. You can call VM to change these and to tell it the port numbers and IRQs of COM and LPT ports (up to COM4 and LPT3), which the BIOS does not know about. These values are physical and therefore global.While the Task Manager is running, VM virtualizes the serial and parallel ports. The method it uses to decide which domain can use the physical ports is based on timeouts and traps, as follows.Timeout values (t) are initially set to 5 seconds for a COM port, and 15 seconds for a printer port, though you may call VM to change the timeout on any port. The operation of timeouts is:
A timeout value of 0 disables virtualization of the port. Any domain may access it freely at any time.A timeout value of -1 sets an "infinite" timeout; thus, once the port is given to a domain, it never becomes free again, unless the domain is deleted. Task Manager
The Task Manager controls switching between multiple DOS applications by giving the VM and DOM modules the appropriate sequences of commands. It accepts instructions from the user via keyboard hot-key combinations. It can also be controlled by software, using its native API (INT 2FH / AH=27H), though only the functions listed inTable 2-10 on page 2-11 are available when the Task Manager is running on the multitasking kernel.
The Task Manager also supports the industry-standard INT 2FH / AH=4BH API for task switchers with its corresponding service and notification functions. This interface is provided to support global programs written to run on other DOS task switchers. Although these functions are not described in this manual, they are listed inTable 2-10 on page 2-11 toTable 2-13 on page 2-13.
When the Task Manager is not present, the kernel does not respond if an application or device driver tries to detect the presence of a switcher (INT 2FH / AX=4B02H) or asks for a switcher ID for itself (INT 2FH / AX=4B03H). When the Task Manager is present, the kernel does respond to these requests. However, the Task Manager does not itself call INT 2FH / AX=4B02H, so it cannot be run if a task switcher is already present.