Mercurial > hg > Members > kono > nitros9-code
view docs/nitros9guide/chap5.chapter @ 2322:61fb37b19edd
Edition #3 - for vtio instead of cc3io Willard Goosey
author | aaronwolfe |
---|---|
date | Mon, 11 Jan 2010 04:20:41 +0000 |
parents | b00cf13c9f61 |
children |
line wrap: on
line source
<chapter> <title>Multiprogramming and Memory Management</title> <para> One of NitrOS-9's most extraordinary abilities is multiprogramming, which is sometimes called timesharing or multitasking. Simply states, NitrOS-9 lets you computer run more than one program at the same time. This can be a tremendous advantage in many situations. For example, you can be editing one program while another is being printed. Or you can use your Color Computer to control household automation and still be able to use it for routine work and entertainment. </para> <para> NitrOS-9 uses this capability all the time for internal functions. The simple way for you to do so is by putting a "&" character at the end of a command line which causes the shell to run your command as a "background task". </para> <para> The information presented in this chapter is intended to give you an insight into how NitrOS-9 performs this amazing feat. You certainly don't have to know every detail of how multiprogramming works in order to use NitrOS-9, but a basic working knowledge can help you discover many new ways to use your Color Computer. </para> <para> In order to allow several programs to run simultaneously and without interference, NitrOS-9 must perform many coordination and resource allocation functions. The major system resources managed by NitrOS-9 are: </para> <simplelist> <member>CPU Time</member> <member>Memory</member> <member>The input/output system</member> </simplelist> <para> In order for the computer to have reasonable performance, these resources must be managed in the most efficient manner possible. Therefore, NitrOS-9 uses many techniques and strategies to optimize system throughput and capacity. </para> <section id="sec5.1"> <title>Processor Time Allocation and Timeslicing</title> <para> CPU time is a resource that must be allocated wisely to maximize the computer's throughput. It is characteristic of many programs to spend much unproductive time waiting for various events, such as an input/output operation. A good example is an interactive program which communicates with a person at a terminal on a line-by line basis. Every time the program has to wait for a line of characters to be typed or displayed, it (typically) cannot do any useful processing and would waste CPU time. An efficient multiprogramming operating system such as NitrOS-9 automatically assigns CPU time to only those programs that can effectively use the, time. </para> <para> NitrOS-9 uses a technique called <emphasis>timeslicing</emphasis> which allows processes to share CPU time with all other active processes. Timeslicing is implemented using both hardware and software functions. The system's CPU is interrupted by a real time clock many (60 in the Color Computer) times each second. This basic time interval is called a "tick", hence, the interval between ticks is a time slice. This technique is called timeslicing because each second of CPU time is sliced up to be shared among several processes. This happens so rapidly that to a human observer all processes appear to execute continuously, unless the computer becomes overloaded with processing. If this happens, a noticeable delay in response to terminal input may occur, or "batch" programs may take much longer to run than they ordinarily do. At any occurrence of a tick, NitrOS-9 can suspend execution of one program and begin execution of another. The starting and stopping of programs is done in a manner that does not affect the program's execution. How frequently a process is given time slices depends upon its assigned priority relative to the assigned priority of other active processes. </para> <para> The percentage of CPU time assigned to any particular process cannot be exactly computed because there are dynamic variables such as time the process spends waiting for I/O devices. It can be roughly approximated by dividing the process's priority by the sum of the priority numbers of all processes: </para> <screen> Process Priority Process CPU Share = ------------------- Sum of All Active Process' Priorities </screen> </section> <section id="sec5.2"> <title>Process States</title> <para> The CPU time allocation system automatically assigns programs one of three "states" that describe their current status. Process states are also important for coordinating process execution. A process may be in one and only one state at any instant, although state changes may be frequent. The states are: </para> <para> <emphasis>ACTIVE:</emphasis> processes which can currently perform useful processing. These are the only processes assigned CPU time. </para> <para> <emphasis>WAITING:</emphasis> processes which have been suspended until another process terminates. This state is used to coordinate execution of sequential programs. The shell, for example, will be in the waiting state during the time a command program it has initiated is running. </para> <para> <emphasis>SLEEPING:</emphasis> processes suspended by self-request for a specified time interval or until receipt of a "signal". Signals are internal messages used to coordinate concurrent processes. This is the typical state of programs which are waiting for input/output operations. </para> <para> Sleeping and waiting processes are not given CPU time until they change to the active state. </para> </section> <section id="sec5.3"> <title>Creation of New Processes</title> <para> The sequence of operations required to create a new process and initially allocate its resources (especially memory) are automatically performed by NitrOS-9's "fork" function. If for any reason any part of the sequence cannot be performed the fork is aborted and the prospective parent is passed an appropriate error code. The most frequent reason for failure is unavailablity of required resources (especially memory) or when the program specified to be run cannot be found. A process can create many new processes, subject only to the limitation of the amount of unassigned memory available. </para> <para> When a process creates a new process, the creator is called the "parent process", and the newly created process is called the "child process". The new child can itself become a parent by creating yet another process. If a parent process creates more than one child process, the children are called "siblings" with respect to each other. If the parent/child relationship of all processes in the system is examined, a hierarchical lineage becomes evident. In fact, this hierarchy is a tree structure that resembles a family tree. The "family" concept makes it easy to describe relationships between processes, and so it is used extensively in descriptions of NitrOS-9's multiprogramming operations. </para> <para> When the parent issues a fork request to NitrOS-9, it must specify the following required information: </para> <itemizedlist mark="square"> <listitem><para> A PRIMARY MODULE, which is the name of the program to be executed by the new process. The program can already be present in memory, or NitrOS-9 may load it from a mass storage file having the same name. </para></listitem> <listitem><para> PARAMETERS, which is data specified by the parent to be passed to and used by the new process. This data is copied to part of the child process' memory area. Parameters are frequently used to pass file names, initialization values, etc. The shell, passes command line parameters this way. </para></listitem> </itemizedlist> <para> The new process also "inherits" copies of certain of its parent's properties. These are: </para> <itemizedlist mark="square"> <listitem><para> A USER NUMBER which is used by the file security system and is used to identify all processes belonging to a specific user (this is not the same as the "process ID", which identifies a specific process) . This number is usually obtained from the system password file when a user logs on. The system manager always is user number zero. </para></listitem> <listitem><para> STANDARD INPUT AND OUTPUT PATHS: the three paths (input, output, and error/status) used for routine input and output. Note that most paths (files) may be shared simultaneously by two or more processes. The two current working directories are also inherited. </para></listitem> <listitem><para> PROCESS PRIORITY which determines what proportion of CPU time the process receives with respect to others. </para></listitem> </itemizedlist> <para> As part of the fork operation, NitrOS-9 automatically assigns: </para> <itemizedlist mark="square"> <listitem><para> A PROCESS ID: a number from 1 to 255, which is used to identify specific processes. Each process has a unique process ID number. </para></listitem> <listitem><para> MEMORY: enough memory required for the new process to run. Level Two systems give each process a unique "address space". In Level One systems, all processes share the single address space. A "data area", used for the program's parameters, variables, and stack is allocated for the process' exclusive use. A second memory area may also be required to load the program (primary module) if it is not resident in memory. </para></listitem> </itemizedlist> <para> To summarize, the following items are given to or associated with new processes: </para> <itemizedlist mark="square"> <listitem><para> Primary Module (program module to be run) </para></listitem> <listitem><para> Parameter(s) passed from parent to child </para></listitem> <listitem><para> User Number </para></listitem> <listitem><para> Standard I/O paths and working directories </para></listitem> <listitem><para> Process Priority </para></listitem> <listitem><para> Process ID </para></listitem> <listitem><para> Memory </para></listitem> </itemizedlist> </section> <section id="sec5.4"> <title>Basic Memory Management Functions</title> <para> An important NitrOS-9 function is memory management. NitrOS-9 automatically allocates all system memory to itself and to processes, and also keeps track of the logical <emphasis>contents</emphasis> of memory (meaning which program modules are resident in memory at any given time). The result is that you seldom have to be bothered with the actual memory addresses of programs or data. </para> <para> Within the address space, memory is assigned from higher addresses downward for program modules, and from lower addresses upward for data areas, as shown below: </para> <screen> +---------------------------+ highest address ! program modules ! ! (RAM or ROM) ! ! ! ! - - - - - - - - - - - - - ! ! ! ! unused space ! ! (RAM or empty) ! ! ! ! - - - - - - - - - - - - - ! ! ! ! data areas ! ! (RAM) ! ! ! +---------------------------+ lowest address (0) </screen> <section id="sec5.4.1"> <title>Loading Program Modules Into Memory</title> <para> When performing a fork operation, NitrOS-9's first step is to attempt to locate the requested program module by searching the "module directory", which has the address of every module present in memory. The &CPU; instruction set supports a type of program called "reentrant code" which means the exact same "copy" of a program can be shared by two or more different processes simultaneously without affecting each other, provided that each "incarnation" of the program has am independent memory area for its variables. </para> <para> Almost all NitrOS-9 family software is reentrant and can make most efficient use of memory. For example, Basic09 requires 22K bytes of memory to load into. If a request to run Basic09 is made, but another user (process) had previously caused it to be loaded into memory, both processes will share the same copy, instead of causing another copy to be loaded (which would use an additional 22K of memory). NitrOS-9 automatically keeps track of how many processes are using each program module and deletes the module (freeing its memory for other uses) when all processes using the module have terminated. </para> <para> If the requested program module is not already in memory, the name is used as a pathlist (file name) and an attempt is made to load the program from mass storage. </para> <para> Every program module has a "module header" that describes the program and its memory requirements. NitrOS-9 uses this to determine how much memory for variable storage should be allocated to the process (it can be given more memory by specifying an optional parameter on the shell command line). The module header also includes other important descriptive information about the program, and is an essential part of NitrOS-9 operation at the machine language level. A detailed description of memory modules and module headers can be found in the "NitrOS-9 System Programmer's Manual". </para> <para> Programs can also be explicitly loaded into memory using the <command>load</command> command. As with fork, the program will actually be loaded only if it is not already in memory. If the module is not in memory, NitrOS-9 will copy a candidate memory module from the file into memory, verify the CRC, and then, if the module is not already in the module directory, add the module to the directory. This process is repeated until all the modules in the file are loaded, the 64K memory limit is exceeded, or until a module with an invalid format is encountered. NitrOS-9 always links to the first module read from the file. </para> <para> If the program module <emphasis>is</emphasis> already in memory, the load will proceed as described above, loading the module from the specified file, verifying the CRC, and when attempting to add the valid module to the module directory, noticing that the module is already known, the load merely increments the known module's link count (the number of processes using the module.) The load command can be used to "lock a program into memory. This can be useful if the same program is to be used frequently because the program will be kept in memory continuously, instead of being loaded repeatedly. </para> <para> The opposite of <command>load</command> is the <command>unlink</command> command, which decreases a program module's link count by one. Recall that when this count becomes zero (indicating the module in no longer used by any process), the module is deleted, e.g., its memory is deallocated and its name is removed from the module directory. The <command>unlink</command> command is generally used in conjunction with the <command>load</command> command (programs loaded by fork are automatically unlinked when the program terminates). </para> <para> Here is an example of the use of <command>load</command> and <command>unlink</command> to lock a program in memory. Suppose the <command>copy</command> command will be used five times. Normally, the copy command would be loaded each time the <command>copy</command> command is called. If the <command>load</command> command is used first, <command>copy</command> will be locked into memory first, for example: </para> <screen> OS9: load copy OS9: copy file1 file1a OS9: copy file2 file2a OS9: copy file3 file3a OS9: unlink copy </screen> <para> It is important to use the <command>unlink</command> command after the program is no longer needed, or the program will continue to occupy memory which otherwise could be used for other purposes. Be very careful <emphasis>not</emphasis> to completely unlink modules in use by any process! This will cause the memory used by the module to be deallocated and its contents destroyed. This will certainly cause all programs using the unlinked module to crash. </para> </section> <section id="sec5.4.2"> <title>Loading Multiple Programs</title> <para> Another important aspect of program loading is the ability to have two or more programs resident in memory at the same time. This is possible because all NitrOS-9 program modules are "position-independent code", or "PIC". PIC programs do not have to be loaded into specific, predetermined memory addresses to work correctly, and can therefore be loaded at different memory addresses at different times. PIC programs require special types of machine language instructions which few computers have. The ability of the &CPU; microprocessor to use this type of program is one of its most powerful features. </para> <para> The <command>load</command> command can therefore be used two or more times (or a single file may contain several memory modules), and each program module will be automatically loaded at different, non-overlapping addresses (most other operating systems write over the previous program's memory whenever a new program is loaded). This technique also relieves the user from having to be directly concerned with absolute memory addresses. Any number of program modules can be loaded until available system memory is full. </para> </section> <section id="sec5.4.3"> <title>Memory Fragmentation</title> <para> Even though PIC programs can be initially loaded at any address where free memory is available, program modules cannot be relocated dynamically afterwards, e.g., once a program is loaded it must remain at the address at which it was originally loaded (however Level Two systems can "load" (map) memory resident programs at different addresses in each process' address space). This characteristic can lead to a sometimes troublesome phenomenon called "memory fragmentation". When programs are loaded, they are assigned the first sufficiently large block of memory at the highest address possible in the address space. If a number of program modules are loaded, and subsequently one or more modules which are located in between other modules are "unlinked", several fragments of free memory space will exist. The sum of the sizes of the free memory space may be quite large, but because they are scattered, not enough space will exist in a single block to load a program module larger than the largest free space. </para> <para> The <command>mfree</command> command shows the location and size of each unused memory area and the <command>mdir -e</command> command shows the address, size, and link (use) count of each module in the address space. These commands can be used to detect fragmentation. Memory can usually be de-fragmemted by unlinking scattered modules and reloading them. <emphasis>Make certain</emphasis> none are in use before doing so. </para> </section> </section> </chapter>