I have a C program with two threads: the main thread continously reads data from the network and prints it out to the screen, while the secondary thread listens for and handles keypresses from standard input.
Currently my program catches SIGINT, SIGTERM, and SIGPIPE in order to terminate the program cleanly. My problem is that at the end of the main thread (once the main loop has terminated from the signal handler), it attempts to revert the terminal settings using tcsetattr, however this blocks until the current fgetc call on the other thread returns.
How can I interrupt the background thread so that the fgetc call returns and the main thread can restore the terminal settings and exit cleanly?
I have tried using pthread_kill(thread, SIGINT) but that just causes my existing signal handler to be called again.
Relevant code:
// If the program should still be running.
static sig_atomic_t running = 1;
// Background thread that reads keypresses.
pthread_t thread;
static void *get_keypresses();
static void receive_signal(int signal) {
(void)signal;
running = 0;
}
int main(int argc, char *argv[]) {
// Set up signal handling.
if(signal(SIGINT, receive_signal) == SIG_ERR) {
fprintf(stderr, "Error setting signal handler for SIGINT.\n");
}
if(signal(SIGTERM, receive_signal) == SIG_ERR) {
fprintf(stderr, "Error setting signal handler for SIGTERM.\n");
}
if(signal(SIGPIPE, receive_signal) == SIG_ERR) {
fprintf(stderr, "Error setting signal handler for SIGPIPE.\n");
}
// Set up thread attributes.
pthread_attr_t thread_attrs;
if(pthread_attr_init(&thread_attrs) != 0) {
perror("Unable to create thread attributes");
exit(2);
}
if(pthread_attr_setdetachstate(&thread_attrs, PTHREAD_CREATE_DETACHED) != 0) {
perror("Unable to set thread attributes");
exit(2);
}
// Set up terminal for reading keypresses.
struct termios orig_term_attr;
struct termios new_term_attr;
tcgetattr(fileno(stdin), &orig_term_attr);
memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
new_term_attr.c_lflag &= ~(ECHO|ICANON);
tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
// Start background thread to read keypresses.
if((pthread_create(&thread, &thread_attrs, &get_keypresses, NULL)) != 0) {
perror("Unable to create thread");
exit(2);
}
// Main loop.
while(running) {
// Read data from network and output to screen.
}
// Restore original terminal attributes. ***IT BLOCKS HERE***
tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
return 0;
}
// Get input from the keyboard.
static void *get_keypresses() {
int c;
while(running) {
// Get keypress. ***NEEDS TO BE INTERRUPTED HERE***
if((c = fgetc(stdin)) != - 1) {
// Handle keypress.
}
}
return NULL;
}
There are two ways to go:
you change your code not to block (using O_NONBLOCK, poll(), select(), etc.),
you force your blocked code to get kicked out of the blocking system call.
Forcing the end of a system call can basically be done in two ways: either you make the system call impossible to finish (for example, you close the file descriptor the blocking call waits on), or you send some signal to that thread, and make sure that the signal handling is properly set up. The proper signal handling means that the signal is not ignored, not masked, and that the signal flags are set up in such a way that the system call does not get restarted after the signal handling (see sigaction(), SA_RESTART flag).
Replace
if((c = fgetc(stdin)) != -1)
with
if (0 < read(fileno(stdin), &c, 1))
read() would be interupted if the thread received a signal.
I managed to find a solution that works well for me: I made reading from standard input non-blocking.
fcntl(fileno(stdin), F_SETFL, O_NONBLOCK);
This also requires some form of sleep (or usleep or nanosleep) in the background thread.
Thanks for HapKoM for getting me thinking in the right direction.
One way that I see is to read stdin by poll() or select() with some small timeout. And when it returns on timeout you can check "running" flag and perform clear termination if it is set to "false" value.
May be it is not the best solution, but it should work.
Related
I'm writing a multithreaded server program in C that works with AF_UNIX sockets.
The basic structure of the server is:
Main thread initialize data structures and spears a pool of "worker" threads.
Worker threads start waiting for new requests on an empty thread-safe queue
Main thread listen on various sockets (new connection and already connected clients) with a select() call.
select() reveals possible read on connection socket: main thread calls accept() and puts the returned file descriptor in the fd_set (read set).
select() reveal possible read on already connected sockets: main thread removes the ready file descriptors from the fd_set (read set) and puts them in the thread-safe queue.
Worker thread extracts a file descriptor from the queue and starts to communicate with the linked client for serve the request. At the end of the service worker thread puts socket file descriptor back to the fd_set (i worte a function to make this operation thread-safe) and it returns waiting again on the queue for a new request.
This routine is repeated in a infinite cycle until a SIGINT is raised.
Another function has to be performed on SIGUSR1 without exiting from the cycle.
My doubt is about this because if I raise a SIGINT my program exit with EINTR = Interrupted system call.
I know about the pselect() call and the "self pipe" trick but i can't figure out how to make the things work in a multithreaded situation.
I'm looking for a (POSIX compatible) signal management that that prevent the EINTR error while main thread is waiting on pselect().
I post some pieces of code for clarification:
Here i set up signal handlers (ignore errorConsolePrint function)
if(signal(SIGINT, &on_SIGINT) == SIG_ERR)
{
errorConsolePrint("File: %s; Line: %d; ", "Setting SIGINT handler", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
if(signal(SIGTERM, &on_SIGINT) == SIG_ERR)
{
errorConsolePrint("File: %s; Line: %d; ", "Setting SIGINT handler", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
if(signal(SIGUSR1, &on_SIGUSR1) == SIG_ERR)
{
errorConsolePrint("File: %s; Line: %d; ", "Setting to SIGUSR1 handler", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
{
errorConsolePrint("File: %s; Line: %d; ", "Setting to ignore SIGPIPE", __FILE__, __LINE__);
exit(EXIT_FAILURE);
}
Here i set up signal mask for pselect
sigemptyset(&mask);
sigemptyset(&saveMask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGUSR1);
sigaddset(&mask, SIGPIPE);
Here i call pselect
test = saveSet(masterSet, &backUpSet, &saveMaxFd);
CHECK_MINUS1(test, "Server: creating master set's backup ");
int test = pselect(saveMaxFd+1, &backUpSet, NULL, NULL, &waiting, &mask);
if(test == -1 && errno != EINTR)
{
...error handling...
continue;
}
Hope in some help!
Thank you all in advance.
What you should probably do is dedicate a thread to signal handling. Here's a sketch:
In main, before spawning any threads, block all signals (using pthread_sigmask) except for SIGILL, SIGABRT, SIGFPE, SIGSEGV, and SIGBUS.
Then, spawn your signal handler thread. This thread loops calling sigwaitinfo for the signals you care about. It takes whatever action is appropriate for each; this could include sending a message to the main thread to trigger a clean shutdown (SIGINT), queuing the "another function" to be processed in the worker pool (SIGUSR1), etc. You do not install handlers for these signals.
Then you spawn your thread pool, which doesn't have to care about signals at all.
I would suggest the following strategy:
During initialization, set up your signal handlers, as you do.
During initialization, block all (blockable) signals. See for example Is it possible to ignore all signals?.
Use pselect in your main thread to unblock threads for the duration of the call, again as you do.
This has the advantage that all of your system calls, including all those in all your worker threads, will never return EINTR, except for the single pselect in the main thread. See for example the answers to Am I over-engineering per-thread signal blocking? and pselect does not return on signal when called from a separate thread but works fine in single thread program.
This strategy would also work with select: just unblock the signals in your main thread immediately before calling select, and re-block them afterwards. You only really need pselect to prevent hanging if your select timeout is long or infinite, and if your file descriptors are mostly inactive. (I've never used pselect myself, having worked mostly with older Unix's which did not have it.)
I am presuming that your signal handlers as suitable: for example, they just atomically set a global variable.
BTW, in your sample code, do you need sigaddset(&mask, SIGPIPE), as SIGPIPE is already ignored?
Ok, finally I got a solution.
The heart of my problem was about the multithreading nature of my server.
After long search I found out that in the case we have signals raised from other process (in an asyncronous way), it doens't matter which thread capture signal because the behaviour remains the same: The signal is catched and the previously registered handler is executed.
Maybe this could be obvious for others but this was driving me crazy because I did not know how to interpret errors that came out during execution.
After that i found another problem that I solved, is about the obsolete signal() call.
During execution, the first time i rise SIGUSR1, the program catch and manage it as expected but the second time it exit with User defined signal 1.
I figured out that signal() call set "one time" handler for a specific signal, after the first time that the signal is handled the behaviour for that signal return the default one.
So here's what I did:
Here the signal handlers:
N.B.: I reset handler for SIGUSR1 inside the handler itself
static void on_SIGINT(int signum)
{
if(signum == SIGINT || signum == SIGTERM)
serverStop = TRUE;
}
static void on_SIGUSR1(int signum)
{
if(signum == SIGUSR1)
pendingSIGUSR1 = TRUE;
if(signal(SIGUSR1, &on_SIGUSR1) == SIG_ERR)
exit(EXIT_FAILURE);
}
Here I set handlers during server's initialization:
if(signal(SIGINT, &on_SIGINT) == SIG_ERR)
exit(EXIT_FAILURE);
if(signal(SIGTERM, &on_SIGINT) == SIG_ERR)
exit(EXIT_FAILURE);
if(signal(SIGUSR1, &on_SIGUSR1) == SIG_ERR)
exit(EXIT_FAILURE);
if(signal(SIGPIPE, SIG_IGN) == SIG_ERR)
exit(EXIT_FAILURE);
And here the server's listening cycle:
while(!serverStop)
{
if (pendingSIGUSR1)
{
... things i have to do on SIGUSR1...
pendingSIGUSR1 = FALSE;
}
test = saveSet(masterSet, &backUpSet, &saveMaxFd);
CHECK_MINUS1(test, "Server: creating master set's backup ");
int test = select(saveMaxFd+1, &backUpSet, NULL, NULL, &waiting);
if((test == -1 && errno == EINTR) || test == 0)
continue;
if (test == -1 && errno != EINTR)
{
perror("Server: Monitoring sockets: ");
exit(EXIT_FAILURE);
}
for(int sock=3; sock <= saveMaxFd; sock++)
{
if (FD_ISSET(sock, &backUpSet))
{
if(sock == ConnectionSocket)
{
ClientSocket = accept(ConnectionSocket, NULL, 0);
CHECK_MINUS1(ClientSocket, "Server: Accepting connection");
test = INset(masterSet, ClientSocket);
CHECK_MINUS1(test, "Server: Inserting new connection in master set: ");
}
else
{
test = OUTset(masterSet, sock);
CHECK_MINUS1(test, "Server: Removing file descriptor from select ");
test = insertRequest(chain, sock);
CHECK_MINUS1(test, "Server: Inserting request in chain");
}
}
}
}
Read first signal(7) and signal-safety(7); you might want to use the Linux specific signalfd(2) since it fits nicely (for SIGTERM & SIGQUIT and SIGINT) into event loops around poll(2) or the old select(2) (or the newer pselect or ppoll)
See also this answer (and the pipe(7) to self trick mentioned there, which is POSIX-compatible) to a very similar question.
Also, signal(2) documents:
The effects of signal() in a multithreaded process are unspecified.
so you really should use sigaction(2) (which is POSIX).
The codes is as below, and is the same as the one in book apue3e:
#include "apue.h"
#include "sys/wait.h"
static void sig_int(int);
int
main(int argc, char *argv[]) {
pid_t pid;
char buf[MAXLINE];
int status;
if (signal(SIGINT, sig_int) == SIG_ERR) {
err_sys("signal error");
}
printf("%% ");
while (fgets(buf, MAXLINE, stdin) != NULL) {
if (buf[strlen(buf)-1] == '\n') {
buf[strlen(buf)-1] = '\0';
}
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) {
execlp(buf, buf, (char *)NULL);
err_ret("couldn't execlvp: %s\n", buf);
exit(127);
}
if ((pid = waitpid(pid, &status, 0)) < 0) {
err_sys("waitpid_error");
}
printf("%% ");
}
exit(0);
}
static void
sig_int(int signo/* arguments */) {
/* code */
printf("Interrupted\n%%3 ");
}
So, my question is why this signal handler doesn't handle the SIGINT signal and exit immediately after pressing the Ctrl+c which i was testing on archlinux.
[W]hy this signal handler doesn't handle the SIGINT signal and exit immediately after pressing the Ctrl+c which i was testing on archlinux.
Given
static void
sig_int(int signo/* arguments */) {
/* code */
printf("Interrupted\n%%3 ");
}
and
signal(SIGINT, sig_int)
Your process doesn't exit when you press CTRL-C for the simple reason your signal handler doesn't cause the process to exit.
You replaced the default SIGINT handler with your own, so the default action of exiting the process no longer happens.
Since you're running on Linux, I'll refer to the GNU glibc documentation on termination signals:
24.2.2 Termination Signals
These signals are all used to tell a process to terminate, in one way
or another. They have different names because they’re used for
slightly different purposes, and programs might want to handle them
differently.
The reason for handling these signals is usually so your program can
tidy up as appropriate before actually terminating. For example, you
might want to save state information, delete temporary files, or
restore the previous terminal modes. Such a handler should end by
specifying the default action for the signal that happened and then
reraising it; this will cause the program to terminate with that
signal, as if it had not had a handler. (See Termination in
Handler.)
The (obvious) default action for all of these signals is to cause the
process to terminate.
...
Macro: int SIGINT
The SIGINT (“program interrupt”) signal is sent when the user types
the INTR character (normally C-c).
The Termination in Handler glibc documentation states:
24.4.2 Handlers That Terminate the Process
Handler functions that terminate the program are typically used to
cause orderly cleanup or recovery from program error signals and
interactive interrupts.
The cleanest way for a handler to terminate the process is to raise
the same signal that ran the handler in the first place. Here is how
to do this:
volatile sig_atomic_t fatal_error_in_progress = 0;
void
fatal_error_signal (int sig)
{
/* Since this handler is established for more than one kind of signal,
it might still get invoked recursively by delivery of some other kind
of signal. Use a static variable to keep track of that. */
if (fatal_error_in_progress)
raise (sig);
fatal_error_in_progress = 1;
/* Now do the clean up actions:
- reset terminal modes
- kill child processes
- remove lock files */
…
/* Now reraise the signal. We reactivate the signal’s
default handling, which is to terminate the process.
We could just call exit or abort,
but reraising the signal sets the return status
from the process correctly. */
signal (sig, SIG_DFL);
raise (sig);
}
Also, note that there can be significant differences between signal() and sigaction(). See What is the difference between sigaction and signal?
Finally, calling printf() from with a signal handler is undefined behavior. Only async-signal-safe functions can be safely called from within a signal handler. See POSIX 2.4 Signal Concepts for the gory details.
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'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.
I have a Xlib-based program with an event loop that uses XNextEvent to receive and process relevant events.
I would like to be able to gracefully close this program from another process (actually from a shell script). I need to do some cleanup when closing, so I considered to setup a signal handler (for example for SIGUSR1) and when this signal is received, do the appropriate cleanup.
My question is, how can I interrupt the (blocking) XNextEvent call from the signal handler?
Any other suggestions?
I found a way to do this based on this SO question and this one.
Basically you can use the ConnectionNumber() macro to get the fd that XNextEvent() is reading from. This lets me call select() myself to wait for data on the Xlib fd and some other fd. Now it is select() that is blocking, and not XNextEvent(). I can easily unblock select() from my signal handler by writing to the second fd.
Pseudo-code for the event loop:
/* Get X11 fd */
x11_fd = ConnectionNumber(display);
while(1) {
/* Create a File Description Set containing x11_fd and other_fd */
FD_ZERO(&in_fds);
FD_SET(x11_fd, &in_fds);
FD_SET(other_fd, &in_fds);
/* Wait for X Event or exit signal */
ret = select(nfds, &in_fds, ...);
if (FD_ISSET(other_fd, &in_fds) {
/* Do any cleanup and exit */
} else {
while (XEventsQueued(display, QueuedAlready) > 0) {
/* Process X events */
}
}
}
Assuming you have the process id, you can use the kill function:
int kill(pid_t pid, int sig);
You can send any signal but SIGKILL (SIGKILL cannot be handled)