Ending a Process

Table of contents:

Eventually all things must come to an end. Now that we have generated processes, we should take a closer look at how to end a process. Under its own power ( assuming the process does not receive a terminating signal and the system has not crashed) a process normally terminates in one of three ways. [6] In order of preference, these are

[6] Of course, the library function abort can also be used to end a process, but its call will result in an abnormal termination of the process.

  1. It issues (at any point in its code) a call to either exit or _exit .
  2. It issues a return in the function main .
  3. It falls off the end of the function main ending implicitly.

Programmers routinely make use of the library function exit to terminate programs. This function, which does not return a value, is defined as shown in Table 3.6.

Table 3.6. Summary of the exit Library Function.

Include File(s)

Manual Section

3

Summary

void exit(int status);

Return

Success

Failure

Sets errno

Does not return

No return

 

In earlier versions of C the inclusion of a specific header file was not required when using exit . More recent versions of C (and C++) require the inclusion of the file (or if going the full ANSI-C++ route) that contains the exit function prototype. The exit function accepts a single parameter, an integer status value that will be returned to the parent process. [7] By convention, a 0 value is returned if the program has terminated normally; other wise, a nonzero value is returned. [8] For those who wish to standardize the value returned by exit when terminating, the header file contains two defined constants, EXIT_SUCCESS and EXIT_FAILURE , which can be used to indicate program success and failure respectively. If we somehow are able to slip by the compiler a call to exit without passing an exit status value (i.e., exit( ) ; ) or issue a return; in main without specifying a value, then what is returned to the parent process is technically undefined.

[7] I know, I knowwhat if the parent is no longer around? Remember that init inherits processes whose parents are gone. The handling of status values is discussed further in Section 3.6.

[8] Only the low-order eight bits are returned, thus values range from 0 to 255. (Hmm, I wonder ... would exit(-1) actually return a 255?)

Upon invocation, the exit function performs several actions. Figure 3.9 shows the relationship of the actions taken.

Figure 3.9. Actions taken by library function exit .

graphics/03fig09.gif

First, exit will call, in reverse order, all functions that have been registered using the atexit library function. The atexit function is relatively new. Some older BSD-based versions of C (as well as some version of GNU) supported a library function called on_exit that offered a similar functionality. As future support for on_exit looks to be a bit sketchy; it might be best to stay clear of it. The atexit function should provide similar functionality.

A brief description of the atexit function is in order. The definition of atexit , shown in Table 3.7, indicates that functions to be called (when the process terminates normally) [9] are registered by passing the atexit function the address of the function. The registered functions should not have any parameters. If atexit is successful in registering the function, atexit returns a 0; otherwise , it returns a -1 but will not set errno . [10]

[9] A normal termination is considered a call to exit or a return in main . On our system, atexit registered functions will be called even if the program ends implicitly (without a return in main ).

[10] This is one of the rare cases where no explanation of errno values is provided by system designers.

Program 3.8 demonstrates the use of atexit .

When run, the output of the program shows that the registered functions are called in inverse order (Figure 3.10).

In older versions of C, once all atexit functions were called, the standard I/O library function _cleanup would be called. Newer versions of GNU C/C++ do not support the _cleanup function. Now when all atexit functions have been processed , exit calls the system call _exit (passing on to it the value of status). Programmers may call _exit directly if they wish to circumvent the invocation of atexit registered functions and the flushing of I/O buffers. See Table 3.8.

Table 3.7. Summary of the atexit Library Function.

Include File(s)

Manual Section

3

Summary

int atexit(void (*function)(void));

Return

Success

Failure

Sets errno

-1

No

Program 3.8 Using the atexit library function.

File : p3.8.cxx
 #include 
 #include 
 using namespace std;
 int
 + main( ){
 void f1( ), f2( ), f3( );
 atexit(f1);
 atexit(f2);
 atexit(f3);
 10 cout << "Getting ready to exit" << endl;
 exit(0);
 }
 void
 f1( ){
 + cout << "Doing F1" << endl;
 }
 void
 f2( ){
 cout << "Doing F2" << endl;
 20 }
 void
 f3( ){
 cout << "Doing F3" << endl;
 }

Figure 3.10 Output of Program 3.8.

linux$ p3.8
Getting ready to exit
Doing F3
Doing F2
Doing F1

EXERCISE

Explore the atexit function. What happens if one of the functions registered with atexit contains a call to exit ? What if the registered function (with the exit call) is called directly rather than having the program exit in main are things handled correctly?

Table 3.8. Summary of the _exit System Call.

Include File(s)

std.h>

Manual Section

2

Summary

void _exit(int status);

Return

Success

Failure

Sets errno

Does not return

Does not return

 

The _exit system call, like its relative, exit , does not return. This call also accepts an integer status value, which will be made available to the parent process. When terminating a process, the system performs a number of housekeeping operations:

  • All open file descriptors are closed.
  • The parent of the process is notified (via a SIGCHLD signal) that the process is terminating.
  • Status information is returned to the parent process (if it is waiting for it). If the parent process is not waiting, the system stores the status information until a wait by the parent process is affected.
  • All child processes of the terminating process have their parent process ID (PPID) set to 1they are inherited by init .
  • If the process was a group leader, process group members will be sent SIGHUP/ SIGCONT signals.
  • Shared memory segments and semaphore references are readjusted.
  • If the process was running accounting, the accounting record is written out to the accounting file.

Programs and Processes

Processing Environment

Using Processes

Primitive Communications

Pipes

Message Queues

Semaphores

Shared Memory

Remote Procedure Calls

Sockets

Threads

Appendix A. Using Linux Manual Pages

Appendix B. UNIX Error Messages

Appendix C. RPC Syntax Diagrams

Appendix D. Profiling Programs



Interprocess Communication in Linux
Interprocess Communications in Linux: The Nooks and Crannies
ISBN: 0130460427
EAN: 2147483647
Year: 2001
Pages: 136

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net