Ver código fonte

faux.eloop: Implement signal event. Using signalfd()

Serj Kalichev 3 anos atrás
pai
commit
83d55a5dec
2 arquivos alterados com 118 adições e 9 exclusões
  1. 3 0
      faux/eloop.h
  2. 115 9
      faux/eloop/eloop.c

+ 3 - 0
faux/eloop.h

@@ -41,6 +41,9 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop);
 bool_t faux_eloop_add_fd(faux_eloop_t *eloop, int fd, short events,
 	faux_eloop_cb_f *event_cb, void *user_data);
 bool_t faux_eloop_del_fd(faux_eloop_t *eloop, int fd);
+bool_t faux_eloop_add_signal(faux_eloop_t *eloop, int signo,
+	faux_eloop_cb_f *event_cb, void *user_data);
+bool_t faux_eloop_del_signal(faux_eloop_t *eloop, int signo);
 
 C_DECL_END
 

+ 115 - 9
faux/eloop/eloop.c

@@ -19,6 +19,7 @@
 #include <time.h>
 #include <signal.h>
 #include <poll.h>
+#include <sys/signalfd.h>
 
 #include "faux/faux.h"
 #include "faux/str.h"
@@ -138,6 +139,24 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop)
 {
 	bool_t retval = BOOL_TRUE;
 	bool_t stop = BOOL_FALSE;
+	sigset_t blocked_signals;
+	sigset_t orig_sig_set;
+
+#ifdef HAVE_SIGNALFD
+	int signal_fd = -1;
+#endif
+
+	// Block signals to prevent race conditions while loop and ppoll()
+	// Catch signals while ppoll() only
+	sigfillset(&blocked_signals);
+	sigprocmask(SIG_SETMASK, &blocked_signals, &orig_sig_set);
+
+#ifdef HAVE_SIGNALFD
+	// Create Linux-specific signal file descriptor. Wait for all signals.
+	// Unneeded signals will be filtered out later.
+	signal_fd = signalfd(-1, &blocked_signals, SFD_NONBLOCK | SFD_CLOEXEC);
+	faux_pollfd_add(eloop->pollfds, signal_fd, POLLIN);
+#endif
 
 /*
 	// Set signal handler
@@ -172,16 +191,10 @@ bool_t faux_eloop_loop(faux_eloop_t *eloop)
 	sig_act.sa_handler = &sigchld_handler;
 	sigaction(SIGCHLD, &sig_act, NULL);
 
-	// Block signals to prevent race conditions while loop and ppoll()
-	// Catch signals while ppoll() only
-	sigemptyset(&sig_set);
-	sigaddset(&sig_set, SIGTERM);
-	sigaddset(&sig_set, SIGINT);
-	sigaddset(&sig_set, SIGQUIT);
-	sigaddset(&sig_set, SIGHUP);
-	sigaddset(&sig_set, SIGCHLD);
-	sigprocmask(SIG_BLOCK, &sig_set, &orig_sig_set);
 */
+
+
+
 	// Main loop
 	while (!stop) {
 		int sn = 0;
@@ -234,6 +247,7 @@ printf("Sheduled event\n");
 */			continue;
 		}
 
+		
 		// File descriptor
 		faux_pollfd_init_iterator(eloop->pollfds, &pollfd_iter);
 		while ((pollfd = faux_pollfd_each_active(eloop->pollfds, &pollfd_iter))) {
@@ -243,6 +257,38 @@ printf("Sheduled event\n");
 			faux_eloop_fd_t *entry = NULL;
 			bool_t r = BOOL_TRUE;
 
+#ifdef HAVE_SIGNALFD
+			// Read special signal file descriptor
+			if (fd == signal_fd) {
+				struct signalfd_siginfo signal_info = {};
+
+				while (faux_read_block(fd, &signal_info,
+					sizeof(signal_info)) == sizeof(signal_info)) {
+					faux_eloop_info_signal_t sinfo = {};
+					faux_eloop_signal_t *sentry =
+						(faux_eloop_signal_t *)faux_list_kfind(
+						eloop->signals, &signal_info.ssi_signo);
+
+					if (!sentry) // Not registered signal. Drop it.
+						continue;
+					event_cb = sentry->context.event_cb;
+					if (!event_cb)
+						event_cb = eloop->default_event_cb;
+					if (!event_cb) // Callback is not defined
+						continue;
+					sinfo.signo = sentry->signo;
+
+					// Execute callback
+					r = event_cb(eloop, FAUX_ELOOP_SIGNAL, &sinfo,
+						sentry->context.user_data);
+					// BOOL_FALSE return value means "break the loop"
+					if (!r)
+						stop = BOOL_TRUE;
+				}
+				continue; // Another fds are common, not signal
+			}
+#endif
+
 			// Prepare event data
 			entry = (faux_eloop_fd_t *)faux_list_kfind(eloop->fds, &fd);
 			assert(entry);
@@ -265,6 +311,16 @@ printf("Sheduled event\n");
 
 	} // Loop end
 
+#ifdef HAVE_SIGNALFD
+	// Close signal file descriptor
+	faux_pollfd_del_by_fd(eloop->pollfds, signal_fd);
+	close(signal_fd);
+#endif
+
+	// Unblock signals
+	sigprocmask(SIG_SETMASK, &orig_sig_set, NULL);
+
+
 	return retval;
 }
 
@@ -314,3 +370,53 @@ bool_t faux_eloop_del_fd(faux_eloop_t *eloop, int fd)
 
 	return BOOL_TRUE;
 }
+
+
+bool_t faux_eloop_add_signal(faux_eloop_t *eloop, int signo,
+	faux_eloop_cb_f *event_cb, void *user_data)
+{
+	faux_eloop_signal_t *entry = NULL;
+
+	if (!eloop || (signo < 0))
+		return BOOL_FALSE;
+
+	if (sigismember(&eloop->sig_set, signo) == 1)
+		return BOOL_FALSE; // Already exists
+
+	// Firstly try to add signal to sigset. Library function will validate
+	// signal number value.
+	if (sigaddset(&eloop->sig_set, signo) < 0)
+		return BOOL_FALSE; // Invalid signal number
+
+	entry = faux_zmalloc(sizeof(*entry));
+	if (!entry) {
+		sigdelset(&eloop->sig_set, signo);
+		return BOOL_FALSE;
+	}
+	entry->signo = signo;
+	entry->context.event_cb = event_cb;
+	entry->context.user_data = user_data;
+
+	if (!faux_list_add(eloop->signals, entry)) {
+		faux_free(entry);
+		sigdelset(&eloop->sig_set, signo);
+		return BOOL_FALSE;
+	}
+
+	return BOOL_TRUE;
+}
+
+
+bool_t faux_eloop_del_signal(faux_eloop_t *eloop, int signo)
+{
+	if (!eloop || (signo < 0))
+		return BOOL_FALSE;
+
+	if (sigismember(&eloop->sig_set, signo) != 1)
+		return BOOL_FALSE; // Doesn't exist
+
+	sigdelset(&eloop->sig_set, signo);
+	faux_list_kdel(eloop->signals, &signo);
+
+	return BOOL_TRUE;
+}