mirror of
https://github.com/ckb-next/ckb-next.git
synced 2026-10-10 12:27:21 -04:00
Merge branch 'feature/increase-signal-safety'
This commit is contained in:
@@ -17,8 +17,10 @@
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Unsigned char/short definition
|
||||
typedef unsigned char uchar;
|
||||
@@ -67,5 +69,7 @@ void timespec_add(struct timespec* timespec, long nanoseconds);
|
||||
#include "structures.h"
|
||||
|
||||
#define THREAD_NAME_MAX 16
|
||||
#define SIGHANDLER_SENDER 0
|
||||
#define SIGHANDLER_RECEIVER 1
|
||||
|
||||
#endif // INCLUDES_H
|
||||
|
||||
+53
-18
@@ -11,6 +11,8 @@ extern int features_mask;
|
||||
// device.c
|
||||
extern int hwload_mode;
|
||||
|
||||
int sighandler_pipe[2] = { 0, 0 };
|
||||
|
||||
// Timespec utility function
|
||||
void timespec_add(struct timespec* timespec, long nanoseconds){
|
||||
nanoseconds += timespec->tv_nsec;
|
||||
@@ -40,20 +42,56 @@ static void quit() {
|
||||
usbkill();
|
||||
}
|
||||
|
||||
void sighandler2(int type){
|
||||
// Don't use ckb_warn, we want an extra \n at the beginning
|
||||
printf("\n[W] Ignoring signal %d (already shutting down)\n", type);
|
||||
///
|
||||
/// \brief ignore_signal
|
||||
/// Nested signal handler for previously received signals.
|
||||
/// \param type received signal type
|
||||
void ignore_signal(int type){
|
||||
// Use signal-safe(7) write(3) call to print warning
|
||||
write(1, "\n[W] Ignoring signal ", 22);
|
||||
switch (type) {
|
||||
case SIGTERM:
|
||||
write(1, "SIGTERM", 7);
|
||||
break;
|
||||
case SIGINT:
|
||||
write(1, "SIGINT", 6);
|
||||
break;
|
||||
case SIGQUIT:
|
||||
write(1, "SIGQUIT", 7);
|
||||
break;
|
||||
default:
|
||||
write(1, "UNKNOWN", 7);
|
||||
break;
|
||||
}
|
||||
write(1, " (already shutting down)\n", 27);
|
||||
}
|
||||
|
||||
void sighandler(int type){
|
||||
signal(SIGTERM, sighandler2);
|
||||
signal(SIGINT, sighandler2);
|
||||
signal(SIGQUIT, sighandler2);
|
||||
///
|
||||
/// \brief exithandler
|
||||
/// Main signal handler to catch further signals and call shutdown
|
||||
/// sequence of daemon. This function is allowed to call unsafe
|
||||
/// (signal-safe(7)) function calls, as it is itself executed in another
|
||||
/// process via the socket handler.
|
||||
/// \param type received signal type
|
||||
void exithandler(int type){
|
||||
signal(SIGTERM, ignore_signal);
|
||||
signal(SIGINT, ignore_signal);
|
||||
signal(SIGQUIT, ignore_signal);
|
||||
|
||||
printf("\n[I] Caught signal %d\n", type);
|
||||
quit();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief signalhandler
|
||||
/// Write the received signal type to the socketpair for signal-safe(7)
|
||||
/// signal handling.
|
||||
/// \param type received signal type
|
||||
void sighandler(int type){
|
||||
write(sighandler_pipe[SIGHANDLER_SENDER], &type, sizeof(int));
|
||||
}
|
||||
|
||||
void localecase(char* dst, size_t length, const char* src){
|
||||
char* ldst = dst + length;
|
||||
char s;
|
||||
@@ -194,17 +232,14 @@ int main(int argc, char** argv){
|
||||
if(!mkdevpath(keyboard))
|
||||
ckb_info("Root controller ready at %s0\n", devpath);
|
||||
|
||||
// Set signals
|
||||
sigset_t signals;
|
||||
sigfillset(&signals);
|
||||
sigdelset(&signals, SIGTERM);
|
||||
sigdelset(&signals, SIGINT);
|
||||
sigdelset(&signals, SIGQUIT);
|
||||
// Set up signal handlers for quitting the service.
|
||||
sigprocmask(SIG_SETMASK, &signals, 0);
|
||||
signal(SIGTERM, sighandler);
|
||||
signal(SIGINT, sighandler);
|
||||
signal(SIGQUIT, sighandler);
|
||||
// Attempt to setup signal-safe signal handlers using socketpair(2)
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sighandler_pipe) != -1){
|
||||
signal(SIGTERM, sighandler);
|
||||
signal(SIGINT, sighandler);
|
||||
signal(SIGQUIT, sighandler);
|
||||
} else
|
||||
ckb_warn_nofile("Unable to setup signal handlers\n");
|
||||
|
||||
|
||||
// Start the USB system
|
||||
int result = usbmain();
|
||||
|
||||
+5
-1
@@ -217,7 +217,7 @@ const char* product_str(ushort product);
|
||||
#define IS_MOUSEPAD_DEV(kb) IS_MOUSEPAD((kb)->vendor, (kb)->product)
|
||||
|
||||
#define USB_DELAY_DEFAULT 5
|
||||
|
||||
|
||||
/// Start the USB main loop. Returns program exit code when finished
|
||||
int usbmain();
|
||||
|
||||
@@ -380,4 +380,8 @@ int usb_tryreset(usbdevice* kb);
|
||||
|
||||
void print_urb_buffer(const char* prefix, const unsigned char* buffer, int actual_length, const char* file, int line, const char* function, int devnum);
|
||||
|
||||
// receive message from initial sighandler socketpair communication
|
||||
extern int sighandler_pipe[2];
|
||||
extern void exithandler(int type);
|
||||
|
||||
#endif // USB_H
|
||||
|
||||
@@ -778,6 +778,7 @@ int usbmain(){
|
||||
udev_monitor_enable_receiving(monitor);
|
||||
// Get an fd for the monitor
|
||||
int fd = udev_monitor_get_fd(monitor);
|
||||
|
||||
fd_set fds;
|
||||
while(udev){
|
||||
FD_ZERO(&fds);
|
||||
@@ -803,6 +804,18 @@ int usbmain(){
|
||||
} else if(!strcmp(action, "remove"))
|
||||
usb_rm_device(dev);
|
||||
udev_device_unref(dev);
|
||||
} else {
|
||||
// if select returns -1 there is a chance that the waiting
|
||||
// was interrupted by a signal
|
||||
// check whether there is data available in the
|
||||
// sighandler_pipe, read if there is and manually call the
|
||||
// signal-handling routine
|
||||
int sighandler_msg;
|
||||
ioctl(sighandler_pipe[SIGHANDLER_RECEIVER], FIONREAD, &sighandler_msg);
|
||||
if (sighandler_msg > 0){
|
||||
read(sighandler_pipe[SIGHANDLER_RECEIVER], &sighandler_msg, sizeof(int));
|
||||
exithandler(sighandler_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
udev_monitor_unref(monitor);
|
||||
|
||||
@@ -952,6 +952,17 @@ void powerEventCallback(void *refcon, io_service_t service, uint32_t type, void
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief mac_exithandler
|
||||
/// Thin layer to deconstruct the CFSocket object into a native one,
|
||||
/// reading the received data from that, and passing it on to the main
|
||||
/// exithandler function.
|
||||
void mac_exithandler(CFSocketRef s, CFSocketCallBackType t, CFDataRef a, const void *data, void *info) {
|
||||
int type;
|
||||
read(CFSocketGetNative(s), &type, sizeof(int));
|
||||
exithandler(type);
|
||||
}
|
||||
|
||||
int usbmain(){
|
||||
int vendor = V_CORSAIR;
|
||||
|
||||
@@ -1034,6 +1045,18 @@ int usbmain(){
|
||||
IORegisterForSystemPower(NULL, ¬ify, powerEventCallback, &iterator_syspower);
|
||||
CFRunLoopAddSource(mainloop, IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
|
||||
|
||||
// setup signal handling via CoreFoundation socket callout mechanism
|
||||
// see mac_exithandler for the reading side of this setup
|
||||
CFSocketRef cf_socket = CFSocketCreateWithNative(
|
||||
NULL,
|
||||
sighandler_pipe[SIGHANDLER_RECEIVER],
|
||||
kCFSocketReadCallBack,
|
||||
mac_exithandler,
|
||||
NULL);
|
||||
CFRunLoopSourceRef socket_source = CFSocketCreateRunLoopSource(NULL, cf_socket, 0);
|
||||
|
||||
CFRunLoopAddSource(mainloop, socket_source, kCFRunLoopCommonModes);
|
||||
|
||||
// Enter loop to scan/connect new devices
|
||||
CFRunLoopRun();
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user