DJWLindenaar balanced tree and master process patch
git-svn-id: https://svn.musicpd.org/mpd/trunk@3669 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
parent
402c8cd707
commit
32e5f4ca2b
@ -84,6 +84,10 @@ AC_CHECK_LIB(nsl,gethostbyname,MPD_LIBS="$MPD_LIBS -lnsl",)
|
||||
|
||||
AC_CHECK_LIB(m,exp,MPD_LIBS="$MPD_LIBS -lm",)
|
||||
|
||||
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.0, [MPD_LIBS="$MPD_LIBS $GLIB_LIBS" MPD_CFLAGS="$MPD_CFLAGS $GLIB_CFLAGS"],[echo "Unable to find glib-2.0 of version 2.0 or above"])
|
||||
|
||||
|
||||
|
||||
dnl doesn't work for systems that don't have CODESET like OpenBSD
|
||||
dnl AC_CHECK_HEADER(langinfo.h,[enable_langinfo=yes;AC_DEFINE(HAVE_LANGINFO,1,[Define if nl_langinfo.h is present])],enable_langinfo=no)
|
||||
AM_LANGINFO_CODESET
|
||||
|
@ -399,7 +399,7 @@ int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
|
||||
pc->error = PLAYER_ERROR_SYSTEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
DEBUG("decoder PID: %d\n", decode_pid);
|
||||
getPlayerData()->playerControl.decode_pid = decode_pid;
|
||||
unblockSignals();
|
||||
|
||||
|
@ -178,7 +178,7 @@ int updateInit(FILE * fp, List * pathList) {
|
||||
if(directory_updatePid==0) {
|
||||
/* child */
|
||||
int dbUpdated = 0;
|
||||
clearPlayerPid();
|
||||
//clearPlayerPid();
|
||||
|
||||
unblockSignals();
|
||||
|
||||
@ -784,6 +784,7 @@ int addToDirectory(Directory * directory, char * shortname, char * name) {
|
||||
|
||||
void closeMp3Directory() {
|
||||
freeDirectory(mp3rootDirectory);
|
||||
destroyTagTracker();
|
||||
}
|
||||
|
||||
Directory * findSubDirectory(Directory * directory,char * name) {
|
||||
|
@ -213,7 +213,10 @@ void closeAllListenSockets() {
|
||||
DEBUG("closing listen socket %i\n", i);
|
||||
while(close(listenSockets[i]) < 0 && errno==EINTR);
|
||||
}
|
||||
freeAllListenSockets();
|
||||
}
|
||||
|
||||
void freeAllListenSockets() {
|
||||
numberOfListenSockets = 0;
|
||||
free(listenSockets);
|
||||
listenSockets = NULL;
|
||||
|
@ -33,6 +33,7 @@ void getConnections(fd_set * fds);
|
||||
int isAListenSocket(int sock);
|
||||
|
||||
void closeAllListenSockets();
|
||||
void freeAllListenSockets();
|
||||
|
||||
/* fdmax should be initialized to something */
|
||||
void addListenSocketsToFdSet(fd_set * fds, int * fdmax);
|
||||
|
74
src/main.c
74
src/main.c
@ -54,6 +54,9 @@
|
||||
#define SYSTEM_CONFIG_FILE_LOCATION "/etc/mpd.conf"
|
||||
#define USER_CONFIG_FILE_LOCATION "/.mpdconf"
|
||||
|
||||
volatile int masterPid = 0;
|
||||
volatile int mainPid = 0;
|
||||
|
||||
typedef struct _Options {
|
||||
int kill;
|
||||
int daemon;
|
||||
@ -288,6 +291,45 @@ void openDB(Options * options, char * argv0) {
|
||||
}
|
||||
}
|
||||
|
||||
void startMainProcess() {
|
||||
int pid;
|
||||
fflush(0);
|
||||
pid = fork();
|
||||
if(pid>0) {
|
||||
initInputStream();
|
||||
initReplayGainState();
|
||||
/* qball crappy code */
|
||||
readAudioDevicesState();
|
||||
|
||||
/* free stuff we don't need */
|
||||
freeAllListenSockets();
|
||||
|
||||
mainPid = pid;
|
||||
masterInitSigHandlers();
|
||||
while (masterHandlePendingSignals()!=COMMAND_RETURN_KILL)
|
||||
waitOnSignals();
|
||||
/* we're killed */
|
||||
playerKill();
|
||||
|
||||
finishAudioConfig();
|
||||
finishAudioDriver();
|
||||
|
||||
/* qball crappy code */
|
||||
saveAudioDevicesState();
|
||||
|
||||
finishPaths();
|
||||
|
||||
kill(mainPid, SIGTERM);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
} else if(pid<0) {
|
||||
ERROR("problems fork'ing main process!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
DEBUG("main process started!\n");
|
||||
}
|
||||
|
||||
void daemonize(Options * options) {
|
||||
FILE * fp;
|
||||
ConfigParam * pidFileParam = parseConfigFilePath(CONF_PID_FILE, 1);
|
||||
@ -338,6 +380,7 @@ void daemonize(Options * options) {
|
||||
DEBUG("writing pid file\n");
|
||||
fprintf(fp, "%lu\n", (unsigned long)getpid());
|
||||
fclose(fp);
|
||||
masterPid = getpid();
|
||||
}
|
||||
|
||||
void setupLogOutput(Options * options, FILE * out, FILE * err) {
|
||||
@ -451,6 +494,7 @@ int main(int argc, char * argv[]) {
|
||||
parseOptions(argc, argv, &options);
|
||||
|
||||
if(options.kill) killFromPidFile(argv[0], options.kill);
|
||||
|
||||
|
||||
initStats();
|
||||
initTagConfig();
|
||||
@ -459,31 +503,39 @@ int main(int argc, char * argv[]) {
|
||||
if(options.createDB <= 0 && !options.updateDB) listenOnPort();
|
||||
|
||||
changeToUser();
|
||||
|
||||
|
||||
openLogFiles(&options, &out, &err);
|
||||
|
||||
initPlayerData();
|
||||
|
||||
daemonize(&options);
|
||||
|
||||
initInputPlugins();
|
||||
initPaths();
|
||||
initAudioConfig();
|
||||
initAudioDriver();
|
||||
|
||||
startMainProcess();
|
||||
/* This is the main process which has
|
||||
* been forked from the master process.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
initPermissions();
|
||||
initReplayGainState();
|
||||
|
||||
initPlaylist();
|
||||
initInputPlugins();
|
||||
|
||||
openDB(&options, argv[0]);
|
||||
|
||||
initCommands();
|
||||
initPlayerData();
|
||||
initAudioConfig();
|
||||
initAudioDriver();
|
||||
initVolume();
|
||||
initInterfaces();
|
||||
initInputStream();
|
||||
|
||||
printMemorySavedByTagTracker();
|
||||
printSavedMemoryFromFilenames();
|
||||
/*printSavedMemoryFromDirectoryNames();*/
|
||||
|
||||
daemonize(&options);
|
||||
|
||||
setupLogOutput(&options, out, err);
|
||||
|
||||
@ -491,8 +543,6 @@ int main(int argc, char * argv[]) {
|
||||
initSigHandlers();
|
||||
readPlaylistState();
|
||||
|
||||
/* qball crappy code */
|
||||
readAudioDevicesState();
|
||||
|
||||
while(COMMAND_RETURN_KILL!=doIOForInterfaces()) {
|
||||
if(COMMAND_RETURN_KILL==handlePendingSignals()) break;
|
||||
@ -502,12 +552,8 @@ int main(int argc, char * argv[]) {
|
||||
}
|
||||
|
||||
savePlaylistState();
|
||||
/* qball crappy code */
|
||||
saveAudioDevicesState();
|
||||
|
||||
|
||||
playerKill();
|
||||
|
||||
freeAllInterfaces();
|
||||
closeAllListenSockets();
|
||||
closeMp3Directory();
|
||||
|
68
src/player.c
68
src/player.c
@ -43,11 +43,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
volatile int player_pid = 0;
|
||||
|
||||
void clearPlayerPid() {
|
||||
player_pid = 0;
|
||||
}
|
||||
extern int masterPid;
|
||||
|
||||
static void resetPlayerMetadata() {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
@ -60,7 +56,7 @@ static void resetPlayerMetadata() {
|
||||
void resetPlayer() {
|
||||
int pid;
|
||||
|
||||
clearPlayerPid();
|
||||
setPlayerPid(0);
|
||||
getPlayerData()->playerControl.stop = 0;
|
||||
getPlayerData()->playerControl.play = 0;
|
||||
getPlayerData()->playerControl.pause = 0;
|
||||
@ -77,7 +73,7 @@ void resetPlayer() {
|
||||
}
|
||||
|
||||
void player_sigChldHandler(int pid, int status) {
|
||||
if(player_pid==pid) {
|
||||
if(getPlayerPid()==pid) {
|
||||
DEBUG("SIGCHLD caused by player process\n");
|
||||
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
|
||||
WTERMSIG(status)!=SIGINT)
|
||||
@ -87,7 +83,7 @@ void player_sigChldHandler(int pid, int status) {
|
||||
}
|
||||
resetPlayer();
|
||||
}
|
||||
else if(pid==getPlayerData()->playerControl.decode_pid && player_pid<=0)
|
||||
else if(pid==getPlayerData()->playerControl.decode_pid && getPlayerPid()<=0)
|
||||
{
|
||||
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) {
|
||||
ERROR("(caught by master parent) "
|
||||
@ -100,24 +96,31 @@ void player_sigChldHandler(int pid, int status) {
|
||||
}
|
||||
|
||||
int playerInit() {
|
||||
kill(masterPid, SIGUSR2);
|
||||
while (getPlayerPid()==0) my_usleep(10000); //we need to wait for the signal to take effect
|
||||
return 0;
|
||||
}
|
||||
|
||||
int playerInitReal() {
|
||||
int player_pid;
|
||||
blockSignals();
|
||||
player_pid = fork();
|
||||
if(player_pid==0) {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
clearUpdatePid();
|
||||
//clearUpdatePid();
|
||||
|
||||
unblockSignals();
|
||||
|
||||
setSigHandlersForDecoder();
|
||||
|
||||
closeAllListenSockets();
|
||||
freeAllInterfaces();
|
||||
closeMp3Directory();
|
||||
finishPlaylist();
|
||||
finishPermissions();
|
||||
finishCommands();
|
||||
finishVolume();
|
||||
//closeAllListenSockets();
|
||||
//freeAllInterfaces();
|
||||
//closeMp3Directory();
|
||||
//finishPlaylist();
|
||||
//finishPermissions();
|
||||
//finishCommands();
|
||||
//finishVolume();
|
||||
|
||||
while(1) {
|
||||
if(pc->play) decode();
|
||||
@ -148,10 +151,13 @@ int playerInit() {
|
||||
else if(player_pid<0) {
|
||||
unblockSignals();
|
||||
ERROR("player Problems fork()'ing\n");
|
||||
setPlayerPid(0);
|
||||
player_pid = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
setPlayerPid(player_pid);
|
||||
|
||||
unblockSignals();
|
||||
|
||||
return 0;
|
||||
@ -183,13 +189,13 @@ int playerPlay(FILE * fp, Song * song) {
|
||||
pc->utf8url[MAXPATHLEN] = '\0';
|
||||
|
||||
pc->play = 1;
|
||||
if(player_pid==0 && playerInit()<0) {
|
||||
if(getPlayerPid()==0 && playerInit()<0) {
|
||||
pc->play = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
resetPlayerMetadata();
|
||||
while(player_pid>0 && pc->play) my_usleep(1000);
|
||||
while(getPlayerPid()>0 && pc->play) my_usleep(1000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -197,9 +203,9 @@ int playerPlay(FILE * fp, Song * song) {
|
||||
int playerStop(FILE * fp) {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
|
||||
if(getPlayerPid()>0 && pc->state!=PLAYER_STATE_STOP) {
|
||||
pc->stop = 1;
|
||||
while(player_pid>0 && pc->stop) my_usleep(1000);
|
||||
while(getPlayerPid()>0 && pc->stop) my_usleep(1000);
|
||||
}
|
||||
|
||||
pc->queueState = PLAYER_QUEUE_BLANK;
|
||||
@ -216,16 +222,16 @@ void playerKill() {
|
||||
playerCloseAudio(stderr);
|
||||
if(player_pid>0 && pc->closeAudio) sleep(1);*/
|
||||
|
||||
pid = player_pid;
|
||||
pid = getPlayerPid();
|
||||
if(pid>0) kill(pid,SIGTERM);
|
||||
}
|
||||
|
||||
int playerPause(FILE * fp) {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
|
||||
if(getPlayerPid()>0 && pc->state!=PLAYER_STATE_STOP) {
|
||||
pc->pause = 1;
|
||||
while(player_pid>0 && pc->pause) my_usleep(1000);
|
||||
while(getPlayerPid()>0 && pc->pause) my_usleep(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -234,7 +240,7 @@ int playerPause(FILE * fp) {
|
||||
int playerSetPause(FILE * fp, int pause) {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if(player_pid<=0) return 0;
|
||||
if(getPlayerPid()<=0) return 0;
|
||||
|
||||
switch(pc->state) {
|
||||
case PLAYER_STATE_PLAY:
|
||||
@ -314,7 +320,7 @@ char * getPlayerErrorStr() {
|
||||
void playerCloseAudio() {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if(player_pid>0) {
|
||||
if(getPlayerPid()>0) {
|
||||
if(playerStop(stderr)<0) return;
|
||||
pc->closeAudio = 1;
|
||||
}
|
||||
@ -354,20 +360,20 @@ void setQueueState(int queueState) {
|
||||
void playerQueueLock() {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
|
||||
if(getPlayerPid()>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
|
||||
{
|
||||
pc->lockQueue = 1;
|
||||
while(player_pid>0 && pc->lockQueue) my_usleep(1000);
|
||||
while(getPlayerPid()>0 && pc->lockQueue) my_usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
void playerQueueUnlock() {
|
||||
PlayerControl * pc = &(getPlayerData()->playerControl);
|
||||
|
||||
if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
|
||||
if(getPlayerPid()>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
|
||||
{
|
||||
pc->unlockQueue = 1;
|
||||
while(player_pid>0 && pc->unlockQueue) my_usleep(1000);
|
||||
while(getPlayerPid()>0 && pc->unlockQueue) my_usleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,7 +400,7 @@ int playerSeek(FILE * fp, Song * song, float time) {
|
||||
resetPlayerMetadata();
|
||||
pc->seekWhere = time;
|
||||
pc->seek = 1;
|
||||
while(player_pid>0 && pc->seek) my_usleep(1000);
|
||||
while(getPlayerPid()>0 && pc->seek) my_usleep(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -34,6 +34,7 @@ int buffered_chunks;
|
||||
#define DEFAULT_BUFFER_BEFORE_PLAY 0
|
||||
|
||||
PlayerData * playerData_pd;
|
||||
int * player_pid;
|
||||
|
||||
void initPlayerData() {
|
||||
float perc = DEFAULT_BUFFER_BEFORE_PLAY;
|
||||
@ -102,6 +103,22 @@ void initPlayerData() {
|
||||
ERROR("problems shmctl'ing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* maybe the following should be put in the same shm block as the previous
|
||||
* or maybe even made a part of the playerData struct
|
||||
*/
|
||||
allocationSize = sizeof(int);
|
||||
if((shmid = shmget(IPC_PRIVATE,allocationSize,IPC_CREAT|0600))<0) {
|
||||
ERROR("problems shmget'ing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if((player_pid = shmat(shmid,NULL,0))<0) {
|
||||
ERROR("problems shmat'ing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (shmctl(shmid, IPC_RMID, 0)<0) {
|
||||
ERROR("problems shmctl'ing\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
buffer = &(playerData_pd->buffer);
|
||||
|
||||
@ -147,6 +164,15 @@ PlayerData * getPlayerData() {
|
||||
return playerData_pd;
|
||||
}
|
||||
|
||||
int getPlayerPid() {
|
||||
return *player_pid;
|
||||
}
|
||||
|
||||
void setPlayerPid(int pid) {
|
||||
*player_pid = pid;
|
||||
}
|
||||
|
||||
void freePlayerData() {
|
||||
shmdt(playerData_pd);
|
||||
shmdt(player_pid);
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ typedef struct _PlayerData {
|
||||
void initPlayerData();
|
||||
|
||||
PlayerData * getPlayerData();
|
||||
int getPlayerPid();
|
||||
void setPlayerPid(int pid);
|
||||
|
||||
void freePlayerData();
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "sig_handlers.h"
|
||||
#include "player.h"
|
||||
#include "playerData.h"
|
||||
#include "playlist.h"
|
||||
#include "directory.h"
|
||||
#include "command.h"
|
||||
@ -33,10 +34,30 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern volatile int masterPid;
|
||||
extern volatile int mainPid;
|
||||
|
||||
int masterHandlePendingSignals() {
|
||||
if(signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
|
||||
DEBUG("master process got SIGINT or SIGTERM, exiting\n");
|
||||
return COMMAND_RETURN_KILL;
|
||||
}
|
||||
|
||||
if(signal_is_pending(SIGHUP)) {
|
||||
signal_clear(SIGHUP);
|
||||
/* Forward it to the main process, which will update the DB */
|
||||
kill(mainPid, SIGHUP);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int handlePendingSignals() {
|
||||
if(signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
|
||||
DEBUG("got SIGINT or SIGTERM, exiting\n");
|
||||
DEBUG("main process got SIGINT or SIGTERM, exiting\n");
|
||||
return COMMAND_RETURN_KILL;
|
||||
}
|
||||
|
||||
@ -57,17 +78,55 @@ int handlePendingSignals() {
|
||||
void chldSigHandler(int signal) {
|
||||
int status;
|
||||
int pid;
|
||||
DEBUG("got SIGCHLD\n");
|
||||
DEBUG("main process got SIGCHLD\n");
|
||||
while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
|
||||
if(pid<0) {
|
||||
if(errno==EINTR) continue;
|
||||
else break;
|
||||
}
|
||||
player_sigChldHandler(pid,status);
|
||||
directory_sigChldHandler(pid,status);
|
||||
}
|
||||
}
|
||||
|
||||
void masterChldSigHandler(int signal) {
|
||||
int status;
|
||||
int pid;
|
||||
DEBUG("master process got SIGCHLD\n");
|
||||
while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
|
||||
if(pid<0) {
|
||||
if(errno==EINTR) continue;
|
||||
else break;
|
||||
}
|
||||
DEBUG("PID: %d\n",pid);
|
||||
if (pid == mainPid) kill(getpid(), SIGTERM);
|
||||
player_sigChldHandler(pid,status);
|
||||
}
|
||||
}
|
||||
|
||||
int playerInitReal();
|
||||
|
||||
void masterSigUsr2Handler(int signal) {
|
||||
DEBUG("Master process got SIGUSR2 starting a new player process\n");
|
||||
if (getPlayerPid() <= 0)
|
||||
playerInitReal();
|
||||
}
|
||||
|
||||
void masterInitSigHandlers() {
|
||||
struct sigaction sa;
|
||||
|
||||
sa.sa_flags = 0;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
|
||||
sa.sa_handler = masterChldSigHandler;
|
||||
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
|
||||
sa.sa_handler = masterSigUsr2Handler;
|
||||
while(sigaction(SIGUSR2,&sa,NULL)<0 && errno==EINTR);
|
||||
signal_handle(SIGUSR1);
|
||||
signal_handle(SIGINT);
|
||||
signal_handle(SIGTERM);
|
||||
signal_handle(SIGHUP);
|
||||
}
|
||||
|
||||
void initSigHandlers() {
|
||||
struct sigaction sa;
|
||||
|
||||
@ -114,17 +173,32 @@ void ignoreSignals() {
|
||||
while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
|
||||
while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
|
||||
while(sigaction(SIGUSR1,&sa,NULL)<0 && errno==EINTR);
|
||||
while(sigaction(SIGUSR2,&sa,NULL)<0 && errno==EINTR);
|
||||
while(sigaction(SIGINT,&sa,NULL)<0 && errno==EINTR);
|
||||
while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
|
||||
while(sigaction(SIGHUP,&sa,NULL)<0 && errno==EINTR);
|
||||
}
|
||||
|
||||
void waitOnSignals() {
|
||||
sigset_t sset;
|
||||
|
||||
sigfillset(&sset);
|
||||
sigdelset(&sset,SIGCHLD);
|
||||
sigdelset(&sset,SIGUSR1);
|
||||
sigdelset(&sset,SIGUSR2);
|
||||
sigdelset(&sset,SIGHUP);
|
||||
sigdelset(&sset,SIGINT);
|
||||
sigdelset(&sset,SIGTERM);
|
||||
sigsuspend(&sset);
|
||||
}
|
||||
|
||||
void blockSignals() {
|
||||
sigset_t sset;
|
||||
|
||||
sigemptyset(&sset);
|
||||
sigaddset(&sset,SIGCHLD);
|
||||
sigaddset(&sset,SIGUSR1);
|
||||
sigaddset(&sset,SIGUSR2);
|
||||
sigaddset(&sset,SIGHUP);
|
||||
sigaddset(&sset,SIGINT);
|
||||
sigaddset(&sset,SIGTERM);
|
||||
@ -137,6 +211,7 @@ void unblockSignals() {
|
||||
sigemptyset(&sset);
|
||||
sigaddset(&sset,SIGCHLD);
|
||||
sigaddset(&sset,SIGUSR1);
|
||||
sigaddset(&sset,SIGUSR2);
|
||||
sigaddset(&sset,SIGHUP);
|
||||
sigaddset(&sset,SIGINT);
|
||||
sigaddset(&sset,SIGTERM);
|
||||
|
@ -22,8 +22,10 @@
|
||||
#include "../config.h"
|
||||
|
||||
int handlePendingSignals();
|
||||
int masterHandlePendingSignals();
|
||||
|
||||
void initSigHandlers();
|
||||
void masterInitSigHandlers();
|
||||
|
||||
void finishSigHandlers();
|
||||
|
||||
@ -31,6 +33,8 @@ void setSigHandlersForDecoder();
|
||||
|
||||
void ignoreSignals();
|
||||
|
||||
void waitOnSignals();
|
||||
|
||||
void blockSignals();
|
||||
|
||||
void unblockSignals();
|
||||
|
140
src/tagTracker.c
140
src/tagTracker.c
@ -1,11 +1,12 @@
|
||||
#include "tagTracker.h"
|
||||
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <glib/gtree.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static List * tagLists[TAG_NUM_OF_ITEM_TYPES] =
|
||||
static GTree * tagLists[TAG_NUM_OF_ITEM_TYPES] =
|
||||
{
|
||||
NULL,
|
||||
NULL,
|
||||
@ -21,89 +22,96 @@ typedef struct tagTrackerItem {
|
||||
mpd_sint8 visited;
|
||||
} TagTrackerItem;
|
||||
|
||||
int keyCompare(const void *a, const void *b, void *data) {
|
||||
return strcmp(a,b);
|
||||
}
|
||||
|
||||
char * getTagItemString(int type, char * string) {
|
||||
ListNode * node;
|
||||
int pos;
|
||||
TagTrackerItem * item;
|
||||
TagTrackerItem ** itemPointer = &item;
|
||||
char *key;
|
||||
char **keyPointer = &key;
|
||||
|
||||
|
||||
/*if(type == TAG_ITEM_TITLE) return strdup(string);*/
|
||||
|
||||
if(tagLists[type] == NULL) {
|
||||
tagLists[type] = makeList(free, 1);
|
||||
sortList(tagLists[type]);
|
||||
tagLists[type] = g_tree_new_full(keyCompare, NULL, free, free);
|
||||
}
|
||||
|
||||
if(findNodeInList(tagLists[type], string, &node, &pos)) {
|
||||
((TagTrackerItem *)node->data)->count++;
|
||||
if((TagTrackerItem *)g_tree_lookup_extended(tagLists[type], string, (void**)keyPointer, (void**)itemPointer )) {
|
||||
item->count++;
|
||||
}
|
||||
else {
|
||||
TagTrackerItem * item = malloc(sizeof(TagTrackerItem));
|
||||
item = malloc(sizeof(TagTrackerItem));
|
||||
item->count = 1;
|
||||
item->visited = 0;
|
||||
node = insertInListBeforeNode(tagLists[type], node, pos,
|
||||
string, item);
|
||||
key = strdup(string);
|
||||
g_tree_insert(tagLists[type], key, item);
|
||||
|
||||
|
||||
}
|
||||
|
||||
return node->key;
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
void removeTagItemString(int type, char * string) {
|
||||
ListNode * node;
|
||||
int pos;
|
||||
TagTrackerItem *item;
|
||||
|
||||
assert(string);
|
||||
|
||||
assert(tagLists[type]);
|
||||
if(tagLists[type] == NULL) return;
|
||||
|
||||
/*if(!node) {
|
||||
free(string);
|
||||
return;
|
||||
}*/
|
||||
|
||||
if(findNodeInList(tagLists[type], string, &node, &pos)) {
|
||||
TagTrackerItem * item = node->data;
|
||||
if((item = g_tree_lookup(tagLists[type], string))) {
|
||||
item->count--;
|
||||
if(item->count <= 0) deleteNodeFromList(tagLists[type], node);
|
||||
if(item->count <= 0) g_tree_remove(tagLists[type], string);
|
||||
}
|
||||
|
||||
if(tagLists[type]->numberOfNodes == 0) {
|
||||
/* why would this be done??? free it when mpd quits...
|
||||
if(tagLists[type]->numberOfNodes == 0) {
|
||||
freeList(tagLists[type]);
|
||||
tagLists[type] = NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void destroyTagTracker() {
|
||||
int type;
|
||||
for (type=0; type < TAG_NUM_OF_ITEM_TYPES; type ++)
|
||||
if (tagLists[type])
|
||||
g_tree_destroy(tagLists[type]);
|
||||
}
|
||||
|
||||
int getNumberOfTagItems(int type) {
|
||||
if(tagLists[type] == NULL) return 0;
|
||||
|
||||
return tagLists[type]->numberOfNodes;
|
||||
return g_tree_nnodes(tagLists[type]);
|
||||
}
|
||||
|
||||
int calcSavedMemory(char *key, TagTrackerItem* value, int* sum) {
|
||||
*sum -= sizeof(int) + 4*sizeof(void*); //sizeof(_GTreeNode)
|
||||
*sum -= sizeof(TagTrackerItem);
|
||||
*sum += (strlen(key)+1)*value->count;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void printMemorySavedByTagTracker() {
|
||||
int i;
|
||||
ListNode * node;
|
||||
size_t sum = 0;
|
||||
|
||||
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
||||
if(!tagLists[i]) continue;
|
||||
|
||||
sum -= sizeof(List);
|
||||
|
||||
node = tagLists[i]->firstNode;
|
||||
|
||||
while(node != NULL) {
|
||||
sum -= sizeof(ListNode);
|
||||
sum -= sizeof(TagTrackerItem);
|
||||
sum -= sizeof(node->key);
|
||||
sum += (strlen(node->key)+1)*(*((int *)node->data));
|
||||
node = node->nextNode;
|
||||
}
|
||||
sum -= 5*sizeof(void*);//sizeof(_GTree)
|
||||
g_tree_foreach(tagLists[i], (GTraverseFunc)calcSavedMemory, &sum);
|
||||
}
|
||||
|
||||
DEBUG("saved memory from tags: %li\n", (long)sum);
|
||||
}
|
||||
|
||||
void sortTagTrackerInfo() {
|
||||
/* implicit sorting
|
||||
int i;
|
||||
|
||||
for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
|
||||
@ -112,56 +120,52 @@ void sortTagTrackerInfo() {
|
||||
DEBUG("sorting %s info\n", mpdTagItemKeys[i]);
|
||||
|
||||
sortList(tagLists[i]);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
int resetVisitedFlag(char *key, TagTrackerItem *value, void *data) {
|
||||
value->visited = 0;
|
||||
return FALSE;
|
||||
}
|
||||
void resetVisitedFlagsInTagTracker(int type) {
|
||||
ListNode * node;
|
||||
|
||||
if(!tagLists[type]) return;
|
||||
|
||||
node = tagLists[type]->firstNode;
|
||||
|
||||
while(node) {
|
||||
((TagTrackerItem *)node->data)->visited = 0;
|
||||
node = node->nextNode;
|
||||
}
|
||||
g_tree_foreach(tagLists[type], (GTraverseFunc)resetVisitedFlag, NULL);
|
||||
}
|
||||
|
||||
int wasVisitedInTagTracker(int type, char * str) {
|
||||
void * item;
|
||||
TagTrackerItem * item;
|
||||
|
||||
if(!tagLists[type]) return 0;
|
||||
|
||||
if(!findInList(tagLists[type], str, &item)) return 0;
|
||||
if(!(item = g_tree_lookup(tagLists[type], str))) return 0;
|
||||
|
||||
return ((TagTrackerItem *)item)->visited;
|
||||
return item->visited;
|
||||
}
|
||||
|
||||
void visitInTagTracker(int type, char * str) {
|
||||
void * item;
|
||||
|
||||
if(!tagLists[type]) return;
|
||||
|
||||
if(!findInList(tagLists[type], str, &item)) return;
|
||||
|
||||
((TagTrackerItem *)item)->visited = 1;
|
||||
}
|
||||
|
||||
void printVisitedInTagTracker(FILE * fp, int type) {
|
||||
ListNode * node;
|
||||
TagTrackerItem * item;
|
||||
|
||||
if(!tagLists[type]) return;
|
||||
|
||||
node = tagLists[type]->firstNode;
|
||||
if(!(item = g_tree_lookup(tagLists[type], str))) return;
|
||||
|
||||
while(node) {
|
||||
item = node->data;
|
||||
if(item->visited) {
|
||||
myfprintf(fp, "%s: %s\n", mpdTagItemKeys[type],
|
||||
node->key);
|
||||
}
|
||||
node = node->nextNode;
|
||||
}
|
||||
item->visited = 1;
|
||||
}
|
||||
|
||||
struct _PrintVisitedUserdata {
|
||||
FILE *fp;
|
||||
char *type;
|
||||
};
|
||||
|
||||
int printVisitedFlag(char *key, TagTrackerItem* value, struct _PrintVisitedUserdata *data) {
|
||||
if(value->visited) myfprintf(data->fp, "%s: %s\n", data->type, key);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void printVisitedInTagTracker(FILE * fp, int type) {
|
||||
struct _PrintVisitedUserdata data = {fp, mpdTagItemKeys[type]};
|
||||
if(!tagLists[type]) return;
|
||||
g_tree_foreach( tagLists[type], (GTraverseFunc)printVisitedFlag, (void*)&data);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
char * getTagItemString(int type, char * string);
|
||||
|
||||
void removeTagItemString(int type, char * string);
|
||||
void destroyTagTracker();
|
||||
|
||||
int getNumberOfTagItems(int type);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user