* 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:
parent
1f29b0cac1
commit
ba29e35bcc
52
inotify.c
52
inotify.c
@ -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;
|
||||
}
|
||||
|
55
minidlna.c
55
minidlna.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ insert_file(char * name, const char * path, const char * parentID, int object);
|
||||
int
|
||||
CreateDatabase(void);
|
||||
|
||||
void *
|
||||
void
|
||||
start_scanner();
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user