Sending signal to all threads - c

I'm trying to create simple signal handling - let's say something like terminating the process. I have three separate threads in my program + main thread.
The problem is that invoking the signal causes the current thread to terminate, while the others are still running.
How can I send the signal to the remaining threads? How can I differentiate these signals while sending them?
I have to use FIFO here by the way.
Here's what I've got so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
int first[2];
int second[2];
#define FIFO_FILE "tmp/myfifo"
void *input(void *ptr)
{
char str[100], fifo[100];
int length;
FILE *fp;
while(1)
{
fp = fopen(FIFO_FILE, "r");
fgets(fifo, 100, fp);
if(fifo == "s1")
{
printf("SIGNAL 1!!!");
exit(1);
}
printf("Enter the message: ");
fflush(stdout);
length = read(STDIN_FILENO, str, sizeof(str));
if(str[0] == ';')
exit(2);
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[1]);
exit(2);
}
if(write(first[1], str, length) != length)
{
perror("write");
exit(2);
}
}
}
void *countChars(void *ptr)
{
char str[100], fifo[100];
int length, count = 0;
FILE *fp;
while(1)
{
fp = fopen(FIFO_FILE, "r");
fgets(fifo, 100, fp);
if(fifo == "s1")
{
printf("SIGNAL 1!!!");
exit(1);
}
length = read(first[0], str, sizeof(str));
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[0]);
close(second[1]);
exit(2);
}
if(write(STDOUT_FILENO, str, length) != length)
{
perror("write");
exit(2);
}
while(str[count] != '\n') count++;
write(second[1], &count, sizeof(count));
count = 0;
}
}
void *output(void *ptr)
{
int length, count = 0;
char fifo[100];
FILE *fp;
while(1)
{
fp = fopen(FIFO_FILE, "r");
fgets(fifo, 100, fp);
if(fifo == "s1")
{
printf("SIGNAL 1!!!");
exit(1);
}
length = read(second[0], &count, sizeof(count));
if(length < sizeof(count))
{
close(second[0]);
exit(2);
}
printf("Number of characters: %d\n", count);
}
}
void s1_handler(int signo)
{
FILE *fp;
if((fp = fopen(FIFO_FILE, "wb")) == NULL)
{
perror("fopen");
exit(2);
}
fputs("s1", fp);
fclose(fp);
}
int main()
{
pthread_t t1, t2, t3;
if(pipe(first) == -1)
{
printf("First pipe error");
exit(1);
}
if(pipe(second) == -1)
{
printf("Second pipe error");
exit(1);
}
pthread_create(&t1, NULL, input, NULL);
pthread_create(&t2, NULL, countChars, NULL);
pthread_create(&t3, NULL, output, NULL);
if(signal(SIGINT, s1_handler) == SIG_ERR)
{
printf("Cant catch SIGINT\n");
}
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
return 0;
}

You have quite a few (conceptual) errors in your program.
Signals: Standard signals (i.e. non-realtime signals like SIGINT) are not queued. Your process will only receive one and any further signals (of the same type) will be thrown away until the one already delivered is somehow processed. Signals (most, anyway) are delivered to the process as a whole. In the absence of your program taking actions to do otherwise, the signal will be delivered to an arbitrary thread within the process. You can resend a signal you catch to your other threads with pthread_kill but this will require you to make each thread id available to every other thread by using, for instance, a global table of TIDs. It is unclear what you are really trying to accomplish with your program but that is almost certainly not what you want to do.
FIFOs: You seem to know that using FIFOs to communicate between threads is a dubious design but if you were told to use them then you have to use them correctly.
(1) When FIFOs are opened (w/o specifying non-blocking mode) the open is going to block until there is both a reader and a writer on each end of the FIFO. This means all 3 of your threads will block on their respective FIFO open calls until your signal handler - see problems with that below - runs and opens the FIFO for writing.
(2) Even when you get past the opens, only one thread is going to read and consume the string that the signal handler wrote. The other threads are going to sit blocking trying to read an empty FIFO and will never process anything. Currently you are just calling exit in the thread that reads the FIFO, which will end the program, but is that what you are really going for?
(3) There is no need to open the FIFO in each thread. You can do this that before creating the threads and either pass the FIFO file descriptor to each thread or just make it global.
(4) You are opening (and not closing) the FIFO in each thread every time through your while(1) loops. You will run out of file descriptors very quickly that way.
Signal Handler: You should not use non-async safe calls in a signal handler. You have at least 3 - fopen, fputs, fclose. Ideally you want to do very simple things, like just set a global switch, in a signal handler and get out. So if this is anything more than a brain dead class assignment you should rethink this entirely.
I would suggest elaborating exactly what your goal is for the program and you can get some advice on how to reach it.

Only one thread receives the signal! Which one? See the quoted details from:
http://www.linuxprogrammingblog.com/all-about-linux-signals?page=11
Which thread receives the signal?
This is the most interesting question. There are two cases:
Process-directed signals (sent to a PID using functions like kill(2)).
Threads have their separate signal mask which can be manipulated using pthread_sigmask(2) similary to sigprocmask(2), so such signal is not delivered to a thread that has this signal blocked. It's delivered to one of threads in the process with this signal unblocked. It's unspecified which thread will get it. If all threads have the signal blocked, it's queued in the per-process queue. If there is no signal handler defined for the signal and the default action is to terminate the process with or without dumping the core the whole process is terminated.
Thread-directed signals. There is a special function to send a signal to a specific thread: pthread_kill(2). It can be used to send a signal from one thread to another (or itself). This way the signal will be delivered or queued for the specific thread. There are also per-thread directed signals generated by the operating system like SIGSEGV. If there is no signal handler defined for a signal that default's action is to terminate the process, a thread-directed signal terminated the whole process.

Related

How to remove a terminated thread from a running process

Sorry if the question is quite basic but I've looked up the QNX documentation, trying every function that can terminate a thread which doesn't work.
I have this test program that creates 2 thread and makes one of them (the one with the main()) run forever while the other terminates on pthread_exit()
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void *thread(void *arg) {
char *ret;
if ((ret = (char*) malloc(20)) == NULL) {
perror("malloc() error");
exit(2);
}
int input;
printf("type a num to exit\n");
scanf("%d",&input);
strcpy(ret, "This is a test");
pthread_exit(ret);
}
int main() {
pthread_t thid;
void *ret;
if (pthread_create(&thid, NULL, thread, NULL) != 0) {
perror("pthread_create() error");
exit(1);
}
while(1){
}
if (pthread_join(thid, &ret) != 0) {
perror("pthread_create() error");
exit(3);
}
printf("thread exited with '%s'\n", ret);
}
Upon start-up, typing pidin | grep will return two threads in one process as expected. But after one thread is terminated, running pidin | grep again still shows two threads, with one of them having DEAD status. I know that the DEAD thread cannot be accessed anymore unless joined when they are not detached. However, I want to know if there is a way to exit one thread and completely remove it from the process, so typing pidin | grep on the process again will only show one thread running instead of two.
Thanks.

Pipe guarantee to close after the child has exited

