Move signal handling to parent thread, add -V and -k options, closing #219, and fixing problems with daemontools
This commit is contained in:
parent
5f922b44d8
commit
d2e5b45bd9
19
src/main.c
19
src/main.c
|
@ -222,6 +222,7 @@ int main(int argc, char *argv[]) {
|
|||
int old_song_count, song_count;
|
||||
int force_non_root=0;
|
||||
int skip_initial=1;
|
||||
int kill_server=0;
|
||||
int convert_conf=0;
|
||||
char *db_type,*db_parms,*web_root,*runas, *tmp;
|
||||
char **mp3_dir_array;
|
||||
|
@ -248,7 +249,7 @@ int main(int argc, char *argv[]) {
|
|||
err_setlevel(2);
|
||||
|
||||
config.foreground=0;
|
||||
while((option=getopt(argc,argv,"D:d:c:P:mfrysiuvab:")) != -1) {
|
||||
while((option=getopt(argc,argv,"D:d:c:P:mfrysiuvab:Vk")) != -1) {
|
||||
switch(option) {
|
||||
case 'a':
|
||||
appdir = 1;
|
||||
|
@ -315,6 +316,14 @@ int main(int argc, char *argv[]) {
|
|||
convert_conf=1;
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
kill_server=1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
fprintf(stderr,"Firefly Media Server: Version %s\n",VERSION);
|
||||
break;
|
||||
|
||||
default:
|
||||
usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -329,6 +338,12 @@ int main(int argc, char *argv[]) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
if(kill_server) {
|
||||
os_signal_server(S_STOP);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* read the configfile, if specified, otherwise
|
||||
* try defaults */
|
||||
config.stats.start_time=start_time=(int)time(NULL);
|
||||
|
@ -562,7 +577,7 @@ int main(int argc, char *argv[]) {
|
|||
time(NULL)-start_time);
|
||||
}
|
||||
|
||||
sleep(MAIN_SLEEP_INTERVAL);
|
||||
os_wait(MAIN_SLEEP_INTERVAL);
|
||||
rescan_counter += MAIN_SLEEP_INTERVAL;
|
||||
}
|
||||
|
||||
|
|
141
src/os-unix.c
141
src/os-unix.c
|
@ -55,7 +55,7 @@
|
|||
#include "conf.h"
|
||||
#include "err.h"
|
||||
#include "daapd.h"
|
||||
#include "os-unix.h"
|
||||
#include "os.h"
|
||||
|
||||
/** You say po-tay-to, I say po-tat-o */
|
||||
#ifndef SIGCLD
|
||||
|
@ -69,12 +69,9 @@
|
|||
|
||||
/* Forwards */
|
||||
static int _os_daemon_start(void);
|
||||
static void *_os_signal_handler(void *arg);
|
||||
static int _os_start_signal_handler(pthread_t *handler_tid);
|
||||
static volatile int _os_signal_pid;
|
||||
static int _os_start_signal_handler(void);
|
||||
|
||||
/* Globals */
|
||||
pthread_t _os_signal_tid;
|
||||
char *_os_pidfile = PIDFILE;
|
||||
|
||||
/**
|
||||
|
@ -98,7 +95,8 @@ int os_init(int foreground, char *runas) {
|
|||
DPRINTF(E_LOG,L_MAIN,"fdopen: %s\n",strerror(errno));
|
||||
}
|
||||
/* just to be on the safe side... */
|
||||
_os_signal_pid=0;
|
||||
fprintf(pid_fp,"%d\n",getpid());
|
||||
fclose(pid_fp);
|
||||
_os_daemon_start();
|
||||
}
|
||||
|
||||
|
@ -109,20 +107,10 @@ int os_init(int foreground, char *runas) {
|
|||
|
||||
/* block signals and set up the signal handling thread */
|
||||
DPRINTF(E_LOG,L_MAIN,"Starting signal handler\n");
|
||||
if(_os_start_signal_handler(&_os_signal_tid)) {
|
||||
if(_os_start_signal_handler()) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error starting signal handler %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
if(pid_fp) {
|
||||
/* wait to for config.pid to be set by the signal handler */
|
||||
while(!_os_signal_pid) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
fprintf(pid_fp,"%d\n",_os_signal_pid);
|
||||
fclose(pid_fp);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -130,10 +118,6 @@ int os_init(int foreground, char *runas) {
|
|||
* do any deinitialization necessary for the platform
|
||||
*/
|
||||
void os_deinit(void) {
|
||||
DPRINTF(E_LOG,L_MAIN,"Stopping signal handler\n");
|
||||
if(!pthread_kill(_os_signal_tid,SIGTERM)) {
|
||||
pthread_join(_os_signal_tid,NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -230,6 +214,51 @@ extern int os_chown(char *path, char *user) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* find the old service pid and send it a SIGTERM
|
||||
*/
|
||||
int os_signal_server(int what) {
|
||||
FILE *pid_fp;
|
||||
int pid;
|
||||
int result = TRUE;
|
||||
int signal;
|
||||
|
||||
if(NULL == (pid_fp = fopen(_os_pidfile, "r"))) {
|
||||
DPRINTF(E_LOG,L_MAIN,"fdopen: %s\n",strerror(errno));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(fscanf(pid_fp,"%d\n",&pid)) {
|
||||
kill(pid,SIGTERM);
|
||||
} else {
|
||||
DPRINTF(E_LOG,L_MAIN,"os_service_kill: can't get pid from pidfile\n");
|
||||
result = FALSE;
|
||||
}
|
||||
|
||||
fclose(pid_fp);
|
||||
|
||||
switch(what) {
|
||||
case S_SCAN:
|
||||
signal=SIGUSR1;
|
||||
break;
|
||||
case S_FULL:
|
||||
signal=SIGUSR2;
|
||||
break;
|
||||
case S_STOP:
|
||||
signal=SIGSTOP;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if(kill(pid,signal)) {
|
||||
perror("kill");
|
||||
result = FALSE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fork and exit. Stolen pretty much straight from Stevens.
|
||||
*
|
||||
|
@ -326,50 +355,46 @@ int os_drop_privs(char *user) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Wait for signals and flag the main process. This is
|
||||
* a thread handler for the signal processing thread. It
|
||||
* does absolutely nothing except wait for signals. The rest
|
||||
* of the threads are running with signals blocked, so this thread
|
||||
* is guaranteed to catch all the signals. It sets flags in
|
||||
* the config structure that the main thread looks for. Specifically,
|
||||
* the stop flag (from an INT signal), and the reload flag (from HUP).
|
||||
* \param arg NULL, but required of a thread procedure
|
||||
* wait for specified time, while setting signal flags
|
||||
* (if necessary)
|
||||
*/
|
||||
void *_os_signal_handler(void *arg) {
|
||||
void os_wait(int seconds) {
|
||||
sigset_t intmask;
|
||||
int sig;
|
||||
int status;
|
||||
int done=0;
|
||||
|
||||
config.stop=0;
|
||||
config.reload=0;
|
||||
_os_signal_pid=getpid();
|
||||
sleep(seconds);
|
||||
|
||||
DPRINTF(E_WARN,L_MAIN,"Signal handler started\n");
|
||||
|
||||
while(!config.stop) {
|
||||
while(!done) {
|
||||
if(!sigpending(&intmask)) {
|
||||
if(sigismember(&intmask, SIGCLD) ||
|
||||
sigismember(&intmask, SIGINT) ||
|
||||
sigismember(&intmask, SIGHUP) ||
|
||||
sigismember(&intmask, SIGTERM)) {
|
||||
/* do a sigwait for it */
|
||||
if((sigemptyset(&intmask) == -1) ||
|
||||
(sigaddset(&intmask, SIGCLD) == -1) ||
|
||||
(sigaddset(&intmask, SIGINT) == -1) ||
|
||||
(sigaddset(&intmask, SIGHUP) == -1) ||
|
||||
(sigaddset(&intmask, SIGTERM) == -1) ||
|
||||
(sigwait(&intmask, &sig) == -1)) {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error waiting for signals. Aborting\n");
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error waiting for signals.");
|
||||
} else {
|
||||
/* process the signal */
|
||||
switch(sig) {
|
||||
case SIGCLD:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n");
|
||||
while (wait3(&status, WNOHANG, NULL) > 0) {
|
||||
}
|
||||
while (wait3(&status, WNOHANG, NULL) > 0) {};
|
||||
break;
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got shutdown signal. Notifying daap server.\n");
|
||||
DPRINTF(E_LOG,L_MAIN,"Got shutdown signal.\n");
|
||||
config.stop=1;
|
||||
return NULL;
|
||||
return;
|
||||
break;
|
||||
case SIGHUP:
|
||||
DPRINTF(E_LOG,L_MAIN,"Got HUP signal. Notifying daap server.\n");
|
||||
DPRINTF(E_LOG,L_MAIN,"Got HUP signal.\n");
|
||||
/* if we can't reload, it keeps the old config file,
|
||||
* so no real damage */
|
||||
conf_reload();
|
||||
|
@ -382,11 +407,26 @@ void *_os_signal_handler(void *arg) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
done=1;
|
||||
}
|
||||
} else {
|
||||
DPRINTF(E_FATAL,L_MAIN,"Error in sigpending\n");
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wait for signals and flag the main process. This is
|
||||
* a thread handler for the signal processing thread. It
|
||||
* does absolutely nothing except wait for signals. The rest
|
||||
* of the threads are running with signals blocked, so this thread
|
||||
* is guaranteed to catch all the signals. It sets flags in
|
||||
* the config structure that the main thread looks for. Specifically,
|
||||
* the stop flag (from an INT signal), and the reload flag (from HUP).
|
||||
* \param arg NULL, but required of a thread procedure
|
||||
*/
|
||||
/**
|
||||
* Block signals, then start the signal handler. The
|
||||
* signal handler started by spawning a new thread on
|
||||
|
@ -394,8 +434,7 @@ void *_os_signal_handler(void *arg) {
|
|||
*
|
||||
* \returns 0 on success, -1 on failure with errno set
|
||||
*/
|
||||
int _os_start_signal_handler(pthread_t *handler_tid) {
|
||||
int error;
|
||||
int _os_start_signal_handler() {
|
||||
sigset_t set;
|
||||
|
||||
if((sigemptyset(&set) == -1) ||
|
||||
|
@ -408,14 +447,6 @@ int _os_start_signal_handler(pthread_t *handler_tid) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if((error=pthread_create(handler_tid, NULL, _os_signal_handler, NULL))) {
|
||||
errno=error;
|
||||
DPRINTF(E_LOG,L_MAIN,"Error creating signal_handler thread\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we'll not detach this... let's join it */
|
||||
//pthread_detach(handler_tid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -428,8 +459,6 @@ int _os_start_signal_handler(pthread_t *handler_tid) {
|
|||
_os_pidfile = file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* load a shared library
|
||||
*
|
||||
|
|
|
@ -142,6 +142,14 @@ void _os_phandle_dump(void) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* wait for signals
|
||||
*
|
||||
* don't care about signals on win32, so we'll just sleep
|
||||
*/
|
||||
void os_wait(int seconds) {
|
||||
Sleep(seconds * 1000);
|
||||
}
|
||||
/**
|
||||
* shutdown the system-specific stuff started in os_init.
|
||||
*/
|
||||
|
@ -193,6 +201,12 @@ extern int os_chown(char *path, char *user) {
|
|||
}
|
||||
|
||||
|
||||
int os_signal_server(int what) {
|
||||
/* this could really control the service somehow */
|
||||
fprintf(stderr,"This function is unimplemented on win32\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int os_register(void) {
|
||||
service_register();
|
||||
elog_register();
|
||||
|
|
6
src/os.h
6
src/os.h
|
@ -22,10 +22,14 @@
|
|||
#ifndef _OS_H_
|
||||
#define _OS_H_
|
||||
|
||||
#define S_STOP 0
|
||||
#define S_SCAN 1
|
||||
#define S_FULL 2
|
||||
|
||||
/* backgrounding, signal handling, etc */
|
||||
extern int os_init(int foreground, char *runas);
|
||||
extern void os_deinit(void);
|
||||
extern void os_wait(int seconds);
|
||||
|
||||
/* system native logging functions */
|
||||
extern int os_opensyslog(void);
|
||||
|
@ -43,7 +47,7 @@ extern int os_stat(const char *path, struct stat *sb);
|
|||
extern int os_lstat(const char *path, struct stat *sb);
|
||||
extern int os_islocaladdr(char *hostaddr);
|
||||
extern char *os_apppath(char *parm);
|
||||
|
||||
extern int os_signal_server(int what); /* signal a running server */
|
||||
|
||||
#ifdef WIN32
|
||||
# include "os-win32.h"
|
||||
|
|
|
@ -476,3 +476,10 @@ void _util_mutex_init(void) {
|
|||
|
||||
pthread_mutex_unlock(&util_mutex);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEM
|
||||
void *util_malloc(char *file, char *line, size_t size);
|
||||
void *util_calloc(char *file, char *line, size_t count, size_t size);
|
||||
void *util_realloc(char *file, char *line, void *ptr, size_t size);
|
||||
void util_free(void *ptr);
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue