Interrupting c/c++ readline with signals - c

I'm attempting to interrupt readline with signals (SIGUSR1), but obviously if the signal isn't handled, the program exits, when handling, it readline proceeds as though nothing has happened. Is readline supposed to be able to be interrupted using signals.
I got the idea from this other question: force exit from readline() function
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <readline/readline.h>
#include <pthread.h>
pthread_t main_id;
void *thread_main(void* arg)
{
sleep(10);
pthread_kill(main_id, SIGUSR1);
}
void signal_handler(int sig)
{
puts("got signal");
(void) sig;
}
int main(int argc, char** argv)
{
struct sigaction sa;
sa.sa_handler = signal_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
main_id = pthread_self();
pthread_t id;
pthread_create(&id, NULL, thread_main, NULL);
char *input = readline("prompt> ");
puts("main thread done");
return 0;
}
The output:
$ ./test
prompt> got signal
enter something
main thread done
$
Thanks.

Joachim Pileborg answered this question in a comment.
The best solution seems to be using the readline alternate interface. The docs are at http://www.delorie.com/gnu/docs/readline/rlman_41.html
Also an extremely basic example at http://www.mcld.co.uk/blog/blog.php?274 that just needs to be adapted to use select instead of polling with sleep.
Much better than using signals!

Change your signal_handler function:
void signal_handler(int sig)
{
puts("got signal");
//(void) sig;
exit(sig);
}

libreadline's default implementation of reading a character (int rl_getc(FILE *)) does handle EINTR (returned by read() if signalled) in a way of simply re-read()ing. Due to this receiving a signal does not cancel the readline().
To work around this you might set the function pointer rl_getc_function to your own implementation to read a character (rl_getc_function points to rl_getc() by default).

Related

Why the signal handler doesn't process the signal

