* Clean up after some memory allocations before exit so valgrind is happy.

* Fork off the scanner process instead of doing it in another thread, so if libavformat leaks memory it will be cleaned up once scanning is finished.
This commit is contained in:
Justin Maggard 2009-10-03 02:08:59 +00:00
parent 1f29b0cac1
commit ba29e35bcc
7 changed files with 80 additions and 40 deletions

View File

@ -11,6 +11,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <poll.h>
#ifdef HAVE_INOTIFY_H
#include <sys/inotify.h>
#else
@ -194,13 +195,18 @@ int
inotify_remove_watches(int fd)
{
struct watch *w = watches;
struct watch *last_w;
int rm_watches = 0;
while( w )
{
last_w = w;
inotify_rm_watch(fd, w->wd);
if( w->path )
free(w->path);
rm_watches++;
w = w->next;
free(last_w);
}
return rm_watches;
@ -593,34 +599,49 @@ inotify_remove_directory(int fd, const char * path)
void *
start_inotify()
{
int fd;
struct pollfd pollfds[1];
int timeout = 1000;
char buffer[BUF_LEN];
char path_buf[PATH_MAX];
int length, i = 0;
char * esc_name = NULL;
struct stat st;
fd = inotify_init();
pollfds[0].fd = inotify_init();
pollfds[0].events = POLLIN;
if ( fd < 0 ) {
if ( pollfds[0].fd < 0 ) {
DPRINTF(E_ERROR, L_INOTIFY, "inotify_init() failed!\n");
}
while( scanning )
{
if( quitting )
goto quitting;
sleep(1);
}
inotify_create_watches(fd);
inotify_create_watches(pollfds[0].fd);
if (setpriority(PRIO_PROCESS, 0, 19) == -1)
DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce inotify thread priority\n");
while( 1 )
while( !quitting )
{
length = read(fd, buffer, BUF_LEN);
if ( length < 0 ) {
DPRINTF(E_ERROR, L_INOTIFY, "read failed!\n");
}
length = poll(pollfds, 1, timeout);
if( !length )
{
continue;
}
else if( length < 0 )
{
if( (errno == EINTR) || (errno == EAGAIN) )
continue;
else
DPRINTF(E_ERROR, L_INOTIFY, "read failed!\n");
}
else
{
length = read(pollfds[0].fd, buffer, BUF_LEN);
}
i = 0;
while( i < length )
@ -639,7 +660,7 @@ start_inotify()
(event->mask & IN_MOVED_TO && event->mask & IN_ISDIR) )
{
DPRINTF(E_DEBUG, L_INOTIFY, "The directory %s was %s.\n", path_buf, (event->mask & IN_MOVED_TO ? "moved here" : "created"));
inotify_insert_directory(fd, esc_name, path_buf);
inotify_insert_directory(pollfds[0].fd, esc_name, path_buf);
}
else if ( event->mask & IN_CLOSE_WRITE || event->mask & IN_MOVED_TO )
{
@ -654,7 +675,7 @@ start_inotify()
if ( event->mask & IN_ISDIR )
{
DPRINTF(E_DEBUG, L_INOTIFY, "The directory %s was %s.\n", path_buf, (event->mask & IN_MOVED_FROM ? "moved away" : "deleted"));
inotify_remove_directory(fd, path_buf);
inotify_remove_directory(pollfds[0].fd, path_buf);
}
else
{
@ -667,8 +688,9 @@ start_inotify()
i += EVENT_SIZE + event->len;
}
}
inotify_remove_watches(fd);
close(fd);
inotify_remove_watches(pollfds[0].fd);
quitting:
close(pollfds[0].fd);
return NULL;
return 0;
}

View File

@ -56,8 +56,6 @@
# define sqlite3_threadsafe() 0
#endif
static volatile int quitting = 0;
/* OpenAndConfHTTPSocket() :
* setup the socket used to handle incoming HTTP connections. */
static int
@ -649,7 +647,8 @@ main(int argc, char * * argv)
int last_changecnt = 0;
char * sql;
short int new_db = 0;
pthread_t thread[2];
pid_t scanner_pid = 0;
pthread_t inotify_thread = 0;
#ifdef TIVO_SUPPORT
unsigned short int beacon_interval = 5;
int sbeacon = -1;
@ -704,7 +703,8 @@ main(int argc, char * * argv)
}
if( sql_get_table(db, "pragma user_version", &result, &rows, 0) == SQLITE_OK )
{
if( atoi(result[1]) != DB_VERSION ) {
if( atoi(result[1]) != DB_VERSION )
{
if( new_db )
{
DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n");
@ -722,27 +722,26 @@ main(int argc, char * * argv)
{
DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n");
}
#if USE_FORK
scanning = 1;
#if USE_FORK
if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 )
{
if( pthread_create(&thread[0], NULL, start_scanner, NULL) )
{
DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_scanner.\n");
}
}
else
sqlite3_close(db);
scanner_pid = fork();
sqlite3_open(DB_PATH "/files.db", &db);
sqlite3_busy_timeout(db, 5000);
if( !scanner_pid ) // child (scanner) process
{
start_scanner();
sqlite3_close(db);
exit(EXIT_SUCCESS);
}
#else
#else
start_scanner();
#endif
#endif
}
sqlite3_free_table(result);
}
if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 &&
GETFLAG(INOTIFYMASK) && pthread_create(&thread[1], NULL, start_inotify, NULL) )
GETFLAG(INOTIFYMASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) )
{
DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify.\n");
}
@ -861,6 +860,12 @@ main(int argc, char * * argv)
#endif
}
if( scanning )
{
if( !scanner_pid || kill(scanner_pid, 0) )
scanning = 0;
}
/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
FD_ZERO(&readset);
@ -981,6 +986,11 @@ main(int argc, char * * argv)
}
shutdown:
/* kill the scanner */
if( scanning && scanner_pid )
{
kill(scanner_pid, 9);
}
/* close out open sockets */
while(upnphttphead.lh_first != NULL)
{
@ -1002,22 +1012,31 @@ shutdown:
for(i=0; i<n_lan_addr; i++)
close(snotify[i]);
if( inotify_thread )
pthread_join(inotify_thread, NULL);
asprintf(&sql, "UPDATE SETTINGS set UPDATE_ID = %u", updateID);
sql_exec(db, sql);
free(sql);
sqlite3_close(db);
struct media_dir_s * media_path = media_dirs;
struct media_dir_s * last_path;
while( media_path )
{
free(media_path->path);
last_path = media_path;
media_path = media_path->next;
free(last_path);
}
struct album_art_name_s * art_names = album_art_names;
struct album_art_name_s * last_name;
while( art_names )
{
free(art_names->name);
last_name = art_names;
art_names = art_names->next;
free(last_name);
}
if(unlink(pidfilename) < 0)
@ -1026,7 +1045,7 @@ shutdown:
}
freeoptions();
return 0;
exit(EXIT_SUCCESS);
}

