Signal and Signal Management Calls

In the previous section we noted that a process can handle a signal by doing nothing (thus allowing the default action to occur), ignoring the signal, or catching the signal. Both the ignoring and catching of a signal entail the association of a signal-catching routine with a signal. In brief, when this is done the process automatically invokes the signal-catching routine when the stipulated signal is received. There are two basic system calls that can be used to modify what a process will do when a signal has been received: signal and sigaction . The signal system call has been present in all versions of UNIX and is now categorized as the ANSI C version signal-handling routine (Table 4.19). The sigaction system call (Table 4.20) is somewhat more recent and is one of a group of POSIX signal management calls.

Table 4.19. Summary of the signal System Call.

Include File(s)

Manual Section

2

Summary

void (*signal(int signum,
 void (*sighandler)(int)))(int);

Return

Success

Failure

Sets errno

Signal's previous disposition

SIG_ERR (defined as -1)

Yes

Table 4.20. Summary of the sigaction System Call.

Include File(s)

Manual Section

2

Summary

int sigaction(int signum, const
 struct sigaction *act,
 struct sigaction *oldact);

Return

Success

Failure

Sets errno

-1

Yes

The most difficult part of using signal is deciphering its prototype. In essence, the prototype declares signal to be a function that accepts two argumentsan integer signum value and a pointer to a functionwhich are called when the signal is received. If the invocation of signal is successful, it returns a pointer to a function that returns nothing ( void ). This is the previous disposition for the signal. The mysterious ( int ) , found at the far right of the prototype, indicates the referenced function has an integer argument. This argument is automatically filled by the system and contains the signal number. Either system call fails and returns the value -1, setting the value in errno to EINTR (4), if it is interrupted or to EINVAL (22) if the value given for signum is not valid or is set to SIGKILL or SIGSTOP. Further, sigaction returns EFAULT (14) if the act or oldact arguments reference an invalid address space.

While both signal and sigaction deal with signal handling, the functionality of each is slightly different. Let's begin with the signal system call.

The first argument to the signal system call is the signal that we intend to associate with a new action. The signal value can be an integer or a symbolic signal name . This value cannot be SIGKILL or SIGSTOP. The second argument to signal is the address of the signal-catching function. The signal-catching function can be a user -defined function or one of the defined constants SIG_DFL or SIG_IGN. Specifying SIG_DFL for a signal resets the action to be taken to its default action when the signal is received. Indicating SIG_IGN for a signal means the process will ignore the receipt of the indicated signal.

An examination of the signal header files shows that SIG_DFL and SIG_IGN are defined as integer values that have been appropriately cast to address locations that are invalid (such as -1, etc.). The declaration most commonly found for SIG_DFL and SIG_IGN is shown below. With these definitions is another defined constant that can be usedSIG_ERR. This constant is the value that is returned by signal if it fails. See Figure 4.8.

Figure 4.8 Defined constants used by signal and sigset .

/* Fake signal functions. */

#define SIG_ERR ((__sighandler_t) -1) /* Error return. */
#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */

Program 4.4 uses the signal system call to demonstrate how a signal can be ignored.

Program 4.4 Pseudo nohup ignoring a signal.

File : p4.4.cxx
 /* Using the signal system call to ignore a hangup signal
 */
 #include 
 + #include 
 #include 
 #include 
 #include 
 #include 
 using namespace std;
 10 const char *file_out = "nohup.out";
 int
 main(int argc, char *argv[]){
 int new_stdout;
 if (argc < 2) {
 + cerr << "Usage: " << *argv << " command [arguments]" << endl;
 return 1;
 }
 if (isatty(1)) {
 cerr << "Sending output to " << file_out << endl;
 20 close(1);
 if ((new_stdout = open(file_out, O_WRONLY O_CREAT 
 O_APPEND, 0644)) == -1) {
 perror(file_out);
 return 2;
 + }
 }
 if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
 perror("SIGHUP");
 return 3;
 30 }
 ++argv;
 execvp(*argv, argv);
 perror(*argv); // Should not get here unless
 return 4; // the exec call fails.
 + }

Program 4.4 is a limited version of the /usr/bin/nohup command found on most UNIX-based systems. The nohup command can be used to run commands so they will be immune to the receipt of SIGHUP signals. If the standard output for the current process is associated with a terminal, the output from nohup will be sent to the file nohup.out . The nohup command is often used with the command-line background specifier & to allow a command to continue its execution in the background even after the user has logged out.

Like the real nohup , our pseudo nohup program (Program 4.4) will execute the command (with optional arguments) that is passed to it on the command line. After checking the number of command-line arguments, the file descriptor associated with stdout is evaluated. The assumption here is that the file descriptor associated with stdout is 1. However, if needed, there is a standard I/O function named fileno that can be used to find the integer file descriptor for a given argument stream. The library function isatty (Table 4.21) is used to determine if the descriptor is associated with a terminal device.

Table 4.21. Summary of the isatty Library Function.

Include File(s)

Manual Section

3

Summary

Int isatty(int desc);

Return

Success

Failure

Sets errno

1

 

The isattty library function takes a single integer desc argument. If desc is associated with a terminal device, isatty returns a 1; otherwise , it returns a 0. In the program, if the isatty function returns a 1, an informational message is displayed to standard error to tell the user where the output from the command passed to the pseudo nohup program can be found. Next, the file descriptor for stdout is closed. The open statement that follows the close returns the first free file descriptor. As we have just closed stdout , the descriptor returned by the open will be that of stdout . Once this reassignment has been done, any information written to stdout ( cout ) by the program will in turn be appended to the file nohup.out . Notice that the call to signal to ignore the SIGHUP signal is done within an if statement. Should the signal system call fail (return a SIG_ERR), a message would be displayed to standard error and the program would exit. If the signal call is successful, the argv pointer is incremented to step past the name of the current program. The remainder of the command line is then passed to the execvp system call. Should the execvp call fail, perror will be invoked and a message displayed. If execvp is successful, the current process will be overlaid by the program/command passed from the command line.

The output in Figure 4.9 shows what happens when the pseudo nohup program is run on a local system and passed a command that takes a long time to execute. In the example the long-running command is a small Korn shell script called count that counts from 1 to 100, sleeping one second after the display of each value. As written, the output from the script would normally be displayed on the screen.

Figure 4.9 Output of Program 4.4 when passed a command that takes a long time to execute.

linux$ cat count
#! /bin/ksh
c=1 
while (($c <= 100))

<-- 1

do
 echo "$c"
 sleep 1
 ((c = c + 1))
done

linux$ ./p4.4 ./count &

<-- 2

Sending output to nohup.out
[1] 19481
linux$ jobs

<-- 3

[1] + Running p4.4 count
linux$ kill -HUP %1

<-- 4

linux$ jobs
[1] + Running p4.4 count
linux$ kill -KILL %1
linux$
[1] Killed p4.4 count
linux$ jobs
linux$

(1) The script count from 1 to 100, sleeping one second in between the display of each number. If run on the command line, it will take approximately 100 seconds to count from 1 to 100.

(2) Pass the count script to our pseudo nohup programplace it in the background.

(3) The operating system returns the PID of the background process.

(4) Sending a hangup signal to the process does not cause it to terminate.

When the program was placed in the background, the system reported the job number (in this case [ 1 ]) and the PID (19481). The jobs command confirms that the process is still running. As can be seen, the kill -HUP %1 command (which sends a hangup signal to the first job in the background) did not cause the program to terminate. This is not unexpected, as the SIGHUP signal was being ignored. The command kill KILL %1 was used to terminate the process by sending it a SIGKILL signal.

EXERCISE

If a find command (e.g., find / -name * -print ) is run by Program 4.4, the error messages from find (such as it not having permission to read certain directories), which are written to stderr , are still displayed. Modify Program 4.4 so that error messages from the program being run are discarded (written to /dev/null ). What are the pros and cons of such a modification?

As noted, if a signal-catching function name is supplied to the signal system call, the process will automatically call this function when the process receives the signal. However, prior to calling the function, if the signal is not SIG KILL, SIGPWR, or SIGTRAP, the system will reset the signal's disposition to its default. This means that if two of the same signals are received successively, it is entirely possible that before the signal-catching routine is executed, the second signal may cause the process to terminate (if that is the default action for the signal). This behavior reduces the reliability of using signals as a communication device. It is possible to reduce, but not entirely eliminate, this window of opportunity for failure by resetting the disposition for the signal in the catching routine. Program 4.5 catches signals and attempts to reduce this window of opportunity.

Program 4.5 Catching SIGINT and SIGQUIT signals.

File : p4.5.cxx
 /* Catching a signal
 */
 #include 
 + #include 
 #include 
 #include 
 #include 
 using namespace std;
 int
 10 main() {
 void signal_catcher(int);
 if (signal(SIGINT , signal_catcher) == SIG_ERR) {
 perror("SIGINT");
 return 1;
 + }
 if (signal(SIGQUIT , signal_catcher) == SIG_ERR) {
 perror("SIGQUIT");
 return 2;
 }
 20 for (int i=0; ; ++i) { // Forever ...
 cout << i << endl; // display a number
 sleep(1);
 }
 return 0;
 + }
 void
 signal_catcher(int the_sig){
 signal(the_sig, signal_catcher); // reset immediately
 cout << endl << "Signal " << the_sig << " received." << endl;
 30 if (the_sig == SIGQUIT)
 exit(3);
 }

In an attempt to avoid taking the default action (which in this case is to terminate) for either of the two caught signals, the first statement (line 28) in the program function signal_catcher is a call to signal . This call reestablishes the association between the signal being caught and the signal-catching routine.

Figure 4.10 shows the output of the program when run on a local system.

Figure 4.10 Output of Program 4.5.

linux$ p4.5
0
1
2

<-- 1

Signal 2 received.
3
4

<-- 2

Signal 2 received.
5

<-- 2

Signal 2 received.
6

Signal 3 received.
linux$

(1) The user types CTRL+C. The terminal program displays a funny graphics character, ².

(2) Here the signals are generated in rapid succession.

From this output we can see that each time CTRL+C was pressed, it was echoed back to the terminal as ² . If CTRL+C was struck twice in quick succession, the program responded with the Signal 2 received message for each keyboard sequence. On this system it appears as if some of the signals were queued if they were received in rapid succession. However, this is somewhat misleading, as the mechanics of terminal I/O come into play. Say we were (via a background process) to deliver to the process, in very rapid succession, multiple copies of the same signal. In this setting we would find most often that only one copy of the signal would be delivered to the process, while the others are discarded. Most systems do not queue the signals 1 through 31. When a SIGQUIT signal was generated, a message was displayed and the program exited.

EXERCISE

Lad wrote the program below in an attempt to determine what keystrokes generate a signal that can be caught.

[View full width]


 

[View full width]

File : lad.cxx /* Lad's signal catching program */ #include + #include #include #include #include using namespace std; int 10 main() { void signal_catcher(int); char a_num[5]; <-- 1 for (int i=1; i < _NSIG; ++i) switch(i){ + case SIGKILL: case SIGSTOP: break; default: <-- 2 if (signal(i , signal_catcher) == SIG_ERR) { sprintf(a_num, "%d", i); 20 perror(a_num); return 1; } } for (int i=0; ; ++i) { // Forever ... + cout << i << endl; // display a graphics/ccc.gif number sleep(1); } return 0; } 30 void signal_catcher(int the_sig){ signal(the_sig, signal_catcher); // reset cout << endl << "Signal " << the_sig << " received." graphics/ccc.gif << endl; if (the_sig == SIGQUIT) + exit(3); }

(1) The constant _NSIG is the upper bound for signal numbers . On some systems, this constant does not have the leading underscore .

(2) Catch all signals that can be caughtmap each to the signal-catching function.

When running his program, how many signals did Lad find he could generate from the keyboard? What are they? Describe what happens (and why) when the following keystrokes are entered? CTRL+S, CTRL+Q, and CTRL+R.

EXERCISE

Remove the statement

if (the_sig == SIGQUIT)
 exit(3);

from Program 4.5. Recompile the program and run it in the background (i.e., p4.5 & ). How did you stop the program from displaying numbers on the screen?

EXERCISE

Write a program that fork s a child process. The parent and child processes should generate and send random signals to each other. In each process, display the signal being sent and the signal that is caught. Be sure both processes exit gracefully and that neither remains active if the other has terminated due to the receipt of a SIGKILL signal. Hint : Remember that you can, with kill , determine if a process is present.

The sigaction system call, like the signal system call, can be used to associate an alternate action with the receipt of a signal. This system call has three arguments. The first is an integer value that specifies the signal. As with the signal system call, this argument can be any valid signal except SIGKILL or SIGSTOP. The second and third arguments are references to a sigaction structure. Respectively these structures store the new and previous action for the signal. The full definition of the sigaction structure is found in the file sigaction.h . This file is automatically included by signal.h. Basically, the sigaction structure is

struct sigaction {
 void (*sa_handler)(int); // 1
 void (*sa_sigaction)(int, siginfo_t *, void *); // 2
 sigset_t sa_mask; // 3
 int sa_flags; // 4
 void (*sa_restorer)(void); // 5
}

Both sa_handler and sa_sigaction can be used to reference a signal handling function. Only one of these should be specified at any given time, as on most systems this data is often stored in a union within the sigaction structure. By definition, a union can hold only one of its members at a time. Our discussion centers on using the sa_handler member. The sa_mask member specifies the signals, which should be blocked when the signal handler is executing. Each signal is represented by a bit. If the bit in the mask is on, the signal is blocked. By default the signal that triggered the handler is blocked. The sa_flags member is used to set flags that modify the behavior of the signal-handling process. Flag constants, shown in Table 4.22, can be combined using a bitwise OR .

Table 4.22. sa_flags Constants.

Flag

Action

SA_NOCLDSTOP

If the signal is SIGCHILD, then the calling process will not receive a SIGCHILD signal when its child processes exit.

SA_ONESHOT or SA_RESETHAND

Restore the default action after the signal handler has been called once (similar to the default of the signal call).

SA_RESTART

Use BSD signal semantics (certain interrupted system calls are restarted after the signal has been caught).

SA_NOMASK or SA_NODEFER

Undo the default whereby the signal triggering the handler is automatically blocked.

SA_SIGINFO

The signal handler has three argumentsuse sa_sigaction , not sa_handler .

The remaining structure member, sa_restorer , is obsolete and should not be used.

Unlike signal , a sigaction installed signal-catching routine remains installed even after it has been invoked. Program 4.6, which is similar to Program 4.5, shows the use of the sigaction system call.

Again, notice that in the program function signal_catcher , it is no longer necessary to reset the association for the signal caught to the signal-catching routine.

Program 4.6 Using the sigaction system call.

File : p4.6.cxx
 /* Catching a signal using sigaction
 */
 #define_GNU_SOURCE
 + #include 
 #include 
 #include 
 #include 
 #include 
 using namespace std;
 10 int
 main() {
 void signal_catcher(int);
 struct sigaction new_action;

<-- 1

new_action.sa_handler = signal_catcher;
 + new_action.sa_flags = 0;

<-- 2

if (sigaction(SIGINT, &new_action, NULL) == -1) {
 perror("SIGINT");

<-- 3

return 1;
 20 }

<-- 3

if (sigaction(SIGQUIT, &new_action, NULL) == -1) {
 perror("SIGQUIT");
 return 2;
 }
 + for (int i=0; ; ++i) { // Forever ...
 cout << i << endl; // display a number
 sleep(1);
 }
 return 0;
 30 }
 void
 signal_catcher(int the_sig){
 cout << endl << "Signal " << the_sig << " received." << endl;
 if (the_sig == SIGQUIT)
 + exit(3);
 }

(1) A sigaction structure is allocated.

(2) The signal catching function is assigned and the sa_flags member set to 0.

(3) A new action is associated with each signal.

Three other POSIX signal- related system calls that can be used for signal management are shown in Table 4.23.

Table 4.23. Summary of the sigprocmask , sigpending , and sigsuspend System Call.

Include File(s)

Manual Section

2

Summary

int sigprocmask (int how, const sigset_t *set,
 sigset_t *oldset);
int sigpending(sigset_t *set);
int sigsuspend(const sigset_t *mask);;

Return

Success

Failure

Sets errno

-1

Yes

Each function returns a 0 if it is successful; otherwise, it returns a -1 and sets the value in errno (Table 4.24).

Table 4.24. sigprocmask , sigpending , and sigsuspend Error Messages.

#

Constant

perror Message

Explanation

4

EINTR

Interrupted system call

A signal was caught during the system call.

14

EFAULT

Bad address

set or oldset references an invalid address space.

The process's signal mask can be manipulated with the sigprocmask system call. The first argument, how , indicates how the list of signals (referenced by the second argument, set ) should be treated. The action that sigprocmask will take, based on the value of how , is summarized in Table 4.25.

Table 4.25. Defined how Constants.

Signal

Action

SIG_BLOCK

Block the signals specified by the union of the current set of signals with those specified by the set argument.

SIG_UNBLOCK

Unblock the signals specified by the set argument.

SIG_SETMASK

Block just those signals specified by the set argument.

If the third argument, oldset , is non-null, the previous value of the signal mask is stored in the location referenced by oldset .

The use of the sigprocmask system call is shown in Program 4.7.

Program 4.7 Using sigprocmask .

File : p4.7.cxx
 /* Demonstration of the sigprocmask call */
 #define_GNU_SOURCE
 #include 
 #include 
 + #include 
 #include 
 using namespace std;
 sigset_t new_signals;
 int
 10 main() {
 void signal_catcher(int);

<-- 1

struct sigaction new_action;

<-- 2

sigemptyset(&new_signals);
 + sigaddset(&new_signals,SIGUSR1);
 
 sigprocmask(SIG_BLOCK, &new_signals, NULL);
 new_action.sa_handler = signal_catcher;
 new_action.sa_flags = 0;
 20 if (sigaction(SIGUSR2, &new_action, NULL) == -1) {
 perror("SIGUSR2");
 return 1;
 }
 cout << "Waiting for signal" << endl;
 + pause();
 cout << "Done" << endl;
 return 0;
 }
 void
 30 signal_catcher(int n) {
 cout << "Received signal " << n << " will release SIGUSR1" << endl;
 sigprocmask(SIG_UNBLOCK, &new_signals, NULL);
 cout << "SIGUSR1 released!" << endl;
 }

(1) Empty (clear) the set of signals.

(2) Add the SIGUSR1 signal to this set.

The example makes use of the SIGUSR1 and SIGUSR2 signals. These are two user-defined signals whose default action is termination of the process. In lines 14 and 15 of the example are two signal-mask manipulation library functions ( sigemptyset and sigaddset ) that are used to clear and then add a signal to the new signal mask. A signal mask is essentially a string of bitseach set bit represents a signal. The signal-mask manipulation library functions are covered in detail in Chapter 11, "Threads." In Program 4.7, the sigprocmask system call in line 17 holds (blocks) incoming SIGUSR1 signals. The sigaction system call (line 20) is used to associate the receipt of SIGUSR2 with the signal-catching routine. Following this, an informational message is displayed, and a call to pause is made. In the program function signal_catcher , the sigprocmask system call is used to release the pending SIGUSR1 signal. Notice that a cout statement was placed before and after the sigprocmask call. A sample of this program run locally is shown in Figure 4.11.

When run, the program is placed in background so the user can continue to issue commands from the keyboard. The system displays the job number for the process and the PID. The program begins by displaying the Waiting for signal message. The user, via the kill command, sends the process a SIGUSR1 signal. This signal, while received by the process, is not acted upon, as the process has been directed to block this signal. When the SIGUSR2 signal is sent to the process, the process catches the signal, and the program function signal_catcher is called. The initial cout statement in the signal-catching routine is executed, and its message about receiving signals is displayed. The following sigprocmask call then unblocks the pending SIGUSR1 signal that was issued earlier. As the default action for SIGUSR1 is termination, the process terminates and the system produces the trailing information indicating the process was terminated via user signal 1. As the process terminates abnormally, the second cout statement in the signal-catching routine and the cout in the main of the program are not executed.

Figure 4.11 Output of Program 4.7.

linux$ ./p4.7 &
Waiting for signal
[1] 21895
linux$ kill -USR1 21895

<-- 1

linux$ kill -USR2 21895

<-- 2

Received signal 12 will release SIGUSR1
linux$
[1] User signal 1 ./p4.7

(1) SIGUSR1 would normally cause the process to exitbut it has been blocked.

(2) SIGUSR2 has been mapped to the signal-catching routine. In this routine, SIGUSR1 is unblocked; consequently, the process exits without executing the second cout statement in the signal catcher .

The sigsuspend system call is used to pause (suspend) a process. It replaces the current signal mask with the one passed as an argument. The process suspends until a signal is delivered whose action is to execute a signal-catching function or terminate the process. Program 4.8 demonstrates the use of the sigsuspend system call.