In the code below, is it safe to rely on read() failure to detect termination of child?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void)
{
int pipefd[2];
pipefd[0] = 0;
pipefd[1] = 0;
pipe(pipefd);
pid_t pid = fork();
if (pid == 0)
{
// child
close(pipefd[0]); // close unused read end
while ((dup2(pipefd[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {} // send stdout to the pipe
while ((dup2(pipefd[1], STDERR_FILENO) == -1) && (errno == EINTR)) {} // send stderr to the pipe
close(pipefd[1]); // close unused write end
char *argv[3];
argv[0] = "worker-app";
argv[1] = NULL;
argv[2] = NULL;
execvp("./worker-app", argv);
printf("failed to execvp, errno %d\n", errno);
exit(EXIT_FAILURE);
}
else if (pid == -1)
{
}
else
{
// parent
close(pipefd[1]); // close the write end of the pipe in the parent
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
while (1) // <= here is it safe to rely on read below to break from this loop ?
{
ssize_t count = read(pipefd[0], buffer, sizeof(buffer)-1);
printf("pipe read return %d\n", (int)count);
if (count > 0)
{
printf("child: %s\n", buffer);
}
else if (count == 0)
{
printf("end read child pipe\n", buffer);
break;
}
else if (count == -1)
{
if (errno == EINTR)
{ continue;
}
printf("error read child pipe\n", buffer);
break;
}
}
close(pipefd[0]); // close read end, prevent descriptor leak
int waitStatus = 0;
waitpid(pid, &waitStatus, 0);
}
fprintf(stdout, "All work completed :-)\n");
return EXIT_SUCCESS;
}
Should I add something in the while(1) loop to detect child termination? What specific scenario could happen and break this app ?
Some thoughts of improvements below. However would I just waste CPU cycles?
Use kill with special argument 0 that won't kill the process but just check if it is responsive:
if (kill(pid, 0)) { break; /* child exited */ };
/* If sig is 0, then no signal is sent, but error checking is still performed; this can be used to check for the existence of a process ID or process group ID. https://linux.die.net/man/2/kill */
Use waitpid non-blocking in the while(1) loop to check if child has exited.
Use select() to check for pipe readability to prevent read() from possibly hanging?
Thanks!
Regarding your ideas:
If the child spawns children of its own, the read() won't return 0 until all of its descendants either die or close stdout and stderr. If it doesn't, or if the child always outlives all of its descendants, then just waiting for read() to return 0 is good enough and won't ever cause a problem.
If the child dies but the parent hasn't yet wait(2)ed on it, then kill(pid, 0) will succeed as if the child were still alive (at least on Linux), so this isn't an effective check from within your parent program.
A non-blocking waitpid() on its own would appear to fix the problem with the child having children of its own, but would actually introduce a subtle race condition. If the child exited right after the waitpid() but before the read(), then the read() would block until the rest of the descendants exited.
On its own, if you used select() in a blocking way, it's no better than just calling read(). If you used select() in a non-blocking way, you'd just end up burning CPU time in a loop.
What I'd do:
Add a no-op signal handler function for SIGCHLD, just so that it causes EINTR when it occurs.
Block SIGCHLD in the parent before you start looping.
Use non-blocking reads, and use pselect(2) to block to avoid spinning the CPU forever.
During the pselect, pass in a sigset_t that doesn't have SIGCHLD blocked, so that it's guaranteed to cause an EINTR for it when it eventually gets sent.
Somewhere in the loop, do a non-blocking waitpid(2), and handle its return appropriately. (Make sure you do this at least once after blocking SIGCHLD but before calling select for the first time, or you'll have a race condition.)

How do I call other functions with the signal function?

I got a Synthasizer yesterday as a gift, and was interested in writing data to it. I got this much working, here is a program that scales through some notes.
Then I thought it would be neat to have it catch the Ctrl+C singal, and close.
The problem with just closing the file descriptor is that the MIDI device still processes the last note it was given, so I wrote the mute function, which tells the midi device to mute. That works.
so then I tried to have the signal handler mute the device before exiting, and I have been struggling ever since. The signal(SIGINT, intHandler); function wont take additional arguments. So I thought I would be clever, and write a function mySig that calls the signal function and takes the device file descriptor, and data pointer, and would be able to do one last write, before exiting.
IDK, that might even work, but mySig function, seems to be called from the start, and scaling never happens.
How can I call my mute function, before exiting the program with the signal function?
This is my first signal handing program, Im running linux, and the program is in C.
#include <sys/soundcard.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static volatile int keepRunning = 1;
char* device = "/dev/midi1";
//function headers:
void mute(int fd, char *data);
void intHandler(int dummy);
void mySig(void (*intHandler)(int dummy), int fd, char *data);
int main(void){
unsigned int note=50;
char data[3] = {0x90, note, 33}; //device address, note, volume
int fd = open(device, O_WRONLY, 0);
if( fd < 0 ){
printf("Error: cannot open Synth %s\n", device);
exit(1);
}
signal(SIGINT, intHandler);
// mySig(intHandler,fd,data);
while(keepRunning){
for( note=30; note < 95; note++ ){
data[1]=note;//change note
write( fd, data, sizeof(data) );
usleep(100000);
if(note>=89){
note =30;
}
}
mute(fd,data); //mutes the data stream.
close(fd); // close device
return 0;
}
}
//functions:
void mute(int fd, char *data){
data[2]=0;//setVolume to 0
write(fd, data, sizeof(data));
close(fd);
}
void mySig(void (*intHandler)(int dummy), int fd, char *data){
printf("my Sig has been called\n");
mute(fd,data);
signal(SIGINT, intHandler);
}
void intHandler(int dummy) {
printf("my Sig has been called\n");
keepRunning = 1;
printf("ctrl+c was pressed, exiting\n");
usleep(10000);
exit(1);
}
Use the signal handler to only clear your keepRunning flag.
Personally, I prefer the opposite flag, as in done:
static volatile sig_atomic_t done = 0;
static void done_handler(int signum)
{
done = 1; /* Or, in Linux, done = signum. */
}
static int install_done(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = done_handler;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
If the user runs the program in a terminal, and they close the terminal unexpectedly, the program will receive a SIGHUP signal; Ctrl+C causes a SIGINT signal; and SIGTERM is often used to ask a program to exit. So, I personally like to do
if (install_done(SIGINT) ||
install_done(SIGHUP) ||
install_done(SIGTERM)) {
fprintf(stderr, "Cannot install signal handlers: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
early in my main().
All you need to do, is to have your loop -- in my case,
while (!done) {
/* Play notes or whatever */
}
and after the loop, mute the last note played, then close the device.
Consider the signal just a request to exit, as soon as is convenient; not a demand to exit immediately. It is expected that programs do necessary cleanup when they receive a signal asking them to exit. If one wants a program to exit right then, one can always kill the process with SIGKILL.

C Programming: Fork() and IPC with Pipes

So I have this problem, I need to create 3 processes (each handle a different task). The first process sends information over to the second (the first waits for an acknowledgement from the second). The second then sends information to the third (the second waits for an acknowledgement from the third). Then the third processes the final information... This process is supposed to loop over and over until process one analyzes an entire text file. So far, I tried writing the communication between the 3 processes with pipes. I'm not sure how I send an acknowledgment from process 2 to process 1 and process 3 to process 2. I'm also not entirely sure how to loop it. Thanks!
I have to use a stop and wait protocol... I'm not sure how that is done.
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int c = 0, t = 0;
int fd1[2], fd2[2];
char *theFile = "/Users/Desktop/thefile";
FILE *file = fopen (theFile, "r");
if (file == NULL) {
perror("FILE DOES NOT EXIST");
exit(1);
}
while (c == 0) {
int status;
char readbuffer[80];
char readbuffer2[80];
int tTemp = 0;
pipe(fd1);
pipe(fd2);
pid_t pid = fork();
if (pid < 0) {
perror("Pipe Error");
exit(1);
}
if (pid == 0) {
//Child 1
close(fd1[0]);
close(fd2[0]);
close(fd2[1]);
char line [80];
int c2 = 0;
file = fopen (theFile, "r");
while (fgets(line, sizeof(line), file) != NULL){
if (c2 == t) {
printf("Line: %s\n", line);
break;
}
c2++;
}
if (t != c2) {
c = 1;
} else {
write(fd1[1], line, (strlen(line)+1));
}
t++;
exit(1);
}
pid_t pid2 = fork();
if (pid2 < 0) {
perror("Pipe Error");
exit(1);
}
if (pid2 == 0) {
//Child 2
close(fd1[1]);
close(fd2[0]);
read(fd1[0], readbuffer, sizeof(readbuffer));
printf("2nd Child string: %s\n", readbuffer);
char string2[80] = "asdfasdf";
write(fd2[1], string2, (strlen(string2)+1));
exit(1);
}
pid_t pid3 = fork();
if (pid3 < 0) {
perror("Pipe Error");
exit(1);
}
if (pid3 == 0) {
//Child 3
close(fd2[1]);
close(fd1[0]);
close(fd1[1]);
read(fd2[0], readbuffer2, sizeof(readbuffer2));
exit(1);
}
waitpid(pid, &status, 0);
waitpid(pid2, &status, 0);
waitpid(pid3, &status, 0);
}
fclose(file);
return 0;
}
As I have come to understand the problem via the comments, you are asking about two distinct requirements:
implementing a "stop & wait" protocol between each pair of processes, and
using waitpid() to collect child processes that finish
The latter is pretty straightforward; what you already have seems fine. The former is what you seem mostly to be stuck on.
There are a couple of things here. One is a question of semantics: stop & wait, in the form we are discussing it, requires the recipient of a message to acknowledge to the sender that a message was successfully received before the sender proceeds. There is a significant difference between characterizing the acknowledgment that way, and characterizing it as a signal for the receiver of the acknowledgment to perform any particular action. What the receiver does in response to the acknowledgment is its own concern, not inherent in the acknowledgment itself.
As to communications, then, I recommend establishing two pipes between each pair of processes, one for communication in each direction. To wait for an acknowledgment, then, a process just performs a blocking read on the appropriate pipe.
As for looping, each process must loop separately, but the loops will all take about the same form:
Read the next line (process 1 gets lines from a file; the others get lines from pipes connected to the previous process)
Terminate if no line is available
Except for process 1, write a one-byte acknowledgment message on the pipe to the previous process
Process the line
Write the line to the appropriate terminus (process 3 writes lines to an unspecified terminus -- maybe stdout -- the others write lines to pipes connected to the next process).
Except for process 3, perform a blocking read to receive an acknowledgment from the next process.
Go to (1)
Be sure to check the result codes of all the functions that provide them. Since that's most library functions and syscalls it can get tedious, so I suggest a macro to help you out there.
For clarity and readability, I suggest writing the work of each of the three processes as a separate function. After fork() to create each process just handle file descriptor mangling as needed and call the appropriate function.

Sending signals between three threads

I had to write a program that uses 3 threads - one to read letters, second to count characters, and the third to output them. This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/stat.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>
int first[2];
int second[2];
void *input(void *ptr)
{
char str[100];
int length;
while(1)
{
printf("Enter the message: ");
fflush(stdout);
length = read(STDIN_FILENO, str, sizeof(str));
if(str[0] == ';')
exit(2);
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[1]);
exit(2);
}
if(write(first[1], str, length) != length)
{
perror("write");
exit(2);
}
}
}
void *countChars(void *ptr)
{
char str[100];
int length, count = 0;
while(1)
{
length = read(first[0], str, sizeof(str));
if(length <= 0)
{
if(length == -1)
perror("read");
close(first[0]);
close(second[1]);
exit(2);
}
if(write(STDOUT_FILENO, str, length) != length)
{
perror("write");
exit(2);
}
while(str[count] != '\n') count++;
write(second[1], &count, sizeof(count));
count = 0;
}
}
void *output(void *ptr)
{
int length, count = 0;
while(1)
{
length = read(second[0], &count, sizeof(count));
if(length < sizeof(count))
{
close(second[0]);
exit(2);
}
printf("Number of characters: %d\n", count);
}
}
int main()
{
pthread_t t1, t2, t3;
if(pipe(first) == -1)
{
printf("First pipe error");
exit(1);
}
if(pipe(second) == -1)
{
printf("Second pipe error");
exit(1);
}
pthread_create(&t1, NULL, input, NULL);
pthread_create(&t2, NULL, countChars, NULL);
pthread_create(&t3, NULL, output, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
return 0;
}
It works, but right now I have to implement signals here. Sending SIGUSR1 signal should stop program execution until sending SIGUSR2 signal.
The problem is that when I send the signal, only one thread gets it. And thus I have to use FIFO to inform other threads which signal was executed and execute it in the rest of them.
How could I do this?
Signals are delivered to the process, not to the threads. Thus any thread that is able to handle a signal may be used to call a signal handler. What you need to do is figure out how to handle the signal and then decide how to communicate that to all the threads. You have not really described what you mean by "stop program execution", so I'll have to guess.
I would suggest using a combination of pthread_sigmask and sigwait. You can use pthread_sigmask to disable automatic handling of SIGUSR1 and SIGUSR2 in your worker threads. Then call sigwait in a fourth signal handler thread to explicitly handle those signals. When the signal handler thread receives a SIGUSR1 it sets a global flag. The worker threads check that flag periodically and go to sleep (on a condition variable maybe?) when it is set. The signal handler thread then loops around and calls sigwait again. When it receives a SIGUSR2, it wakes up the worker threads, then loops around and calls sigwait, once again.

Resources