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

View File

@ -56,8 +56,6 @@
# define sqlite3_threadsafe() 0 # define sqlite3_threadsafe() 0
#endif #endif
static volatile int quitting = 0;
/* OpenAndConfHTTPSocket() : /* OpenAndConfHTTPSocket() :
* setup the socket used to handle incoming HTTP connections. */ * setup the socket used to handle incoming HTTP connections. */
static int static int
@ -649,7 +647,8 @@ main(int argc, char * * argv)
int last_changecnt = 0; int last_changecnt = 0;
char * sql; char * sql;
short int new_db = 0; short int new_db = 0;
pthread_t thread[2]; pid_t scanner_pid = 0;
pthread_t inotify_thread = 0;
#ifdef TIVO_SUPPORT #ifdef TIVO_SUPPORT
unsigned short int beacon_interval = 5; unsigned short int beacon_interval = 5;
int sbeacon = -1; 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( 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 ) if( new_db )
{ {
DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n"); 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"); DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n");
} }
#if USE_FORK
scanning = 1; scanning = 1;
#if USE_FORK sqlite3_close(db);
if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 ) scanner_pid = fork();
{ sqlite3_open(DB_PATH "/files.db", &db);
if( pthread_create(&thread[0], NULL, start_scanner, NULL) ) sqlite3_busy_timeout(db, 5000);
{ if( !scanner_pid ) // child (scanner) process
DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_scanner.\n");
}
}
else
{ {
start_scanner(); start_scanner();
sqlite3_close(db);
exit(EXIT_SUCCESS);
} }
#else #else
start_scanner(); start_scanner();
#endif #endif
} }
sqlite3_free_table(result); sqlite3_free_table(result);
} }
if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 && 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"); DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify.\n");
} }
@ -861,6 +860,12 @@ main(int argc, char * * argv)
#endif #endif
} }
if( scanning )
{
if( !scanner_pid || kill(scanner_pid, 0) )
scanning = 0;
}
/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
FD_ZERO(&readset); FD_ZERO(&readset);
@ -981,6 +986,11 @@ main(int argc, char * * argv)
} }
shutdown: shutdown:
/* kill the scanner */
if( scanning && scanner_pid )
{
kill(scanner_pid, 9);
}
/* close out open sockets */ /* close out open sockets */
while(upnphttphead.lh_first != NULL) while(upnphttphead.lh_first != NULL)
{ {
@ -1002,22 +1012,31 @@ shutdown:
for(i=0; i<n_lan_addr; i++) for(i=0; i<n_lan_addr; i++)
close(snotify[i]); close(snotify[i]);
if( inotify_thread )
pthread_join(inotify_thread, NULL);
asprintf(&sql, "UPDATE SETTINGS set UPDATE_ID = %u", updateID); asprintf(&sql, "UPDATE SETTINGS set UPDATE_ID = %u", updateID);
sql_exec(db, sql); sql_exec(db, sql);
free(sql); free(sql);
sqlite3_close(db); sqlite3_close(db);
struct media_dir_s * media_path = media_dirs; struct media_dir_s * media_path = media_dirs;
struct media_dir_s * last_path;
while( media_path ) while( media_path )
{ {
free(media_path->path); free(media_path->path);
last_path = media_path;
media_path = media_path->next; media_path = media_path->next;
free(last_path);
} }
struct album_art_name_s * art_names = album_art_names; struct album_art_name_s * art_names = album_art_names;
struct album_art_name_s * last_name;
while( art_names ) while( art_names )
{ {
free(art_names->name); free(art_names->name);
last_name = art_names;
art_names = art_names->next; art_names = art_names->next;
free(last_name);
} }
if(unlink(pidfilename) < 0) if(unlink(pidfilename) < 0)
@ -1026,7 +1045,7 @@ shutdown:
} }
freeoptions(); 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() start_scanner()
{ {
struct media_dir_s * media_path = media_dirs; struct media_dir_s * media_path = media_dirs;
@ -822,7 +822,6 @@ start_scanner()
if( flag ) if( flag )
fclose(flag); fclose(flag);
#endif #endif
scanning = 1;
freopen("/dev/null", "a", stderr); freopen("/dev/null", "a", stderr);
while( media_path ) while( media_path )
{ {
@ -830,7 +829,6 @@ start_scanner()
media_path = media_path->next; media_path = media_path->next;
} }
freopen("/proc/self/fd/2", "a", stderr); freopen("/proc/self/fd/2", "a", stderr);
scanning = 0;
#ifdef READYNAS #ifdef READYNAS
if( access("/ramfs/.rescan_done", F_OK) == 0 ) if( access("/ramfs/.rescan_done", F_OK) == 0 )
system("/bin/sh /ramfs/.rescan_done"); 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 * This index is very useful for large libraries used with an XBox360 (or any
* client that uses UPnPSearch on large containers). */ * client that uses UPnPSearch on large containers). */
sql_exec(db, "create INDEX IDX_SEARCH_OPT ON OBJECTS(OBJECT_ID, CLASS, DETAIL_ID);"); 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 int
CreateDatabase(void); CreateDatabase(void);
void * void
start_scanner(); start_scanner();
#endif #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) if(!psong->title)
{ {
char *suffix; char *suffix;
@ -228,6 +228,7 @@ _make_composite_tags(struct song_metadata *psong)
suffix = strrchr(psong->title, '.'); suffix = strrchr(psong->title, '.');
if(suffix) *suffix = '\0'; 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 album_art_name_s * album_art_names = NULL;
struct client_cache_s clients[CLIENT_CACHE_SLOTS]; struct client_cache_s clients[CLIENT_CACHE_SLOTS];
short int scanning = 0; short int scanning = 0;
volatile short int quitting = 0;
volatile __u32 updateID = 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 album_art_name_s * album_art_names;
extern struct client_cache_s clients[CLIENT_CACHE_SLOTS]; extern struct client_cache_s clients[CLIENT_CACHE_SLOTS];
extern short int scanning; extern short int scanning;
extern volatile short int quitting;
extern volatile __u32 updateID; extern volatile __u32 updateID;
#endif #endif