I'm trying to make a program that simulates the command nohup. The program gets as a first parameter, the name of a command that is gonna be executed.
The program executed by my program must not be notified when the terminal is closed, it will have to ignore the SIGHUP.
If I test my program with with the following command:
./mynohup sleep 120 &
And then I try to send a SIGHUP from another terminal, sleep terminates when it should be immune to it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include "utils.h"
#define NOHUP_OUT_FILE "nohup.out"
static void handle_signal(int signum)
{
if(signum == SIGHUP)
{
printf("This is ignored\n");
}
else
{
printf("Not ignored\n");
}
fflush(stdout);
}
/* configure handlers */
static void set_signals(void)
{
struct sigaction sa;
int rc;
/* TODO - ignore SIGHUP */
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = handle_signal;
rc = sigaction(SIGHUP, &sa, NULL);
DIE(rc == -1, "sigaction");
}
/* execute a new program */
static void exec_func(int argc, char **argv)
{
int rc;
int i;
char **exec_args;
int fd;
set_signals(); /* ignore SIGHUP */
if(isatty(STDOUT_FILENO))
{
fd = open(NOHUP_OUT_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
DIE(fd < 0, "open");
dup2(fd, STDOUT_FILENO);
close(fd);
}
/* exec a new process */
exec_args = malloc(argc * sizeof(*exec_args));
DIE(exec_args == NULL, "malloc");
for (i = 0; i < argc-1; i++)
exec_args[i] = argv[i+1];
exec_args[argc-1] = NULL;
execvp(exec_args[0], exec_args);
DIE(1, "execvp");
}
int main(int argc, char **argv)
{
if (argc <= 1) {
fprintf(stderr, "Usage: %s command_and_arguments\n", argv[0]);
exit(EXIT_FAILURE);
}
exec_func(argc, argv);
return 0;
}
I tried to skip creating a new process and the signal handler works great.
If the signal handler is in the following form the program works
static void set_signals(void)
{
struct sigaction sa;
int rc;
/* ignore SIGHUP */
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
rc = sigaction(SIGHUP, &sa, NULL);
DIE(rc == -1, "sigaction");
}
I don't understand why when I create the first version of the signal handler the program doesn't works and with the second one it works.
Thanks in advance!
All exec functions reset the dispositions of caught signals to their default dispositions.
When you exec, your process image is destroyed and replaced by the process image of the new program. In it, the pointer to the handle_function you passed to sigaction no longer has meaning, or the old meaning at least. The only sensible thing the OS can do with handled signals upon execve is to reset them.
The meaning of SIG_IGN is universal and independent of the current program and that's why SIG_IGN can be, and is, inherited.
execvp() is a front end for the execve() syscall.
From its linux manpage:
All process attributes are preserved during an execve(), except the following:
* The dispositions of any signals that are being caught are reset to
the default (signal(7)).
So the signal handler you installed is reset.
CORRECTION: (see history of changes for original text)
The nohup(1) program just shifts the progran name (nohup) and the options to it, from the argc/argv parameters to main, redirects stdout/stderr to a file (nohup.out) in case one or both are directed to a tty device, and then just ignores SIGHUP and execvp(*argv, argv); for the original program to execute. It even does no fork(2) at all.
The source code of FreeBSD nohup is available here.

signal handler in child thread

I tried to install SIGINT handler for the child thread in the code below. I expect the child thread to print hello when it receives SIGINT from the parent process. However, nothing comes out and the program exits immediately.
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
typedef struct proxy_node_t{
pthread_t sub_thread;
pthread_t p_self;
}proxy_node;
proxy_node* proxy;
static void proxy_singnal_handler(){
printf("Hello\n");
return;
}
static void* t_consensus(void *arg){
signal(SIGINT,proxy_singnal_handler);
sleep(1);
return NULL;
}
int main(int argc, char **argv)
{
proxy = (proxy_node*)malloc(sizeof(proxy_node));
proxy->p_self = pthread_self();
pthread_create(&proxy->sub_thread,NULL,t_consensus,NULL);
pthread_kill(proxy->sub_thread,SIGINT);
sleep(1);
return 0;
}
There are several problems.
1) The signal handler signature is not correct. It should take an int whereas you define it with no parameter.
i.e.
static void proxy_singnal_handler(){
should be
static void proxy_singnal_handler(int sig){
2) You can't call functions that are not async-signal-safe from a signal handler (printf() in your case). See signal(7) for details. You can instead use write(2) to print that message:
printf("Hello\n");
can be:
write(1, "Hello\n", 6);
3) When main thread sends SIGINT, the t_consensus thread might not have even started. So, signal() may not have been installed yet. So, you need to make sure signal() is installed before pthread_kill() could send SIGINT.
Just to demonstrate it, I have added some sleep calls (see comments in the code). But please note that sleep() is not a good way to synchronization and if you intend to adapt this example then you should use a conditional variable instead.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
typedef struct proxy_node_t{
pthread_t sub_thread;
pthread_t p_self;
}proxy_node;
proxy_node* proxy;
static void proxy_singnal_handler(int sig){
write(1, "Hello\n", 6);
return;
}
static void* t_consensus(void *arg){
signal(SIGINT,proxy_singnal_handler);
while(1); /* infinite loop */
return NULL;
}
int main(int argc, char **argv)
{
proxy = (proxy_node*)malloc(sizeof(proxy_node));
proxy->p_self = pthread_self();
pthread_create(&proxy->sub_thread,NULL,t_consensus,NULL);
sleep(2); /* delay to ensure signal handler is installed */
pthread_kill(proxy->sub_thread,SIGINT);
sleep(2); /* delay to ensure signal gets executed before the process exits */
return 0;
}
Since #Maxim Egorushkin wanted to see a solution that exits gracefully and uses semaphores:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>
typedef struct proxy_node_t{
pthread_t sub_thread;
pthread_t p_self;
}proxy_node;
proxy_node* proxy;
static void proxy_singnal_handler(int sig)
{
write(1, "Hello\n", 6);
return;
}
sem_t sema1;
sem_t sema2;
static void* t_consensus(void *arg)
{
signal(SIGINT,proxy_singnal_handler);
sem_post(&sema1); /*notify main thread that signal-handler is installed*/
sem_wait(&sema2); /*ensure thread exists to be pthread_kill'ed, could use sigsuspend instead*/
return NULL;
}
int main(int argc, char **argv)
{
sem_init(&sema1, 0, 0);
sem_init(&sema2, 0, 0);
proxy = (proxy_node*)malloc(sizeof(proxy_node));
proxy->p_self = pthread_self();
pthread_create(&proxy->sub_thread,NULL,t_consensus,NULL);
sem_wait(&sema1); /*wait until the thread has installed the signal handler*/
pthread_kill(proxy->sub_thread,SIGINT);
sem_post(&sema2); /*not strictly necessary if the thread uses sigsuspend*/
pthread_join(proxy->sub_thread, NULL);
free(proxy); /*not strictly necessary before exiting*/
sem_destroy(&sema1);
sem_destroy(&sema2);
return 0;
}

sigaction's signal handler not called in child process

