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
	 Qball Cow
					Qball Cow