Created
January 23, 2014 01:49
-
-
Save sorin-ionescu/8571344 to your computer and use it in GitHub Desktop.
MiniDLNA 1.1.1 kqueue patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/configure.ac b/configure.ac | |
index 9ba8fac..4fa72a7 100644 | |
--- a/configure.ac | |
+++ b/configure.ac | |
@@ -437,7 +437,7 @@ AC_CHECK_LIB(vorbisfile, vorbis_comment_query, | |
################################################################################################################ | |
### Header checks | |
-AC_CHECK_HEADERS([arpa/inet.h asm/unistd.h endian.h machine/endian.h fcntl.h libintl.h locale.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/file.h sys/inotify.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h]) | |
+AC_CHECK_HEADERS([arpa/inet.h asm/unistd.h endian.h machine/endian.h fcntl.h libintl.h locale.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/file.h sys/inotify.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h sys/event.h]) | |
AC_CHECK_FUNCS(inotify_init, AC_DEFINE(HAVE_INOTIFY,1,[Whether kernel has inotify support]), [ | |
AC_MSG_CHECKING([for __NR_inotify_init syscall]) | |
diff --git a/inotify.c b/inotify.c | |
index 935edb2..effa2b3 100644 | |
--- a/inotify.c | |
+++ b/inotify.c | |
@@ -15,9 +15,10 @@ | |
* You should have received a copy of the GNU General Public License | |
* along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>. | |
*/ | |
+ | |
#include "config.h" | |
-#ifdef HAVE_INOTIFY | |
+#if defined(HAVE_INOTIFY) || defined(HAVE_SYS_EVENT_H) | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdlib.h> | |
@@ -31,11 +32,16 @@ | |
#include <sys/time.h> | |
#include <sys/resource.h> | |
#include <poll.h> | |
+#ifdef HAVE_INOTIFY | |
#ifdef HAVE_SYS_INOTIFY_H | |
#include <sys/inotify.h> | |
-#else | |
+#else /*HAVE_SYS_INOTIFY_H*/ | |
#include "linux/inotify.h" | |
#include "linux/inotify-syscalls.h" | |
+#endif /*HAVE_SYS_INOTIFY_H*/ | |
+#else | |
+#include <sys/event.h> | |
+#include <fcntl.h> | |
#endif | |
#include "libav.h" | |
@@ -49,11 +55,13 @@ | |
#include "playlist.h" | |
#include "log.h" | |
+#ifdef HAVE_INOTIFY | |
#define EVENT_SIZE ( sizeof (struct inotify_event) ) | |
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) ) | |
#define DESIRED_WATCH_LIMIT 65536 | |
#define PATH_BUF_SIZE PATH_MAX | |
+#endif | |
struct watch | |
{ | |
@@ -86,12 +94,34 @@ add_watch(int fd, const char * path) | |
struct watch *nw; | |
int wd; | |
+#ifdef HAVE_INOTIFY | |
wd = inotify_add_watch(fd, path, IN_CREATE|IN_CLOSE_WRITE|IN_DELETE|IN_MOVE); | |
if( wd < 0 ) | |
{ | |
DPRINTF(E_ERROR, L_INOTIFY, "inotify_add_watch(%s) [%s]\n", path, strerror(errno)); | |
return -1; | |
} | |
+#else /*HAVE_INOTIFY*/ | |
+ wd = open(path, O_RDONLY); | |
+ if (wd == -1) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "inotify_add_watch[kqueue,open](%s) [%s]\n", path, strerror(errno)); | |
+ return -1; | |
+ } | |
+ | |
+ struct kevent ke; | |
+ EV_SET(&ke, wd, | |
+ EVFILT_VNODE, | |
+ EV_ADD | EV_ENABLE | EV_CLEAR, | |
+ NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND /*| NOTE_ATTRB*/, | |
+ 0, NULL); | |
+ | |
+ if( kevent(fd, &ke, 1, NULL, 0, NULL) == -1 ) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "inotify_add_watch[kqueue](%s) [%s]\n", path, strerror(errno)); | |
+ return -1; | |
+ } | |
+#endif | |
nw = malloc(sizeof(struct watch)); | |
if( nw == NULL ) | |
@@ -125,7 +155,12 @@ remove_watch(int fd, const char * path) | |
for( w = watches; w; w = w->next ) | |
{ | |
if( strcmp(path, w->path) == 0 ) | |
+#ifdef HAVE_INOTIFY | |
return(inotify_rm_watch(fd, w->wd)); | |
+#else | |
+ close(w->wd); /* kqueue cleans up events when handle dies*/ | |
+ return(0); | |
+#endif | |
} | |
return 1; | |
@@ -145,8 +180,7 @@ next_highest(unsigned int num) | |
int | |
inotify_create_watches(int fd) | |
{ | |
- FILE * max_watches; | |
- unsigned int num_watches = 0, watch_limit; | |
+ unsigned int num_watches = 0; | |
char **result; | |
int i, rows = 0; | |
struct media_dir_s * media_path; | |
@@ -165,7 +199,11 @@ inotify_create_watches(int fd) | |
num_watches++; | |
} | |
sqlite3_free_table(result); | |
- | |
+ | |
+#ifdef HAVE_INOTIFY | |
+ FILE * max_watches; | |
+ unsigned int watch_limit; | |
+ | |
max_watches = fopen("/proc/sys/fs/inotify/max_user_watches", "r"); | |
if( max_watches ) | |
{ | |
@@ -204,6 +242,7 @@ inotify_create_watches(int fd) | |
DPRINTF(E_WARN, L_INOTIFY, "WARNING: Could not read inotify max_user_watches! " | |
"Hopefully it is enough to cover %u current directories plus any new ones added.\n", num_watches); | |
} | |
+#endif | |
return rows; | |
} | |
@@ -218,7 +257,11 @@ inotify_remove_watches(int fd) | |
while( w ) | |
{ | |
last_w = w; | |
+#ifdef HAVE_INOTIFY | |
inotify_rm_watch(fd, w->wd); | |
+#else | |
+ close(w->wd); /*kqueue cleans up after fhandle dies*/ | |
+#endif | |
free(w->path); | |
rm_watches++; | |
w = w->next; | |
@@ -294,6 +337,8 @@ inotify_insert_file(char * name, const char * path) | |
struct media_dir_s * media_path = media_dirs; | |
struct stat st; | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "inotify_insert_file: %s @ %s\n", name, path); | |
+ | |
/* Is it cover art for another file? */ | |
if( is_image(path) ) | |
update_if_album_art(path); | |
@@ -421,7 +466,7 @@ inotify_insert_file(char * name, const char * path) | |
if( !depth ) | |
{ | |
- //DEBUG DPRINTF(E_DEBUG, L_INOTIFY, "Inserting %s\n", name); | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Inserting %s\n", name); | |
insert_file(name, path, id+2, get_next_available_id("OBJECTS", id)); | |
sqlite3_free(id); | |
if( (is_audio(path) || is_playlist(path)) && next_pl_fill != 1 ) | |
@@ -446,6 +491,8 @@ inotify_insert_directory(int fd, char *name, const char * path) | |
struct media_dir_s* media_path; | |
struct stat st; | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "inotify_insert_directory: %s @ %s\n", name, path); | |
+ | |
if( access(path, R_OK|X_OK) != 0 ) | |
{ | |
DPRINTF(E_WARN, L_INOTIFY, "Could not access %s [%s]\n", path, strerror(errno)); | |
@@ -538,6 +585,8 @@ inotify_remove_file(const char * path) | |
int64_t detailID; | |
int rows, playlist; | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "inotify_remove_file: %s\n", path); | |
+ | |
if( ends_with(path, ".srt") ) | |
{ | |
return sql_exec(db, "DELETE from CAPTIONS where PATH = '%q'", path); | |
@@ -582,6 +631,8 @@ inotify_remove_file(const char * path) | |
continue; | |
if( children < 2 ) | |
{ | |
+ sql_exec(db, "DELETE from DETAILS where ID =" | |
+ " (SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s')", result[i]); | |
sql_exec(db, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]); | |
ptr = strrchr(result[i], '$'); | |
@@ -589,6 +640,8 @@ inotify_remove_file(const char * path) | |
*ptr = '\0'; | |
if( sql_get_int_field(db, "SELECT count(*) from OBJECTS where PARENT_ID = '%s'", result[i]) == 0 ) | |
{ | |
+ sql_exec(db, "DELETE from DETAILS where ID =" | |
+ " (SELECT DETAIL_ID from OBJECTS where OBJECT_ID = '%s')", result[i]); | |
sql_exec(db, "DELETE from OBJECTS where OBJECT_ID = '%s'", result[i]); | |
} | |
} | |
@@ -613,6 +666,8 @@ inotify_remove_directory(int fd, const char * path) | |
int64_t detailID = 0; | |
int rows, i, ret = 1; | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "inotify_remove_directory: %s\n", path); | |
+ | |
/* Invalidate the scanner cache so we don't insert files into non-existent containers */ | |
valid_cache = 0; | |
remove_watch(fd, path); | |
@@ -639,6 +694,7 @@ inotify_remove_directory(int fd, const char * path) | |
return ret; | |
} | |
+#ifdef HAVE_INOTIFY | |
void * | |
start_inotify() | |
{ | |
@@ -649,7 +705,7 @@ start_inotify() | |
int length, i = 0; | |
char * esc_name = NULL; | |
struct stat st; | |
- | |
+ | |
pollfds[0].fd = inotify_init(); | |
pollfds[0].events = POLLIN; | |
@@ -667,10 +723,10 @@ start_inotify() | |
DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce inotify thread priority\n"); | |
sqlite3_release_memory(1<<31); | |
av_register_all(); | |
- | |
+ | |
while( !quitting ) | |
{ | |
- length = poll(pollfds, 1, timeout); | |
+ length = poll(pollfds, 1, timeout); | |
if( !length ) | |
{ | |
if( next_pl_fill && (time(NULL) >= next_pl_fill) ) | |
@@ -682,14 +738,14 @@ start_inotify() | |
} | |
else if( length < 0 ) | |
{ | |
- if( (errno == EINTR) || (errno == EAGAIN) ) | |
- continue; | |
- else | |
+ if( (errno == EINTR) || (errno == EAGAIN) ) | |
+ continue; | |
+ else | |
DPRINTF(E_ERROR, L_INOTIFY, "read failed!\n"); | |
} | |
else | |
{ | |
- length = read(pollfds[0].fd, buffer, BUF_LEN); | |
+ length = read(pollfds[0].fd, buffer, BUF_LEN); | |
} | |
i = 0; | |
@@ -755,4 +811,222 @@ quitting: | |
return 0; | |
} | |
+#else | |
+void * | |
+start_kqueue() | |
+{ | |
+ int global_kqueue_handle = -1; | |
+ | |
+ global_kqueue_handle = kqueue(); | |
+ if ( global_kqueue_handle < 0 ) | |
+ DPRINTF(E_ERROR, L_INOTIFY, "kqueue() failed: %s\n", strerror(errno)); | |
+ | |
+ while( scanning ) | |
+ { | |
+ if( quitting ) | |
+ goto quitting; | |
+ sleep(1); | |
+ } | |
+ | |
+ inotify_create_watches(global_kqueue_handle); | |
+ if (setpriority(PRIO_PROCESS, 0, 19) == -1) | |
+ DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce kqueue thread priority\n"); | |
+ sqlite3_release_memory(1<<31); | |
+ av_register_all(); | |
+ | |
+ while( !quitting ) | |
+ { | |
+ struct kevent ke; | |
+ if ( kevent(global_kqueue_handle, NULL, 0, &ke, 1, NULL) == -1 ) | |
+ { | |
+ DPRINTF(E_WARN, L_INOTIFY, "kevent polling failure: %s\n", strerror(errno)); | |
+ } | |
+ | |
+ /*DPRINTF(E_DEBUG, L_INOTIFY, "GOT KEVENT:\n" | |
+ "ident=0x%X, filter=0x%X, flags=0x%X, fflags=0x%X, data=0x%X, udata=0x%X\n", | |
+ ke.ident, ke.filter, ke.flags, ke.fflags, ke.data, ke.udata);*/ | |
+ | |
+ char* dir_path = get_path_from_wd(ke.ident); | |
+ if (dir_path == NULL) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "Path with FD=0x%X can't be resolved.\n", ke.ident); | |
+ continue; | |
+ } | |
+ | |
+ if (ke.fflags & NOTE_DELETE) | |
+ { | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Path [%s] deleted.\n", dir_path); | |
+ inotify_remove_directory(ke.ident, dir_path); | |
+ } | |
+ else if ((ke.fflags & (NOTE_WRITE | NOTE_LINK)) == (NOTE_WRITE | NOTE_LINK)) | |
+ { | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Path [%s] content updated (directory).\n", dir_path); | |
+ | |
+ char * sql; | |
+ char **result; | |
+ int i, rows; | |
+ sql = sqlite3_mprintf("SELECT PATH from DETAILS where (PATH > '%q/' and PATH <= '%q/%c')" | |
+ " and SIZE = ''", dir_path, dir_path, 0xFF); | |
+ if( (sql_get_table(db, sql, &result, &rows, NULL) != SQLITE_OK) ) | |
+ { | |
+ DPRINTF(E_WARN, L_INOTIFY, "Read state [%s]: Query failed, not updating\n", dir_path); | |
+ sqlite3_free(sql); | |
+ continue; | |
+ } | |
+ | |
+ for( i=1; i <= rows; i++ ) | |
+ { | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Indexed content: %s\n", result[i]); | |
+ if (access(result[i], R_OK) == -1) | |
+ { | |
+ /* actually, global_kqueue_handle is not used here */ | |
+ inotify_remove_directory(global_kqueue_handle, result[i]); | |
+ } | |
+ } | |
+ | |
+ DIR* d; | |
+ struct dirent * entry; | |
+ d = opendir(dir_path); | |
+ if (!d) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "Can't list [%s] (%s)\n", dir_path, strerror(errno)); | |
+ continue; | |
+ } | |
+ | |
+ for ( entry = readdir(d); entry != NULL; entry = readdir(d) ) | |
+ { | |
+ if ( (entry->d_type == DT_DIR) && | |
+ (strcmp(entry->d_name, "..") != 0) && | |
+ (strcmp(entry->d_name, ".") != 0) ) | |
+ { | |
+ char tmp_path[PATH_MAX]; | |
+ int result_path_len; | |
+ | |
+ result_path_len = snprintf(tmp_path, PATH_MAX, | |
+ "%s/%s", dir_path, entry->d_name); | |
+ if (result_path_len >= PATH_MAX) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "File path too long for %s!", entry->d_name); | |
+ continue; | |
+ } | |
+ | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Walking %s\n", tmp_path); | |
+ char found_flag = 0; | |
+ for( i=1; i <= rows; i++ ) | |
+ { | |
+ if (strcmp(result[i], tmp_path) == 0) | |
+ { | |
+ found_flag = 1; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if ( !found_flag ) | |
+ { | |
+ char * esc_name = NULL; | |
+ esc_name = modifyString(strdup(entry->d_name), "&", "&amp;"); | |
+ inotify_insert_directory(global_kqueue_handle, esc_name, tmp_path); | |
+ free(esc_name); | |
+ } | |
+ } | |
+ } | |
+ | |
+ sqlite3_free_table(result); | |
+ sqlite3_free(sql); | |
+ } | |
+ else if (ke.fflags & NOTE_WRITE) | |
+ { | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Path [%s] content updated (file).\n", dir_path); | |
+ | |
+ char * sql; | |
+ char **result; | |
+ int i, rows; | |
+ sql = sqlite3_mprintf("SELECT PATH from DETAILS where (PATH > '%q/' and PATH <= '%q/%c')" | |
+ " and SIZE <> ''", dir_path, dir_path, 0xFF); | |
+ if( (sql_get_table(db, sql, &result, &rows, NULL) != SQLITE_OK) ) | |
+ { | |
+ DPRINTF(E_WARN, L_INOTIFY, "Read state [%s]: Query failed, not updating\n", dir_path); | |
+ sqlite3_free(sql); | |
+ continue; | |
+ } | |
+ | |
+ for( i=1; i <= rows; i++ ) | |
+ { | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Indexed content: %s\n", result[i]); | |
+ if (access(result[i], R_OK) == -1) /*oops, our file is gone*/ | |
+ { | |
+ inotify_remove_file(result[i]); | |
+ } | |
+ } | |
+ | |
+ DIR* d; | |
+ struct dirent * entry; | |
+ d = opendir(dir_path); | |
+ if (!d) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "Can't list [%s] (%s)\n", dir_path, strerror(errno)); | |
+ continue; | |
+ } | |
+ | |
+ for ( entry = readdir(d); entry != NULL; entry = readdir(d) ) | |
+ { | |
+ if ( (entry->d_type == DT_REG) || | |
+ (entry->d_type == DT_LNK) ) | |
+ { | |
+ char tmp_path[PATH_MAX]; | |
+ int result_path_len; | |
+ | |
+ result_path_len = snprintf(tmp_path, PATH_MAX, | |
+ "%s/%s", dir_path, entry->d_name); | |
+ if (result_path_len >= PATH_MAX) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "File path too long for %s!", entry->d_name); | |
+ continue; | |
+ } | |
+ | |
+ DPRINTF(E_DEBUG, L_INOTIFY, "Walking %s\n", tmp_path); | |
+ | |
+ char found_flag = 0; | |
+ for( i=1; i <= rows; i++ ) | |
+ { | |
+ if (strcmp(result[i], tmp_path) == 0) | |
+ { | |
+ found_flag = 1; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ if ( !found_flag ) | |
+ { | |
+ char * esc_name = NULL; | |
+ struct stat st; | |
+ | |
+ if( stat(tmp_path, &st) != 0 ) | |
+ { | |
+ DPRINTF(E_ERROR, L_INOTIFY, "'%s' disappeared!", tmp_path); | |
+ continue; | |
+ } | |
+ | |
+ esc_name = modifyString(strdup(entry->d_name), "&", "&amp;"); | |
+ if ( S_ISDIR(st.st_mode) ) | |
+ inotify_insert_directory(global_kqueue_handle, esc_name, tmp_path); | |
+ else | |
+ inotify_insert_file(esc_name, tmp_path); | |
+ free(esc_name); | |
+ } | |
+ } | |
+ } | |
+ | |
+ sqlite3_free_table(result); | |
+ sqlite3_free(sql); | |
+ } | |
+ } | |
+ inotify_remove_watches(global_kqueue_handle); | |
+quitting: | |
+ | |
+ return 0; | |
+} | |
#endif | |
+ | |
+#endif // defined(HAVE_INOTIFY) || defined(HAVE_SYS_EVENT_H) | |
+ | |
diff --git a/inotify.h b/inotify.h | |
index 0f378c2..ff8b51d 100644 | |
--- a/inotify.h | |
+++ b/inotify.h | |
@@ -4,4 +4,10 @@ inotify_remove_file(const char * path); | |
void * | |
start_inotify(); | |
+#elif defined(HAVE_SYS_EVENT_H) | |
+int | |
+inotify_remove_file(const char* path); | |
+ | |
+void * | |
+start_kqueue(); | |
#endif | |
diff --git a/metadata.c b/metadata.c | |
index a322c2b..c6606aa 100644 | |
--- a/metadata.c | |
+++ b/metadata.c | |
@@ -492,7 +492,7 @@ GetAudioMetadata(const char *path, char *name) | |
m.dlna_pn, song.mime?song.mime:m.mime, album_art); | |
if( ret != SQLITE_OK ) | |
{ | |
- fprintf(stderr, "Error inserting details for '%s'!\n", path); | |
+ DPRINTF(E_ERROR, L_DB_SQL, "Error inserting details for '%s'!\n", path); | |
ret = 0; | |
} | |
else | |
@@ -675,7 +675,7 @@ no_exifdata: | |
m.rotation, thumb, m.creator, m.dlna_pn, m.mime); | |
if( ret != SQLITE_OK ) | |
{ | |
- fprintf(stderr, "Error inserting details for '%s'!\n", path); | |
+ DPRINTF(E_ERROR, L_DB_SQL, "Error inserting details for '%s'!\n", path); | |
ret = 0; | |
} | |
else | |
@@ -1587,7 +1587,7 @@ video_no_dlna: | |
m.mime, album_art); | |
if( ret != SQLITE_OK ) | |
{ | |
- fprintf(stderr, "Error inserting details for '%s'!\n", path); | |
+ DPRINTF(E_ERROR, L_DB_SQL, "Error inserting details for '%s'!\n", path); | |
ret = 0; | |
} | |
else | |
diff --git a/minidlna.c b/minidlna.c | |
index e77dffb..c2dd08a 100644 | |
--- a/minidlna.c | |
+++ b/minidlna.c | |
@@ -999,6 +999,15 @@ main(int argc, char **argv) | |
else if (pthread_create(&inotify_thread, NULL, start_inotify, NULL) != 0) | |
DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify. EXITING\n"); | |
} | |
+#elif defined(HAVE_SYS_EVENT_H) | |
+ if( GETFLAG(INOTIFY_MASK) ) | |
+ { | |
+ if (!sqlite3_threadsafe() || sqlite3_libversion_number() < 3005001) | |
+ DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe! " | |
+ "Kqueue will be disabled.\n"); | |
+ else if (pthread_create(&inotify_thread, NULL, start_kqueue, NULL) != 0) | |
+ DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_kqueue. EXITING\n"); | |
+ } | |
#endif | |
smonitor = OpenAndConfMonitorSocket(); | |
diff --git a/scanner.c b/scanner.c | |
index 67d9617..f2079cc 100644 | |
--- a/scanner.c | |
+++ b/scanner.c | |
@@ -590,7 +590,7 @@ CreateDatabase(void) | |
sql_failed: | |
if( ret != SQLITE_OK ) | |
- fprintf(stderr, "Error creating SQLite3 database!\n"); | |
+ DPRINTF(E_ERROR, L_DB_SQL, "Error creating SQLite3 database!\n"); | |
return (ret != SQLITE_OK); | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git 1/configure.ac 2/configure.ac | |
index f9fcfc0..73e8fb2 100644 | |
--- 1/configure.ac | |
+++ 2/configure.ac | |
@@ -455,6 +455,8 @@ AC_CHECK_LIB(vorbisfile, vorbis_comment_query, | |
AC_CHECK_HEADERS([arpa/inet.h asm/unistd.h endian.h machine/endian.h fcntl.h libintl.h locale.h netdb.h netinet/in.h stddef.h stdlib.h string.h sys/file.h sys/inotify.h sys/ioctl.h sys/param.h sys/socket.h sys/time.h unistd.h sys/event.h]) | |
+AC_CHECK_FUNCS([getrlimit setrlimit]) | |
+ | |
AC_CHECK_FUNCS(inotify_init, AC_DEFINE(HAVE_INOTIFY,1,[Whether kernel has inotify support]), [ | |
AC_MSG_CHECKING([for __NR_inotify_init syscall]) | |
AC_COMPILE_IFELSE( | |
diff --git 1/inotify.c 2/inotify.c | |
index 5e7d806..5e467e1 100644 | |
--- 1/inotify.c | |
+++ 2/inotify.c | |
@@ -806,13 +806,9 @@ quitting: | |
#else | |
void * | |
-start_kqueue() | |
+start_kqueue(void* arg) | |
{ | |
- int global_kqueue_handle = -1; | |
- | |
- global_kqueue_handle = kqueue(); | |
- if ( global_kqueue_handle < 0 ) | |
- DPRINTF(E_ERROR, L_INOTIFY, "kqueue() failed: %s\n", strerror(errno)); | |
+ int global_kqueue_handle = *((int *)arg); | |
while( scanning ) | |
{ | |
@@ -821,20 +817,48 @@ start_kqueue() | |
sleep(1); | |
} | |
+#if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) | |
+ struct rlimit rl; | |
+ | |
+ if (!getrlimit(RLIMIT_NOFILE, &rl)) | |
+ { | |
+ rl.rlim_cur = rl.rlim_max; | |
+ if (setrlimit(RLIMIT_NOFILE, &rl) != 0) | |
+ { | |
+#if defined(__APPLE__) && defined(RLIMIT_NOFILE) && defined(OPEN_MAX) | |
+ // On Mac OS X, setrlimit(RLIMIT_NOFILE, &rl) fails to set | |
+ // rlim_cur above OPEN_MAX even if rlim_max > OPEN_MAX. | |
+ if (rl.rlim_cur > OPEN_MAX) | |
+ { | |
+ rl.rlim_cur = OPEN_MAX; | |
+ setrlimit(RLIMIT_NOFILE, &rl); | |
+ } | |
+#endif | |
+ } | |
+ } | |
+#endif | |
+ | |
inotify_create_watches(global_kqueue_handle); | |
if (setpriority(PRIO_PROCESS, 0, 19) == -1) | |
DPRINTF(E_WARN, L_INOTIFY, "Failed to reduce kqueue thread priority\n"); | |
sqlite3_release_memory(1<<31); | |
av_register_all(); | |
+ struct kevent ke; | |
+ EV_SET(&ke, 0, EVFILT_USER, EV_ADD, 0, NULL, NULL); | |
+ if (kevent(global_kqueue_handle, &ke, 1, NULL, 0, NULL) == -1) | |
+ DPRINTF(E_ERROR, L_INOTIFY, "Failed to register kqueue quitting event\n"); | |
+ EV_SET(&ke, 0, 0, 0, 0, 0, 0); | |
while( !quitting ) | |
{ | |
- struct kevent ke; | |
if ( kevent(global_kqueue_handle, NULL, 0, &ke, 1, NULL) == -1 ) | |
{ | |
DPRINTF(E_WARN, L_INOTIFY, "kevent polling failure: %s\n", strerror(errno)); | |
} | |
+ if (ke.filter == EVFILT_USER && ke.ident == 0) | |
+ continue; | |
+ | |
/*DPRINTF(E_DEBUG, L_INOTIFY, "GOT KEVENT:\n" | |
"ident=0x%X, filter=0x%X, flags=0x%X, fflags=0x%X, data=0x%X, udata=0x%X\n", | |
ke.ident, ke.filter, ke.flags, ke.fflags, ke.data, ke.udata);*/ | |
diff --git 1/minidlna.c 2/minidlna.c | |
index 154ddc1..3838c6b 100644 | |
--- 1/minidlna.c | |
+++ 2/minidlna.c | |
@@ -75,6 +75,10 @@ | |
#include <libintl.h> | |
#endif | |
+#ifdef HAVE_SYS_EVENT_H | |
+#include <sys/event.h> | |
+#endif | |
+ | |
#include "upnpglobalvars.h" | |
#include "sql.h" | |
#include "upnphttp.h" | |
@@ -958,6 +962,9 @@ main(int argc, char **argv) | |
struct sockaddr_in tivo_bcast; | |
struct timeval lastbeacontime = {0, 0}; | |
#endif | |
+#ifdef HAVE_SYS_EVENT_H | |
+ int global_kqueue_handle = -1; | |
+#endif | |
for (i = 0; i < L_MAX; i++) | |
log_level[i] = E_WARN; | |
@@ -1003,7 +1010,11 @@ main(int argc, char **argv) | |
if (!sqlite3_threadsafe() || sqlite3_libversion_number() < 3005001) | |
DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe! " | |
"Kqueue will be disabled.\n"); | |
- else if (pthread_create(&inotify_thread, NULL, start_kqueue, NULL) != 0) | |
+ | |
+ global_kqueue_handle = kqueue(); | |
+ if (global_kqueue_handle < 0) | |
+ DPRINTF(E_ERROR, L_INOTIFY, "kqueue() failed: %s\n", strerror(errno)); | |
+ if (pthread_create(&inotify_thread, NULL, start_kqueue, (void *)&global_kqueue_handle) != 0) | |
DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_kqueue. EXITING\n"); | |
} | |
@@ -1283,8 +1294,15 @@ shutdown: | |
close(lan_addr[i].snotify); | |
} | |
- if (inotify_thread) | |
+ if (inotify_thread) { | |
+#ifdef HAVE_SYS_EVENT_H | |
+ struct kevent quit_event; | |
+ EV_SET(&quit_event, 0, EVFILT_USER, 0, NOTE_TRIGGER, NULL, NULL); | |
+ if (kevent(global_kqueue_handle, &quit_event, 1, NULL, 0, NULL ) == -1) | |
+ DPRINTF(E_ERROR, L_GENERAL, "Failed to trigger quit event: %s\n", strerror(errno)); | |
+#endif | |
pthread_join(inotify_thread, NULL); | |
+ } | |
sql_exec(db, "UPDATE SETTINGS set VALUE = '%u' where KEY = 'UPDATE_ID'", updateID); | |
sqlite3_close(db); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment