2. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
Signals are software interrupts.
Signals provide a way of handling asynchronous events: a user at a terminal
typing the interrupt key to stop a program or the next program in a pipeline
terminating prematurely.
When a signal is sent to a process, it is pending on the process to handle it.
The process can react to pending signals in one of three ways:
1. Accept the default action of the signal, which for most signals will terminate the
process.
2. Ignore the signal. The signal will be discarded and it has no affect whatsoever on the
recipient process.
3. Invoke a user-defined function. The function is known as a signal handler routine
and the signal is said to be caught when this function is called.
2PROF. SYED MUSTAFA, HKBKCE
3. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
3PROF. SYED MUSTAFA, HKBKCE
Name Description Default action
SIGABRT abnormal termination (abort) terminate+core
SIGALRM timer expired (alarm) terminate
SIGCHLD change in status of child ignore
SIGCONT continue stopped process continue/ignore
SIGFPE arithmetic exception terminate+core
SIGINT terminal interrupt character terminate
SIGIO asynchronous I/O terminate/ignore
SIGKILL termination terminate
SIGPIPE write to pipe with no readers terminate
SIGQUIT terminal quit character terminate+core
SIGSEGV invalid memory reference terminate+core
SIGSTOP stop stop process
4. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
4PROF. SYED MUSTAFA, HKBKCE
Name Description Default action
SIGTTOU background write to control tty stop process
SIGUSR1 user-defined signal Terminate
SIGUSR2 user-defined signal Terminate
SIGTERM termination Terminate
SIGTSTP terminal stop character stop process
SIGTTIN background read from control tty stop process
5. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
5PROF. SYED MUSTAFA, HKBKCE
THE UNIX KERNEL SUPPORT OF SIGNALS
When a signal is generated for a process, the kernel will set the corresponding
signal flag in the process table slot of the recipient process.
If the recipient process is asleep, the kernel will awaken the process by scheduling it.
When the recipient process runs, the kernel will check the process U-area that
contains an array of signal handling specifications.
If array entry contains a zero value, the process will accept the default action of the
signal.
If array entry contains a 1 value, the process will ignore the signal and kernel will
discard it.
If array entry contains any other value, it is used as the function pointer for a user-
defined signal handler routine.
6. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
6PROF. SYED MUSTAFA, HKBKCE
The function prototype of the signal API is:
#include <signal.h>
void (*signal(int sig_no, void (*handler)(int)))(int);
Returns: previous disposition of signal (see following) if OK, SIG_ERR on error
The formal argument of the API are:
sig_no is a signal identifier like SIGINT or SIGTERM.
The handler argument is the function pointer of a user-defined signal handler function.
7. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
7PROF. SYED MUSTAFA, HKBKCE
The function prototype of the signal API is:
#include <signal.h>
void (*signal(int sig_no, void (*handler)(int)))(int);
The sig_no argument is just the name of the signal.
The value of handler is
(a) the constant SIG_IGN,
(b) the constant SIG_DFL, or
(c) the address of a function to be called when the signal occurs.
8. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
8PROF. SYED MUSTAFA, HKBKCE
The function prototype of the signal API is:
#include <signal.h>
void (*signal(int sig_no, void (*handler)(int)))(int);
If we specify SIG_IGN, we are telling the system to ignore the signal.
(Remember that we cannot ignore the two signals SIGKILL and SIGSTOP)
When we specify SIG_DFL, we are setting the action associated with the signal to its
default value.
When we specify the address of a function to be called when the signal occurs, we are
arranging to "catch" the signal. We call the function either the signal handler or the
signal-catching function.
9. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
9PROF. SYED MUSTAFA, HKBKCE
The function prototype of the signal API is:
#include <signal.h>
void (*signal(int sig_no, void (*handler)(int)))(int);
The prototype for the signal function states that the function requires two arguments
and returns a pointer to a function that returns nothing (void).
The signal function's first argument, sig_no, is an integer.
The second argument is a pointer to a function that takes a single integer argument and
returns nothing.
The function whose address is returned as the value of signal takes a single integer
argument (the final (int)).
10. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
10PROF. SYED MUSTAFA, HKBKCE
The function prototype of the signal API is:
#include <signal.h>
void (*signal(int sig_no, void (*handler)(int)))(int);
If we examine the system's header <signal.h>, we probably find declarations of the form
#define SIG_ERR (void (*)())-1
#define SIG_DFL (void (*)())0
#define SIG_IGN (void (*)())1
These constants can be used in place of the "pointer to a function that takes an integer
argument and returns nothing," the second argument to signal, and the return value
from signal.
The three values used for these constants need not be -1, 0, and 1.
They must be three values that can never be the address of any declarable function.
11. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
11PROF. SYED MUSTAFA, HKBKCE
The following example attempts to catch the SIGTERM signal, ignores the SIGINT signal,
and accepts the default action of the SIGSEGV signal. The pause API suspends the calling
process until it is interrupted by a signal and the corresponding signal handler does a
return:
#include<iostream.h>
#include<signal.h>
/*signal handler function*/
void catch_sig(int sig_num)
{
signal (sig_num,catch_sig);
cout<<”catch_sig:”<<sig_num<<endl;
}
int main() /*main function*/
{
signal(SIGTERM,catch_sig);
signal(SIGINT,SIG_IGN);
signal(SIGSEGV,SIG_DFL);
pause( );/*wait for a signal interruption*/
}
The SIG_IGN specifies a signal is to be ignored, which means that if the signal is generated to the process,
it will be discarded without any interruption of the process.
12. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
12PROF. SYED MUSTAFA, HKBKCE
#include<stdio.h>
#include<signal.h>
/*signal handler function*/
static void sig_usr(int signo)
/* arg is signal number */
{
if (signo == SIGUSR1)
printf("received SIGUSR1n");
else if (signo == SIGUSR2)
printf("received SIGUSR2n");
else
printf("received signal %dn", signo);
}
int main(void)
{
if (signal(SIGUSR1, sig_usr) == SIG_ERR)
perror("can't catch SIGUSR1");
if (signal(SIGUSR2, sig_usr) == SIG_ERR)
perror("can't catch SIGUSR2");
for ( ; ; )
pause();
}
13. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
13PROF. SYED MUSTAFA, HKBKCE
$ ./a.out & start process in background
[1] 7216 job-control shell prints job number and process ID
$ kill -USR1 7216 send it SIGUSR1
received SIGUSR1
$ kill -USR2 7216 send it SIGUSR2
received SIGUSR2
$ kill 7216 now send it SIGTERM
[1]+ Terminated ./a.out
When we send the SIGTERM signal, the process is terminated, since it doesn't catch the
signal, and the default action for the signal is termination.
14. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
14PROF. SYED MUSTAFA, HKBKCE
kill and raise Functions
The kill function sends a signal to a process or a group of processes.
The raise function allows a process to send a signal to itself.
#include <signal.h>
int kill(pid_t pid, int signo);
int raise(int signo);
Both return: 0 if OK, –1 on error
The call
raise(signo);
is equivalent to the call
kill(getpid(), signo);
15. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
15PROF. SYED MUSTAFA, HKBKCE
kill and raise Functions
#include <signal.h>
int kill(pid_t pid, int signo);
There are four different conditions for the pid argument to kill.
Pid value Meaning
Pid > 0 The signal is sent to the process whose process ID is pid.
Pid==0 The signal is sent to all processes whose process group ID equals the process
group ID of the sender and for which the sender has permission to send the
signal.
Pid<0 The signal is sent to all processes whose process group ID equals the absolute
value of pid and for which the sender has permission to send the signal.
Pid==-1 The signal is sent to all processes on the system for which the sender has
permission to send the signal.
16. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
16PROF. SYED MUSTAFA, HKBKCE
#include<iostream.h>
#include<signal.h>
/*signal handler function*/
void catch_sig(int sig_num)
{
cout<<”catch_sig:”<<sig_num<<endl;
}
int main() /*main function*/
{
signal (SIGINT,catch_sig);
cout<<“from mainn”;
kill(getpid, SIGINT);
}
#include<iostream.h>
#include<signal.h>
/*signal handler function*/
void catch_sig(int sig_num)
{
cout<<”catch_sig:”<<sig_num<<endl;
}
int main() /*main function*/
{
signal (SIGQUIT,catch_sig);
cout<<“from mainn”;
raise(SIGQUIT);
}
17. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
17PROF. SYED MUSTAFA, HKBKCE
alarm and pause Functions
The alarm function allows us to set a timer that will expire at a specified time in the
future.
When the timer expires, the SIGALRM signal is generated.
If we ignore or don't catch this signal, its default action is to terminate
the process.
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
Returns: 0 or number of seconds until previously set alarm.
The seconds value is the number of clock seconds in the future when the signal should
be generated.
18. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
18PROF. SYED MUSTAFA, HKBKCE
alarm and pause Functions
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
If, when we call alarm, a previously registered alarm clock for the process has not yet
expired, the number of seconds left for that alarm clock is returned as the value of
this function.
That previously registered alarm clock is replaced by the new value.
If a previously registered alarm clock for the process has not yet expired and if the
seconds value is 0, the previous alarm clock is canceled.
The number of seconds left for that previous alarm clock is still returned as the value
of the function.
Although the default action for SIGALRM is to terminate the process, most processes
that use an alarm clock catch this signal.
19. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
19PROF. SYED MUSTAFA, HKBKCE
alarm and pause Functions
The pause function suspends the calling process until a signal is caught.
#include <unistd.h>
int pause(void);
Returns: –1 with errno set to EINTR
The only time pause returns is if a signal handler is executed and that handler returns.
In that case, pause returns –1 with errno set to EINTR.
20. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
20PROF. SYED MUSTAFA, HKBKCE
alarm and pause Functions
Using alarm and pause, we can put a process to sleep for a specified amount of time.
The sleep() can be implemented using alarm() and pause().
#include <signal.h>
#include <unistd.h>
static void sig_alrm(int signo)
{
/* nothing to do, just return to
wake up the pause */
}
unsigned int sleep(unsigned int nsecs)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return(nsecs);
alarm(nsecs); /* start the timer */
pause(); /* next caught signal wakes us up */
return(alarm(0));
/* turn off timer, return unslept time */
}
21. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
21PROF. SYED MUSTAFA, HKBKCE
SIGNAL SETS
We need a data type to represent multiple signals—a signal set
POSIX.1 defines the data type sigset_t to contain a signal set and the following five
functions to manipulate signal sets.
#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
Returns: 0 if OK, -1 on error.
22. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
22PROF. SYED MUSTAFA, HKBKCE
SIGNAL SETS
int sigismember(const sigset_t *set, int signo);
Returns: 1 if true, 0 if false, –1 on error
The function sigemptyset() initializes the signal set pointed to by set so that all signals
are excluded
The function sigfillset() initializes the signal set so that all signals are included.
All applications have to call either sigemptyset() or sigfillset() once for each signal set,
before using the signal set.
Once we have initialized a signal set, we can add and delete specific signals in the set.
The function sigaddset() adds a single signal to an existing set, and sigdelset()
removes a single signal from a set.
23. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
23PROF. SYED MUSTAFA, HKBKCE
SIGNAL MASK
A process initially inherits the parent’s signal mask when it is created, but any pending
signals for the parent process are not passed on.
A process may query or set its signal mask via the sigprocmask API:
#include <signal.h>
int sigprocmask(int cmd, const sigset_t *new_mask, sigset_t *old_mask);
Returns: 0 if OK, -1 on error
.
24. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
24PROF. SYED MUSTAFA, HKBKCE
SIGNAL MASK
The new_mask argument defines a set of signals to be set or reset in a calling process
signal mask, and the cmd argument specifies how the new_mask value is to be used by
the API.
The possible values of cmd and the corresponding use of the new_mask value are:
.
Cmd value Meaning
SIG_SETMASK
Overrides the calling process signal mask with the value specified in the new_mask
argument.
SIG_BLOCK
Adds the signals specified in the new_mask argument to the calling process signal
mask.
SIG_UNBLOCK
Removes the signals specified in the new_mask argument from the calling process
signal mask.
25. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
25PROF. SYED MUSTAFA, HKBKCE
SIGNAL MASK
The following example checks whether the SIGINT signal is present in a process signal mask
and adds it to the mask if it is not there. Then clears the SIGSEGV signal from the process
signal mask.
#include <stdio.h>
#include <signal.h>
int main()
{
sigset_t mask;
sigemptyset(&mask);
/*initialize set*/
if (sigprocmask(0, 0, &mask) == -1)
{ /*get current signal mask*/
perror(“sigprocmask”);
exit(1);
}
else
sigaddset(&mask, SIGINT); /*set SIGINT flag*/
sigdelset(&mask, SIGSEGV);
/*clear SIGSEGV flag*/
if (sigprocmask(SIG_SETMASK, &mask, 0) == -1)
perror(“sigprocmask”);
/*set a new signal mask*/
} .
26. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
26PROF. SYED MUSTAFA, HKBKCE
SIGNAL MASK
The program prints the names of the signals in the signal mask of the calling process
#include <stdio.h>
#include <signal.h>
int main()
{
sigset_t sigset;
sigemptyset(&sigset);
/*initialize set*/
if (sigprocmask(0, NULL, &sigset) < 0)
perror("sigprocmask error");
if (sigismember(&sigset, SIGINT))
printf("SIGINT ");
if (sigismember(&sigset, SIGQUIT))
printf("SIGQUIT ");
if (sigismember(&sigset, SIGUSR1))
printf("SIGUSR1 ");
if (sigismember(&sigset, SIGALRM))
printf("SIGALRM ");
}
27. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
27PROF. SYED MUSTAFA, HKBKCE
SIGPENDING FUNCTION
The sigpending function returns the set of signals that are blocked from delivery and
currently pending for the calling process.
The set of signals is returned through the set argument
#include <signal.h>
int sigpending(sigset_t *set);
Returns: 0 if OK, –1 on error.
28. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
The process blocks SIGQUIT, saving its current signal mask (to reset later),
and then goes to sleep for 5 seconds.
Any occurrence of the quit signal during this period is blocked and won't be
delivered until the signal is unblocked.
At the end of the 5-second sleep, we check whether the signal is pending
and unblock the signal.
28PROF. SYED MUSTAFA, HKBKCE
SIGPENDING FUNCTION
29. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS - SIGPENDING FUNCTION
29PROF. SYED MUSTAFA, HKBKCE
#include <signal.h>
#include <unistd.h>
static void sig_quit(int signo)
{
printf("caught SIGQUITn");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
perror("can't reset SIGQUIT");
}
int main(void)
{
sigset_t newmask, oldmask, pendmask;
if (signal(SIGQUIT, sig_quit) == SIG_ERR)
perror("can't catch SIGQUIT");
/* Block SIGQUIT and save current signal mask*/
sigemptyset(&newmask);
sigaddset(&newmask, SIGQUIT);
if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
perror("SIG_BLOCK error");
sleep(5);
/* SIGQUIT here will remain pending */
if (sigpending(&pendmask) < 0)
perror("sigpending error");
if (sigismember(&pendmask, SIGQUIT))
printf("nSIGQUIT pendingn");
/* Reset signal mask which unblocks SIGQUIT*/
if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
perror("SIG_SETMASK error");
printf("SIGQUIT unblockedn");
sleep(5);
/* SIGQUIT here will terminate with core file */
exit(0);
}
30. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
The sigaction() function allows us to examine or modify (or both) the action
associated with a particular signal.
This function supersedes the signal() function from earlier releases of the
UNIX System.
#include <signal.h>
int sigaction(int signo, const struct sigaction *restrict act,
struct sigaction *restrict oact);
Returns: 0 if OK, –1 on error
30PROF. SYED MUSTAFA, HKBKCE
Sigaction() Function
31. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
sigaction() Function
The sigaction API is a replacement for the signal API in the latest UNIX and
POSIX systems.
The sigaction API is called by a process to set up a signal handling method
for each signal it wants to deal with.
sigaction API returns the previous signal handling method for a given signal.
31PROF. SYED MUSTAFA, HKBKCE
32. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
sigaction() Function
The struct sigaction data type is defined in the <signal.h> header as
struct sigaction
{
void (*sa_handler)(int); /* addr of signal handler, or SIG_IGN, or SIG_DFL */
sigset_t sa_mask; /* additional signals to block */
int sa_flags; /* signal options */
void (*sa_sigaction)(int, siginfo_t *, void *); /* alternate handler */
};
32PROF. SYED MUSTAFA, HKBKCE
33. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
sigaction() Function
The sa_handler field can be set to SIG_IGN, SIG_DFL, or a user defined
signal handler function.
The sa_mask field specifies additional signals that process wishes to block
when it is handling signo signal.
The signalno argument designates which signal handling action is defined in
the action argument.
The previous signal handling method for signalno will be returned via the
oldaction argument if it is not a NULL pointer.
If action argument is a NULL pointer, the calling process‘s existing signal
handling method for signalno will be unchanged.
33PROF. SYED MUSTAFA, HKBKCE
34. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS - sigaction FUNCTION
34PROF. SYED MUSTAFA, HKBKCE
#include <signal.h>
#include <iostream.h>
void callme ( int sig_num )
{
cout <<“catch signal:”<<sig_num<< endl;
}
int main(void)
{
sigset_t sigmask;
struct sigaction action, old_action;
sigemptyset(&sigmask);
if ( sigaddset( &sigmask, SIGTERM) == -1 ||
sigprocmask( SIG_SETMASK, &sigmask, 0) == -1)
perror(“Set signal mask”);
sigemptyset( &action.sa_mask);
sigaddset( &action.sa_mask, SIGSEGV);
action.sa_handler = callme;
action.sa_flags = 0;
if (sigaction (SIGINT, &action, &old_action) == -1)
perror(“sigaction”);
pause(); /* wait for signal interruption*/
return 0;
}
35. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS - sigaction FUNCTION
In the program, the process signal mask is set with SIGTERM signal.
The process then defines a signal handler for the SIGINT signal and also
specifies that the SIGSEGV signal is to be blocked when the process is
handling the SIGINT signal.
The process then terminates its execution via the pause API.
The output of the program would be as:
% cc sigaction.c –o sigaction
% ./sigaction &
[1] 495
% kill –INT 495
catch signal: 2
sigaction exits
[1] Done sigaction
35PROF. SYED MUSTAFA, HKBKCE
36. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
THE SIGCHLD SIGNAL AND THE waitpid API
When a child process terminates or stops, the kernel will generate a SIGCHLD signal to its
parent process. Depending on how the parent sets up the handling of the SIGCHLD signal,
different events may occur:
1. Parent accepts the default action of the SIGCHLD signal:
SIGCHLD does not terminate the parent process.
Parent process will be awakened.
API will return the child’s exit status and process ID to the parent.
Kernel will clear up the Process Table slot allocated for the child process.
Parent process can call the waitpid API repeatedly to wait for each child it created.
36PROF. SYED MUSTAFA, HKBKCE
37. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
THE SIGCHLD SIGNAL AND THE waitpid API
2. Parent ignores the SIGCHLD signal:
SIGCHLD signal will be discarded.
Parent will not be disturbed even if it is executing the waitpid system call.
If the parent calls the waitpid API, the API will suspend the parent until all its child
processes have terminated.
Child process table slots will be cleared up by the kernel.
API will return a -1 value to the parent process.
3. Process catches the SIGCHLD signal:
The signal handler function will be called in the parent process whenever a child process
terminates.
If the SIGCHLD arrives while the parent process is executing the waitpid system call, the
waitpid API may be restarted to collect the child exit status and clear its process table
slots.
Depending on parent setup, the API may be aborted and child process table slot not
freed.
37PROF. SYED MUSTAFA, HKBKCE
38. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
abort() Function
abort function causes abnormal program termination
#include <stdlib.h>
void abort(void);
This function never returns.
This function sends the SIGABRT signal to the caller.
Processes should not ignore this signal.
ISO C states that calling abort will deliver an unsuccessful termination notification to the
host environment by calling raise(SIGABRT).
38PROF. SYED MUSTAFA, HKBKCE
39. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
system() Function
#include <stdlib.h>
int system(const char *command);
This function returns is -1 on error.
If the value of command is NULL, system() returns nonzero if the shell is available, and zero
if not.
system() executes a command specified in command by calling /bin/sh -c command, and
returns after the command has been completed. During execution of the
command, SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored
Eg: system(“ls –l”);
39PROF. SYED MUSTAFA, HKBKCE
40. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
sleep() Function
sleep - sleep for the specified number of seconds
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
Returns: 0 or number of unslept seconds.
This function causes the calling process to be suspended until either
1. The amount of wall clock time specified by seconds has elapsed.
2. A signal is caught by the process and the signal handler returns.
Eg:
sleep(60); // suspend the process for one minute.
40PROF. SYED MUSTAFA, HKBKCE
41. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
Job-Control Signals
POSIX.1 considers six signals as job-control signals:
41PROF. SYED MUSTAFA, HKBKCE
Signal Meaning
SIGCHLD Child process has stopped or terminated.
SIGCONT Continue process, if stopped.
SIGSTOP Stop signal (can't be caught or ignored).
SIGTSTP Interactive stop signal.
SIGTTIN Read from controlling terminal by member of a background process
group
SIGTTOU Write to controlling terminal by member of a background process group
42. UNIT 6 SIGNALS AND DAEMON PROCESSES
SIGNALS
Job-Control Signals
When we type the suspend character (usually Control-Z), SIGTSTP is sent to all processes
in the foreground process group.
When we tell the shell to resume a job in the foreground or background, the shell sends
all the processes in the job the SIGCONT signal.
Similarly, if SIGTTIN or SIGTTOU is delivered to a process, the process is stopped by
default, and the job-control shell recognizes this and notifies us.
When any of the four stop signals (SIGTSTP, SIGSTOP, SIGTTIN, or SIGTTOU) is generated
for a process, any pending SIGCONT signal for that process is discarded.
Similarly, when the SIGCONT signal is generated for a process, any pending stop signals
for that same process are discarded.
The default action for SIGCONT is to continue the process, if it is stopped; otherwise, the
signal is ignored.
42PROF. SYED MUSTAFA, HKBKCE
43. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Daemons are processes that live for a long time.
They are often started when the system is bootstrapped and terminate only when the
system is shut down.
Because they don't have a controlling terminal, we say that they run in the background.
UNIX systems have numerous daemons that perform day-to-day activities.
43PROF. SYED MUSTAFA, HKBKCE
44. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Deamon Characteristics
$ps -axj
44PROF. SYED MUSTAFA, HKBKCE
45. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Deamon Characteristics
Daemons run in background.
Daemons have super-user privilege.
Daemons don’t have controlling terminal.
Daemons are session and group leaders.
45PROF. SYED MUSTAFA, HKBKCE
46. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Deamon Characteristics
Anything with a parent process ID of 0 is usually a kernel process started as part of the
system bootstrap procedure.
Kernel processes are special and generally exist for the entire lifetime of the system.
They run with superuser privileges and have no controlling terminal and no command
line.
Process ID of 1 is usually init.
It is a system daemon responsible for, among other things, starting system services
specific to various run levels.
46PROF. SYED MUSTAFA, HKBKCE
47. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Deamon Characteristics
keventd daemon provides process context for running scheduled functions in the kernel.
The kapmd daemon provides support for the advanced power management features
available with various computer systems.
The kswapd daemon is also known as the pageout daemon.
It supports the virtual memory subsystem by writing dirty pages to disk slowly over time,
so the pages can be reclaimed.
The inetd daemon (xinetd) listens on the system's network interfaces for incoming
requests for various network servers.
The nfsd, lockd, and rpciod daemons provide support for the
Network File System (NFS).
The cron daemon (crond) executes commands at specified dates and times. Numerous
system administration tasks are handled by having programs executed regularly by cron.
The cupsd daemon is a print spooler; it handles print requests on the system.
47PROF. SYED MUSTAFA, HKBKCE
48. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
CODING RULES
1. Call umask to set the file mode creation mask to 0. The file mode creation
mask that's inherited could be set to deny certain permissions. If the
daemon process is going to create files, it may want to set specific
permissions.
2. Call fork and have the parent exit. This does several things. First, if the
daemon was started as a simple shell command, having the parent
terminate makes the shell think that the command is done. Second, the
child inherits the process group ID of the parent but gets a new process ID,
so we're guaranteed that the child is not a process group leader.
48PROF. SYED MUSTAFA, HKBKCE
49. UNIT 6 SIGNALS AND DAEMON PROCESSESDAEMON PROCESSES
CODING RULES
3. Call setsid to create a new session. The process (a) becomes a session
leader of a new session, (b) becomes the process group leader of a new
process group, and (c) has no controlling terminal.
4. Change the current working directory to the root directory. The current
working directory inherited from the parent could be on a mounted file
system. Since daemons normally exist until the system is rebooted, if the
daemon stays on a mounted file system, that file system cannot be
unmounted.
5. Unneeded file descriptors should be closed. This prevents the daemon
from holding open any descriptors that it may have inherited from its
parent.
49PROF. SYED MUSTAFA, HKBKCE
50. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
CODING RULES
6. Some daemons open file descriptors 0, 1, and 2 to /dev/null so that any
library routines that try to read from standard input or write to standard
output or standard error will have no effect. Since the daemon is not
associated with a terminal device, there is nowhere for output to be
displayed; nor is there anywhere to receive input from an interactive user.
Even if the daemon was started from an interactive session, the daemon
runs in the background, and the login session can terminate without
affecting the daemon. If other users log in on the same terminal device, we
wouldn't want output from the daemon showing up on the terminal, and
the users wouldn't expect their input to be read by the daemon.
50PROF. SYED MUSTAFA, HKBKCE
52. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Error Logging
One problem a daemon has is how to handle error messages.
It can't simply write to standard error, since it shouldn't have a controlling
terminal.
We don't want all the daemons writing to the console device, since on
many workstations, the console device runs a windowing system.
We also don't want each daemon writing its own error messages into a
separate file.
A central daemon errorlogging facility is required.
52PROF. SYED MUSTAFA, HKBKCE
53. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Error Logging
53PROF. SYED MUSTAFA, HKBKCE
54. UNIT 6 SIGNALS AND DAEMON PROCESSES
DAEMON PROCESSES
Error Logging
There are three ways to generate log messages:
1. Kernel routines can call the log function.
These messages can be read by any user process that opens and reads the
/dev/klog device.
2. Most user processes (daemons) call the syslog(3) function to generate log
messages. This causes the message to be sent to the UNIX domain datagram
socket /dev/log.
3. A user process on this host, or on some other host that is connected to this
host by a TCP/IP network, can send log messages to UDP port 514.
The syslogd daemon reads all three forms of log messages.
On start-up, this daemon reads a configuration file, usually /etc/syslog.conf,
which determines where different classes of messages are to be sent.
54PROF. SYED MUSTAFA, HKBKCE
55. UNIT 7 INTERPROCESSES COMMUNICATION
INTORDUCTION
55PROF. SYED MUSTAFA, HKBKCE
IPC ( InterProcess Communication)
It is a mechanism whereby two or more processes communicate with
each other to perform tasks.
These processes may interact in a client/server manner or in a peer-to-
peer fashion.
IPC enables one application to control another application, and for
several applications to share the same data without interfering with one
another.
IPC is required in all multiprocessing systems, but it is not generally
supported by single-process operating systems.
56. UNIT 7 INTERPROCESSES COMMUNICATION
INTORDUCTION
56PROF. SYED MUSTAFA, HKBKCE
IPC ( InterProcess Communication)
The various forms of IPC that are supported on a UNIX system are as
follows :
The first seven forms of IPC are usually restricted to IPC between processes
on the same host.
The final two i.e. Sockets and STREAMS are the only two that are generally
supported for IPC between processes on different hosts.
1. Half duplex Pipes 2. Full duplex Pipes
3. FIFO’s 4. Named full duplex Pipes
5. Message queues 6. Shared memory
7. Semaphores 8. Sockets 9. STREAMS
57. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
Pipes are the oldest form of UNIX System IPC.
Pipes have two limitations.
1. Historically, they have been half duplex
(i.e.data flows in only one direction)
2. Pipes can be used only between processes that have a common
ancestor.
Normally, a pipe is created by a process, that process calls fork,
and the pipe is used between the parent and the child.
57PROF. SYED MUSTAFA, HKBKCE
58. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
A pipe is created by calling the pipe function.
#include <unistd.h>
int pipe(int fd[2]);
Returns: 0 if OK, –1 on error
Despite these limitations, half-duplex pipes are still the most commonly
used form of IPC.
Every time we type a sequence of commands in a pipeline for the shell to
execute, the shell creates a separate process for each command and links
the standard output of one to the standard input of the next using a pipe.
58PROF. SYED MUSTAFA, HKBKCE
59. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
Two file descriptors are returned through the fd argument:
fd[0] is open for reading, and
fd[1] is open for writing.
The output of fd[1] is the input for fd[0].
POSIX.1 allows for an implementation to support full-duplex pipes.
For these implementations,
fd[0] and fd[1] are open for both reading and writing.
59PROF. SYED MUSTAFA, HKBKCE
60. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
Two ways to picture a half-duplex pipe are shown in the given diagrams below:
60PROF. SYED MUSTAFA, HKBKCE
61. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
The left half of the diagram shows the two ends of the pipe connected in a
single process.
The right half of the diagram emphasizes that the data in the pipe flows
through the kernel.
A pipe in a single process is next to useless.
Normally, the process that calls pipe then calls fork, creating an IPC channel
from the parent to the child or vice versa.
61PROF. SYED MUSTAFA, HKBKCE
63. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
63PROF. SYED MUSTAFA, HKBKCE
For a pipe from the parent to the child, the parent closes the read end of
the pipe (fd[0]), and the child closes the write end (fd[1]).
64. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
64PROF. SYED MUSTAFA, HKBKCE
For a pipe from the parent to the child, the parent closes the read end of
the pipe (fd[0]), and the child closes the write end (fd[1]).
For a pipe from the child to the parent, the parent closes fd[1], and the
child closes fd[0].
65. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
65PROF. SYED MUSTAFA, HKBKCE
For a pipe from the child to the parent, the parent closes fd[1], and the
child closes fd[0].
66. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
66PROF. SYED MUSTAFA, HKBKCE
When one end of a pipe is closed, the following two rules apply.
1. If we read from a pipe whose write end has been closed, read returns
0 to indicate an end of file after all the data has been read
2. If we write to a pipe whose read end has been closed, the signal
SIGPIPE is generated. If we either ignore the signal or catch it and
return from the signal handler, write returns –1 with errno set to
EPIPE.
67. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
67PROF. SYED MUSTAFA, HKBKCE
Program to show the code to create a pipe between a parent and its child
and to send data down the pipe.
int main(void)
{
int n, fd[2];
pid_t pid;
char line[1000];
if (pipe(fd) < 0)
perror("pipe error");
if ((pid = fork()) < 0)
perror("fork error");
else if (pid > 0)
{ /* parent */
close(fd[0]);
write(fd[1], "hello worldn", 12);
}
else
{ /* child */
close(fd[1]);
n = read(fd[0], line,1000);
write(1, line, n);
}
exit(0);
}
68. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
68PROF. SYED MUSTAFA, HKBKCE
Program to show the code for I/O redirection using dup2().
#include<fcntl.h>
main()
{
int fd,fd2;
char c[256],con[]="This is simple file
for demonstration";
fd=open("sample1",O_RDWR|O_CR
EAT,0777);
printf("original file desc is %dn",fd);
fd2=dup2(fd,7);
printf("new file desc is %dn", fd2);
if(fd==-1)
perror("Can't creat file");
else if(read(fd2,&c,10)==0)
write(fd2,con,sizeof(con));
else
printf("%sn",c);
close(fd);
}
69. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
69PROF. SYED MUSTAFA, HKBKCE
Program to show the code for I/O redirection using dup().
#include<fcntl.h>
main()
{
int fd,fd2;
char c[256],con[]="This is simple file
for demonstration";
fd=open("sample1",O_RDWR|O_CR
EAT,0777);
printf("original file desc is %dn",fd);
fd2=dup(fd);
printf("new file desc is %dn", fd2);
if(fd==-1)
perror("Can't creat file");
else if(read(fd2,&c,10)==0)
write(fd2,con,sizeof(con));
else
printf("%sn",c);
close(fd);
}
70. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
70PROF. SYED MUSTAFA, HKBKCE
Program to show the code child writes to the parent through pipe.
#include<unistd.h>
#include<sys/types.h>
main()
{
pid_t pid;
int fd[2],s;
char c[5];
pipe(fd);
pid=fork();
if (pid==0)
{
close(fd[0]);
write(fd[1],"hello",5);
}
else
{
wait(&s);
close(fd[1]);
read(fd[0],c,5);
c[5]='0';
printf("%sn",c);
}
}
71. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
71PROF. SYED MUSTAFA, HKBKCE
Program to show the code for broken pipe.
#include<unistd.h>
#include<sys/types.h>
main()
{
pid_t pid;
int fd[2];
char c[5];
pipe(fd);
pid=fork();
if (pid>0)
{
close(fd[0]);
write(fd[1],"hello",5);
}
else
{
close(fd[0]); /*read end closed*/
sleep(1);
read(fd[0],c,5);
printf("%sn",c);
exit(0);
}
}
72. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
72PROF. SYED MUSTAFA, HKBKCE
Program to show the code for UNIX command redirection for “ls|wc -l”.
#include<fcntl.h>
main()
{
int p[2],pid;
pipe(p);
pid=fork();
if(pid==0)
{
close(p[0]);
printf("p[1]=%dn",p[1]);
dup2(p[1],1);
execl("/bin/ls","ls",(char *)0);
perror("from ls:");
}
else
{
close(p[1]);
printf("p[0]=%dn",p[0]);
dup2(p[0],0);
execl("/usr/bin/wc","wc","-l",(char *)0);
perror("from wc");
}
}
73. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
73PROF. SYED MUSTAFA, HKBKCE
Program to implement unix command “who|sort|wc –l”
main()
{
int p[2], q[2], pid, pid1;
pipe(p);
pid = fork();
if(0 == pid)
{
close(1);
close(p[0]);
dup(p[1]);
execlp("who", "who",0);
perror("error at cat");
}
else
{
pipe(q);
pid1 = fork();
if(0 == pid1)
{
close(1);
close(0);
close(p[1]);
close(q[0]);
dup(p[0]);
dup(q[1]);
execlp("sort", "sort", (char*)0);
perror("error at grep");
}
else
{
close(0);
close(q[1]);
close(p[1]);
close(p[0]);
dup(q[0]);
execl("/usr/bin/wc", "wc", "-l", 0);
perror("error at wc");
}
}
} //end of main()
74. UNIT 7 INTERPROCESSES COMMUNICATION
Popen() and pclose() Functions
PROF. SYED MUSTAFA, HKBKCE 74
Since a common operation is to create a pipe to another process, to
either read its output or send it input, the standard I/O library has
historically provided the popen and pclose functions.
These two functions handle all the dirty work that we've been doing
ourselves: creating a pipe, forking a child, closing the unused ends of
the pipe, executing a shell to run the command, and waiting for the
command to terminate.
75. UNIT 7 INTERPROCESSES COMMUNICATION
Popen() and pclose() Functions
75PROF. SYED MUSTAFA, HKBKCE
76. UNIT 7 INTERPROCESSES COMMUNICATION
Popen() and pclose() Functions
PROF. SYED MUSTAFA, HKBKCE 76
The function popen does a fork and exec to execute the cmdstring, and
returns a standard I/O file pointer.
If type is "r", the file pointer is connected to the standard output of
cmdstring
77. UNIT 7 INTERPROCESSES COMMUNICATION
Popen() and pclose() Functions
PROF. SYED MUSTAFA, HKBKCE 77
The pclose function closes the standard I/O stream, waits for the
command to terminate, and returns the termination status of the
shell.
If the shell cannot be executed, the termination status returned by
pclose is as if the shell had executed exit(127).
The cmdstring is executed by the Bourne shell, as in
$ sh -c cmdstring
This means that the shell expands any of its special characters in
cmdstring. Example:
fp = popen("ls *.c", "r"); or fp = popen("cmd 2>&1", "r");
78. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
78PROF. SYED MUSTAFA, HKBKCE
Program to sort the strings using popen().
#define MAXSTRS 4
int main(void)
{
int i;
FILE *pipe_fp;
char *strings[MAXSTRS] =
{ "echo", "bravo", "alpha", "charlie"};
/* Create 1 way pipe line with call to popen() */
pipe_fp = popen("sort", "w");
if (pipe_fp== NULL)
{
perror("popen");
exit(1);
}
/* Processing loop */
for(i=0; i<MAXSTRS; i++)
{
fputs(strings[i], pipe_fp);
fputc('n', pipe_fp);
}
/* Close the pipe */
pclose(pipe_fp);
return(0);
}
79. UNIT 7 INTERPROCESSES COMMUNICATION
PIPES
79PROF. SYED MUSTAFA, HKBKCE
Program to implement UNIX command redirection for “ls|sort” using popen().
int main(void)
{
FILE *pipein_fp, *pipeout_fp;
char readbuf[80];
/* Create one way pipe line with call to popen() */
pipein_fp = popen("ls", "r");
if (pipein_fp== NULL)
{
perror("popen");
exit(1);
}
/* Create one way pipe line with call to popen() */
pipeout_fp = popen("sort", "w“);
if (pipeout_fp == NULL)
{
perror("popen");
exit(1);
}
/* Processing loop */
while(fgets(readbuf, 80, pipein_fp))
fputs(readbuf, pipeout_fp);
/* Close the pipes */
pclose(pipein_fp);
pclose(pipeout_fp);
return(0); }
80. UNIT 7 INTERPROCESSES COMMUNICATION
Coprocesses
PROF. SYED MUSTAFA, HKBKCE 80
A UNIX system filter is a program that reads from standard input and
writes to standard output.
Filters are normally connected linearly in shell pipelines.
A filter becomes a coprocess when the same program generates
the filter's input and reads the filter's output.
The Korn shell provides coprocesses.
The Bourne shell, the Bourne-again shell, and the C shell don't provide a
way to connect processes together as coprocesses.
A coprocess normally runs in the background from a shell, and its
standard input and standard output are connected to another program
using a pipe.
81. UNIT 7 INTERPROCESSES COMMUNICATION
Coprocesses
PROF. SYED MUSTAFA, HKBKCE 81
Whereas popen gives us a one-way pipe to the standard input or from
the standard output of another process.
With a coprocess, we have two one-way pipes to the other process: one
to its standard input and one from its standard output.
The process creates two pipes: one is the standard input of the
coprocess, and the other is the standard output of the coprocess.
The diagram shows this arrangement.
82. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 82
FIFOs are sometimes called named pipes.
Pipes can be used only between related processes when a common
ancestor has created the pipe.
With FIFOs, unrelated processes can exchange data.
Creating a FIFO is similar to creating a file.
Indeed, the pathname for a FIFO exists in the file system.
83. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 83
Once we have used mkfifo to create a FIFO, we open it using open().
When we open a FIFO, the non blocking flag (O_NONBLOCK) affects what
happens:
1. In the normal case (O_NONBLOCK not specified), an open for read-only
blocks until some other process opens the FIFO for writing. Similarly,
an open for write-only blocks until some other process opens the FIFO
for reading
2. If O_NONBLOCK is specified, an open for read-only returns
immediately. But an open for write-only returns 1 with errno set to
ENXIO if no process has the FIFO open for reading.
84. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 84
There are two uses for FIFOs.
1. FIFOs are used by shell commands to pass data from one shell pipeline
to another without creating intermediate temporary files.
2. FIFOs are used as rendezvous points in client–server applications to
pass data between the clients and the servers.
85. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 85
Example Using FIFOs to Duplicate Output Streams:
FIFOs can be used to duplicate an output stream in a series of shell
commands.
This prevents writing the data to an intermediate disk file.
Consider a procedure that needs to process a filtered input stream
twice.
Procedure that processes a filtered input stream twice.
86. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 86
Example Using FIFOs to Duplicate Output Streams:
With a FIFO and the UNIX program tee(1), we can accomplish this procedure
without using a temporary file.
87. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 87
Example Using FIFOs to Duplicate Output Streams:
The tee program copies its standard input to both its standard output and
to the file named on its command line.
mkfifo fifo1 prog3 < fifo1 &
prog1 < infile | tee fifo1 | prog2
We create the FIFO and then start prog3 in the background, reading from
the FIFO.
We then start prog1 and use tee to send its input to both the FIFO and
prog2.
88. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 88
Example Client-Server Communication Using a FIFO
FIFO’s can be used to send data between a client and a server.
If we have a server that is contacted by numerous clients, each client can
write its request to a well-known FIFO that the server creates.
Since there are multiple writers for the FIFO, the requests sent by the
clients to the server need to be less than PIPE_BUF bytes in size.
This prevents any interleaving of the client writes.
The problem in using FIFOs for this type of client server communication is
how to send replies back from the server to each client.
89. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 89
Example Client-Server Communication Using a FIFO
A single FIFO can’t be used, as the clients would never know when to read
their response versus responses for other clients.
One solution is for each client to send its process ID with the request.
The server then creates a unique FIFO for each client, using a pathname
based on the client’s process ID.
For example, the server can create a FIFO with the name /home/
ser.XXXXX, where XXXXX is replaced with the client’s process ID.
This arrangement works, although it is impossible for the server to tell
whether a client crashes.
90. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 90
Example Client-Server Communication Using a FIFO
This causes the client-specific FIFOs to be left in the file system.
The server also must catch SIGPIPE, since it’s possible for a client to send a
request and terminate before reading the response, leaving the client-
specific FIFO with one writer (the server) and no reader.
Clients sending requests to a server using aFIFO
91. UNIT 7 INTERPROCESSES COMMUNICATION
FIFOs
PROF. SYED MUSTAFA, HKBKCE 91
Example Client-Server Communication Using a FIFO
92. UNIT 7 INTERPROCESSES COMMUNICATION
Message Queues
PROF. SYED MUSTAFA, HKBKCE 92
A message queue is a linked list of messages stored within the kernel and
identified by a message queue identifier.
A new queue is created or an existing queue opened by msgget().
New messages are added to the end of a queue by msgsnd().
Every message has a positive long integer type field, a non-negative
length, and the actual data bytes (corresponding to the length), all of
which are specified to msgsnd() when the message is added to a queue.
Messages are fetched from a queue by msgrcv().
We don't have to fetch the messages in a first-in, first-out order.
Instead, we can fetch messages based on their type field.
93. UNIT 7 INTERPROCESSES COMMUNICATION
Message Queues
PROF. SYED MUSTAFA, HKBKCE 93
This structure defines the current status of the queue.
The members shown are the ones defined by the Single UNIX Specification.
94. UNIT 7 INTERPROCESSES COMMUNICATION
Message Queues
PROF. SYED MUSTAFA, HKBKCE 94
The first function normally called is msgget() to either open an existing queue
or create a new queue.
95. UNIT 7 INTERPROCESSES COMMUNICATION
Message Queues
PROF. SYED MUSTAFA, HKBKCE 95
The msgctl function performs various operations on a queue.
96. UNIT 7 INTERPROCESSES COMMUNICATION
Message Queues
PROF. SYED MUSTAFA, HKBKCE 96
Each message is composed of a positive long integer type field, a non-negative length
(nbytes), and the actual data bytes (corresponding to the length).
Messages are always placed at the end of the queue.
The ptr argument points to a long integer that contains the positive integer message
type, and it is immediately followed by the message data.
There is no message data if nbytes is 0. If the largest message we send is 512 bytes, we
can define the following structure:
struct mymesg {
long mtype; /* positive message type */
char mtext[512]; /* message data, of length nbytes */
};
The ptr argument is then a pointer to a mymesg structure.
The message type can be used by the receiver to fetch messages in an order other than
first in, first out.