Hi I've this problem to solve with a functional program in C.
"Write a C program where a process F create a childprocess C.
The childprocess C waits the user to type the password, if is correct sends a signal SIGUSR1 to the father, if after 3 attempts the password is still incorrect it will send a SIGUSR2 signal to the father and terminate; if it receives from the father SIGUSR1 signal must stop viewing the "timeout" message.
His father after 30 seconds (if it has not received any signal from the child) must send the signal SIGUSR1 to the child and end with exit(1); if it receives the SIGUSR1 signal must end with exit(0); if it receives the signal SIGUSR2 must end with exit (2)."
I'm trying to solve it but I'm stuck. This is what I've done:
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
void fatherprocess(int mysignal){
if (mysignal == SIGUSR1) {
printf("ACCESS GRANTED!\n");
exit(0);
}
if (mysignal == SIGUSR2){
printf("ACCESS DISCARDED! More than 3 tentatives!\n");
exit(2);
}
}
void childprocess(int mysignal){
if (mysignal == SIGUSR1) {
printf("TIMEOUT\n");
exit(1);
}
}
int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[], password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;
fatherpid = getpid();
childpid = fork();
if (childpid == 0) {
printf("Child Process waiting for a password\n");
while (1){
if (i < 3) {
printf("Enter Password: ");
scanf("%s", enteredpassword);
if (enteredpassword == password)
signal(SIGUSR1, fatherprocess);
} else {
signal(SIGUSR2, fatherprocess);
exit(1);
}
i++;
}
} else {
printf("Father Process\n");
while(time_to_sleep){
time_to_sleep = sleep(time_to_sleep);
signal(SIGUSR1, childprocess);
}
}
return 0;
}
I've edited my program in this way:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
void fatherprocess(int mysignal, int fatherpid){
if (mysignal == SIGUSR1) {
printf("ACCESS GRANTED!\n");
kill(fatherpid, SIGUSR1);
exit(0);
}
if (mysignal == SIGUSR2){
printf("ACCESS DISCARDED! More than 3 tentatives!\n");
kill(fatherpid, SIGUSR2);
exit(2);
}
}
void childprocess(int mysignal, int childpid){
if (mysignal == SIGUSR1) {
printf("TIMEOUT\n");
kill(childpid, SIGUSR1);
exit(1);
}
}
int main(int argc, char *argcv[]){
int fatherpid, childpid;
char enteredpassword[] = "test", password[] = "test";
int i =0;
unsigned int time_to_sleep = 30;
fatherpid = getpid();
childpid = fork();
if (childpid == 0) {
printf("Child Process waiting for a password\n");
while (1){
if (i < 3) {
printf("Enter Password: ");
scanf("%s", enteredpassword);
if (strcmp(enteredpassword, password) == 0)
fatherprocess(SIGUSR1, fatherpid);
} else {
fatherprocess(SIGUSR2, fatherpid);
exit(1);
}
i++;
}
} else {
printf("Father Process\n");
while(time_to_sleep){
time_to_sleep = sleep(time_to_sleep);
childprocess(SIGUSR1, childpid);
}
}
return 0;
}
Now it works perfectly but I don't know if I've respected the exercise text.
As was mentioned in the comments (by Jonathan Leffler), you need to use the kill() system call (to send the signals) and register a signal handler using a call like sigaction(). I have linked these two calls to online manual pages that provide additional information about them.
Here's some code that demonstrates how these can be used towards achieving your stated goal. You will still need to add/modify the code for things like the prompts you want and the acceptable input string. Please note that I'm not claiming this to be the best way to do it, only that it's an example of how it could be done (it compiled and worked for me):
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
static void get_password(char* buf, int maxbuf)
{
fgets(buf, maxbuf, stdin);
}
static int is_password_correct(char* buf)
{
return buf[0] == 'a';
}
volatile int got_signal = 0;
volatile int child_signal = 0;
static void parent_sig_handler(int signum)
{
if (!got_signal)
{
got_signal = signum;
printf("parent_sig_handler: got sig %d\n", signum);
}
}
static void child_sig_handler(int signum)
{
if (!child_signal)
{
child_signal = signum;
printf("child_sig_handler: got sig %d\n", signum);
}
}
int main()
{
struct sigaction act;
sigfillset(&act.sa_mask);
act.sa_handler = parent_sig_handler;
sigaction(SIGALRM, &act, NULL);
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
pid_t child_pid = fork();
if (child_pid == -1)
{
perror("error forking");
exit(3);
}
if (child_pid == 0)
{
printf("child running\n");
act.sa_handler = child_sig_handler;
sigaction(SIGUSR1, &act, NULL);
pid_t parent_pid = getppid();
for (int i = 0; i < 3; ++i)
{
char passwd[64];
passwd[0] = '\0';
get_password(passwd, sizeof(passwd));
if (is_password_correct(passwd))
{
kill(parent_pid, SIGUSR1);
exit(0);
}
}
kill(parent_pid, SIGUSR2);
exit(2);
}
printf("parent running\n");
alarm(30); /* sets parent up to receive a SIGALRM signal in 30 seconds */
sigset_t sigmask;
sigemptyset(&sigmask);
while (!got_signal)
{
sigsuspend(&sigmask);
}
switch (got_signal)
{
case SIGALRM:
kill(child_pid, SIGUSR1);
exit(1);
case SIGUSR1:
exit(0);
case SIGUSR2:
exit(2);
default:
exit(3);
}
exit(3);
}
Related
The following program checks if a signal is pending. I use the sigpending function to return blocked (or waiting) signals. The problem is that I don't want this, I would like to display all the blocked and pending signals at some point, how can I do that? What should I change?
code:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void catcher(int signum) {
puts("inside catcher!");
if (signum != 0)
perror("signum error");
}
void check_pending(int signum, char * signame) {
sigset_t sigset;
if (sigpending( & sigset) != 0)
perror("sigpending() error");
else if (sigismember( & sigset, signum))
printf("a %s signal is pending\n", signame);
else
printf("no %s signals are pending\n", signame);
}
int main() {
struct sigaction sigact;
sigset_t sigset;
sigemptyset( & sigact.sa_mask);
sigact.sa_flags = 0;
sigact.sa_handler = catcher;
if (sigaction(SIGUSR1, & sigact, NULL) != 0)
perror("sigaction() error");
else {
sigemptyset( & sigset);
sigaddset( & sigset, SIGUSR1);
if (sigprocmask(SIG_SETMASK, & sigset, NULL) != 0)
perror("sigprocmask() error");
else {
puts("SIGUSR1 signals are now blocked");
kill(getpid(), SIGUSR1);
printf("after kill: ");
check_pending(SIGUSR1, "SIGUSR1");
sigemptyset( & sigset);
sigprocmask(SIG_SETMASK, & sigset, NULL);
puts("SIGUSR1 signals are no longer blocked");
check_pending(SIGUSR1, "SIGUSR1");
}
}
}
Use sigignore to dispose the signal. Program below will check pending signals in 1s intervals and display theirs numbers. Terminate with sending SIGTERM.
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int i;
sigset_t sigset;
printf("my pid is %d\n", getpid());
sigfillset(&sigset);
sigprocmask(SIG_SETMASK, &sigset, NULL);
while (1) {
sigpending(&sigset);
for (i = 1; i < 32; ++i) {
if (sigismember(&sigset, i)) {
printf("signal %d pending\n", i);
sigignore(i);
if (i == SIGTERM) {
exit(0);
}
}
}
sleep(1);
}
return 0;
}
I am trying to send a message from child to parent (it has 2 children). But it returns error "Invalid Argument" when I run it in Xcode and when I run it in vim it is just pending and doing nothing. I want to send a message from 2nd child to Parent.
I have checked these, they are working finely :
Parent and child id matching
Arguments of msgrcv and msgsnd
fork and message queue creation
(I have added appropriate headers)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
void signalHandler(int signumber,siginfo_t* info,void* nonused){
printf("Signal with number %i has arrived\n",signumber);
switch (info->si_code){
case SI_USER:
printf("Process (PID number %i) sent the signal \n",info->si_pid); break;
case SI_QUEUE:
printf("It was sent by a sigqueue, sending process (PID %i)\n",info->si_pid);
default: printf("");
}
}
struct messg {
long mtype;
char mtext[1024];
};
int sendMsg (int mqueue){
const struct messg m = {5,"Test message"};
int status;
status = msgsnd(mqueue, &mqueue, strlen(m.mtext) + 1, IPC_NOWAIT);
if (status < 0){
perror("Message send error!");
}
return 0;
}
int receiveMsg(int mqueue){
struct messg m;
int status;
status = msgrcv(mqueue, &m, 1024 - sizeof(long), 5, 0);
if (status < 0){
printf("Errno : %d\n",status);
perror("Message recieve error!");
} else {
printf("Received msg : %s",m.mtext);
}
return 0;
}
int main(int argc, const char * argv[]) {
struct sigaction sigact;
sigact.sa_sigaction=signalHandler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags=SA_SIGINFO;
sigaction(SIGTERM,&sigact,NULL);
key_t key = ftok(argv[0],1);
int messg = msgget(key, 0600 | IPC_CREAT);
pid_t parent_co;
int pid_co_parent[2];
if (messg < 0){
perror("Message creation error!");
return 1;
}
pid_t child_nhp;
int pid_child_nhp[2];
char sz[250];
if(pipe(pid_co_parent) == -1){
perror("Pipe");
exit(0);
}
if(pipe(pid_co_parent) == -1){
perror("Pipe");
exit(0);
}
parent_co = fork();
if (parent_co == 0) {
sleep(3);
printf("(Police Lieutenant-colon) Child process : child_id : %d, parent_id : %d\n",getpid(),getppid());
kill(getppid(), SIGTERM);
read(pid_co_parent[0], sz, sizeof(sz));
printf("(Communication Officer) : %s\n" ,sz);
char answer[250];
strcpy(answer, "Yes, it is compulsory to wear the mask when you leave your flat!");
write(pid_co_parent[1], answer, strlen(answer) + 1);
close(pid_co_parent[0]);
return 0;
} else {
printf("(Communication Officer) Parent process_id : %d\n",getpid());
pause();
char ques[250];
strcpy(ques, "Is it compulsory to wear a mask in the shops?");
write(pid_co_parent[1], ques, strlen(ques) + 1);
close(pid_co_parent[1]);
read(pid_co_parent[0], sz, sizeof(sz));
printf("(Police Lieutenant-colon) : %s\n",sz);
close(pid_co_parent[0]);
child_nhp = fork();
if (child_nhp < 0){
perror("fork error for child nhp!");
exit(0);
}
if (child_nhp == 0) {
printf("(National Head Physician) child_id : %d, parent_id : %d\n",getpid(),getppid());
receiveMsg(messg);
return 0;
} else {
sendMsg(messg);
wait(NULL);
// parent process
}
fflush(NULL);
wait(NULL);
}
return 0;
}
I need to create a program, which will create child process that will handle processes. In case of SIGXCPU called, child process should close, but when other signal is received, process shouldn't close, but display information. How could I change signals_handler function to stop closing my process?
I call signals from second terminal window.
void signals_handler(int signal) {
psignal(signal,"\nRecived signal");
printf("Signal number is: %d\n", signal);
return;
}
void sig_XCPU(int signal() {
signal(XCPU, sig_XCPU);
}
...
int main(void)
{
if(fork() == 0) {
print("PID: %d", getpid();
signal(SIGXCPU, sig_xcpu)
for(int = 1; i < 65; i++) {
if(i != 24) //SIGXCPU number
signal(i, signals_handler);
}
sleep(100);
return 0;
}
}
return 0;
}
You can test like this:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
void signal_handle(int sig) {
switch (sig) {
case SIGXCPU: {
char st[] = "child recesive SIGXCPU, quit\n";
write(STDOUT_FILENO, st, sizeof(st));
exit(EXIT_SUCCESS);
break;
}
case SIGINT: {
char st[] = "child recesive SIGINT\n";
write(STDOUT_FILENO, st, sizeof(st));
break;
}
default: break;
}
return;
}
void set_signal() {
signal(SIGXCPU, signal_handle);
signal(SIGINT, signal_handle);
}
int main() {
pid_t pid = fork();
if (pid == 0) { // child
set_signal();
char st[] = "child set signal\n";
write(STDOUT_FILENO, st, sizeof(st));
for (;;)
;
}
// parent
sleep(3); // wait child set_signal
// test SIGINT
{
char st[] = "parent send SIGINT\n";
write(STDOUT_FILENO, st, sizeof(st));
kill(pid, SIGINT);
}
sleep(3);
// test SIGXCPU
{
char st[] = "parent send SIGXCPU\n";
write(STDOUT_FILENO, st, sizeof(st));
kill(pid, SIGXCPU);
}
wait(NULL);
return 0;
}
I am trying to write a C program which has some number of processes. One of them sends a random signal in the range SIGRTMIN and SIGRTMAX to all other processes but I want this signal will be ignored in main process.I used the global variable to have randomized signal to ignore with SIG_IGN. It looks It is not helping because the main stops with real-time signal when wants to ignore the first randomized signal.
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
volatile sig_atomic_t disarming_signal = 0;
void disarming_handler (int sig) {
disarming_signal = sig;
fprintf(stderr,"signal %d is handeled", disarming_signal);
}
int rand_range(int min_n, int max_n){
int rand_n = rand() % (max_n - min_n) + min_n;
return rand_n;
}
int sethandler (void (*f)(int), int sigNo) {
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = f;
if (-1==sigaction(sigNo, &act, NULL))
return -1;
return 0;
}
void sigchld_handler(int sig){
pid_t pid;
for(;;){
pid=waitpid(0, NULL, WNOHANG);
if(pid==0) return;
if(pid<=0) {
if(errno==ECHILD) return;
perror("waitpid:");
exit(EXIT_FAILURE);
}
}
}
void usage(){
fprintf(stderr,"USAGE: sappartherroryst n\n");
fprintf(stderr,"n - number of Therrorysts\n");
}
void therroryst_work(){
int s,k,t;
srand(getpid());
s = rand_range(SIGRTMIN, SIGRTMAX);
t = rand_range(10, 20);
k = t;
if(sethandler(disarming_handler, s)){
perror("Seting therroryst handeler");
exit(EXIT_FAILURE);
}
fprintf(stderr, "[%d] I am therroryst. My disarming signal is [%d]. I will wait [%d] Sec.\n", getpid(), s, t);
while(k>0) {
k=sleep(k);
if(disarming_signal == s){
fprintf(stderr, "I got signal [%d]\n.",disarming_signal);
return ;
}
}
fprintf(stderr, "[%d] KABOOM\n",getpid());
exit(EXIT_SUCCESS);
}
void create_therrorysts(int n){
while(n-->0){
switch(fork()) {
case 0:
therroryst_work();
exit(EXIT_SUCCESS);
case -1:
perror("Fork():");
exit(EXIT_FAILURE);
}
}
}
void sapper_work(){
int sig_dis, i;
struct timespec t, tn = {1,0};
fprintf(stderr,"[%d] I am sapper.\n", getpid());
for(i=0;i<10;i++){
for(t=tn;nanosleep(&t,&t););
sig_dis = rand_range(SIGRTMIN, SIGRTMAX);
if(kill(0, sig_dis)<0){
perror("Disarming_send\n");
exit(EXIT_FAILURE);
}
fprintf(stderr,"I sended signal [%d].\n",sig_dis);
disarming_signal = sig_dis;
}
fprintf(stderr, "end of sending");
exit(EXIT_SUCCESS);
}
void create_sapper(){
switch(fork()) {
case 0:
sapper_work();
exit(EXIT_SUCCESS);
case -1:
perror("Fork():");
exit(EXIT_FAILURE);
}
}
int main(int argc, char** argv){
int n;
pid_t pid;
if(argc != 2){
usage();
return EXIT_FAILURE;
}
n = atoi(argv[1]);
if(n <= 0){
usage();
return EXIT_FAILURE;
}
if(sethandler(sigchld_handler, SIGCHLD)) {
perror("Seting parent SIGCHLD:");
exit(EXIT_FAILURE);
}
create_therrorysts(n);
create_sapper();
sleep(5);
for(;;) {
if(sethandler(SIG_IGN, disarming_signal)){
perror("Seting parent disarming111");
exit(EXIT_FAILURE);
}
}
for(;;){
pid=wait(NULL);
if(pid<0)
switch (errno){
case ECHILD:
return EXIT_SUCCESS;
case EINTR:
continue;
default:
perror("wait:");
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}
You have sleep(5) after the create_sapper and before sethandler(IGN). That means it's very likely that the signal is sent before your main process has ignored it.
EDIT: Adding comment from Jonathan Leffler into this answer as it is equally (or even more) important:
There's also a problem with setting the signal handler even if you put the sleep() after that loop - the parent doesn't get to see what the child chooses as disarming_signal.
I'm trying to implement interprocess communication by using POSIX signals in C, especially I'm writing Ping-Pong problem. So here's my source code:
#define CHILD 0
#define PARENT 1
int flag[2];
void handler(int sig) {
if (sig == SIGUSR1) {
flag[PARENT] = 1;
} else {
flag[CHILD] = 1;
}
return;
}
void child_process() {
while (1) {
printf("Ping!\n");
kill(getppid(), SIGUSR2);
while (flag[PARENT] == 0) { }
}
return;
}
void parent_process(pid_t t) {
while (1) {
//kill(t, SIGUSR1);
while (flag[CHILD] == 0) { }
printf("Pong!\n");
kill(t, SIGUSR1);
}
return;
}
void setup() {
flag[CHILD] = 0;
flag[PARENT] = 0;
signal(SIGUSR1, handler);
signal(SIGUSR2, handler);
}
int main(int argc, char* argv[]) {
setup();
pid_t t = fork();
if (t == 0) {
child_process();
} else {
parent_process(t);
}
return 0;
}
My program is not working properly, because sometimes I get "Pong!" "Pong!" "Pong!" or "Ping!" "Ping!" output. What's the problem?
And one more question, is my way of handling signals correct? Or there are more advanced ways to do it?
(1) Parent and child do not share the same memory. flag[CHILD] and flag[PARENT] will never know about each other because they are different copies in different processes.
(2) Yes, pretty much everything about your signal handling is wrong for what you are trying to do. You are trying to synchronize the signals so you need to use a mechanism that actually synchronizes them e.g. sigsuspend.
#define _POSIX_C_SOURCE 1
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <errno.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
void sig_hand(int sig) {}
sigset_t saveMask, blockMask;
void child_process()
{
int x = 0;
while(x < 10)
{
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
printf("Pong %d!\n", ++x);
kill(getppid(), SIGUSR1);
}
return ;
}
void parent_process(pid_t pid)
{
int y = 0;
while (y < 10)
{
printf("Ping %d!\n", ++y);
kill(pid, SIGUSR1);
if (sigsuspend(&saveMask) == -1 && errno != EINTR)
errExit("sigsuspend");
}
return ;
}
int main(int argc, char* argv[])
{
//block SIGUSR1 in parent & child until ready to process it
sigemptyset(&blockMask);
sigaddset(&blockMask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &blockMask, &saveMask) == -1)
errExit("sigprocmask");
//set up signal handler for parent & child
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sig_hand;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
errExit("sigaction");
pid_t pid = fork();
if (pid == 0)
child_process();
else
parent_process(pid);
return 0;
}
Although it may not be your problem, remember anytime you are modifying variables asynchronous to program flow, you need to make those variables volatile so that the compilers does not optimize the accesses to them away.
I would think that semaphore.h has much more useful tools (sem_open, sem_post, sem_wait, sem_trywait).
I'd use the sigaction() and pause() functions, along with nanosleep() to rate-limit the activity.
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
enum { MAX_PINGS = 10 };
static sig_atomic_t sig_num;
static void err_exit(const char *fmt, ...)
{
int errnum = errno;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
if (errnum != 0)
fprintf(stderr, ": (%d) %s", errnum, strerror(errnum));
putc('\n', stderr);
}
static void catcher(int sig)
{
sig_num = sig;
}
static void child_process(void)
{
struct timespec nap = { .tv_sec = 0, .tv_nsec = 100000000 };
while (1)
{
pause();
printf("Pong!\n");
nanosleep(&nap, 0);
kill(getppid(), SIGUSR1);
}
}
static void parent_process(pid_t pid)
{
struct timespec nap = { .tv_sec = 0, .tv_nsec = 100000000 };
for (int pings = 0; pings < MAX_PINGS; pings++)
{
printf("Ping %d!\n", pings);
nanosleep(&nap, 0);
kill(pid, SIGUSR1);
pause();
}
kill(pid, SIGTERM);
}
int main(void)
{
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = catcher;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
err_exit("Failed to set SIGUSR1 handler");
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork()");
else if (pid == 0)
child_process();
else
parent_process(pid);
return 0;
}
The variable sig_num is there to quell complaints from the compiler about unused arguments (to the catcher function). The signal catcher is set before the fork(). The child process pauses until a signal arrives; then prints 'Pong!', takes a nap for 1/10 seconds, and then signals the parent process to wake. The parent process prints 'Ping!', takes a nap, signals the child process, and pauses until a signal arrives. It limits the loops to 10 (enough to show it is working), and when it is done, terminates the child before exiting.
Example output
$ ./pingpong
Ping 0!
Pong!
Ping 1!
Pong!
Ping 2!
Pong!
Ping 3!
Pong!
Ping 4!
Pong!
Ping 5!
Pong!
Ping 6!
Pong!
Ping 7!
Pong!
Ping 8!
Pong!
Ping 9!
Pong!
$
Clearly, it would not be hard to print a counter on the 'Pong' values too.