Program 4.8 Using sigsuspend .

File : p4.8.cxx
 /* Pausing with sigsuspend */
 #define_GNU_SOURCE
 #include 
 #include 
 + #include 
 #include 
 using namespace std;
 int
 main(){
 10 void signal_catcher(int);
 struct sigaction new_action;
 sigset_t no_sigs, blocked_sigs, all_sigs;
 
 sigfillset (&all_sigs); // turn all bits on
 + sigemptyset(&no_sigs); // turn all bits off
 sigemptyset(&blocked_sigs);
 // Associate with catcher
 new_action.sa_handler = signal_catcher;
 new_action.sa_mask = all_sigs;
 20 new_action.sa_flags = 0;
 if (sigaction(SIGUSR1, &new_action, NULL) == -1) {
 perror("SIGUSR1");
 return 1;
 }
 + sigaddset(&blocked_sigs, SIGUSR1);
 sigprocmask(SIG_SETMASK, &blocked_sigs, NULL);
 while (1) {
 cout << "Waiting for SIGUSR1 signal" << endl;
 sigsuspend(&no_sigs); // Wait
 30 }
 cout << "Done." << endl;
 return 0;
 }
 void
 + signal_catcher(int n){
 cout << "Beginning important stuff" << endl;
 sleep(10); // Simulate work ....
 cout << "Ending important stuff" << endl;
 }

In main , the signal-catching function is established. Lines 14 to 16 create three signal masks. The sigfillset call turns all bits on, while the sigemptyset turns all bits off. The filled set (all bits on, denoting all signals) becomes the signal mask for the signal-catching routine. Thus specified, this directs the signal-catching routine to block all signals. In line 21 the receipt of signal SIGUSR1 is associated with the signal-catching function signal_catcher . In lines 25 and 26 the process is directed to block any SIGUSR1 signals. While at first glance this might seem superfluous, as receipt of this signal has been mapped to signal_catcher , it allows duplicate SIGUSR1 signals to be pending rather than discarded. Then, in an endless loop, the program pauses when the sigsuspend statement is reached, waiting for the receipt of the SIGUSR1 signal. Once the SIGUSR1 signal is received (caught), the signal-catching function is executed. While in the signal-catching function, all signals that can be blocked are held. A set of messages indicating the beginning and end of an important section of code are displayed. When the signal-catching routine is exited, any blocked signals are released. In summary, the program defers the execution of an interrupt-protected section of code until it receives a SIGUSR1 signal. A run of the program produces the output shown in Figure 4.12.

Figure 4.12 Output of Program 4.8.

linux$ p4.8 &
Waiting for SIGUSR1 signal
[1] 6277
linux$ kill -USR1 %1
Beginning important stuff
linux$ kill -INT %1
linux$ jobs
[1] + Running p4.8
linux$ Ending important stuff
[1] Interrupt p4.8

The process was first sent a SIGUSR1 signal that caused it to begin the program function signal_catcher . While it was in the signal_catcher function, an interrupt signal was sent to the process. This signal did not cause the process to immediately terminate, as the process had indicated that all signals were to be blocked (held). The jobs command confirms that the process is still active after the interrupt command was sent. However, once the blocked signals are released (when the signal-catching routine is exited), the pending SIGINT signal is acted upon and the process terminates.

EXERCISE

Examine Figure 4.12 carefully . Run program p4 . 8 and place it in the background. Experiment with issuing multiple kill -USR1 %1 commands before you issue the kill -INT %1 command (note, you may need to increase the sleep time from 10 to something more if you type slowly and want to issue the signals when the process is in the signal-catching routine). Does the system process all the blocked SIGUSR1 signals before it responds to the SIGINT signal. Why or why not?

EXERCISE

Write a program that generates a parent and child process that solves the producer/consumer problem presented in Exercise 4-3. Make the parent process the producer and the child process the consumer. In place of a lock file, use signals to coordinate the activities of the processes. One approach would be to use SIGUSR1 to indicate the resource is available to be accessed and use signal SIGUSR2 to indicate a new value is available. Do signals provide a reliable way of solving the problem? What problems are inherent in their use?

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
Similar book on Amazon

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