• Aucun résultat trouvé

task management

Dans le document TEKTRONIX SMALLTALK (Page 192-199)

markAndSlgnalAIl

Mark the status #nonexistent and signal the wait semaphore of each previously scheduled subtask. This method is used when restoring after a snapshot.

terminate: aTask

Terminate aTask and remove it from the task list.

termlnateAII

Terminate all the scheduled tasks and remove them from the task list.

terminate Unconditionally: aTask

Terminate the spawned task and remove it from the task list.

Rationale

Tektronix Smalltalk adds support for subtasks to make the job of creating, running, and communicating with the subtasks straightforward. Interfaces to operating system signals, program parameters, environment variables, and subtask priorities are also supported.

Background

Mu Ill-tasking

Most operating systems support multi-tasking. To the operating system, your running Smalltalk program is another task. Although Smalltalk has its own

processes, Smalltalk can also create and communicate with operating system tasks.

Operating system subtasks provide access to other executable programs. By using the class Subtask, you can create a child task so that you can use some resource - an operating system command, or a program you have written in the C language, etc. - outside of the Smalltalk process.

By spawning new tasks, multi-tasking is accessible without leaving the Smalltalk environment. A newly spawned task is called a child task or a subtask. The original task is referred to as the parent task. The child task is a "copy" of the parent task -it shares resources w-ith the parent task. Since only one task can execute at a time, CPU time is also shared, initially in a predetermined fashion. Common practice is for the spawned child task to perform some chore, and then report back to the parent task. After reporting, the child task terminates. A parent may choose to relinquish use of the CPU until a subtask terminates. It does this by an operation called waiting. While waiting, the parent task is blocked and cannot do anything else until the child task terminates.

Subtask OS-Interface

The child task's chore is often accomplished by finding some other program to do the work. The use of this other program is known as an exec operation (for execute). In an exec operation, the spawned task "turns itself into" the other program.

Pipes

A pipe is used to convey data from one process (task) to another. Pipes are data structures set up in computer memory to be transient, even though they share other characteristics with files.

Frequently, a parent task may want to communicate with a child task. Information can be sent to and from the child task by using pipes; however, each pipe can send information in only one direction. If communication in two directions is desired, two pipes must be used. Pipes are similar to files with two critical differences.

• Files can be reopened many times. Pipes can only be opened once. Once a pipe is closed it is gone.

• Files can be reset and repositioned. It is not possible to reposition a pipe.

Usually the parent task creates a pipe. Each end of the pipe is assigned a file descriptor, one for reading and one for writing. When a subtask is created it inherits these open file descriptors. The parent task saves one file descriptor, the one which is appropriate for its direction of communication. For example, if the parent task wants to send information to the child, the parent saves the file descriptor for writing.

Since the parent will not be using the reading end of the pipe, it should close this unused end. The child task must also save the appropriate file descriptor and close the file descriptor corresponding to the unused end of the pipe. Neglecting to close these unused pipe file descriptors might mean the task could run out of file

descriptors, since there is a limit on the number of open file descriptors per task.

Sometimes it is not possible for the child task to know that it should use the pipe's file descriptors for reading and writing. For instance, the child task might execute a program that writes on standard output. It is possible for the child task to redirect its 1/0 by mapping its pipe descriptors to known file descriptors. Redirection allows a file descriptor to capture all the data intended for another descriptor. Tektronix Smalltalk Pipe protocol supports this functionality. Once a pipe's file descriptor is mapped, it becomes obsolete and should be closed. For example, the child task may want to write to the pipe, but the program is designed so write operations go to standard output. The write file descriptor of the pipe must be mapped to standard output's file descriptor (1), and the pipe's original write file descriptor should be closed. The effect of the mapping in this example is for the child task's write operations going to standard output to be performed on the write end of the pipe

Subtask OS-Interface

instead.

Operating System Multi-tasking -Implementation

In a multi-tasking operating system, programs generally execute by duplicating the parent program (task), transforming the duplicate (child) task into the new program.

Upon termination of the new program, the parent task is signaled; if it suspended execution, the parent task resumes. Specific system calls are used to accomplish these tasks. Afork call causes the duplication of the parent task. An exec call causes the duplicate task (i.e., the child task) to "transform" into a desired executable program. An

exit

call terminates the sending task and causes the operating system to send a "dead child signal" to the parent task - this indicates that a spawned task has terminated. A

wait

call executed by the parent task, besides suspending the parent task until termination of the child task, returns the termination status of the child task. Termination status includes information such as which signal caused the termination and whether the termination was abnormal.

For example, suppose you type the command

Is

at the keyboard. As you know, the shell program is waiting to interpret your keystrokes. Here the shell is a parent task.

If the shell determines that you have typed Is correctly, it forks another shell task-a child ttask-ask. This ttask-ask then executes task-an exec ctask-all which overltask-ays the child ttask-ask with the Is program.

Is

executes, outputs directory information to the screen, and exits normally. The shell task receives the termination status via a

wait

call and resumes its lID wait for more input from you.

Discussion

A subtask is spawned in a Unix-like operating system in three phases:

• a fork system call,

• a set-up phase, and

• the exec system call.

Most of the code for what takes place in the set-up phase is encapsulated in the subtask at the point of instance creation. Between fork and exec the subtask is running Smalltalk, but it is limited. The keyboard and the mouse cannot be used to communicate with Smalltalk, so no debugging can take place if the set-up code doesn't execute as anticipated.

In the set-up phase, depending upon which instance creation message selector is used and the values of instance variables, several things can take place, such as:

Subtask OS-Interface

• a block of code executes concerning signals and communication;

• priority of the subtask is set;

• the environment is changed from the environment that the subtask inherited from its parent task.

Subtask Instance Protocol

Accessing

methods enable the user to set and access the values of instance variables. Some instance variables control what happens in the set-up phase, others contain information about the termination of the subtask.

Controlling

methods start the subtask, wait for the subtask, and allow the task to be interrupted or terminated.

Testing

methods provide information about the subtask, such as whether it is active, terminated abnormally, is or is not terminated, and whether the subtask exists.

Subtask Class Protocol

Environment variables

methods provide information about the current environment and allow the environment of the subtask to be modified. The default environment for a subtask is the environment of the parent task.

Instance creation

methods provide the encapsulation of data to be used in the set-up phase of the subtask.

Scheduled subtasks

and

task management

methods deal with the subtask management system and you will probably not use them directly.

Relation to the System Call and Pipe Classes

The system call class is used for the implementation of fork, exec, and wait. It also contains protocol for various other operations used by a subtask, including setting up signals and priorities. Communication between tasks is currently provided by the pipe classes. Access to other communication implementations, such as sockets, is available through system calls.

Management of Subtasks

A subtask management process is part of Tektronix Smalltalk - it is implemented in the metaclass of Subtask. Unlike the C programming environment where the only type of waiting available is complete suspension until the child task terminates, the task management system allows two types of waiting, described below.

Subtask OS-Interface

The subtask manager runs continuously, monitoring child tasks. When a task is started, it is registered with the task mn.nagement system. Two lists are used to keep track of subtasks - class instance variables scheduledSubtasks and unscheduledSubtasks.

When a subtask terminates, the manager receives a dead child signal. The manager releases a terminated task from its list; if the parent process has been suspended, the manager sends a signal for it to resume.

Waiting

There are two methods that deal with waiting by the parent task - wait and waitWithSmalltalkSuspended. The message wait causes the suspension of only the parent process of the subtask. When the subtask ends, the parent is signaled to resume.

The message waitWithSmalltalkSuspended causes the entire Smalltalk task to suspend. While Smalltalk is suspended there is no way to interact with the Smalltalk task using the keyboard or the mouse. This version of waiting is used for efficiency, for example, while a Fortran program doing a lot of calculations is running - like a fast Fourier transform.

Concurrent subtasks may use either form of waiting - their terminations are handled appropriately by the subtask manager.

Snapshots

If a subtask is running when a snapshot is made, certain things occur. In the Smalltalk image that continues to run after the snapshot, the subtask is not affected.

When you quit, any running subtasks are terminated by the operating system.

When a Smalltalk image is "brought up" (loaded by the Smalltalk interpreter), the subtask management system is installed with empty task lists. If subtasks were running when the snapshot was made, they will be marked as #nonexistent. Their status can be checked and they can be restarted by application programs.

Examples

See the file lusrlliblsmalltalklfileInlExamples-Subtasking.st (this path correct for UTek only) for some examples illustrating how to use Subtask in an application example.

Read further for an introduction to using Subtask.

Subtask OS-Interface

The Simplest Example

Here is a very simple example that uses Subtask.

"Execute a simple binary program with no arguments."

I

task

I

task ~ Subtask

fork: ~ lusr/bin/pretend ~

then: [ ].

task start task wait

The code above can be executed in a workspace, assuming that the

"/usrlbin/pretend" file exists. It contains the simplest form of subtask instance creation, since it has no arguments and does not include a block of code to be executed between fork and exec. The default set-up takes place, not a user-specified set-up. The task then starts and the parent waits for the subtask to terminate.

Add Some Interest

Here is a method which executes a program requiring two arguments. It illustrates some variations of Subtask protocol and adds error checking code.

execute Utility: aCommand withArgumentl: argumentString 1 withArgument2: argumentStriog2

"Execute a binary program with two arguments. Set the priority of the subtask to the highest possible, and ignore dead child signals in the child task. Create an error if the program cannot be executed or if the program terminates abnormally."

I argumentList task envDictionary I argumentList ~ OrderedCollection

with: argumentStringl with: argumentString2.

task ~ Subtask fork: aCommand

withArguments: argumentList

then: [OS ignorelnterrupt: OS deadChildlnterrupt1.

envDictionary ~ Subtask currentEnvironment copy.

envDictionary at: #PARENT put: ~sma11ta1k~.

task environment: envDictionary.

Subtask OS-Interface

task enhancedPriority.

task start isNil

iITrue: [self error: 'Cannot execute' , aCommandl.

Cursor execute

showWhile: [task wait], task abnormalTermination

iITrue: [self error: ' Abnormal termination from' , aCommand]

In the code above, we begin by placing the arguments in an OrderedCollection, since the instance creation method expects arguments in that form. This example uses an instance creation message different from the first example - this one allows us to pass arguments to the executable program.

Set-up Phase

The block of code after then: is executed only by the child task; it is done in the set-up phase. Here the set-set-up changes the action of an interrset-upt - the dead child interrupt is ignored. The current environment is stored in a temporary variable,

envDictionary,

and the association of #Parent->'smalltalk' is added to it. Then the subtask's environment instance variable is set to the value of the temporary variable,

envDictionary.

The subtask is given the highest possible priority. The start message causes the execution of the set-up code.

Start and Finish

If start returns an error, a notifier is displayed. While the subtask is executing and the parent process waits for the subtask to terminate, the cursor is in the form of a star (Cursor execute showWhile:). If the subtask terminates abnormally, an error notifier is displayed.

Related Classes

In Smalltalk code, the typical reference to the system call class is

as,

a global variable which is the appropriate system call class for your operating system. You might want to refer to these classes in this manual for further information:

• the system call class for your operating system and its superclasses,

• the Pipe Stream hierarchy of classes, and

• Pipe.

Pipe is not directly used in the implementation of Subtask, but it is essential to complete usage of subtasks.

Dans le document TEKTRONIX SMALLTALK (Page 192-199)