I've a program, which installs a signal handler for SIGSEGV. In signal handler ( I try to catch crash ) I restart my application.
But when my application is resurrected it doesn't handle SIGSEGV anymore.
Here's an example:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
const char * app = 0;
void sig_handler(int signo)
{
puts("sig_handler");
const pid_t p = fork();
if (p == 0)
{
printf("Running app %s\n", app);
execl(app, 0);
}
exit(1);
}
int main(int argc, char** argv)
{
app = argv[0];
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler = sig_handler;
act.sa_flags = 0;
const int status = sigaction(SIGSEGV, &act, 0) == 0;
printf("signaction = %d\n", status);
sleep(5);
int* a = 0;
int b = *a;
return 0;
}
what I get in output is:
./signals
signaction = 1
sig_handler
Running app ./signals
signaction = 1
So I can see sighandler was set in right way, but resurrected app simply crashed silently.
What am I missing?
What you're missing is that, by default, when you handle a signal, any additional delivery of that signal is blocked until the handling function returns. Since you never return from your signal handler (you call execl() instead) then your second SIGSEGV isn't being delivered. It's waiting until your signal handler function returns, which it never will.
To get the results you seem to want, you have to change this default behavior. The easiest way to do that is to set the appropriate flag when you register the signal handler:
act.sa_flags = SA_NODEFER;
and you'll get the recursive behavior you seem to be looking for. Your other option is to unblock it with sigprocmask() before your execl() call.
Couple of other ancillary points:
puts(), printf(), execl() and exit() are not async-safe, and shouldn't be called from a signal handler. execle() and _exit() would be OK.
You're not calling execl() properly. The first argument should be the application name, so execl(app, app, (char *)0); would be correct. The cast to char *, which you omit, is required.

C - Processes in linux handle with any signal

I'm writing code that have process who have to handle with any signal i gave him. I read that i should do something like that
void signalHandler(int sig_num)
{
// some stuff
}
//My process
int i;
for (i = 1; i <= 64; i++)
signal(i, signalHandler);
Is this correct solution ??
Although #Dylan's solution seems good and it is but it poses the a common problem and that is compatibility issue with signal function. It is hence recommended that you use sigaction always. Here is an example
#include <stdio.h>
#include <signal.h>
static void handler(int signo){
write(stdout, &signo, sizeof(int));
}
int main() {
struct sigaction sa;
sa.sa_handler = handler;
int i;
for (i = 1; i <= 64; i++) {
sigaction(i, &sa, NULL);
}
while(1);
return 0;
}
Try to avoid the use of signal as much as possible
Never use any function which are not Reentrant or not Async-signal-safe functions in signal handler like printf
Check the list of allowed functions in signal handler from here
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2)
requires an implementation to guarantee that the following functions
can be safely called inside a signal handler:
You are on the right track if you want to handle signals 1 through 64 with the same signal handler. This test program will handle signals 1 through 64 by printing out its number.
#include <stdio.h>
#include <signal.h>
void signalHandler(int sig_num)
{
printf("Signal %d caught!\n", sig_num);
}
int main(int argc, char const *argv[])
{
//My process
int i;
for (i = 1; i <= 64; i++) {
signal(i, signalHandler);
}
while (1);
return 0;
}
For example, when you press CTRL+C while this program is running. The kernel sends signal 2 SIGINT to the program, and calls signalHandler(2). This program prints "Signal 2 caught!"
Post-Facepalm edit: this program obviously needs to be terminated with a kill -9 command........

how to intercept linux signals ? (in C)

I need to intercept and trace signals from any binaries, like strace does it under linux.
I don't need a so verbose output like the real one strace.
I just want to know how it works, how can I intercept signal and how can I trace them.
Thanks in advance :)
strace uses the ptrace() system call for tracing, which also allows you to intercept (and possibly manipulate) signals sent to the process.
Here's a tiny example:
#include <sys/ptrace.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
/* simple example, child is traced, uses alarm which causes a signal to be
* set up */
pid_t child;
child = fork();
if (child == 0)
{
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
alarm(3);
while(1)
{
}
exit(0);
}
/* parent */
while(1)
{
int wstatus;
int signum;
wait(&wstatus);
if (WIFEXITED(wstatus) || WIFSIGNALED(wstatus))
break;
signum = WSTOPSIG(wstatus);
printf("child stopped with signal %d\n", signum);
/* resume execution */
ptrace(PTRACE_CONT, child, NULL, signum);
}
return 0;
}
This is a simple implementation:
Put somewhere in your int main() several calls to signal(), one for each signal you want to catch. The first argument is the signal name; the second is the signal handler function (more on that below):
signal(SIGFPE, SignalHandler);
signal(SIGILL, SignalHandler);
signal(SIGINT, SignalHandler);
signal(SIGSEGV, SignalHandler);
signal(SIGTERM, SignalHandler);
#ifndef WIN32
signal(SIGHUP, SignalHandler);
signal(SIGQUIT, SignalHandler);
signal(SIGKILL, SignalHandler);
signal(SIGPIPE, SignalHandler);
signal(SIGCHLD, SignalHandler);
#endif
Now, write a signal function. It must return void and accept an int: void SignalHandler(int signal_number):
void SignalHandler(int signal_number)
{
printf("Received signal: %s\n", strsignal(signal_number);
// Do something
}
That's it! You can also test it by sending a signal to yourself with the function raise(SIGNAL_NAME); for example, try raise(SIGTERM);!
Intercepting signals to other processes is something you should not do for any reason other than debugging them. This is what strace is intended for. Processes should be capable of handling their own signals.
Needless to say, if you are writing a debugger, understand ptrace().

Resources