Why write() terminate my thread? - c

I created a thread with pthread_create() for the execution of a function, inside the function there is a write() function to send data via socket descriptor. If the write() function fails to send data (because the socket connection is lost), my thread is terminated.
Can I keep a thread when write() fails?
This is my code:
void broadcastMsg(char *msg) {
int i=0;
while(1) {
...
...
// My thread terminated from here
if(write(client_database.sock_desc[i], msg, strlen(msg)) < 0) {
client_database.sock_desc[i] = -3;
i++;
continue;
}
i++;
}
}
/* Start thread from this function */
void *cliListener(void *argvp) {
int read_desc;
char buf[MAX_TRANSFER_BUF];
int cli_sock_desc_id = atoi(argvp);
while(1) {
memset(buf, 0, MAX_TRANSFER_BUF);
read_desc = read(client_database.sock_desc[cli_sock_desc_id], buf, MAX_TRANSFER_BUF);
...
...
broadcastMsg(buf);
}
}
int main(void) {
...
...
pthread_t tid_1;
pthread_create(&tid_1, NULL, cliListener, cli_listener_arg);
...
...
}

If you try to write to a pipe or socket descriptor where the other end of the pipe or socket has been closed (so noone will ever read it), the system will send a SIGPIPE signal to your process, which by default will kill the process1. You can avoid this fate by ignoring SIGPIPE, generally early in the main function:
signal(SIGPIPE, SIG_IGN);
once you do this, the write will no longer kill your thread or process; instead it will return an error (-1) with errno set to EPIPE. You need to make sure you are ALWAYS checking the return value of your write calls, and doing the appropriate thing when there is an error, otherwise your program might run on in background after you think it has stopped...
1Depending on how you've set things up it might kill just the thread and not the entire process, but for general safety and hygiene its supposed to kill the entire process

Related

Robust graceful shutdown of an application

To ensure that all destructors are properly called if the program is terminated from keyboard (Ctrl+C), the approach with signals are used:
a handler, which sets an exit flag, is set for SIGINT
if a blocking call (accept(), read(), connect(), etc) is waiting for completion, it returns -1 and errno is set to EINTR
The problem is that SIGINT can arrive between check for exit flag (while (!finish)) and calling read(). In this case, read() will be blocked until the signal is sent once again.
This is a minimal working example:
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
enum { STDIN, STDOUT, STDERR };
static unsigned char finish=0;
static void handleSignal(int signal) {
finish=1;
}
int main(int argc, char ** e) {
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler=handleSignal;
action.sa_flags=0;
sigaction(SIGINT, &action, NULL);
char buffer[256];
puts("<<");
while (!finish) {
sleep(2);
ssize_t n=read(STDIN, buffer, sizeof(buffer));
if (n==0) {
// End of stream
finish=1;
}
else if (n<0) {
// Error or interrupt
if (errno!=EINTR)
perror("read");
}
else {
// Convert data to hexadecimal format
for (size_t i=0; i<n; i++)
printf("%02x", buffer[i]);
}
}
puts(">>\n");
return 0;
}
sleep(2) is added for visibility (a real program may perform some preparational work before reading from file descritor).
If there any way of reliable handling of signals without using non-crossplatform things like signalfd()?
The pselect(2) system call was invented to solve this exact problem. It's POSIX, so hopefully cross-platform enough for you.
The purpose of pselect is to atomically unblock some signals, wait for I/O as select() does, and reblock them. So your loop can look something like the following pseudocode:
sigprocmask(SIG_BLOCK, {SIGINT});
while (1) {
if (finish)
graceful_exit();
int ret = pselect(1, {STDIN}, ..., { /* empty signal set */});
if (ret > 0) {
read(STDIN, buf, size); // will not block
// process data
// If you like you can do
sigprocmask(SIG_UNBLOCK, {SIGINT});
// work work work
if (finish)
graceful_exit();
// work work work
sigprocmask(SIG_BLOCK, {SIGINT});
} else {
// handle timeout or other errors
}
}
There is no race here because SIGINT is blocked for the time in between checking the finish flag and the call to pselect, so it cannot be delivered during that window. But the signal is unblocked while pselect is waiting, so if it arrives during that time (or already arrived while it was blocked), pselect will return without further delay. We only call read when pselect has told us it was ready for reading, so it cannot block.
If your program is multithreaded, use pthread_sigmask instead of sigprocmask.
As was noted in comments, you have to make your finish flag volatile, and for best compatibility it should be of type sig_atomic_t.
There is more discussion and another example in the select_tut(2) man page.

Parent process in server stuck in accept call. How do I terminate the parent cleanly from child

