Task
I should write a program which creates a thread with printing text routine, and after two seconds of executing this thread should be canceled and the message of cancelling should be printed. The task condition is such that phtread_cleanup_push(3C) should be used for this purpose.
A little description of my code
I create a thread by pthread_create() calling with an infinity routine of text printing. The thread is created with default values of cancelation state and cancelation type, so the cancelation of the created thread occurs when the thread reaches the cancelation point. The main thread waits two seconds and then calls pthread_cancel(3C) to the child thread.
The created thread is printing the text with 0,1 second time interval using usleep(). Also I pasted pthread_testcancel() call inside infinity loop. So we have two cancelation point inside the loop: one is the system defined - usleep() and the second is created by calling pthread_testcancel().
Before the infinity loop I pasted the pthread_cleanup_push() with another printing text routine. And after the infinity loop I pasted pthread_cleanup_pop() statement, because both of this statements are implemented as the macro and according to the official documentation they should be in the same lexical scope.
Problem
Unfortunately cleanup handler routine doesn't executed. Child thread is canceling but no message about it is printing. I've been searching the answer for my problem for a long time, but nothing I've found was similar to my problem, so I'll be very thankful for any recommendation about solving my problem.
Code and environment
Here is my code below and it's output. I am using Oracle VM Virtual Box on Windows 10 (64-bit) on which Oracle Solaris-10 (64-bit) is running. I compile my program using bash 3.2 with the command:
gcc -o lab5 -threads -lpthread -std=c99 lab5.c
code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#define SUCCESS 0
#define FAILED 1
#define WAIT_TIME 2
#define PRINT_DELTA_TIME 1 * 100000 // in microseconds
char* printing_text = "Child thread text\n"; // this text will be printed by child thread
char* termination_text = "Child thread is terminated\n";
void cleanup_handler(void* arg) {
printf(termination_text);
}
// infinity routine of printing text
void *print_text() {
pthread_cleanup_push(cleanup_handler, NULL); // push cleanup routine to the stack
while (1) {
pthread_testcancel();
printf("%s\n", printing_text);
usleep(PRINT_DELTA_TIME);
}
pthread_cleanup_pop(1);
return NULL;
}
// cancel a thread with exception handling
int try_cancel_thread(pthread_t *thread) {
int code = pthread_cancel(*thread);
if (code != SUCCESS) {
char* error_message = strerror(code);
fprintf(stderr, "%s%s\n", "can't cancel a child thread:", error_message);
return FAILED;
}
return SUCCESS;
}
// creating a thread with exception handling
int try_create_thread(pthread_t *thread) {
int code = pthread_create(thread, NULL, print_text, NULL);
if (code != SUCCESS) {
char* error_message = strerror(code);
fprintf(stderr, "%s%s\n", "can't create a child thread:", error_message);
return FAILED;
}
return SUCCESS;
}
int main() {
pthread_t child_thread;
if (try_create_thread(&child_thread) == FAILED) {return FAILED;}
sleep(WAIT_TIME);
if (try_cancel_thread(&child_thread) == FAILED) {return FAILED;}
printf("the execution is succefully completed\n");
return SUCCESS;
}
#undef SUCCESS
#undef FAILED
#undef WAIT_TIME
#undef PRINT_DELTA_TIME
output:
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
Child thread text
the execution is succefully completed
Related
I'm writing a program in c, which make use of threads, and i also want to catch Ctrl+C signal from the user. So, before i go multithreading, i make the signal catching.
My main thread (i mean besides the actual main thread that the program runs on), is a method to deal with user input, and i also join this thread to the main program thread.
The problem is, when testing and hitting Ctrl+C to exit program,
the thread responsible for receiving user input doesn't close until i hit "return" on my keyboard - like its stuck on infinite loop.
When exiting by typing 'q', all threads end up properly.
I use a global variable exit_flag to indicate the threads to finish their loops.
Also, in init_radio_stations method there's another single thread creation, that loops in the exact same way - on the exit_flag status, and this thread DOES close properly
Here's my main loop code:
void main_loop()
{
status_type_t rs = SUCCESS;
pthread_t thr_id;
/* Catch Ctrl+C signals */
if(SIG_ERR == signal(SIGINT, close_server)) {
error("signal() failed! errno = ");
}
printf("\n~ Welcome to radio_server! ~\n Setting up %d radio stations... ", srv_params.num_of_stations);
init_radio_stations();
printf("Done!\n\n* Hit 'q' to exit the application\n* Hit 'p' to print stations & connected clients info\n");
/* Create and join a thread to handle user input */
if(pthread_create(&thr_id, NULL, &rcv_usr_input, NULL)) {
error("main_loop pthread_create() failed! errno = ");
}
if(pthread_join(thr_id, NULL)) {
error("main_loop pthread_join() failed! errno = ");
}
}
close_server method:
void close_server(int arg)
{
switch(arg) {
case SIGINT: /* 2 */
printf("\n^C Detected!\n");
break;
case ERR: /* -1 */
printf("\nError occured!\n");
break;
case DEF_TO: /* 0 */
printf("\nOperation timed-out!\n");
break;
default: /* will handle USER_EXIT, and all other scenarios */
printf("\nUser abort!\n");
}
printf("Signaling all threads to free up all resources and exit...\n");
/* Update exit_flag, and wait 1 sec just in case, to give all threads time to close */
exit_flag = TRUE;
sleep(1);
}
And rcv_usr_input handle code:
void * rcv_usr_input(void * arg_p)
{
char in_buf[BUFF_SIZE] = {0};
while(FALSE == exit_flag) {
memset(in_buf, 0, BUFF_SIZE);
if(NULL == fgets(in_buf, BUFF_SIZE, stdin)) {
error("fgets() failed! errno = ");
}
/* No input from the user was received */
if('\0' == in_buf[0]) {
continue;
}
in_buf[0] = tolower(in_buf[0]);
if( ('q' == in_buf[0]) && ('\n' == in_buf[1]) ) {
close_server(USER_EXIT);
} else {
printf("Invalid input!\nType 'q' or 'Q' to exit only\n");
}
}
printf("User Input handler is done\n");
return NULL;
}
I'm guessing my problem is related to joining the thread that uses rcv_usr_input at the end of my main loop, but i can't figure out what exactly causing this behavior.
I'll be glad to get some help, Thanks
Mike and Kaylum have correctly identified the fundamental problem of blocking by fgets(). The larger issue remains, however: how to terminate a blocking thread when the process receives a SIGINT. There are several solutions.
Thead Detachment:
One solution is to detach the blocking thread because detached threads do not prevent the process from terminating when the last non-detached thread terminates. A thread is detached either by calling pthread_detach() on it, e.g.,
#include <pthread.h>
// Called by pthread_create()
static void* start(void* arg)
{
pthread_detach();
...
}
or by creating the thread with the PTHREAD_CREATE_DETACHED attribute, e.g.,
#include <pthread.h>
...
pthread_attr_t attr;
(void)pthread_attr_init(&attr);
(void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
...
(void)pthread_t thread;
(void)pthread_create(&thread, &attr, ...);
Note that pthread_join() should not be called on a detached thread.
Signal Forwarding: Another solution is not to detach the blocking thread but to forward signals like SIGINT to the thread via pthread_kill() if the signal has not been received on the blocking thread, e.g.,
#include <pthread.h>
#include <signal.h>
...
static pthread_t thread;
...
static void handle_sigint(int sig)
{
if (!pthread_equal(thread, pthread_self()) // Necessary
(void)pthread_kill(thread, SIGINT);
}
...
sigaction_t sigaction;
sigaction.sa_mask = 0;
sigaction.sa_flags = 0;
sigaction.sa_handler = handle_sigint;
(void)sigaction(SIGHUP, &sigaction, ...);
...
(void)pthread_create(&thread, ...);
...
(void)pthread_join(thread, ...);
...
This will cause the blocking function to return with errno set to EINTR.
Note that use of signal() in a multi-threaded process is unspecified.
Thread Cancellation: Another solution is to cancel the blocking thread via pthread_cancel(), e.g.,
#include <pthread.h>
...
static void cleanup(...)
{
// Release allocated resources
...
}
...
static void* start(void* arg)
{
pthread_cleanup_push(cleanup, ...);
for (;;) {
...
// Call the blocking function
...
}
pthread_cleanup_pop(...);
...
}
....
static void handle_sigint(int sig)
{
(void)pthread_cancel(thread);
}
...
sigaction_t sigaction;
sigaction.sa_mask = 0;
sigaction.sa_flags = 0;
sigaction.sa_handler = handle_sigint;
(void)sigaction(SIGHUP, &sigaction, ...);
...
(void)pthread_create(&thread, ..., start, ...);
...
(void)pthread_join(thread, ...);
...
There is yet another solution for threads that block in a call to select() or poll(): create a file descriptor on which the blocking function also waits and close that descriptor upon receipt of an appropriate signal -- but that solution is, arguably, beyond the scope of this question.
According to http://www.cplusplus.com/reference/cstdio/fgets/, fgets blocks until the specified number of bytes have been read.
I suggest trying fread or some other input reception function that isn't blocking and then read only one byte at a time. Here's sample code to help you:
if (fread(in_buf, 1,1, stdin) > 0){
//character has been read
}
And I wouldn't worry about the extra sleep statement in your signal handler as it causes delays in forceful exiting at best.
The explanation is straight forward.
fgets(in_buf, BUFF_SIZE, stdin);
That call blocks the thread until it receives a line of input. That is, it does not return until a newline is input or BUFF_SIZE-1 characters are input.
So even though the signal handler sets exit_flag to FALSE, the rcv_usr_input thread will not see that until it unblocks from fgets. Which happens when you pressed "return".
I want to know if its possible to interrupt main thread and ask it to execute some callback. The main thread should continue with what it was doing after completing the callback.
For instance, we have 2 threads t1 and m1 (main thread). t1 will interrupt m1 (main thread) and ask it to call a function with some parameters. The m1 (main thread) will stop doing what it was doing before and will start executing the function. The after finishing the function, it will get back to what it was doing earlier.
I want to replicate what hardware interrupt does. I have one thread that reads data from a file. Then it should ask main thread to call a function. Main thread will be doing something. It should stop doing it and start executing the function. After completing it, main thread should continue with what it was doing
I have written following code using signals
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
static void catch_function(int signo) {
int id = GetCurrentThreadId();
printf("\nThread ID is %d",id);
signal(SIGINT, catch_function);
}
DWORD WINAPI MyThreadFunction( LPVOID lpParam )
{
int id = GetCurrentThreadId();
printf("\nChild Thread ID is %d",id);
while(1)
{
Sleep(50);
if (raise(SIGINT) != 0) {
fputs("Error raising the signal.\n", stderr);
return EXIT_FAILURE;
}
}
return 0;
}
int main(void) {
int id = GetCurrentThreadId();
printf("\nMain Thread ID is %d",id);
if (signal(SIGINT, catch_function) == SIG_ERR) {
fputs("An error occurred while setting a signal handler.\n", stderr);
return EXIT_FAILURE;
}
HANDLE thread;
DWORD threadId;
thread = CreateThread(NULL, 0, &MyThreadFunction, NULL, 0, &threadId);
if(!thread)
{
printf("CreateThread() failed");
}
while(1)
{
Sleep(50);
}
return 0;
}
The output of code is
Main Thread ID is 6124
Child Thread ID is 7854
Thread ID is 7854
Thread ID is 7854
So my question is should not the signal handler be called in Main thread? I want main thread to call the handler function not the thread which raise the signal?
please let me know what is the correct way of achieving this.
PS. I have to do it for both windows and linux.
I can only offer advice from a Linux side, but as you said that was of interest too then...
... raise does the following (from the manual page):
The raise() function sends a signal to the calling process or thread.
So in a multi-threaded program it is the thread that calls raise that will get the signal.
On Linux, for threading, you'll probably be using pthreads, in which case you have pthread_kill, this sends a specific signal to a specific thread. You'd need to use pthread_self in the main thread to get the thread id, then pass this to the worker thread. The worker thread can then send signals directly to the main thread.
I suspect you need to find something similar for Windows, but that's not something I know about.
The only one that can interrupt a thread is itself or the Task Scheduler.
If you were to stop someone else you would need direct access to timer hardware.
You can do what Ed Heal said. Use conditional variables and semaphores. My advice is to build up a linked list or even just an array storing what to do and who is the one wich should do it.
See what Windows does to send messages to the program in "event-driven UI".
A MSG struct is given to the application with some integers, like message code, WPARAM and LPARAM.
Define a structure of your own and use it to send messages to each thread (some form of interprocess communication). And, that's important, set a timer to a callback function or keep with your Sleep(50) (or more) to not keep "bothering" your processor for nothing.
Hope this helps and sorry for bad english.
I got a problem in C when I try to pause an execution of a system() call.
A thread calls some application (e.g. some benchmark) repeatedly. Whenever it gets a signal SIGUSR1, the execution shall be paused and resumed on receiving SIGUSR2.
The source looks like this:
#include <signal.h>
#include <pthread.h>
void* run_app(sigset_t* signalsBetweenControllerandLoad)
{
/* assign handler */
signal(SIGUSR1, pausesignal_handler)
signal(SIGUSR2, pausesignal_handler)
pthread_sigmask(SIG_UNBLOCK, signalsBetweenControllerandLoad, NULL))
/* call application repeatedly */
while(1) {
system(SOMECOMMAND);
}
return(0);
}
static void pausesignal_handler(int signo)
{
int caughtSignal;
caughtSignal = 0;
/* when SIGUSR1 is received, wait until SIGUSR2 to continue execution */
if (signo == SIGUSR1) {
signal(signo, pausesignal_handler);
while (caughtSignal != SIGUSR2) {
sigwait (signalsBetweenControllerandLoad, &caughtSignal);
}
}
}
When I use some commands (e.g. a for loop as below that makes some computations) instead of system(SOMECOMMAND) this code works. But a program called by system() is not paused when the handler is active.
int i;
for(i=0;i<10;i++) {
sleep(1);
printf("Just a text");
}
Is there a way to pause the execution of the system() command by using thread signals? And is there even a way to stop the application called by system without needing to wait until the program is finished?
Thank you very much in advance!
system runs the command in a separate process, which doesn't even share address space with the invoking program, never mind signal handlers. The process which called system is sitting in a waitpid (or equivalent), so pausing and unpausing it will have little effect (except that if it is paused, it won't return to the loop to call system again.)
In short, there is no way to use signals sent to the parent process to pause an executable being run in a child, for example with the system() call or with fork()/exec().
If the executable itself implements the feature (which is unlikely, unless you wrote it yourself), you could deliver the signal to that process, not the one which called system.
Alternatively, you could send the SIGSTOP signal to the executable's process, which will unconditionally suspend execution. To do that, you'll need to know its pid, which suggests the use of the fork()/exec()/waitpid() sequence -- a little more work than system(), but cleaner, safer, and generally more efficient -- and you'll need to deal with a couple of issues:
A process cannot block or trap SIGSTOP, but it can trap SIGCONT so the sequence is not necessarily 100% transparent.
Particular care needs to be taken if the stopped process is the terminal's controlling process, since when it is resumed with SIGCONT it will need to reacquire the terminal. Furthermore, if the application has placed the terminal in a non-standard state -- for example, by using the readline or curses libraries which typically put the terminal into raw mode and disable echoing -- then the terminal may be rendered unusable.
Your process will receive a SIGCHLD signal as a result of the child processed being stopped. So you need to handle that correctly.
I want to present you my (shortened) resulting code after the help of #rici. Again, thank you very much.
Shortly described, the code forks a new process (calling fork) and executes there a command with exec. The parent then catches user defined signals SIGNAL_PAUSE and SIGNAL_RESUME and forwards signals to the forked child accordingly. Whenever the command finishes - catched by waitpid - the parent forks again and restarts the load.
This gets repeated until SIGNAL_STOP is sent where the child gets a SIGINT and gets cancelled.
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#define SIGNAL_PAUSE (SIGUSR1)
#define SIGNAL_RESUME (SIGUSR2)
#define SIGNAL_STOP (SIGSYS)
/* File scoped functions */
static void pausesignal_handler(int signo);
static void stopsignal_handler(int signo);
void send_signal_to_load_child(int signo);
/*Set file scope variables as handlers can only have signal-number as argument */
sigset_t* signalsBetweenControllerandLoad;
int restart_benchmark;
pid_t child_pid;
void* Load(char* load_arguments[MAX_NR_LOAD_ARGS], sigset_t* signalsToCatch) {
int load_ID;
pid_t p;
signalsBetweenControllerandLoad = signalsToCatch;
/* set signal handlers to catch signals from controller */
signal(SIGNAL_PAUSE, pausesignal_handler)
signal(SIGNAL_RESUME, pausesignal_handler)
signal(SIGNAL_STOP, stopsignal_handler)
pthread_sigmask(SIG_UNBLOCK, signalsBetweenControllerandLoad[load_ID], NULL)
/* Keep restarting benchmark until Stop signal was received */
restart_benchmark[load_ID] = 1;
/* execute benchmark, repeat until stop signal received */
while(restart_benchmark[load_ID])
{
if (child_pid == 0) {
if ((p = fork()) == 0) {
execv(load_arguments[0],load_arguments);
exit(0);
}
}
/* Parent process: Wait until child with benchmark finished and restart it */
if (p>0) {
child_pid = p; /* Make PID available for helper functions */
wait(child_pid); /* Wait until child finished */
child_pid = 0; /* Reset PID when benchmark finished */
}
}
return(0);
}
static void pausesignal_handler(int signo) {
static double elapsedTime;
int caughtSignal;
caughtSignal = 0;
if (signo == SIGNAL_PAUSE) {
send_signal_to_load_child(SIGSTOP);
printf("Load Paused, waiting for resume signal\n");
while (restart_benchmark == 1 && caughtSignal != SIGNAL_RESUME) {
sigwait (signalsBetweenControllerandLoad, &caughtSignal);
if (caughtSignal == SIGNAL_STOP) {
printf("Load caught stop signal when waiting for resume\n");
stopsignal_handler(caughtSignal);
} else if (caughtSignal != SIGNAL_RESUME) {
printf("Load caught signal %d which is not Resume (%d), keep waiting...\n",caughtSignal,SIGNAL_RESUME);
}
}
if (restart_benchmark[load_ID]) {
send_signal_to_load_child(SIGCONT, load_ID);
printf("Load resumed\n");
}
} else {
printf("Load caught unexpected signal %d.\n",signo);
}
/* reassign signals for compatibility reasons */
signal(SIGNAL_PAUSE, pausesignal_handler);
signal(SIGNAL_RESUME, pausesignal_handler);
}
static void stopsignal_handler(int signo) {
double elapsedTime;
signal(SIGNAL_STOP, stopsignal_handler);
if (signo == SIGNAL_STOP) {
restart_benchmark = 0;
send_signal_to_load_child(SIGINT);
printf("Load stopped.\n");
} else {
printf("catched unexpected stop-signal %d\n",signo);
}
}
void send_signal_to_load_child(int signo) {
int dest_pid;
dest_pid = child_pid;
printf("Error sending %d to Child: PID not set.\n",signo);
kill(dest_pid, signo);
}
void main ( )
{ int x;
signal (SIGUSR1, f);
x= fork ( );
if (x == -1) exit (1);
if (x != 0)
{ kill (x, SIGUSR1) ;
sleep (2);
exit (0);
}
}
void f ( )
{
printf ("signal received");
exit (0);
}
I think that the program above asks the system to launch the f function ( which displays "signal received" ) when the SIGUSR1 signal is received by the parent process. but I'm not sure about that, please feel free to correct or to give more details. Thank for the help !
There are some mistakes in your code:
Avoid calling printf( ) function in signal handler. SIGNAL(7) manual provides a list of authorized functions calling them is safe inside signal-handlers. Read:
Async-signal-safe functions
A signal handler function must be very careful, since processing
elsewhere may be interrupted at some arbitrary point in the execution
of the program. POSIX has the concept of "safe function". If a
signal interrupts the execution of an unsafe function, and handler
calls an unsafe function, then the behavior of the program is
undefined.
Use return type of main() int; read "What should main() return in C?"
x should be pid_t. (Process Identification).
Now lets suppose your program compile and run (not interrupted by any other signal while handler executing):
I am just indenting your code and shifting f() function definition before main because function declaration is missing, also adding some comments that you should read:
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
void f( )
{
printf ("signal received\n");
exit (0);//if child receives signal then child exits from here
} // ******* mostly happens
int main ( )
{ int x;
signal (SIGUSR1, f);// First: handler registered
x = fork ( ); // Second: Child created, now child will execute in
if (x == -1) // parallel with parent
exit (1);
if (x != 0) {// parent
kill(x, SIGUSR1) ; // Third: sends signal to child
sleep(2); // Forth: parent sleep
}
return 0; // parent always exits
// Child can exits from here ****
// if signal sent from parent delayed
}
In main() function, you registers f() function for SIGUSR1 signal and after that calls fork() to create a new process. In runtime as fork() function returns a child-process starts executing in parallel with parent process.
As I can see your code, I think that you understands that child-process is copy of parent-process except values of variables can be different from the point fork() returns and hence x is different in child and parent process. We can use the return value from fork to tell whether the program is running in the parent-process or in child. But note that it is not parent but actually the child-process that receives signal SIGUSR1. Value of self process id is always 0 for any process. You checks the return value x = fork() that is pid of newly created child-process, in child-process value of x is 0 and in parent x != 0. Hence signal is sent from parent process to child process.
Your comments:
I think that the program above asks the system to launch the f( ) function ( which displays "signal received") when the SIGUSR1 signal is received by the parent process.
I have impression that you don't consider that both processes execute concurrently and "it can be happen that soon after fork() create a child-process, child-process start executing and immediately terminate before parent-process can send a signal to child (or child-process can receive the signal)". In that case, function f() will never get a chance to execute and printf in signal handler never prints.
But the possibility of what I have described just above is very low because fork takes time to create a new process. And even if you execute the code again and again most of the times signal sent from the parent process will execute signal-handler.
What is correct way of writing this code?
Code is x.c: Correct way is set a flag that indicates that signal handler executed and then call printf function on the bases of flag value outside signal-handler as I have described in my answer: How to avoid using printf in a signal handler? And reason behind it explained by Jonathan Leffler in his answer.
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
volatile sig_atomic_t flag = 0; //initially flag == 0
void f(){
flag = 1; // flag is one if handler executes
}
int main(void){
pid_t x;
(void) signal (SIGUSR1, f);
x = fork();
if(x == -1)
exit(EXIT_FAILURE);
if (x != 0){// parent
kill(x, SIGUSR1);
sleep(1);
}
if(flag)//print only if signal caught and flag == 1
printf("%s signal received \n", x == 0 ? "Child:" : "Parent:");
return EXIT_SUCCESS;
}
Now compile it and execute:
#:~$ gcc -Wall -pedantic -std=c99 x.c -o x
#:~$ ./x
Child: signal received
#:~$
Notice child-process prints because parent sends signal to child(but parent process doesn't prints as no signal catch in parent). So behavior of above code still similar as you was getting in your code. Below I have added one more example in which I am trying to demonstrate that 'concurrent execution of processes results different at different instance of execution'(read comments).
// include header files...
volatile sig_atomic_t flag = 0;
void f(){
flag = 1;
}
int main(void){
pid_t x;
(void) signal (SIGUSR1, f);
(void) signal (SIGUSR2, f); // added one more signal
x= fork ( );
if(x == -1)
exit(EXIT_FAILURE);
if (x != 0){// parent
kill(x, SIGUSR1);
while(!flag); // in loop until flag == 0
}
if (x == 0){//child
kill(getppid(), SIGUSR2); // send signal to parent
while(!flag); // in loop until flag == 0
}// ^^^^ loop terminates just after signal-handler sets `flag`
if(flag)
printf("%s signal received \n", x == 0 ? "Child:" : "Parent:");
return EXIT_SUCCESS;
}
In above code, two signals are registered in both parent and child process. Parent process doesn't sleeps but busy in a while loop until a signal sets flag. Similarly child-process has a loop that breaks as flag becomes 1 in signal-handler. Now compile this code and run repeatedly. I frequently tried an got following output in my system.
#:~$ gcc -Wall -pedantic -std=c99 x.c -o x
#:~$ ./x
Child: signal received
Parent: signal received
#:~$ ./x
Child: signal received
Parent: signal received
#:~$ ./x
Child: signal received
Parent: signal received
#:~$ ./x
Parent: signal received // <------
#:~$ Child: signal received
./x
Child: signal received
Parent: signal received
#:~$ ./x
Parent: signal received // <------
#:~$ Child: signal received
#:~$
Notice output, one case is: "till child process created parent sent signal and enter in while-loop and when child-process get chance to execute(depends on CPU scheduling) it send back a signal to parents and before parent process get chance to execute child receives signal and prints message". But it also happens sometimes that before child printf print; parent receives and print message (that is I marked using arrow).
In last example I am trying to show child-process executes in parallel with parent- process and output can be differs if you don't applies concurrency control mechanism.
Some good resource To learn signals (1) The GNU C Library: Signal Handling
(2) CERT C Coding Standard 11. Signals (SIG).
One problem is that the child process doesn't do anything, but will return immediately from the main function, maybe before the parent process can send the signal.
You might want to call e.g. pause in the child.
For the sake of the exercise, here is a corrected version of the original code which will compile and run.
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <bits/signum.h>
void f ( );
int main ( )
{ int x;
signal (SIGUSR1, f);
x= fork ( );
if (x == -1) exit (1);
if (x != 0)
{ kill (x, SIGUSR1) ;
sleep (2);
exit (0);
}
}
void f ( )
{
printf ("signal received\n");
exit (0);
}
This does exactly what the original question suggested the program should do. Try it out and see what happens if you don't believe me.
BTW: I'm not very experienced at C. There are a number of comments asserting that using printf() in the child process is unsafe. Why?? The child process is a duplicate of the parent including virtual address space. So why is printf() unsafe?
I am building a simple debugger for my university class and I have a problem in handling SIGINT.
What I want to do is when the debugger process (from now on PDB) takes a SIGINT signal passes that to the child process (the one that is being actually debugged by PDB).
I am doing this:
pid_t childid;
void catch_sigint(int sig)
{
signal(SIGINT,SIG_DFL);
kill(childid,sig);
}
int debuger (char *address, parm *vars)
{
int ignore=1;
int status;
childid = fork();
signal(SIGINT,catch_sigint);
if(childid==0)
{
ptrace(PTRACE_TRACEME,0, NULL,NULL);
if(execve(address,NULL,NULL)==-1)
{
perror("ERROR occured when trying to create program to trace\n");
exit(1);
}
}
else
{
int f_time=1;
while(1)
{
long system_call;
wait(&status);
if(WIFEXITED(status))break;
if(WIFSIGNALED(status))break;
system_call = ptrace(PTRACE_PEEKUSER,childid, 4 * ORIG_EAX, NULL);
if(!strcmp(vars->category,"process-control") || !strcmp(vars->category,"all"))
ignore = pr_calls(system_call,ignore,limit,childid,vars->mode); //function that takes the system call that is made and prints info about it
if(!strcmp(vars->category,"file-management") || !strcmp(vars->category,"all"))
ignore = fl_calls(system_call,ignore,limit,childid,vars->mode);
if(f_time){ignore=1;f_time=0;}
ptrace(PTRACE_SYSCALL,childid, NULL, NULL);
}
}
signal(SIGINT,SIG_DFL);
return 0;
}
This program runs and forks a child process and execs a program to trace its system calls. That works fine when it doesn't get any signal.
But when in the middle of some tracing I press ctrl+c I expect the child process to stop and PDB to continue and stop (because of this line if(WIFSIGNALED(status))break;. That never happens. The program it traces continues its system calls and prints.
The tracing program is that:
#include <stdio.h>
int main(void)
{
for(;;) printf("HELLO WORLD\n");
return 0;
}
That program continues printing HELLO WORLD even after I hit ctrl+c.
I also observed that the system calls that ptrace gives after ctrl+c are -38 and that the status in wait changes only once after the signal from 1407 (I think is the normal value) to 639 and then back again to 1407 on the next wait.
So what I am doing wrong in that?
The problem it's on this line:
ptrace(PTRACE_SYSCALL,childid, NULL, NULL);
It has to be like that:
ptrace(PTRACE_SYSCALL,childid, NULL, signal_variable);
Where signal_variable is an int declared in global scope so the handler and the debugger can see it. It has a starting value of 0.
The signal handler now takes the signal and passes it in this variable and at the next loop when the ptrace orders the tracee program to continue it sends it the signal too.
That happens because when you trace a program the tracee stops execution when it receives a signal and waits further instruction for what to do with the signal from the tracer through ptrace.