ryanheise.comsoftwarerheise.osdevelopment → process termination

Process termination

When a process is terminated, the system must perform the following tasks:
  1. safely terminate all threads of the target process
  2. release all resources held by that process
Both of these tasks are complicated by direct object sharing. In rheise.os, direct object sharing between processes is used as a form of inter-process communication. For example, it is possible for the screen drawing process to export java.awt.Graphics instances to other processes that wish to draw to certain regions of the screen. Care must be taken in terminating a process if any of its threads are currently manipulating objects of other processes, or if other processes hold references to objects in the process about to be terminated.

Thread termination

A process cannot be completely terminated until all of its threads have been safely terminated. Without direct object sharing, all threads could be terminated immediately. Leaving objects in a half edited state is not a problem because those objects will not be used after the process is terminated. However, if the thread is operating on objects belonging to a second process, leaving those objects in a half-edited state may cause unexpected behaviour in the second process after the first process has been terminated.

Threads that are not executing critical code in another process can be terminated immediately. However, if a thread is executing critical code in another process, the system must wait until the thread has left the critical section before terminating the thread. Marking which sections of code are critical and which sections are not can be done in Java using using the synchronized keyword.

Because critical sections are typically as small as possible, the short delay in process termination is acceptable. However, if the server gets stuck in one of its critical sections (eg. due to a bug), a request to kill the client process would also hang. In this case, the user could be prompted to force-kill the client, and by implication the server along with it. (another option is to give the server a chance to recover)

Resource reclamation

When a process is terminated, some resources should be released immediately (file and socket handles) while others can be reclaimed by the system at some later stage (such as memory). In Java, the finalize method is used to release resources such as file and socket handles, while the garbage collector is used to reclaim memory. The garbage collector also invokes the finalize method of each object before it is reclaimed. One approach to process termination is to simply invoke the garbage collector after all threads have been stopped. Then all resources would be reclaimed immediately. However, if some objects are referred to by other processes, not all objects will be garbage collected, and not all resources will be released immediately.

There is no reason why the finalize methods and the garbage collector need to be run at the same time. It is possible to handle resource reclamation in two stages. First, all objects of the process are invalidated and finalized. Second, the objects are garbage collected when the garbage collector finds that there are no more references to them. All objects that were only referenced within the process are immediately considered garbage. Objects that are referred to by other processes are considered garbage once all references are released.

Once the process is terminated, other processes that hold references to objects of the dead process will be holding references to invalid objects. These are objects that are still in memory, but access to fields or methods of that object is denied by throwing an InvalidReferenceError.

This two stage process of garbage collection is shown in the following state diagram:

A single stage garbage collector can either be run whenever the system decides, or explicitly by invoking System.gc(). Similarly in the two-stage garbage collector described above, each stage may be run either explicitly or when the system decides. When a process is terminated, the system will invoke the first stage of the garbage collector explicitly. The actual objects can then be reclaimed at any later stage.