I have a small C program which does the following:
- Open multiple thread(s), each of which spawns an
ssh
process usingpopen()
. - For each thread, processes the output from the
FILE
return frompopen()
. (Think opening anssh
command and tailing).
I'm trying to make it so that if the user presses Ctrl+C
(Once), all the open ssh
processes (spawned by threads) will be killed and the process will exit accordingly.
I've tried a solution similar to the top answer here: POSIX pthread programming
This example works, however, if I change the thread function to do what mine is doing (calling popen()
), it requires me hitting Ctrl+C
several times (presumably # of threads that are open). I'm guessing this has to do with the fact that the ssh
process opened by popen()
is not ignoring the SIGINT
signal, allowing it to pass through to my defined handler. Is this correct?
Here's my current code:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void handler(int signo) {
printf("I'm in the handler with SIGNAL %d!", signo);
exit(0);
}
void *thread(void *argument) {
// Hardcoding to "myuser@myhost.com" here for sake of example, but you
// could image the host is different per thread
FILE *file = popen("ssh myuser@myhost.com \"tail -f /path/to/some/log.log\"", "r");
if (file == null) {
printf("Error opening file\n");
exit(1);
}
char line[2048];
while (fgets(line, sizeof(line), fp) != NULL) {
printf("%s\n", line);
}
return NULL;
}
int main(void) {
// Block the SIGINT signal. The threads will inherit the signal mask.
// This will avoid them catching SIGINT instead of this thread.
sigset_t sigset, oldset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
pthread_sigmask(SIG_BLOCK, &sigset, &oldset);
// Spawn the two threads.
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread, &(unsigned int){1});
pthread_create(&thread2, NULL, thread, &(unsigned int){2});
// Install the signal handler for SIGINT.
struct sigaction s;
s.sa_handler = handler;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(SIGINT, &s, NULL);
// Restore the old signal mask only for this thread.
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
// Wait for SIGINT to arrive.
pause();
// Cancel both threads.
pthread_cancel(thread1);
pthread_cancel(thread2);
// Join both threads.
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// Done.
puts("Terminated.");
return EXIT_SUCCESS;
}
Is my assumption on what's happening correct? If not, any ideas what I'm doing wrong?