1.25 Process Control

A process is a program that is being executed. The attributes that a process can have vary from one operating system to another. For this reason, the process control functions work in ways that are specific to certain systems.

1.25.1 Communication with the Operating System

Environment

In operating systems such as Unix and Windows, each process is started in an environment represented by a list of strings with the form NAME=VALUE. These "environment variables" can be read using the function getenv().

System calls

The function system() invokes the system's command interpreter and gives it a command to execute.

Program termination

A C program is normally terminated via a call to the function exit(), or by a return statement in the function main(). On normal termination, the following actions are performed:

1.  Any functions that have been installed by atexit() are executed.

2.  The I/O buffers are flushed and the files closed.

3.  The files created by tmpfile() are deleted.

The function abort(), on the other hand, ends a C program without performing the actions just listed. This function does produce an error message announcing that the program was aborted, however.

The function exit() can be called with one of the constants EXIT_FAILURE and EXIT_SUCCESS, defined in stdlib.h, as an argument. In this way the program can inform its parent process whether it "failed" or "succeeded."

All of the functions described in this section are declared in the header file stdlib.h.

1.25.2 Signals

The operating system can send processes a signal when an exceptional situation occurs. This may happen in the event of a severe fault, such as a memory addressing error for example, or when a hardware interrupt occurs. Signals can also be triggered by the user at the console, however, or by the program itself, using the function raise(). Functions and macros for dealing with signals are declared in the header file signal.h.

Each type of signal is assigned a constant signal number and identified by a macro name. These include the signals listed in Table 1-41.

Table 1-41. Macros for signals in signal.h

Signal number

Meaning

SIGABRT

Abort: abnormal program termination, as caused by the abort() function

SIGFPE

Floating point exception: caused by an overflow, division by 0, or other FPU or emulation errors

SIGILL

Illegal instruction: an invalid instruction was encountered in the machine code

SIGINT

Interrupt: the break key (e. g., Ctrl-C) was pressed

SIGSEGV

Segmentation violation: illegal memory access

SIGTERM

Terminate: a request to terminate the program (in Unix, the standard signal sent by the kill command)

Other signals may be defined depending on the operating system.

int raise ( int sig  );

Sends the signal sig to the program which called the function.

void ( *signal ( int sig , void ( *func  )( int )) )( int );

Specifies how the program responds to a signal with the number sig. The second argument, func, identifies the signal handler. This may be a pointer to a function, or one of the following constants:

·     SIG_DFL Execute the default signal handler.

·     SIG_IGN Ignore the signal.

The default signal handler terminates the program. If unsuccessful, signal() returns the value SIG_ERR.

The header file signal.h also defines the integer type sig_atomic_t. This type is used for static objects which can be accessed by a hardware interrupt signal handler.

1.25.3 Non-Local Jumps

Local jumps, or jumps within a function, are performed by the goto statement. The macro setjmp(), on the other hand, marks a location in the program (by storing the pertinent process information) so that execution can be resumed at that point at any time by a call to the function longjmp(). The longjmp() function and the setjmp() macro are declared in the header file setjmp.h.

int setjmp ( jmp_buf env  );

Saves the current calling environment (CPU registers and stack) in the buffer env, which has the type jmp_buf.

void longjmp ( jmp_buf env , int retval  );

Restores the saved environment, so that program execution continues at the point where setjmp() was called.

The program can use the return value of setjmp() to determine whether setjmp() itself was just called, or whether a jump to this point by means of longjmp() has just occurred. setjmp() itself returns the value 0, but after a call to longjmp() the apparent return value of setjmp() is the value of the argument retval. If retval is equal to 0, the apparent return value is 1.

1.25.4 Error Handling for System Functions

If an error occurs during a call to a system function, the global error variable errno is assigned an appropriate error code. The following three functions are used to provide the corresponding system error messages:

void perror ( const char *string  );

Declared in stdio.h

Writes the text pointed to by string, followed by the system error message corresponding to the current value of errno, to the standard error stream.

char *strerror ( int errnum  );

Declared in string.h

Returns a pointer to the system error message corresponding to errnum. The value of errnum is usually obtained from the error variable errno.

The following two statements result in the same output:

perror( "OPEN" );
fprintf( stderr, "OPEN: %s\n", strerror( errno ) );
void assert ( int expression  );  Declared in assert.h

This macro tests the scalar expression expression. If the result is 0, or "false", then assert() writes the expression, function name, filename, and line number to the standard error stream, and then aborts program. If the expression is "true" (i.e., not equal to 0), no action is taken and the program continues.

If the macro NDEBUG is defined, calls to assert() have no effect.