View File

@ -809,7 +809,7 @@ ScanDirectory(const char * dir, const char * parent, enum media_types dir_type)
}
}
void *
void
start_scanner()
{
struct media_dir_s * media_path = media_dirs;
@ -822,7 +822,6 @@ start_scanner()
if( flag )
fclose(flag);
#endif
scanning = 1;
freopen("/dev/null", "a", stderr);
while( media_path )
{
@ -830,7 +829,6 @@ start_scanner()
media_path = media_path->next;
}
freopen("/proc/self/fd/2", "a", stderr);
scanning = 0;
#ifdef READYNAS
if( access("/ramfs/.rescan_done", F_OK) == 0 )
system("/bin/sh /ramfs/.rescan_done");
@ -840,6 +838,4 @@ start_scanner()
* This index is very useful for large libraries used with an XBox360 (or any
* client that uses UPnPSearch on large containers). */
sql_exec(db, "create INDEX IDX_SEARCH_OPT ON OBJECTS(OBJECT_ID, CLASS, DETAIL_ID);");
return 0;
}

View File

@ -38,7 +38,7 @@ insert_file(char * name, const char * path, const char * parentID, int object);
int
CreateDatabase(void);
void *
void
start_scanner();
#endif

View File

@ -220,7 +220,7 @@ _make_composite_tags(struct song_metadata *psong)
}
}
#if 0 // already taken care of by scanner.c
if(!psong->title)
{
char *suffix;
@ -228,6 +228,7 @@ _make_composite_tags(struct song_metadata *psong)
suffix = strrchr(psong->title, '.');
if(suffix) *suffix = '\0';
}
#endif
}

View File

@ -46,4 +46,5 @@ struct media_dir_s * media_dirs = NULL;
struct album_art_name_s * album_art_names = NULL;
struct client_cache_s clients[CLIENT_CACHE_SLOTS];
short int scanning = 0;
volatile short int quitting = 0;
volatile __u32 updateID = 0;

View File

@ -111,6 +111,7 @@ extern struct media_dir_s * media_dirs;
extern struct album_art_name_s * album_art_names;
extern struct client_cache_s clients[CLIENT_CACHE_SLOTS];
extern short int scanning;
extern volatile short int quitting;
extern volatile __u32 updateID;
#endif