Please refer previous post #1: Handling child process. Since, current post is continuation of the post #1.
We already see the use of wait() function. This function call blocks the parent process, reads the exit value of child process and instructs the kernel's process manager to destroy the child process.
Wait() function is synchronous call, it will suspend/block the execution of parent process i.e. parent can't continue its operation/execution until child terminates.
Now, we will see another API "Signals" which uses Asynchronous method.
This method allows the parent process to register a function call back. This function will be executed when the child process terminates. So, the child and parent process can be executed simultaneously without any parent blocking.
Here, we have two different APIs to do this job.
Signal API :
Sigaction API:
We already see the use of wait() function. This function call blocks the parent process, reads the exit value of child process and instructs the kernel's process manager to destroy the child process.
Wait() function is synchronous call, it will suspend/block the execution of parent process i.e. parent can't continue its operation/execution until child terminates.
Now, we will see another API "Signals" which uses Asynchronous method.
This method allows the parent process to register a function call back. This function will be executed when the child process terminates. So, the child and parent process can be executed simultaneously without any parent blocking.
Here, we have two different APIs to do this job.
- Signal API
- Sigaction API
Signal API :
=========
Signals are asynchronous calls, means these will block current execution of process and requires immediate response (registered function call be will be called automatically when the signal interrupt is received).
Once the signal is received, the process can able to perform three different tasks
- Calls default signal handler
- Calls its own defined signal handler
- Ignores the signal
The below Sample code will describe the use of 2nd case (process calls its own defined signal handler).
For 1st case, pass second argument as SIG_DFL in signal() function call. Kernel process manager will call the default function for the signal generated.
For 3rd case (Ignore the signal), use 2nd argument as SIG_IGN in signal() function.
-------------------------------------------------------------------------------------------
Sample code:
----------------
- #include<unistd.h>
- #include<stdio.h>
- #include<stdlib.h>
- #include<signal.h>
- #define CHILD 0
- void sighand(int signum)
- {
- printf("I am in signal handler: %d\n", signum);
- }
- int main()
- {
- pid_t child_pid;
- child_pid = fork();
- if (child_pid == CHILD) {
- /* child process */
- printf("child: %d, parent: %d\n", getpid(), getppid());
- sleep(10);
- exit(100);
- } else {
- /* parent process */
- signal(SIGCHLD, sighand);
- printf("Successfully registered sighand for SIGCHLD: %d\n", SIGCHLD);
- printf("parent: %d\n", getpid());
- while(1) {
- printf("in parent\n");
- sleep(2);
- }
- }
- return 0;
- }
output:
=======
Successfully registered sighand for SIGCHLD: 17
parent: 2274
in parent
child: 2275, parent: 2274
in parent
in parent
in parent
in parent
in parent
I am in signal handler: 17
in parent
in parent
in parent
.
.
observation:
=========
signal is not a blocking call like wait().
Since in wait() case, parent process is blocked until child terminated.
But here in signal() case, parent process is executing continuously and received asynchronous interrupt (SIGCHLD) when child terminates. sighand() is called in response to this interrupt.
ps -Af (Before SIGCHLD interrupt received)
-----------------
rrajk 2285 2039 0 10:59 pts/0 00:00:00 ./fork4_signal
rrajk 2286 2285 0 10:59 pts/0 00:00:00 ./fork4_signal
ps -Af (After SIGCHLD received:)
----------------
rrajk 2285 2039 0 10:59 pts/0 00:00:00 ./fork4_signal
rrajk 2286 2285 0 10:59 pts/0 00:00:00 [fork4_signal] <defunct>
Since child process terminated, but parent process is still executing then child process put into defunc state.
------------------------------------------------------------------------------------------
Sigaction API:
============
Signal API is an ANSI C Standard API.
Sigaction API is a POSIX standard API.
We use sigaction APIs for changing the signal disposition in better way compared to signal.
Using sigaction, we can block/unblock required set of signals with ease of operations.
Sigaction() prototype declaration
--------------------------------------
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sigaction is alternative signal API for changing signal
disposition.
Sample code:
struct sigaction
sa;
memset(&sa,
0, sizeof(sa));
/* Install signal
Handler */
sa.sa_handler =
handler;
if (sigaction(SIGALRM,
&sa, NULL) < 0)
printf(“Sigaction
failed\n”);
When a signal is generated and it is being currently handled,
another occurrence of the same signal shall be queued (queue size = 1) until
handler returns. If more than 1 signal is generated in this case, they will be
lost.
But, occurrence of Real Time signals are never lost, they will be
queued.
sa.sa_flags:
==========
sa.sa_flags =
SA_NODEFER;
Signals are not
queued, they directly send to the registered process. No delay in delivery. No
queue also.
sa.sa_mask:
==========
If one signal is in its handler, and if another signal is
generated then 1st signal is terminated immediately and 2nd signal handler will
start its execution.
Ex: CTRL+C SIGTERM and CTRL+\ SIGQUIT
Sigaction provide a mechanism to block this 2nd signal until 1st
signal completed its handler function.
Sample code:
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask,
SIGQUIT); /* block SIGQUIT if a signal is already in its handler */
sigaddset(&sigmask,
SIGTERM);
sa.sa_handler =
handler;
sa.sa_mask =
sigmask;
if
(sigaction(SIGINT, &sa, NULL) < 0)
printf(“sigaction
is failed\n”);
Sigprocmask:
=============
Applications can also block/unblock signal delivery while
executing the primary functionality in the main thread.
Int sigprocmask(int
how, const sigset_t *set, sigset_t *old_set);
how: SIG_BLOCK or SIG_UNBLOCK
Sample code:
struct sigaction
sa;
sigset_t set;
memset(&sa,
0, sizeof(sa));
sigemptyset(&set);
sigaddset(&set,
SIGQUIT);
sigaddset(&set,
SIGTERM);
/* ovrride signal mask set */
sigprocmask(SIG_BLOCK
| SIG_SETMASK, &set, NULL);
/* Append to signal mask list */
sigprocmask(SIG_BLOCK,
&set, NULL);
Examples will be posted in next post [Operating Systems #3].
Examples will be posted in next post [Operating Systems #3].
No comments:
Post a Comment