I have to send signal p1 -> p2 -> p3 ->p1 ... in order to change the value of shared file. however p3 -> p1 is not working(p1 doesn't catch the signal). I put sleep to make time difference between each transition but idk what's wrong.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
void sig_usr (int signo)
{
printf("%d\n",getpid());
// longjmp(jumpbuffer,1);
}
int main(int argc, char **argv)
{
signal(SIGUSR1, sig_usr);
jmp_buf jumpbuffer;
pid_t next,ppid,granmaduh;
granmaduh = getpid();
if ((next = fork()) <0 )
{
fprintf(stderr, "fork() error");
exit(1);
}
else if (next == 0 )
{
next = fork();
if (next >0)
{
sleep(6);
}
else
{
next = granmaduh;
sleep(10);
}
}
sleep(2);
printf("%d\n",next);
//setjmp(jumpbuffer);
kill(next, SIGUSR1);
exit(1);
}
#include <signal.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>
static void signal_handler(int);
int i, pid1, pid2,pid3, status;
int main( int argc, char *argv[], char *env[] )
{
int exit_status;
if( signal( SIGUSR1, signal_handler) == SIG_ERR )
{
printf("Pærent: Unable to create handler for SIGUSR1\n");
}
// if( signal( SIGUSR2, signal_handler) == SIG_ERR )
// {
// printf("Pærent: Unable to create handler for SIGUSR2\n");
// }
printf( "Parent pid = %d\n", pid1=getpid() );
if( (pid2 = fork()) == 0 )
{
printf( "Child pid = %d\n", getpid() );
//printf( "Child: %d sending parent SIGUSR1\n", getpid() ); //kill( pid1, SIGUSR1 );
if( (pid3 = fork()) == 0 )
{
printf( "GranChild pid = %d\n", getpid() );
printf( "Child: %d sending parent SIGUSR1\n", getpid() ); kill( pid2, SIGUSR1 );
}
for( ;; ); /* loop forever */
}
else
{
/*
* This waits for ANY child to die. It doesn't matter if the child
* dies normally or from a signal. The satus information is then
* stored in the status integer.
*
* If you want to wait on a particular process use waitpid():
* waitpid( childPID, &status, 0 );
* is the common usage.
*
* Solaris acts weirdly when a signal is given to the parent process.
* Therefore we place the wait() inside a while loop so that wait()
* will not return before the child has died.
*/
/* while( (wait( &status ) == -1) && (errno == EINTR) ) {} */
wait(&status);
/*
* The information in status is *NOT* the return code!! To make use
* of the information we must macros to extract the needed
* information.
*/
/* WIFEXITED() determines if the process exited normally (returned a
* number). This can be done through a return or exit()
*/
if( WIFEXITED( status ) )
{
/*
* Now we know the process exited properly so we can get the
* return value
*
* Note that WEXITSTATUS only retuns the lower 8 bits! That means
* that if we ever expect a negative number then we have to count
* the 8th bit as a sign bit.
*/
exit_status = WEXITSTATUS( status );
/*
* Since we expect negative numbers...
*
* If the exit_status is greater than 2^7 (128), thæn the eigth bit
* is a 1, so we subtract 2^8 (256) from it to make it look like
* a negative number.
*/
if( exit_status > 128 )
{
exit_status -= 256;
}
printf( "Child return - %d\n", WEXITSTATUS( status ) );
}
else
{
/* Well it didn't exit properly. Was it a signal? */
if( WIFSIGNALED( status ) )
{
/*
* Yes. A signal killed the child process. Now we can extract
* the signal information from status
*/
printf( "Child died on signal - %d\n", WTERMSIG( status ));
}
}
/*
* There are two other macros most UNIXes use. They are:
* WIFSTOPPED() and WSTOPSIG(). See the man pages on the dells for
* more information.
*
* To wait on a particular pid - see waitpid()
*/
}
return 0;
}
static void signal_handler(int signo)
{
/* signo contains the signal number that was received */
switch( signo )
{
/* Signal is a SIGUSR1 */
case SIGUSR1:
printf( "Process %d: received SIGUSR1 \n", getpid() );
if(pid1==getpid()) /* it is the parent */
{
printf( "Process %d is passing SIGUSR1 to %d...\n", getpid(),pid2 );
kill( pid2, SIGUSR1 );
}
else if(pid2==getpid()) /* it is the child */
{
printf( "Process %d is passing SIGUSR2 to itself...\n", getpid());
kill(getpid(), SIGUSR2);
}
else
{
printf( "Process %d is passing SIGUSR2 to itself...\n", getpid());
kill(pid3, SIGUSR2);
}
break;
/* It's a SIGUSR2 */
case SIGUSR2:
printf( "Process %d: received SIGUSR2 \n", getpid() );
if(pid1==getpid())
{
printf( "Process %d is passing SIGUSR2 to %d...\n", getpid(),pid2 );
kill( pid2, SIGUSR2 );
}
else if(pid2==getpid())/* it is the child */
{
printf( "Process %d is passing SIGUSR2 to %d...\n", getpid(),pid3 );
kill(pid3, SIGINT);
}
else /* it is the child */
{
printf( "Process %d is passing SIGUSR2 to %d...\n", getpid() );
kill(getpid(), SIGINT);
}
break;
default:
break;
}
return;
}
Related
I'm trying to have it execute in a loop where the parent randomly picks between SIGUSR1 and SIGUSR2 and send it to the child process to receive and write to a file
My problem is the signal will only send in the first loop and after that it stops
int main(int argc, char* argv[], char *envp[]){
time_t start, finish; //for example purposes, to save the time
struct sigaction sact; //signal action structure
sact.sa_handler = &handler;
sact.sa_handler = &handler2;
sigset_t new_set, old_set; //signal mask data-types
FILE *file = fopen("received_signal.txt", "w");
fprintf(file,"%s\t %s\t %s\n", "Signal Type",
"Signal Time", "thread ID");
fclose(file);
int pid;
int cpid;
pid = fork();
if(pid == 0){//recieves
//sigaction(SIGUSR1, &sact, NULL);
while(1){
signal(SIGUSR1, handler);
signal(SIGUSR2, handler2);
sleep(1);
}
} else{ //generates
while(1){
sleep(1); // give child time to spawn
printf("hello\n");
parent_func(0);
//wait(NULL);
usleep(((rand() % 5) + 1) * 10000);
}
}
return 0;
}
void parent_func(int child_pid){
srand(time(NULL));
int rnd = rand();
int result = (rnd & 1) ? 2 : 1;
struct timeval t;
gettimeofday(&t, NULL);
unsigned long time = 1000000 * t.tv_sec + t.tv_usec;
printf("result: %d\n", result);
printf("time: %ld\n", time);
if(result == 1){
//sigaction(SIGUSR1, &sact, NULL);
kill(child_pid, SIGUSR1);
log(SIGUSR1);
} else{
//sigaction(SIGUSR2, &sact, NULL);
kill(child_pid, SIGUSR2);
log(SIGUSR2);
}
}
void handler(int sig){
if (sig == SIGUSR1){
puts("child received SIGUSR1");
}
}
void handler2(int sig){
if (sig == SIGUSR2){
puts("child received SIGUSR2");
}
}
Tried throwing the child in a while loop to get it to repeat but no such luck
man signal(2) tells you that the handler is reset to SIG_DFL once a signal is delivered:
If the disposition is set to a function, then first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum. If invocation of the handler caused the signal to be blocked, then the signal is unblocked upon return from the handler.
I suggest you use sigaction instead of signal:
#define _XOPEN_SOURCE 500
#define _POSIX_C_SOURCE 199309L
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
void handler(int sig) {
char s[] = "child received signal SIGUSR?\n";
char *s2 = strchr(s, '?');
*s2 = sig == SIGUSR1 ? '1' : '2';
write(STDOUT_FILENO, s, strlen(s));
}
int main(int argc, char* argv[], char *envp[]){
pid_t child_pid = fork();
if(!child_pid) {
struct sigaction sa = {
.sa_handler = &handler
};
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
for(;;) {
sleep(1);
}
return 0;
}
for(;;) {
sleep(1);
int s = (int []){SIGUSR1, SIGUSR2}[rand() % 2];
printf("parent sending signal %d to %d\n", s, child_pid);
kill(child_pid, s);
}
}
and sample output:
parent sending signal 12 to 521586
child received signal SIGUSR2
parent sending signal 10 to 521586
child received signal SIGUSR1
parent sending signal 12 to 521586
child received signal SIGUSR2
parent sending signal 12 to 521586
child received signal SIGUSR2
I'm beginner to signal and practicing by writing a function kill_parent_process that will be used as a signal handler.
This func will asks parents to exit() (either sending SIGKILL or other methods). The way I did is let child sending a signal to parents and the handler exit(). But I do feel this is where the problem because when I exit, I might just exit in child process. However, it looks like the handler never been called. Here is my code
void kill_parent_process(int code) {
fprintf(stderr, "KIll the Parent\n");
exit(1);
}
int main() {
struct sigaction sa;
sa.sa_handler = kill_parent_process;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
int r = fork();
if (r == 0) {
sigaction(SIGUSR1, &sa, NULL);
kill(getppid(), SIGUSR1);
exit(1);
} else if (r > 0) {
while (1) {
sleep(1);
printf("%d\n",getpid());
}
int status;
wait(&status);
if (WIFEXITED(status)) {
int result = WEXITSTATUS(status);
fprintf(stderr, "%d\n", result);
}
}
}
I receive a message User defined signal 1: 30 when I ran the program and kill_parent_process never been called. What is the problem with this code?
the following proposed code:
performs the desired functionality
cleanly compiles
documents why most of the header files are being included
does not invoke any signal handlers, etc, rather uses the default action
properly checks for and handles errors
and now the proposed code:
#include <stdio.h> // perror(), puts()
#include <stdlib.h> // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <sys/types.h> // for 'kill()' and 'getppid()'
#include <signal.h> // kill()
#include <unistd.h> // getppid(), fork()
int main( void )
{
pid_t pid = fork();
if( pid < 0 )
{
perror( "fork failed" );
exit( EXIT_FAILURE );
}
else if( pid == 0 )
{ // then child
puts( "in child process" );
kill( getppid(), SIGUSR1 );
exit( EXIT_SUCCESS );
}
else // if ( pid > 0 )
{ // then parent
while(1)
{
puts( "in parent process" );
sleep(1);
}
}
}
the (typical) output of the proposed code is:
in parent process
in child process
User defined signal 1
So i just want to create a simple forking program that forks 5 children at the rate of 1 per every half second and then displays the date and time when each fork is complete.. so this is the jist of the code
int count = 1;
while(count <= 5){
int kid = fork();
if(kid == -1){
perror("error in fork");
exit(0);
} else if(!kid){
numbytes = read(sockfd, buf, sizeof(buf)-1);
buf[numbytes] = '\0';
printf("%s\n",buf);
}
count++;
usleep(500000); //create per every half second, 500000 = 0.5sec
close(sockfd);
}
return 0;
}
which I thought should be simple enough, but instead of forking 5 times it doubles after each fork.. so it forks 1 time, then 2, then 4, 8.. etc.
Help?
A fork is generally of this form.
int pid = fork();
if( pid == -1 ) { /* error */
fprintf(stderr, "Error forking: %s", strerror(errno));
exit(1);
}
else if( pid == 0 ) { /* child */
puts("Child");
exit(0);
}
/* Parent */
printf("Forked %d\n", pid);
Note that the child has to exit else it will continue executing the rest of the program. Usually you have the child process run a function and exit.
The other part is the main program should wait until all child processes are complete, else you get zombies. Usually a loop calling wait() until there's no more children.
int wpid;
int wstatus;
while( (wpid = wait(&wstatus)) != -1 ) {
printf("Child %d exited with status %d\n", wpid, wstatus);
}
Put it all together and here's how you fork and wait for 5 child processes.
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main() {
int max_children = 5;
for( int i = 0; i < max_children; i++ ) {
int pid = fork();
if( pid == -1 ) { /* error */
fprintf(stderr, "Error forking: %s", strerror(errno));
}
else if( pid == 0 ) { /* child */
puts("Child");
exit(0);
}
/* Parent */
printf("Forked %d\n", pid);
}
int wpid;
int wstatus;
while( (wpid = wait(&wstatus)) != -1 ) {
printf("Child %d exited with status %d\n", wpid, wstatus);
}
}
I need to create a program that creates n number of processes and displays information. When each process ends, I am to print it's PID and the exit status. The way I am doing it, the parent program waits to create the next process until the current one ends. I need it so that it keeps creating the child processes and just displays the exit information when ever one process ends without blocking the parent from continuing. I can;t figure out where to put my wait to ensure this. Below is my code:
int main (int argc, char *argv[])
{
if (argc < 2)
{
printf("\n\nUsage: %s <enter a number (12 or less)>\n\n", argv[0]);
exit (-1);
}
else
{
int *processNum = (int *)malloc(sizeof(12));
int processNumTemp;
processNumTemp = atoi(argv[1]);
processNum = &processNumTemp;
if(*processNum > 12 || *processNum < 1)
{
printf("\n\nUsage: %s <enter a number (12 or lrss)>\n\n", argv[0]);
}
else
{
parentInfo(processNum);
createChildProcess(processNum);
}
}
return 0;
}
//Name: parentInfo
//Description: Displays information about the parent process
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void parentInfo(int *processNum)
{
printf("Parent process ID: %d\n", getppid());
printf("Number of processes to create: %d\n", *processNum);
}
//Name: createChildProcess
//Description: Creates n number of child processes.
// For each child process, it says its a child process and it
// displays its PID.
// After each child process closes, the parent displays info.
//Parameters: processNum - stores the number of child processes to create
// (entered at the command line).
//Return: none
void createChildProcess(int *processNum)
{
int i;
int childStatus;
pid_t childpid;
/*The for loop will create n number of processes based on the value of processNum.*/
for(i = 1; i <= *processNum; i++)
childpid = fork();
//Executes if fork didn't work
if(childpid < 0)
{
perror("fork");
exit(1);
}
//Executes if the fork worked
else if( childpid == 0)
{
int pid = getpid();
//Prints a message and the child processe's PID
printf("\nHello I am a child process.\n");
printf("My PID is %d. \n", getpid());
for(int x = 1; x <= pid; x ++);
exit(15);
}
}
//Executes after the child process has ended
//Checks the child process's exit status
waitpid(childpid, &childStatus, WUNTRACED);
printf("\nPID of the child process that was just created: %d.\n", childpid);
if(WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else if(WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else if(WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
Before fork code
signal(SIGCHLD, childHandler);
In childHandler put your waitpid code.
void childHandler(int signum)
{
pid_t childpid;
int childstatus;
while ((childpid = waitpid( -1, &childstatus, WNOHANG)) > 0)
{
if (WIFEXITED(childStatus))
{
printf("PID %d exited normally. Exit number: %d\n", childpid, WEXITSTATUS(childStatus));
}
else
if (WIFSTOPPED(childStatus))
{
printf("PID %d was stopped by %d\n", childpid, WSTOPSIG(childStatus));
}
else
if (WIFSIGNALED(childStatus))
{
printf("PID %d exited due to signal %d\n.", childpid, WTERMSIG(childStatus));
}
else
{
perror("waitpid");
}
}
}
}
You should not use async-unsafe calls like printf inside a signal handler so alter your code to save the status in a global or heap allocated array - you know the size to create from processNum - and print the status info outside the handler.
Also, as currently structured, your parent could end before reaping all the children. Add a counter for the children so that you wait on all of them before the parent exits.
Look into signal SIGCHLD. If you have it blocked, you must unblock it or might instead explicitly check for it.
The purpose of wait is to, well, wait, so the way to solve your problem is to first create all the children, then start waiting for them to terminate.
Here is a program which does that:
// fork
#include <unistd.h>
// wait
#include <sys/types.h>
#include <sys/wait.h>
// exit
#include <stdlib.h>
//printf
#include <stdio.h>
void child( int id)
{
int seed= id;
int x= rand_r( &seed) % 10;
sleep( x);
exit( x);
}
int main( int argc, char *argv[])
{
const int n= 5;
int i;
printf( "creating %d children.\n", n);
for ( i= 0; i < n; ++i) {
pid_t pid= fork();
if ( !pid)
child( i); // does not return
else
printf( "child [0x%x] created.\n", pid);
}
// all the children are created now
// now we wait for them to terminate
printf( "waiting for children to terminate.\n", n);
for ( i= 0; i < n; ++i) {
int result;
pid_t pid= wait( &result);
printf( "child [0x%x] terminated with result [%u].\n", pid, WEXITSTATUS( result));
}
puts( "all children terminated.");
}
I was trying to implement a checkpointing scheme based on multithreaded fork using fork combined with setjmp/longjmp. I was hoping my solution would work but as expected it didn't. The code is shown below with an example usage for checkpoint/rollback.
The main idea is to allocate stacks for the threads myself, as done by using the function pthread_create_with_stack and then just use a fork from the main thread. The forked process (checkpoint) is suspended at the beginning and when awoken (rollbacking), the main thread of the forked process recreates the threads by calling pthread_create and use the same stacks as threads in original process. Also longjmp is done in the thread routine at the beginning, so as to jump to the same point in the code when process was forked as a checkpoint. Note that all setjmp calls are done inside function my_pthread_barrier_wait so that no thread has acquired a lock.
I think the problem here is setjmp/lonjmp. Will getcontext/savecontext/makecontext help here, or anything else? Can even setjmp/longjmp be used in such a way here that it works? Any solution will be greatly appreciated.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <setjmp.h>
#define PERFORM_JMP
#define NUM_THREADS 4
void *stackAddr[NUM_THREADS];
pthread_t thread[NUM_THREADS];
jmp_buf buf[NUM_THREADS];
pthread_attr_t attr[NUM_THREADS];
pthread_barrier_t bar;
sem_t sem;
pid_t cp_pid;
int rollbacked;
int iter;
long thread_id[NUM_THREADS];
void *BusyWork(void *t);
void sig_handler(int signum)
{
printf( "signal_handler posting sem!\n" );
sem_post( &sem );
}
int pthread_create_with_stack( void *(*start_routine) (void *), int tid )
{
const size_t STACKSIZE = 0xC00000; //12582912
size_t i;
pid_t pid;
int rc;
printf( "tid = %d\n", tid );
pthread_attr_init( &attr[tid] );
stackAddr[tid] = malloc(STACKSIZE);
pthread_attr_setstack( &attr[tid], stackAddr[tid], STACKSIZE );
thread_id[tid] = tid;
rc = pthread_create( &thread[tid], &attr[tid], start_routine, (void*)&thread_id[tid] );
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
return rc;
}
pid_t checkpoint()
{
pid_t pid;
int t, rc;
switch (pid=fork())
{
case -1:
perror("fork");
break;
case 0: // child process starts
sem_wait( &sem );
rollbacked = 1;
printf( "case 0: rollbacked = 1, my pid is %d\n", getpid() );
for( t = 1; t < NUM_THREADS; t++ )
{
printf( "checkpoint: creating thread %d again\n", t );
rc = pthread_create( &thread[t], &attr[t], BusyWork, (void*)&thread_id[t] );
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
return 1; // child process ends
default: // parent process starts
return pid;
}
}
void restart_from_checkpoint( pid_t pid )
{
printf( "Restart_from_checkpoint, sending signal to %d!\n", pid );
kill( pid, SIGUSR1 );
exit( 0 );
}
void take_checkpoint_or_rollback( int sig_diff )
{
if ( cp_pid )
{
if ( sig_diff )
{
printf( "rollbacking\n" );
if ( !rollbacked )
restart_from_checkpoint( cp_pid );
}
else
{
kill( cp_pid, SIGKILL );
cp_pid = checkpoint();
printf( "%d: cp_pid = %d!\n", getpid(), cp_pid );
}
}
else
cp_pid = checkpoint();
}
void my_pthread_barrier_wait( int tid, pthread_barrier_t *pbar )
{
pthread_barrier_wait( pbar );
#ifdef PERFORM_JMP
if ( tid == 0 )
{
if ( !rollbacked )
{
take_checkpoint_or_rollback( ++iter == 4 );
}
}
if ( setjmp( buf[tid] ) != 0 ) {}
else {}
printf( "%d: %d is waiting at the second barrier!\n", getpid(), tid );
#endif
pthread_barrier_wait( pbar );
}
void *BusyWork(void *t)
{
volatile int i;
volatile long tid = *((long*)t);
volatile double result = 0.0;
printf( "thread %ld in BusyWork!\n", tid );
#ifdef PERFORM_JMP
if ( rollbacked )
{
printf( "hmm, thread %ld is now doing a longjmp, goodluck!\n", tid );
longjmp( buf[tid], 1 );
}
#endif
printf("Thread %ld starting...\n",tid);
for ( i = 0; i < 10; i++)
{
result += (tid+1) * i;
printf( "%d: tid %ld: result = %g\n", getpid(), tid, result );
my_pthread_barrier_wait(tid, &bar);
}
printf("Thread %ld done. Result = %g\n", tid, result);
//pthread_exit((void*) t);
}
int main (int argc, char *argv[])
{
int rc;
long t;
void *status;
/* Initialize and set thread detached attribute */
pthread_barrier_init(&bar, NULL, NUM_THREADS);
#ifdef PERFORM_JMP
signal(SIGUSR1, sig_handler);
sem_init( &sem, 0, 0 );
#endif
for( t = 1; t < NUM_THREADS; t++ )
{
printf( "Main: creating thread %ld\n", t );
rc = pthread_create_with_stack( BusyWork, t ); // This is the line 52
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
thread_id[0] = 0;
BusyWork( &thread_id[0] );
/* Free attribute and wait for the other threads */
for(t=1; t<NUM_THREADS; t++)
{
rc = pthread_join(thread[t], &status);
if (rc)
{
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status"
"of %ld\n",t,(long)status);
}
printf("Main: program completed. Exiting.\n");
pthread_exit(NULL);
}
What you're trying to do is simply impossible. fork is fundamentally incompatible with synchronization. Even if you could recreate threads reliably in the child process, they would have new thread ids, and thus they would not be the owners of the locks they're supposed to own.
The only way to do checkpointing is with advanced operating system support for it. This would have to include separate pid namespaces, so that the checkpointed copy of the program would have the same pid, and all its threads would have the same thread ids. Even then, if it's performing communication with other processes or the outside world, it won't work. I believe there are some tools for doing this on Linux, but I'm not familiar with them, and at this point you're getting to level of hacks where it's appropriate to ask if there's a better way to achieve what you're trying to do.