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:
		@@ -84,6 +84,10 @@ AC_CHECK_LIB(nsl,gethostbyname,MPD_LIBS="$MPD_LIBS -lnsl",)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
AC_CHECK_LIB(m,exp,MPD_LIBS="$MPD_LIBS -lm",)
 | 
					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 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)
 | 
					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
 | 
					AM_LANGINFO_CODESET
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -399,7 +399,7 @@ int decoderInit(PlayerControl * pc, OutputBuffer * cb, DecoderControl * dc) {
 | 
				
			|||||||
		pc->error = PLAYER_ERROR_SYSTEM;
 | 
							pc->error = PLAYER_ERROR_SYSTEM;
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						DEBUG("decoder PID: %d\n", decode_pid);
 | 
				
			||||||
	getPlayerData()->playerControl.decode_pid = decode_pid;
 | 
						getPlayerData()->playerControl.decode_pid = decode_pid;
 | 
				
			||||||
	unblockSignals();
 | 
						unblockSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,7 +178,7 @@ int updateInit(FILE * fp, List * pathList) {
 | 
				
			|||||||
       	if(directory_updatePid==0) {
 | 
					       	if(directory_updatePid==0) {
 | 
				
			||||||
              	/* child */
 | 
					              	/* child */
 | 
				
			||||||
                int dbUpdated = 0;
 | 
					                int dbUpdated = 0;
 | 
				
			||||||
		clearPlayerPid();
 | 
							//clearPlayerPid();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
		unblockSignals();
 | 
							unblockSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -784,6 +784,7 @@ int addToDirectory(Directory * directory, char * shortname, char * name) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void closeMp3Directory() {
 | 
					void closeMp3Directory() {
 | 
				
			||||||
	freeDirectory(mp3rootDirectory);
 | 
						freeDirectory(mp3rootDirectory);
 | 
				
			||||||
 | 
						destroyTagTracker();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Directory * findSubDirectory(Directory * directory,char * name) {
 | 
					Directory * findSubDirectory(Directory * directory,char * name) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,7 +213,10 @@ void closeAllListenSockets() {
 | 
				
			|||||||
		DEBUG("closing listen socket %i\n", i);
 | 
							DEBUG("closing listen socket %i\n", i);
 | 
				
			||||||
		while(close(listenSockets[i]) < 0 && errno==EINTR);
 | 
							while(close(listenSockets[i]) < 0 && errno==EINTR);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						freeAllListenSockets();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void freeAllListenSockets() {
 | 
				
			||||||
	numberOfListenSockets = 0;
 | 
						numberOfListenSockets = 0;
 | 
				
			||||||
	free(listenSockets);
 | 
						free(listenSockets);
 | 
				
			||||||
	listenSockets = NULL;
 | 
						listenSockets = NULL;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,6 +33,7 @@ void getConnections(fd_set * fds);
 | 
				
			|||||||
int isAListenSocket(int sock);
 | 
					int isAListenSocket(int sock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void closeAllListenSockets();
 | 
					void closeAllListenSockets();
 | 
				
			||||||
 | 
					void freeAllListenSockets();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* fdmax should be initialized to something */
 | 
					/* fdmax should be initialized to something */
 | 
				
			||||||
void addListenSocketsToFdSet(fd_set * fds, int * fdmax);
 | 
					void addListenSocketsToFdSet(fd_set * fds, int * fdmax);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										72
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								src/main.c
									
									
									
									
									
								
							@@ -54,6 +54,9 @@
 | 
				
			|||||||
#define SYSTEM_CONFIG_FILE_LOCATION	"/etc/mpd.conf"
 | 
					#define SYSTEM_CONFIG_FILE_LOCATION	"/etc/mpd.conf"
 | 
				
			||||||
#define USER_CONFIG_FILE_LOCATION	"/.mpdconf"
 | 
					#define USER_CONFIG_FILE_LOCATION	"/.mpdconf"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile int masterPid = 0;
 | 
				
			||||||
 | 
					volatile int mainPid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct _Options {
 | 
					typedef struct _Options {
 | 
				
			||||||
	int kill;
 | 
						int kill;
 | 
				
			||||||
        int daemon;
 | 
					        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) {
 | 
					void daemonize(Options * options) {
 | 
				
			||||||
	FILE * fp;
 | 
						FILE * fp;
 | 
				
			||||||
	ConfigParam * pidFileParam = parseConfigFilePath(CONF_PID_FILE, 1);
 | 
						ConfigParam * pidFileParam = parseConfigFilePath(CONF_PID_FILE, 1);
 | 
				
			||||||
@@ -338,6 +380,7 @@ void daemonize(Options * options) {
 | 
				
			|||||||
	DEBUG("writing pid file\n");
 | 
						DEBUG("writing pid file\n");
 | 
				
			||||||
	fprintf(fp, "%lu\n", (unsigned long)getpid());
 | 
						fprintf(fp, "%lu\n", (unsigned long)getpid());
 | 
				
			||||||
	fclose(fp);
 | 
						fclose(fp);
 | 
				
			||||||
 | 
						masterPid = getpid();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void setupLogOutput(Options * options, FILE * out, FILE * err) {
 | 
					void setupLogOutput(Options * options, FILE * out, FILE * err) {
 | 
				
			||||||
@@ -452,6 +495,7 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if(options.kill) killFromPidFile(argv[0], options.kill);
 | 
						if(options.kill) killFromPidFile(argv[0], options.kill);
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        initStats();
 | 
					        initStats();
 | 
				
			||||||
	initTagConfig();
 | 
						initTagConfig();
 | 
				
			||||||
        initLog();
 | 
					        initLog();
 | 
				
			||||||
@@ -462,28 +506,36 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
	
 | 
						
 | 
				
			||||||
        openLogFiles(&options, &out, &err);
 | 
					        openLogFiles(&options, &out, &err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        initPlayerData();
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						daemonize(&options);
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
 | 
					        initInputPlugins();
 | 
				
			||||||
	initPaths();
 | 
						initPaths();
 | 
				
			||||||
 | 
						initAudioConfig();
 | 
				
			||||||
 | 
					        initAudioDriver();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						startMainProcess();
 | 
				
			||||||
 | 
						/* This is the main process which has
 | 
				
			||||||
 | 
						 * been forked from the master process.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
	initPermissions();
 | 
						initPermissions();
 | 
				
			||||||
        initReplayGainState();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        initPlaylist();
 | 
					        initPlaylist();
 | 
				
			||||||
        initInputPlugins();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        openDB(&options, argv[0]);
 | 
					        openDB(&options, argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        initCommands();
 | 
					        initCommands();
 | 
				
			||||||
        initPlayerData();
 | 
					 | 
				
			||||||
        initAudioConfig();
 | 
					 | 
				
			||||||
        initAudioDriver();
 | 
					 | 
				
			||||||
        initVolume();
 | 
					        initVolume();
 | 
				
			||||||
        initInterfaces();
 | 
					        initInterfaces();
 | 
				
			||||||
	initInputStream(); 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printMemorySavedByTagTracker();
 | 
						printMemorySavedByTagTracker();
 | 
				
			||||||
	printSavedMemoryFromFilenames();
 | 
						printSavedMemoryFromFilenames();
 | 
				
			||||||
	/*printSavedMemoryFromDirectoryNames();*/
 | 
						/*printSavedMemoryFromDirectoryNames();*/
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
        daemonize(&options);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        setupLogOutput(&options, out, err);
 | 
					        setupLogOutput(&options, out, err);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -491,8 +543,6 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
        initSigHandlers();
 | 
					        initSigHandlers();
 | 
				
			||||||
        readPlaylistState();
 | 
					        readPlaylistState();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* qball crappy code */
 | 
					 | 
				
			||||||
	readAudioDevicesState();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while(COMMAND_RETURN_KILL!=doIOForInterfaces()) {
 | 
					        while(COMMAND_RETURN_KILL!=doIOForInterfaces()) {
 | 
				
			||||||
		if(COMMAND_RETURN_KILL==handlePendingSignals()) break;
 | 
							if(COMMAND_RETURN_KILL==handlePendingSignals()) break;
 | 
				
			||||||
@@ -502,12 +552,8 @@ int main(int argc, char * argv[]) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        savePlaylistState();
 | 
					        savePlaylistState();
 | 
				
			||||||
	/* qball crappy code */
 | 
					 | 
				
			||||||
	saveAudioDevicesState();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
        playerKill();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        freeAllInterfaces();
 | 
					        freeAllInterfaces();
 | 
				
			||||||
	closeAllListenSockets();
 | 
						closeAllListenSockets();
 | 
				
			||||||
        closeMp3Directory();
 | 
					        closeMp3Directory();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										68
									
								
								src/player.c
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								src/player.c
									
									
									
									
									
								
							@@ -43,11 +43,7 @@
 | 
				
			|||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
volatile int player_pid = 0;
 | 
					extern int masterPid;
 | 
				
			||||||
 | 
					 | 
				
			||||||
void clearPlayerPid() {
 | 
					 | 
				
			||||||
	player_pid = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void resetPlayerMetadata() {
 | 
					static void resetPlayerMetadata() {
 | 
				
			||||||
        PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
					        PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
@@ -60,7 +56,7 @@ static void resetPlayerMetadata() {
 | 
				
			|||||||
void resetPlayer() {
 | 
					void resetPlayer() {
 | 
				
			||||||
	int pid;
 | 
						int pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clearPlayerPid();
 | 
						setPlayerPid(0);
 | 
				
			||||||
	getPlayerData()->playerControl.stop = 0;
 | 
						getPlayerData()->playerControl.stop = 0;
 | 
				
			||||||
	getPlayerData()->playerControl.play = 0;
 | 
						getPlayerData()->playerControl.play = 0;
 | 
				
			||||||
	getPlayerData()->playerControl.pause = 0;
 | 
						getPlayerData()->playerControl.pause = 0;
 | 
				
			||||||
@@ -77,7 +73,7 @@ void resetPlayer() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void player_sigChldHandler(int pid, int status) {
 | 
					void player_sigChldHandler(int pid, int status) {
 | 
				
			||||||
	if(player_pid==pid) {
 | 
						if(getPlayerPid()==pid) {
 | 
				
			||||||
		DEBUG("SIGCHLD caused by player process\n");
 | 
							DEBUG("SIGCHLD caused by player process\n");
 | 
				
			||||||
		if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
 | 
							if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM &&
 | 
				
			||||||
				WTERMSIG(status)!=SIGINT) 
 | 
									WTERMSIG(status)!=SIGINT) 
 | 
				
			||||||
@@ -87,7 +83,7 @@ void player_sigChldHandler(int pid, int status) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		resetPlayer();
 | 
							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) {
 | 
							if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) {
 | 
				
			||||||
			ERROR("(caught by master parent) "
 | 
								ERROR("(caught by master parent) "
 | 
				
			||||||
@@ -100,24 +96,31 @@ void player_sigChldHandler(int pid, int status) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int playerInit() {
 | 
					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();
 | 
						blockSignals();
 | 
				
			||||||
	player_pid = fork();
 | 
						player_pid = fork();
 | 
				
			||||||
	if(player_pid==0) {
 | 
						if(player_pid==0) {
 | 
				
			||||||
		PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
							PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		clearUpdatePid();
 | 
							//clearUpdatePid();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unblockSignals();
 | 
							unblockSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		setSigHandlersForDecoder();
 | 
							setSigHandlersForDecoder();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		closeAllListenSockets();
 | 
							//closeAllListenSockets();
 | 
				
			||||||
		freeAllInterfaces();
 | 
							//freeAllInterfaces();
 | 
				
			||||||
		closeMp3Directory();
 | 
							//closeMp3Directory();
 | 
				
			||||||
		finishPlaylist();
 | 
							//finishPlaylist();
 | 
				
			||||||
		finishPermissions();
 | 
							//finishPermissions();
 | 
				
			||||||
		finishCommands();
 | 
							//finishCommands();
 | 
				
			||||||
		finishVolume();
 | 
							//finishVolume();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		while(1) {
 | 
							while(1) {
 | 
				
			||||||
			if(pc->play) decode();
 | 
								if(pc->play) decode();
 | 
				
			||||||
@@ -148,10 +151,13 @@ int playerInit() {
 | 
				
			|||||||
	else if(player_pid<0) {
 | 
						else if(player_pid<0) {
 | 
				
			||||||
		unblockSignals();
 | 
							unblockSignals();
 | 
				
			||||||
		ERROR("player Problems fork()'ing\n");
 | 
							ERROR("player Problems fork()'ing\n");
 | 
				
			||||||
 | 
							setPlayerPid(0);
 | 
				
			||||||
		player_pid = 0;
 | 
							player_pid = 0;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						else 
 | 
				
			||||||
 | 
							setPlayerPid(player_pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unblockSignals();
 | 
						unblockSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -183,13 +189,13 @@ int playerPlay(FILE * fp, Song * song) {
 | 
				
			|||||||
	pc->utf8url[MAXPATHLEN] = '\0';
 | 
						pc->utf8url[MAXPATHLEN] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pc->play = 1;
 | 
						pc->play = 1;
 | 
				
			||||||
	if(player_pid==0 && playerInit()<0) {
 | 
						if(getPlayerPid()==0 && playerInit()<0) {
 | 
				
			||||||
		pc->play = 0;
 | 
							pc->play = 0;
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
        resetPlayerMetadata();
 | 
					        resetPlayerMetadata();
 | 
				
			||||||
	while(player_pid>0 && pc->play) my_usleep(1000);
 | 
						while(getPlayerPid()>0 && pc->play) my_usleep(1000);
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -197,9 +203,9 @@ int playerPlay(FILE * fp, Song * song) {
 | 
				
			|||||||
int playerStop(FILE * fp) {
 | 
					int playerStop(FILE * fp) {
 | 
				
			||||||
	PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
						PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
 | 
						if(getPlayerPid()>0 && pc->state!=PLAYER_STATE_STOP) {
 | 
				
			||||||
		pc->stop = 1;
 | 
							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;
 | 
						pc->queueState = PLAYER_QUEUE_BLANK;
 | 
				
			||||||
@@ -216,16 +222,16 @@ void playerKill() {
 | 
				
			|||||||
	playerCloseAudio(stderr);
 | 
						playerCloseAudio(stderr);
 | 
				
			||||||
	if(player_pid>0 && pc->closeAudio) sleep(1);*/
 | 
						if(player_pid>0 && pc->closeAudio) sleep(1);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pid = player_pid;
 | 
						pid = getPlayerPid();
 | 
				
			||||||
	if(pid>0) kill(pid,SIGTERM);
 | 
						if(pid>0) kill(pid,SIGTERM);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int playerPause(FILE * fp) {
 | 
					int playerPause(FILE * fp) {
 | 
				
			||||||
	PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
						PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
 | 
						if(getPlayerPid()>0 && pc->state!=PLAYER_STATE_STOP) {
 | 
				
			||||||
		pc->pause = 1;
 | 
							pc->pause = 1;
 | 
				
			||||||
		while(player_pid>0 && pc->pause) my_usleep(1000);
 | 
							while(getPlayerPid()>0 && pc->pause) my_usleep(1000);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -234,7 +240,7 @@ int playerPause(FILE * fp) {
 | 
				
			|||||||
int playerSetPause(FILE * fp, int pause) {
 | 
					int playerSetPause(FILE * fp, int pause) {
 | 
				
			||||||
	PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
						PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(player_pid<=0) return 0;
 | 
						if(getPlayerPid()<=0) return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch(pc->state) {
 | 
						switch(pc->state) {
 | 
				
			||||||
	case PLAYER_STATE_PLAY:
 | 
						case PLAYER_STATE_PLAY:
 | 
				
			||||||
@@ -314,7 +320,7 @@ char * getPlayerErrorStr() {
 | 
				
			|||||||
void playerCloseAudio() {
 | 
					void playerCloseAudio() {
 | 
				
			||||||
	PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
						PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(player_pid>0) {
 | 
						if(getPlayerPid()>0) {
 | 
				
			||||||
		if(playerStop(stderr)<0) return;
 | 
							if(playerStop(stderr)<0) return;
 | 
				
			||||||
		pc->closeAudio = 1;
 | 
							pc->closeAudio = 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -354,20 +360,20 @@ void setQueueState(int queueState) {
 | 
				
			|||||||
void playerQueueLock() {
 | 
					void playerQueueLock() {
 | 
				
			||||||
	PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
						PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
 | 
						if(getPlayerPid()>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		pc->lockQueue = 1;
 | 
							pc->lockQueue = 1;
 | 
				
			||||||
		while(player_pid>0 && pc->lockQueue) my_usleep(1000);
 | 
							while(getPlayerPid()>0 && pc->lockQueue) my_usleep(1000);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void playerQueueUnlock() {
 | 
					void playerQueueUnlock() {
 | 
				
			||||||
	PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
						PlayerControl * pc = &(getPlayerData()->playerControl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
 | 
						if(getPlayerPid()>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		pc->unlockQueue = 1;
 | 
							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();
 | 
					                resetPlayerMetadata();
 | 
				
			||||||
		pc->seekWhere = time;
 | 
							pc->seekWhere = time;
 | 
				
			||||||
		pc->seek = 1;
 | 
							pc->seek = 1;
 | 
				
			||||||
		while(player_pid>0 && pc->seek) my_usleep(1000);
 | 
							while(getPlayerPid()>0 && pc->seek) my_usleep(1000);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,6 +34,7 @@ int buffered_chunks;
 | 
				
			|||||||
#define DEFAULT_BUFFER_BEFORE_PLAY	0
 | 
					#define DEFAULT_BUFFER_BEFORE_PLAY	0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PlayerData * playerData_pd;
 | 
					PlayerData * playerData_pd;
 | 
				
			||||||
 | 
					int * player_pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void initPlayerData() {
 | 
					void initPlayerData() {
 | 
				
			||||||
	float perc = DEFAULT_BUFFER_BEFORE_PLAY;
 | 
						float perc = DEFAULT_BUFFER_BEFORE_PLAY;
 | 
				
			||||||
@@ -102,6 +103,22 @@ void initPlayerData() {
 | 
				
			|||||||
		ERROR("problems shmctl'ing\n");
 | 
							ERROR("problems shmctl'ing\n");
 | 
				
			||||||
		exit(EXIT_FAILURE);
 | 
							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);
 | 
						buffer = &(playerData_pd->buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -147,6 +164,15 @@ PlayerData * getPlayerData() {
 | 
				
			|||||||
	return playerData_pd;
 | 
						return playerData_pd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int getPlayerPid() {
 | 
				
			||||||
 | 
						return *player_pid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setPlayerPid(int pid) {
 | 
				
			||||||
 | 
						*player_pid = pid;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void freePlayerData() {
 | 
					void freePlayerData() {
 | 
				
			||||||
	shmdt(playerData_pd);
 | 
						shmdt(playerData_pd);
 | 
				
			||||||
 | 
						shmdt(player_pid);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,8 @@ typedef struct _PlayerData {
 | 
				
			|||||||
void initPlayerData();
 | 
					void initPlayerData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PlayerData * getPlayerData();
 | 
					PlayerData * getPlayerData();
 | 
				
			||||||
 | 
					int getPlayerPid();
 | 
				
			||||||
 | 
					void setPlayerPid(int pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void freePlayerData();
 | 
					void freePlayerData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "sig_handlers.h"
 | 
					#include "sig_handlers.h"
 | 
				
			||||||
#include "player.h"
 | 
					#include "player.h"
 | 
				
			||||||
 | 
					#include "playerData.h"
 | 
				
			||||||
#include "playlist.h"
 | 
					#include "playlist.h"
 | 
				
			||||||
#include "directory.h"
 | 
					#include "directory.h"
 | 
				
			||||||
#include "command.h"
 | 
					#include "command.h"
 | 
				
			||||||
@@ -33,10 +34,30 @@
 | 
				
			|||||||
#include <sys/resource.h>
 | 
					#include <sys/resource.h>
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
#include <errno.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() {
 | 
					int handlePendingSignals() {
 | 
				
			||||||
        if(signal_is_pending(SIGINT) || signal_is_pending(SIGTERM)) {
 | 
					        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;
 | 
							return COMMAND_RETURN_KILL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,17 +78,55 @@ int handlePendingSignals() {
 | 
				
			|||||||
void chldSigHandler(int signal) {
 | 
					void chldSigHandler(int signal) {
 | 
				
			||||||
	int status;
 | 
						int status;
 | 
				
			||||||
	int pid;
 | 
						int pid;
 | 
				
			||||||
	DEBUG("got SIGCHLD\n");
 | 
						DEBUG("main process got SIGCHLD\n");
 | 
				
			||||||
	while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
 | 
						while(0 != (pid = wait3(&status,WNOHANG,NULL))) {
 | 
				
			||||||
		if(pid<0) {
 | 
							if(pid<0) {
 | 
				
			||||||
			if(errno==EINTR) continue;
 | 
								if(errno==EINTR) continue;
 | 
				
			||||||
			else break;
 | 
								else break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		player_sigChldHandler(pid,status);
 | 
					 | 
				
			||||||
		directory_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() {
 | 
					void initSigHandlers() {
 | 
				
			||||||
	struct sigaction sa;
 | 
						struct sigaction sa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -114,17 +173,32 @@ void ignoreSignals() {
 | 
				
			|||||||
	while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
 | 
						while(sigaction(SIGPIPE,&sa,NULL)<0 && errno==EINTR);
 | 
				
			||||||
	while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
 | 
						while(sigaction(SIGCHLD,&sa,NULL)<0 && errno==EINTR);
 | 
				
			||||||
	while(sigaction(SIGUSR1,&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(SIGINT,&sa,NULL)<0 && errno==EINTR);
 | 
				
			||||||
	while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
 | 
						while(sigaction(SIGTERM,&sa,NULL)<0 && errno==EINTR);
 | 
				
			||||||
	while(sigaction(SIGHUP,&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() {
 | 
					void blockSignals() {
 | 
				
			||||||
	sigset_t sset;
 | 
						sigset_t sset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sigemptyset(&sset);
 | 
						sigemptyset(&sset);
 | 
				
			||||||
	sigaddset(&sset,SIGCHLD);
 | 
						sigaddset(&sset,SIGCHLD);
 | 
				
			||||||
	sigaddset(&sset,SIGUSR1);
 | 
						sigaddset(&sset,SIGUSR1);
 | 
				
			||||||
 | 
						sigaddset(&sset,SIGUSR2);
 | 
				
			||||||
	sigaddset(&sset,SIGHUP);
 | 
						sigaddset(&sset,SIGHUP);
 | 
				
			||||||
	sigaddset(&sset,SIGINT);
 | 
						sigaddset(&sset,SIGINT);
 | 
				
			||||||
	sigaddset(&sset,SIGTERM);
 | 
						sigaddset(&sset,SIGTERM);
 | 
				
			||||||
@@ -137,6 +211,7 @@ void unblockSignals() {
 | 
				
			|||||||
	sigemptyset(&sset);
 | 
						sigemptyset(&sset);
 | 
				
			||||||
	sigaddset(&sset,SIGCHLD);
 | 
						sigaddset(&sset,SIGCHLD);
 | 
				
			||||||
	sigaddset(&sset,SIGUSR1);
 | 
						sigaddset(&sset,SIGUSR1);
 | 
				
			||||||
 | 
						sigaddset(&sset,SIGUSR2);
 | 
				
			||||||
	sigaddset(&sset,SIGHUP);
 | 
						sigaddset(&sset,SIGHUP);
 | 
				
			||||||
	sigaddset(&sset,SIGINT);
 | 
						sigaddset(&sset,SIGINT);
 | 
				
			||||||
	sigaddset(&sset,SIGTERM);
 | 
						sigaddset(&sset,SIGTERM);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,8 +22,10 @@
 | 
				
			|||||||
#include "../config.h"
 | 
					#include "../config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int handlePendingSignals();
 | 
					int handlePendingSignals();
 | 
				
			||||||
 | 
					int masterHandlePendingSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void initSigHandlers();
 | 
					void initSigHandlers();
 | 
				
			||||||
 | 
					void masterInitSigHandlers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void finishSigHandlers();
 | 
					void finishSigHandlers();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,6 +33,8 @@ void setSigHandlersForDecoder();
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void ignoreSignals();
 | 
					void ignoreSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void waitOnSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void blockSignals();
 | 
					void blockSignals();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void unblockSignals();
 | 
					void unblockSignals();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										136
									
								
								src/tagTracker.c
									
									
									
									
									
								
							
							
						
						
									
										136
									
								
								src/tagTracker.c
									
									
									
									
									
								
							@@ -1,11 +1,12 @@
 | 
				
			|||||||
#include "tagTracker.h"
 | 
					#include "tagTracker.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "list.h"
 | 
					 | 
				
			||||||
#include "log.h"
 | 
					#include "log.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <glib/gtree.h>
 | 
				
			||||||
#include <assert.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,
 | 
				
			||||||
	NULL,
 | 
						NULL,
 | 
				
			||||||
@@ -21,89 +22,96 @@ typedef struct tagTrackerItem {
 | 
				
			|||||||
	mpd_sint8 visited;
 | 
						mpd_sint8 visited;
 | 
				
			||||||
} TagTrackerItem;
 | 
					} TagTrackerItem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int keyCompare(const void *a, const void *b, void *data) {
 | 
				
			||||||
 | 
						return strcmp(a,b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char * getTagItemString(int type, char * string) {
 | 
					char * getTagItemString(int type, char * string) {
 | 
				
			||||||
	ListNode * node;
 | 
						TagTrackerItem * item;
 | 
				
			||||||
	int pos;
 | 
						TagTrackerItem ** itemPointer = &item;
 | 
				
			||||||
 | 
						char *key;
 | 
				
			||||||
 | 
						char **keyPointer = &key;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*if(type == TAG_ITEM_TITLE) return strdup(string);*/
 | 
						/*if(type == TAG_ITEM_TITLE) return strdup(string);*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(tagLists[type] == NULL) {
 | 
						if(tagLists[type] == NULL) {
 | 
				
			||||||
		tagLists[type] = makeList(free, 1);
 | 
							tagLists[type] = g_tree_new_full(keyCompare, NULL, free, free);
 | 
				
			||||||
		sortList(tagLists[type]);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(findNodeInList(tagLists[type], string, &node, &pos)) {
 | 
						if((TagTrackerItem *)g_tree_lookup_extended(tagLists[type], string, (void**)keyPointer, (void**)itemPointer )) {
 | 
				
			||||||
		((TagTrackerItem *)node->data)->count++;
 | 
							item->count++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		TagTrackerItem * item = malloc(sizeof(TagTrackerItem));
 | 
							item = malloc(sizeof(TagTrackerItem));
 | 
				
			||||||
		item->count = 1;
 | 
							item->count = 1;
 | 
				
			||||||
		item->visited = 0;
 | 
							item->visited = 0;
 | 
				
			||||||
		node = insertInListBeforeNode(tagLists[type], node, pos, 
 | 
							key = strdup(string);
 | 
				
			||||||
				string, item);
 | 
							g_tree_insert(tagLists[type], key, item);
 | 
				
			||||||
 | 
							
 | 
				
			||||||
				
 | 
									
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return node->key;
 | 
						return key;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void removeTagItemString(int type, char * string) {
 | 
					void removeTagItemString(int type, char * string) {
 | 
				
			||||||
	ListNode * node;
 | 
						TagTrackerItem *item;
 | 
				
			||||||
	int pos;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert(string);
 | 
						assert(string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert(tagLists[type]);
 | 
						assert(tagLists[type]);
 | 
				
			||||||
	if(tagLists[type] == NULL) return;
 | 
						if(tagLists[type] == NULL) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*if(!node) {
 | 
						if((item = g_tree_lookup(tagLists[type], string))) {
 | 
				
			||||||
		free(string);
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if(findNodeInList(tagLists[type], string, &node, &pos)) {
 | 
					 | 
				
			||||||
		TagTrackerItem * item = node->data;
 | 
					 | 
				
			||||||
		item->count--;
 | 
							item->count--;
 | 
				
			||||||
		if(item->count <= 0) deleteNodeFromList(tagLists[type], node);
 | 
							if(item->count <= 0) g_tree_remove(tagLists[type], string);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* why would this be done??? free it when mpd quits...
 | 
				
			||||||
 	if(tagLists[type]->numberOfNodes == 0) {
 | 
					 	if(tagLists[type]->numberOfNodes == 0) {
 | 
				
			||||||
		freeList(tagLists[type]);
 | 
							freeList(tagLists[type]);
 | 
				
			||||||
		tagLists[type] = NULL;
 | 
							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) {
 | 
					int getNumberOfTagItems(int type) {
 | 
				
			||||||
	if(tagLists[type] == NULL) return 0;
 | 
						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() {
 | 
					void printMemorySavedByTagTracker() {
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	ListNode * node;
 | 
					 | 
				
			||||||
	size_t sum = 0;
 | 
						size_t sum = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
 | 
						for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
 | 
				
			||||||
		if(!tagLists[i]) continue;
 | 
							if(!tagLists[i]) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sum -= sizeof(List);
 | 
							sum -= 5*sizeof(void*);//sizeof(_GTree)
 | 
				
			||||||
		
 | 
							g_tree_foreach(tagLists[i], (GTraverseFunc)calcSavedMemory, &sum);
 | 
				
			||||||
		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;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DEBUG("saved memory from tags: %li\n", (long)sum);
 | 
						DEBUG("saved memory from tags: %li\n", (long)sum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sortTagTrackerInfo() {
 | 
					void sortTagTrackerInfo() {
 | 
				
			||||||
 | 
						/* implicit sorting
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
 | 
						for(i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
 | 
				
			||||||
@@ -112,56 +120,52 @@ void sortTagTrackerInfo() {
 | 
				
			|||||||
		DEBUG("sorting %s info\n", mpdTagItemKeys[i]);
 | 
							DEBUG("sorting %s info\n", mpdTagItemKeys[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		sortList(tagLists[i]);
 | 
							sortList(tagLists[i]);
 | 
				
			||||||
	}
 | 
						}*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int resetVisitedFlag(char *key, TagTrackerItem *value, void *data) {
 | 
				
			||||||
 | 
						value->visited = 0;
 | 
				
			||||||
 | 
						return FALSE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
void resetVisitedFlagsInTagTracker(int type) {
 | 
					void resetVisitedFlagsInTagTracker(int type) {
 | 
				
			||||||
	ListNode * node;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(!tagLists[type]) return;
 | 
						if(!tagLists[type]) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	node = tagLists[type]->firstNode;
 | 
						g_tree_foreach(tagLists[type], (GTraverseFunc)resetVisitedFlag, NULL);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	while(node) {
 | 
					 | 
				
			||||||
		((TagTrackerItem *)node->data)->visited = 0;
 | 
					 | 
				
			||||||
		node = node->nextNode;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int wasVisitedInTagTracker(int type, char * str) {
 | 
					int wasVisitedInTagTracker(int type, char * str) {
 | 
				
			||||||
	void * item;
 | 
						TagTrackerItem * item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(!tagLists[type]) return 0;
 | 
						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 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;
 | 
						TagTrackerItem * item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(!tagLists[type]) return;
 | 
						if(!tagLists[type]) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	node = tagLists[type]->firstNode;
 | 
						if(!(item = g_tree_lookup(tagLists[type], str))) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while(node) {
 | 
						item->visited = 1;
 | 
				
			||||||
		item = node->data;
 | 
					}
 | 
				
			||||||
		if(item->visited) {
 | 
					
 | 
				
			||||||
			myfprintf(fp, "%s: %s\n", mpdTagItemKeys[type],
 | 
					struct _PrintVisitedUserdata {
 | 
				
			||||||
					node->key);
 | 
						FILE *fp;
 | 
				
			||||||
		}
 | 
						char *type;
 | 
				
			||||||
		node = node->nextNode;
 | 
					};
 | 
				
			||||||
	}
 | 
					
 | 
				
			||||||
 | 
					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);
 | 
					char * getTagItemString(int type, char * string);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void removeTagItemString(int type, char * string);
 | 
					void removeTagItemString(int type, char * string);
 | 
				
			||||||
 | 
					void destroyTagTracker();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int getNumberOfTagItems(int type);
 | 
					int getNumberOfTagItems(int type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user