clean up signal handling using a polling method, from the genius that is mackstann

git-svn-id: https://svn.musicpd.org/mpd/trunk@697 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
Warren Dukes 2004-04-11 23:07:43 +00:00
parent 063affb047
commit ae33b348af
11 changed files with 108 additions and 87 deletions

View File

@ -5,13 +5,13 @@ mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
tag.h player.h listen.h conf.h ogg_decode.h volume.h flac_decode.h \ tag.h player.h listen.h conf.h ogg_decode.h volume.h flac_decode.h \
audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \ audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \
audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \ audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \
mp4_decode.h aac_decode.h mp4_decode.h aac_decode.h signal_check.h
mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \ mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \ song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \
tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \ tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \
audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \ audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \ audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \
aac_decode.c $(mpd_headers) aac_decode.c signal_check.c $(mpd_headers)
mpd_CFLAGS = $(MPD_CFLAGS) mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB) mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)

View File

@ -58,9 +58,10 @@ void decodeSigHandler(int sig) {
if(sig==SIGCHLD) { if(sig==SIGCHLD) {
int status; int status;
if(decode_pid && *decode_pid==wait3(&status,WNOHANG,NULL)) { if(decode_pid && *decode_pid==wait3(&status,WNOHANG,NULL)) {
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) { if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
ERROR("decode process died from a " WTERMSIG(status)!=SIGINT)
"non-TERM signal: %i\n", {
ERROR("decode process died from signal: %i\n",
WTERMSIG(status)); WTERMSIG(status));
} }
*decode_pid = 0; *decode_pid = 0;

View File

@ -74,6 +74,8 @@ char directorydb[MAXPATHLEN+1];
int directory_updatePid = 0; int directory_updatePid = 0;
int directory_reReadDB = 0;
mpd_uint16 directory_updateJobId = 0; mpd_uint16 directory_updateJobId = 0;
DirectoryList * newDirectoryList(); DirectoryList * newDirectoryList();
@ -112,16 +114,22 @@ void directory_sigChldHandler(int pid, int status) {
WTERMSIG(status)); WTERMSIG(status));
} }
else if(WEXITSTATUS(status)==EXIT_SUCCESS) { else if(WEXITSTATUS(status)==EXIT_SUCCESS) {
readDirectoryDB();
incrPlaylistVersion();
DEBUG("direcotry_sigChldHandler: " DEBUG("direcotry_sigChldHandler: "
"updated db succesffully\n"); "updated db succesffully\n");
directory_reReadDB = 1;
} }
else ERROR("problems updating db\n");
directory_updatePid = 0; directory_updatePid = 0;
} }
} }
void readDirectoryDBIfUpdateIsFinished() {
if(directory_reReadDB && 0==directory_updatePid) {
DEBUG("readDirectoryDB since update finished successfully\n");
readDirectoryDB();
directory_reReadDB = 0;
}
}
int updateInit(FILE * fp, List * pathList) { int updateInit(FILE * fp, List * pathList) {
if(directory_updatePid > 0) { if(directory_updatePid > 0) {
myfprintf(fp,"%s already updating\n",COMMAND_RESPOND_ERROR); myfprintf(fp,"%s already updating\n",COMMAND_RESPOND_ERROR);
@ -135,13 +143,6 @@ int updateInit(FILE * fp, List * pathList) {
if(directory_updatePid==0) { if(directory_updatePid==0) {
unblockSignals(); unblockSignals();
/* child */ /* child */
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sigaction(SIGCHLD,&sa,NULL);
finishSigHandlers(); finishSigHandlers();
close(listenSocket); close(listenSocket);

View File

@ -29,6 +29,8 @@
extern char directorydb[MAXPATHLEN+1]; extern char directorydb[MAXPATHLEN+1];
void readDirectoryDBIfUpdateIsFinished();
int isUpdatingDB(); int isUpdatingDB();
void directory_sigChldHandler(int pid, int status); void directory_sigChldHandler(int pid, int status);

View File

@ -451,10 +451,10 @@ int main(int argc, char * argv[]) {
while(COMMAND_RETURN_KILL!=doIOForInterfaces()) { while(COMMAND_RETURN_KILL!=doIOForInterfaces()) {
syncPlayerAndPlaylist(); syncPlayerAndPlaylist();
closeOldInterfaces(); closeOldInterfaces();
if(COMMAND_RETURN_KILL==handlePendingSignals()) break;
readDirectoryDBIfUpdateIsFinished();
} }
finishSigHandlers();
savePlaylistState(); savePlaylistState();
playerKill(); playerKill();

View File

@ -69,9 +69,11 @@ void resetPlayer() {
void player_sigChldHandler(int pid, int status) { void player_sigChldHandler(int pid, int status) {
if(player_pid==pid) { if(player_pid==pid) {
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) { DEBUG("SIGCHLD caused by player process\n");
ERROR("player process died from a " if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
"non-TERM signal: %i\n", WTERMSIG(status)!=SIGINT)
{
ERROR("player process died from signal: %i\n",
WTERMSIG(status)); WTERMSIG(status));
} }
resetPlayer(); resetPlayer();
@ -100,12 +102,11 @@ int playerInit() {
sa.sa_flags = 0; sa.sa_flags = 0;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN; finishSigHandlers();
sigaction(SIGPIPE,&sa,NULL);
sigaction(SIGHUP,&sa,NULL);
sa.sa_handler = decodeSigHandler; sa.sa_handler = decodeSigHandler;
sigaction(SIGCHLD,&sa,NULL); sigaction(SIGCHLD,&sa,NULL);
sigaction(SIGTERM,&sa,NULL); sigaction(SIGTERM,&sa,NULL);
sigaction(SIGINT,&sa,NULL);
close(listenSocket); close(listenSocket);
freeAllInterfaces(); freeAllInterfaces();

View File

@ -102,8 +102,6 @@ void initPlaylist() {
playlist.random = 0; playlist.random = 0;
playlist.queued = -1; playlist.queued = -1;
blockTermSignal();
playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10); playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10);
if(*test!='\0') { if(*test!='\0') {
ERROR("max playlist length \"%s\" is not an integer\n", ERROR("max playlist length \"%s\" is not an integer\n",
@ -137,7 +135,6 @@ void initPlaylist() {
playlist_stateFile = getConf()[CONF_STATE_FILE]; playlist_stateFile = getConf()[CONF_STATE_FILE];
} }
unblockTermSignal();
} }
void finishPlaylist() { void finishPlaylist() {
@ -152,10 +149,8 @@ int clearPlaylist(FILE * fp) {
if(stopPlaylist(fp)<0) return -1; if(stopPlaylist(fp)<0) return -1;
blockTermSignal();
for(i=0;i<playlist.length;i++) playlist.songs[i] = NULL; for(i=0;i<playlist.length;i++) playlist.songs[i] = NULL;
playlist.length = 0; playlist.length = 0;
unblockTermSignal();
incrPlaylistVersion(); incrPlaylistVersion();
@ -176,7 +171,6 @@ void savePlaylistState() {
if(playlist_stateFile) { if(playlist_stateFile) {
FILE * fp; FILE * fp;
blockTermSignal();
while(!(fp = fopen(playlist_stateFile,"w")) && errno==EINTR); while(!(fp = fopen(playlist_stateFile,"w")) && errno==EINTR);
if(!fp) { if(!fp) {
ERROR("problems opening state file \"%s\" for " ERROR("problems opening state file \"%s\" for "
@ -216,7 +210,6 @@ void savePlaylistState() {
myfprintf(fp,"%s\n",PLAYLIST_STATE_FILE_PLAYLIST_END); myfprintf(fp,"%s\n",PLAYLIST_STATE_FILE_PLAYLIST_END);
while(fclose(fp) && errno==EINTR); while(fclose(fp) && errno==EINTR);
unblockTermSignal();
} }
} }
@ -518,7 +511,6 @@ int swapSongsInPlaylist(FILE * fp, int song1, int song2) {
return -1; return -1;
} }
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) { if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0) { if(playlist.queued>=0) {
@ -552,8 +544,6 @@ int swapSongsInPlaylist(FILE * fp, int song1, int song2) {
else if(playlist.current==song2) playlist.current = song1; else if(playlist.current==song2) playlist.current = song1;
} }
unblockTermSignal();
incrPlaylistVersion(); incrPlaylistVersion();
return 0; return 0;
@ -572,7 +562,6 @@ int deleteFromPlaylist(FILE * fp, int song) {
return -1; return -1;
} }
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) { if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0 && (playlist.order[playlist.queued]==song if(playlist.queued>=0 && (playlist.order[playlist.queued]==song
|| playlist.order[playlist.current]==song)) || playlist.order[playlist.current]==song))
@ -602,8 +591,6 @@ int deleteFromPlaylist(FILE * fp, int song) {
playlist.songs[playlist.length-1] = NULL; playlist.songs[playlist.length-1] = NULL;
playlist.length--; playlist.length--;
unblockTermSignal();
incrPlaylistVersion(); incrPlaylistVersion();
if(playlist_state!=PLAYLIST_STATE_STOP && playlist.current==songOrder) { if(playlist_state!=PLAYLIST_STATE_STOP && playlist.current==songOrder) {
@ -820,7 +807,6 @@ int moveSongInPlaylist(FILE * fp, int from, int to) {
return -1; return -1;
} }
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) { if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0) { if(playlist.queued>=0) {
@ -866,8 +852,6 @@ int moveSongInPlaylist(FILE * fp, int from, int to) {
playlist.current++; playlist.current++;
} }
unblockTermSignal();
incrPlaylistVersion(); incrPlaylistVersion();
return 0; return 0;
@ -878,7 +862,6 @@ void orderPlaylist() {
playlist.current = playlist.order[playlist.current]; playlist.current = playlist.order[playlist.current];
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) { if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0) { if(playlist.queued>=0) {
lockPlaylistInteraction(); lockPlaylistInteraction();
@ -891,7 +874,6 @@ void orderPlaylist() {
playlist.order[i] = i; playlist.order[i] = i;
} }
unblockTermSignal();
} }
void swapOrder(int a, int b) { void swapOrder(int a, int b) {
@ -906,8 +888,6 @@ void randomizeOrder(int start,int end) {
DEBUG("playlist: randomize from %i to %i\n",start,end); DEBUG("playlist: randomize from %i to %i\n",start,end);
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) { if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=start && playlist.queued<=end) { if(playlist.queued>=start && playlist.queued<=end) {
lockPlaylistInteraction(); lockPlaylistInteraction();
@ -923,7 +903,6 @@ void randomizeOrder(int start,int end) {
swapOrder(i,ri); swapOrder(i,ri);
} }
unblockTermSignal();
} }
int setPlaylistRandomStatus(FILE * fp, int status) { int setPlaylistRandomStatus(FILE * fp, int status) {
@ -978,7 +957,6 @@ int shufflePlaylist(FILE * fp) {
int ri; int ri;
if(playlist.length>1) { if(playlist.length>1) {
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) { if(playlist_state==PLAYLIST_STATE_PLAY) {
lockPlaylistInteraction(); lockPlaylistInteraction();
clearPlayerQueue(); clearPlayerQueue();
@ -999,7 +977,6 @@ int shufflePlaylist(FILE * fp) {
ri = rand()%(playlist.length-1)+1; ri = rand()%(playlist.length-1)+1;
swapSongs(i,ri); swapSongs(i,ri);
} }
unblockTermSignal();
incrPlaylistVersion(); incrPlaylistVersion();
} }
@ -1068,7 +1045,6 @@ int savePlaylist(FILE * fp, char * utf8file) {
return -1; return -1;
} }
while(!(fileP = fopen(actualFile,"w")) && errno==EINTR); while(!(fileP = fopen(actualFile,"w")) && errno==EINTR);
if(fileP==NULL) { if(fileP==NULL) {
myfprintf(fp,"%s Problems opening file\n",COMMAND_RESPOND_ERROR); myfprintf(fp,"%s Problems opening file\n",COMMAND_RESPOND_ERROR);

View File

@ -20,35 +20,41 @@
#include "player.h" #include "player.h"
#include "playlist.h" #include "playlist.h"
#include "directory.h" #include "directory.h"
#include "command.h"
#include "signal_check.h"
#include "log.h"
#include <signal.h> #include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <errno.h>
struct sigaction original_termSa; int handlePendingSignals() {
struct sigaction original_hupSa; if(signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
DEBUG("got SIGINT or SIGTERM, exiting\n");
return COMMAND_RETURN_KILL;
}
void termSigHandler(int signal) { if(signal_is_pending(SIGHUP)) {
if(signal==SIGTERM) { DEBUG("got SIGHUP, rereading DB\n");
savePlaylistState(); signal_clear(SIGHUP);
playerKill(); readDirectoryDB();
exit(EXIT_SUCCESS);
} }
}
void usr1SigHandler(int signal) { return 0;
}
void hupSigHandler(int signal) {
readDirectoryDB();
} }
void chldSigHandler(int signal) { void chldSigHandler(int signal) {
int status; int status;
int pid; int pid;
while((pid = wait3(&status,WNOHANG,NULL)) > 0) { DEBUG("got SIGCHLD\n");
while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
if(pid<0) {
if(errno==EINTR) continue;
else break;
}
player_sigChldHandler(pid,status); player_sigChldHandler(pid,status);
directory_sigChldHandler(pid,status); directory_sigChldHandler(pid,status);
} }
@ -61,19 +67,19 @@ void initSigHandlers() {
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL); sigaction(SIGPIPE,&sa,NULL);
sa.sa_handler = usr1SigHandler;
sigaction(SIGUSR1,&sa,NULL);
sa.sa_handler = chldSigHandler; sa.sa_handler = chldSigHandler;
sigaction(SIGCHLD,&sa,NULL); sigaction(SIGCHLD,&sa,NULL);
sa.sa_handler = hupSigHandler; signal_handle(SIGUSR1);
sigaction(SIGHUP,&sa,&original_hupSa); signal_handle(SIGINT);
sa.sa_handler = termSigHandler; signal_handle(SIGTERM);
sigaction(SIGTERM,&sa,&original_termSa); signal_handle(SIGHUP);
} }
void finishSigHandlers() { void finishSigHandlers() {
sigaction(SIGHUP,&original_termSa,NULL); signal_unhandle(SIGINT);
sigaction(SIGTERM,&original_termSa,NULL); signal_unhandle(SIGUSR1);
signal_unhandle(SIGTERM);
signal_unhandle(SIGHUP);
} }
void blockSignals() { void blockSignals() {
@ -95,21 +101,3 @@ void unblockSignals() {
sigaddset(&sset,SIGHUP); sigaddset(&sset,SIGHUP);
sigprocmask(SIG_UNBLOCK,&sset,NULL); sigprocmask(SIG_UNBLOCK,&sset,NULL);
} }
void blockTermSignal() {
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset,SIGTERM);
sigaddset(&sset,SIGHUP);
sigprocmask(SIG_BLOCK,&sset,NULL);
}
void unblockTermSignal() {
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset,SIGTERM);
sigaddset(&sset,SIGHUP);
sigprocmask(SIG_UNBLOCK,&sset,NULL);
}

View File

@ -21,6 +21,8 @@
#include "../config.h" #include "../config.h"
int handlePendingSignals();
void initSigHandlers(); void initSigHandlers();
void finishSigHandlers(); void finishSigHandlers();

38
src/signal_check.c Normal file
View File

@ -0,0 +1,38 @@
#include "signal_check.h"
volatile sig_atomic_t __caught_signals[NSIG];
static void __signal_handler(int sig)
{
__caught_signals[sig] = 1;
}
static void __set_signal_handler(int sig, void (* handler)(int))
{
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = handler;
sigaction(sig, &act, 0);
}
void signal_handle(int sig)
{
__set_signal_handler(sig, __signal_handler);
}
void signal_unhandle(int sig)
{
signal_clear(sig);
__set_signal_handler(sig, SIG_DFL);
}
int signal_is_pending(int sig)
{
return __caught_signals[sig];
}
void signal_clear(int sig)
{
__caught_signals[sig] = 0;
}

12
src/signal_check.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef SIGNAL_CHECK_H
#define SIGNAL_CHECK_H
#include <signal.h>
void signal_handle(int sig);
void signal_unhandle(int sig);
int signal_is_pending(int sig);
void signal_clear(int sig);
#endif /* SIGNAL_CHECK_H */