Signals

ewillwin·2022년 5월 31일
0

System Programming Lab

목록 보기
8/15

Multitasking
fork() spawns new process -> Called once, returns twice
exit() terminates own process -> Called once, never returns / Puts it into "zombie" status
wait() and waitpid() wait for and reap terminated children
execve() runs new program in existing process -> Called once, never returns

Signals

  • A signal is a small message that notifies a process that an event of some type has occured in the system
  • Kernel abstraction for exceptions and interrupts
  • Sent from kernel (sometimes at the request of another process) to a process
  • Different signals are identified by small integer ID's
  • The only information in a signal is its ID and the fact that it arrived

Sending Signals

Sending signals from the keyboard
-> Typing ctrl-c (ctrl-z) sends a SIGINT (SIGTSTP) to every job in the foreground process group

int kill(pid_t pid, int sig)
Can be used to send any signal to any process group or process

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>

#define N 10

int main(void) {
	pid_t pid[N];
    int i, child_status;
    for (i = 0; i < N; i++){
    	if ((pid[i] == fork()) == 0) {
        	while(1); /* Child infinite loop */
        }
    }
    
    /* Parent terminates the child processes */
    for (i = 0; i< N; i++) {
    	printf("Killing process %d\n", pid[i]);
        kill(pid[i], SIGINT);
    }
    /* Parent reaps terminated children */
    for (i = 0; i < N; i++) {
    	pid_t wpid = wait(&child_status);
        if (WIFEXITED(child_status))
        	printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
        else
        	printf("Child %d terminated abnormally\n", wpid);
    }
    
    return 0;
}

sighandler_t signal (int sig, sighandler_t handler)
The signal function modifies the default action associated with the receipt of signal sig

void int_handler(int sig)
{
	printf("Process %d received signal %d\n", getpid(), sig);
    exit(22);
}

int main(void) {
	pid_t pid[N];
    int i, child_status;
    signal(SIGINT, int_handler);
    for (i = 0; i < N; i++){
    	if ((pid[i] == fork()) == 0) {
        	while(1); /* Child infinite loop */
        }
    }
    
    /* Parent terminates the child processes */
    for (i = 0; i< N; i++) {
    	printf("Killing process %d\n", pid[i]);
        kill(pid[i], SIGINT);
    }
    /* Parent reaps terminated children */
    for (i = 0; i < N; i++) {
    	pid_t wpid = wait(&child_status);
        if (WIFEXITED(child_status))
        	printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
        else
        	printf("Child %d terminated abnormally\n", wpid);
    }
    
    return 0;
}

Handling Signals

  • Pending signals are not queued
  • A newly arrived signal is blocked while the handler of the signal is running
  • Sometimes system calls such as read() are not restarted automatically after they are interrupted by the delivery of a signal
#define N (10)

pid_t pid[N];
int ccount = 0;

void handler (int sig) {
	pid_t id;
    while((id = waitpid(-1, NULL, WNOHANG))>0) {
    	ccount--;
        printf("Received signal %d from pid %d\n", sig, id);
    }
}

int main(void) {
	int i;
    ccount = N;
    signal(SIGCHLD, handler);
    for (i = 0; i < N; i++){
    	if ((pid[i] = fork()) == 0) {
        	exit(0); /* child */
        }
    }
    
    while (ccount > 0)
    	sleep(5);
        
    return 0;
}

Make queued signal

  • Sender is parent process and receiver is child process
  • The program gets the number of signals to send via argv[1]
  • Use SIGUSR1, SIGUSR2 signal

Sender

  • Sender sends signal(SIGUSR1) to receiver and receives ack signal from receiver
  • Sender check the number of sending signals and received ack signals
  • If sender have not received all acks for sent signals, send remaining signals again after 1 second
    -> Do not use wait or sleep function, use alarm(1)
    -> alarm(int sec) function sends signal SIGALRM to self after sec seconds
    -> Print "__sender: total remaining signal(s): %d\n"
  • If the number of received acks the number of sent signals are same, send SIGINT to receiver and exit sender process
    -> print "__sender: all signals have been send\n"

Receiver

  • Receiver receives signal and sends ack signal(SIGUSR2) to sender
    -> Print "receiver: received #%d signal and sending ack\n"
  • If receiver receives SIGINT, print how many signals received and terminate
    -> Print "receiver: total received signals(s): %d\n"
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

pid_t sender, receiver;
int total_number_of_signals = 0;
int total_received_signals = 0;
int total_acked_signals = 0;
//int total_sending_signals = 0;

void sigalrm_handler(int sig)
{
	//This function is called upon receiving the signal SIGALRM
	//See how many acks are received
	//Send the signals again for the remaining number
	if(total_acked_signals < total_number_of_signals){
		for(int i= 0; i < total_number_of_signals - total_acked_signals; i++)
		kill(receiver, SIGUSR1);
	
		alarm(1);
	}
	else exit(0);
	//kill(receiver, sig);
	
}

void sigusr1_handler(int sig)
{
	//receive the signal
	//increase the number of received one
	//send the ack back to the parent
	total_received_signals++;
	//kill(sender, sig);
	printf("receiver: received #%d signal and sending ack\n", total_received_signals);
	kill(sender, SIGUSR2);

}

void sigusr2_handler(int sig)
{
	//upon receiving the ack, increase the number of acks
	//if equals the number of total signals send SIGINT to the child

	total_acked_signals++;
	printf("sender: total remaining signal(s): %d\n", total_number_of_signals - total_acked_signals);
	if (total_acked_signals == total_number_of_signals)
	{
		kill(receiver, SIGINT);	
	}
}

void sigint_handler(int sig)
{
	//upon receiving this signal just terminate
	printf("sender: all signals have been sent\n");
	printf("receiver: total received signals(s): %d\n", total_received_signals);
	exit(0);
}

int main(int argc, char* argv[])
{
	signal(SIGUSR1, sigusr1_handler);
	signal(SIGINT, sigint_handler);
	signal(SIGALRM, sigalrm_handler);
	signal(SIGUSR2, sigusr2_handler);

	if(argc != 2){
		printf("please input total number of signals\n");
		return -1;
	}
	total_number_of_signals = atoi(argv[1]);
	printf("total number of signal(s): %d\n", total_number_of_signals);
	sender = getpid();

	if((receiver = fork()) == 0){
		while(1){}
	}
	else{
		for(int i = 0; i < total_number_of_signals - total_acked_signals; i++){
			kill(receiver, SIGUSR1);
		}
		alarm(1);
	}
	while(1);
}
profile
💼 Software Engineer @ LG Electronics | 🎓 SungKyunKwan Univ. CSE

0개의 댓글