Uff, signal handling geschafft...
Erst wollte ich einfach zusätzlich noch auf stdin lauschen - mit select geht das ja. Doch nachdem ich das implementiert hatte, habe ich gemerkt und ist mir wieder eingefallen, dass man nicht nach stdin eines im Terminal laufenden Processes mittels "echo /proc/pid/fd/0" pipen kann, weil diese fds immer zu denen des jeweiligen /dev/pts umgeleitet sind...
Aber eigentlich scheint es mir so jetzt auch eleganter. Ich nutze sigaction und etabliere vor dem loop eine Aktion, die beim Empfangen von SIGTERM (also "kill -15 pid") ausgeführt wird. Diese Aktion ist einfach das Umschalten einer toggle-Variable (ich mag toggle-Variablen

), auf deren Ursprungszustand der while-loop basiert. Wird sie also umgeschaltet, beendet sich der loop und dann werden die unter dem Loop stehenden Aufräumarbeiten ausgeführt. Man kann den Vorgang mit eingeschobenen printfs verifizieren.
(Das einzig Doofe ist, dass man die Variable signum benutzen muss, weil sich sonst gcc beklagt...)
Das kommt dann also bei "kill -15" heraus:
Code: Alles auswählen
/opt/scripts/dev$ ./test2xd
Hello, I am the signal handler.
Hello, I am the end of the main function.
Der Code mit den Test-printfs:
Code: Alles auswählen
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
static const char program_name[] = "test2xd";
static Display *dpy;
static int screen;
static Window root;
static XEvent ev;
static int finish;
static void
term_hdl (int signum)
{
/* we have to use signum */
switch (signum) {
case SIGTERM:
printf("Hello, I am the signal handler.\n");
finish = 1;
}
}
int
main(void)
{
char *display_name = NULL;
char name[BUFSIZ];
int fd;
struct sigaction term_act;
memset(&term_act, 0, sizeof(term_act));
dpy = XOpenDisplay(display_name);
if (dpy == '\0') {
fprintf(stderr, "%s: unable to open display '%s'\n",
program_name, XDisplayName (display_name));
exit(2);
}
root = RootWindow(dpy, screen);
/* fd = open("/tmp/dwmblocks_fifo_intern", O_RDWR | O_NONBLOCK); */
fd = open("/home/user/fifo", O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(1);
}
term_act.sa_handler = term_hdl;
if (sigaction(SIGTERM, &term_act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
fd_set rfds;
int rc;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
while (finish == 0) {
rc = select(fd + 1, &rfds, NULL, NULL, NULL);
if (rc > 0) {
memset(name, 0, sizeof(name)-1);
ssize_t got = read(fd, name, sizeof(name)-1);
if (got < 0) {
perror("read");
break;
} else if (got == 0) {
printf("EOF\\n");
break;
}
else {
/* remove trailing newline */
if (name[strlen(name)-1] == '\n')
name[strlen(name)-1] = '\0';
XStoreName(dpy, root, name);
while (XPending(dpy))
XNextEvent(dpy, &ev);
}
}
}
/* will never get here */
close(fd);
XCloseDisplay(dpy);
printf("Hello, I am the end of the main function.\n");
exit(EXIT_SUCCESS);
}
Wie findet ihr das? Jetzt könnte ich doch das Programm mittels "kill -15 pid" aus dem Parent-Wrapper-Script heraus auf jeden Fall sauber beenden.