Hello from a beginner C programmer.
I have a simple server client setup. I only want one client to connect to the server, but I want other clients to be able to try and get a message that the server is occupied.
I am able to connect to the server with one client, and let other clients trying to connect know there is no room. My problem occurs when the client tells the server to shut down. The child process is able to break out of the loops and terminate. The parent, however, is not able to receive the message from the child using pipe, because it is stuck on accept.
I could use kill(2) to end the parent, but will I get a clean termination with closing of sockets and files then?
I have also tried to let the parent not stop at accept using fcntl(sock_desc, F_SETFL, fcntl(sock_desc, F_GETFL, 0) | O_NONBLOCK); but this opens up new problems.
I want to somehow make the child tell the parent to skip the accept line and continue so that it gets the pipe message and exits the loop.
If this is a bad way to terminate servers I would appreciate to learn about that.
Simplified server code:
void termination_handler (int signum)
{
if(signum == SIGTERM){
//Is this where the accept call is changed?
}
}
void main(){
struct sigaction sa = {0}; //2b) Initialise the struct sigaction variable to all 0s beforehand.
sa.handler = termination_handler; //2a) Set the member for handler (to the signal-handler function)
sigaction(SIGTERM, &sa, NULL);
pid_t pid;
int loop = 1;
while(loop){
int sock = accept(net_sock, NULL, NULL); //After connection
//parent is stuck here
if(kill(pid,0) == -1){
pid = fork();
}
else{
//Tell second client there is no room and close socket
}
//Child
if(pid == 0){
while(loop){
//Read signal in from client to end child loop and terminate child
//Write with pipe to parent to end parent loop and terminate parent
kill(getppid(), SIGTERM) // Is this how I do it?
}
}
//Parent
else{
close(sock);
//Read with pipe from child to end loop
//After first connection, the parent won't get this message
}
}
The OS will close filedescriptors for you. Unless you have other cleanup work to do (such as writing into files or removing some files), a kill with an unhandled terminating signal (e.g., SIGTERM or SIGINT) should be sufficient.
If you do have other cleanup work to do, have the child signal the parent with a signal for which the parent has a signal handler established (you need to establish the handler with sigaction). That will break accept with return code -1 and errno == EINTR, allowing you to do whatever you need to do.
volatile sig_atomic_t usr1 = 0;
void usr1_handler(int Sig) { usr1 = 1; }
//...
int main() { //...
sigaction(SIGUSR1, &(struct sigaction){.sa_handler=usr1_handler},0);
//...
usr1 = 0;
sock = accept( /*... */ );
if ( -1 == sock && EINTR == errno && usr1 ) //was interrupted by USR1
/* cleanup and exit */;
Let the child signal it's parent before ending. If done correctly accept() returns on signal reception, returning -1 and setting errno to EINTR.
From accept()'s documentation:
RETURN VALUE
Upon successful completion, accept() shall return the non-negative file descriptor of the accepted socket. Otherwise, -1 shall be returned, errno shall be set to indicate the error, [...]
[...]
ERRORS
The accept() function shall fail if:
[...]
[EINTR]
The accept() function was interrupted by a signal that was caught before a valid connection arrived.

Trouble with signal catching and thread termination - C

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".

sigpipe c server/client - where does the program restart?

I've a client/server program, now I want to handle signals. When the client closes the connection (if for example I close the terminal), the server has to handle a SIGPIPE, am I right? I'd like to implement something like this. Is it possible?
server.c:
void function(){
printf("...");
read(socket,buff,size);
//IF THE CLIENT CLOSES, THE SERVER RECEIVES A SIGPIPE
...the resting part of the scheduled code should be ignored if sigpipe is received, and the program should begin from where I wrote on the handler of the sigpipe...
printf("not working"); //this should be ignored, but it's printed 2 times immediatly, and when I've finished the actions indicated in the function by the handler, it prints it another time, because the program counter restarts from here...
}
void sigpipehandler(){
close(socket);
main(); //I'd like that the program restarts from the main when I've received a SIGPIPE. It restarts from the main, but only after having printed "not working" two times...
}
int main(){
sigPipe.sa_sigaction = &sigpipehandler;
sigPipe.sa_flags = SA_SIGINFO;
sigaction(SIGPIPE, &sigpipehandler, NULL);
...code...
}
Converting comments into an answer.
Note that you only get SIGPIPE when you write to a pipe where there is no process with the read end of the pipe open. You get EOF (zero bytes read) when you read from a pipe that has no process with the write end of the pipe open.
So, if I change the read() with a write() in the example. How can I handle the SIGPIPE?
Simplest is to ignore SIGPIPE (signal(SIGPIPE, SIG_IGN)) and then monitor the return value from write(). If it comes back with -1 and errno set to EINTR, you can assume you got interrupted by some signal, and most probably a SIGPIPE, especially if you don't have any other signal handling set. Of course, you should be looking at the return value from write() — and read() — anyway.
Alternatively, if you want an explicit SIGPIPE handler, then you definitely do not want to recursively call main() from your signal handler. You can write a loop in main(), and have the signal handler set a flag which you test in the loop. Per Standard C, about the only thing you can do in a signal handler is modify a variable or exit.
static volatile sigatomic_t sig_recvd = 0;
static int sock_fd = -1;
void sigpipehandler(int signum)
{
close(sock_fd);
sock_fd = -1;
sig_recvd = signum;
}
int main(void)
{
sigPipe.sa_sigaction = &sigpipehandler;
sigPipe.sa_flags = SA_SIGINFO;
sigemptyset(&sigPipe.sa_mask);
sigaction(SIGPIPE, &sigpipehandler, NULL);
int done = 0;
while (!done)
{
if (sock_fd == -1)
{
if (sig_recvd != 0)
{
...report signal received...
sig_recvd = 0;
}
...(re)open socket on sock_fd...
}
...code as before - sets done = 1 when loop should terminate...
}
return 0;
}
Note that naming a variable the same as a system call (socket in your code) is treading on thin ice; hence, I renamed it sock_fd. A global variable called socket would be a really bad idea.

Wake up thread blocked on accept() call

Sockets on Linux question
I have a worker thread that is blocked on an accept() call. It simply waits for an incoming network connection, handles it, and then returns to listening for the next connection.
When it is time for the program to exit, how do I signal this network worker thread (from the main thread) to return from the accept() call while still being able to gracefully exit its loop and handle its cleanup code.
Some things I tried:
pthread_kill to send a signal. Feels kludgy to do this, plus it doesn't reliably allow the thread to do it's shutdown logic. Also makes the program terminate as well. I'd like to avoid signals if at all possible.
pthread_cancel. Same as above. It's a harsh kill on the thread. That, and the thread may be doing something else.
Closing the listen socket from the main thread in order to make accept() abort. This doesn't reliably work.
Some constraints:
If the solution involves making the listen socket non-blocking, that is fine. But I don't want to accept a solution that involves the thread waking up via a select call every few seconds to check the exit condition.
The thread condition to exit may not be tied to the process exiting.
Essentially, the logic I am going for looks like this.
void* WorkerThread(void* args)
{
DoSomeImportantInitialization(); // initialize listen socket and some thread specific stuff
while (HasExitConditionBeenSet()==false)
{
listensize = sizeof(listenaddr);
int sock = accept(listensocket, &listenaddr, &listensize);
// check if exit condition has been set using thread safe semantics
if (HasExitConditionBeenSet())
{
break;
}
if (sock < 0)
{
printf("accept returned %d (errno==%d)\n", sock, errno);
}
else
{
HandleNewNetworkCondition(sock, &listenaddr);
}
}
DoSomeImportantCleanup(); // close listen socket, close connections, cleanup etc..
return NULL;
}
void SignalHandler(int sig)
{
printf("Caught CTRL-C\n");
}
void NotifyWorkerThreadToExit(pthread_t thread_handle)
{
// signal thread to exit
}
int main()
{
void* ptr_ret= NULL;
pthread_t workerthread_handle = 0;
pthread_create(&workerthread, NULL, WorkerThread, NULL);
signal(SIGINT, SignalHandler);
sleep((unsigned int)-1); // sleep until the user hits ctrl-c
printf("Returned from sleep call...\n");
SetThreadExitCondition(); // sets global variable with barrier that worker thread checks on
// this is the function I'm stalled on writing
NotifyWorkerThreadToExit(workerthread_handle);
// wait for thread to exit cleanly
pthread_join(workerthread_handle, &ptr_ret);
DoProcessCleanupStuff();
}
Close the socket using the shutdown() call. This will wake up any threads blocked on it, while keeping the file descriptor valid.
close() on a descriptor another thread B is using is inherently hazardous: another thread C may open a new file descriptor which thread B will then use instead of the closed one. dup2() a /dev/null onto it avoids that problem, but does not wake up blocked threads reliably.
Note that shutdown() only works on sockets -- for other kinds of descriptors you likely need the select+pipe-to-self or cancellation approaches.
You can use a pipe to notify the thread that you want it to exit. Then you can have a select() call which selects on both the pipe and the listening socket.
For example (compiles but not fully tested):
// NotifyPipe.h
#ifndef NOTIFYPIPE_H_INCLUDED
#define NOTIFYPIPE_H_INCLUDED
class NotifyPipe
{
int m_receiveFd;
int m_sendFd;
public:
NotifyPipe();
virtual ~NotifyPipe();
int receiverFd();
void notify();
};
#endif // NOTIFYPIPE_H_INCLUDED
// NotifyPipe.cpp
#include "NotifyPipe.h"
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
NotifyPipe::NotifyPipe()
{
int pipefd[2];
int ret = pipe(pipefd);
assert(ret == 0); // For real usage put proper check here
m_receiveFd = pipefd[0];
m_sendFd = pipefd[1];
fcntl(m_sendFd,F_SETFL,O_NONBLOCK);
}
NotifyPipe::~NotifyPipe()
{
close(m_sendFd);
close(m_receiveFd);
}
int NotifyPipe::receiverFd()
{
return m_receiveFd;
}
void NotifyPipe::notify()
{
write(m_sendFd,"1",1);
}
Then select with receiverFd(), and notify for termination using notify().
Close the listening socket and accept will return an error.
What doesn't reliably work with this? Describe the problems you're facing.
pthread_cancel to cancel a thread blocked in accept() is risky if the pthread implementation does not implement cancellation properly, that is if the thread created a socket, just before returning to your code, a pthread_cancel() is called for it, the thread is canceled, and the newly created socket is leaked. Although FreeBSD 9.0 and later does not have such a race condition problem, but you should check your OS first.

Resources