Change how the worker threads are started so daemon() works
authorSteve McIntyre <steve@einval.com>
Sun, 15 May 2011 21:31:05 +0000 (22:31 +0100)
committerSteve McIntyre <steve@einval.com>
Sun, 15 May 2011 21:31:05 +0000 (22:31 +0100)
Previously, things would only work properly when run in the
foreground. The reason for that was that the daemon() call broke links
between the main thread and threads already started. Move the thread
startup code into a helper function init_threads(), and use
pthread_once to make sure it's called once by whichever of the main
fuse interface functions gets called first.

C/fuse-music.c

index b10d0e3..65f330c 100644 (file)
@@ -132,6 +132,8 @@ struct
     int  num;
 } dir_state;
 
+pthread_once_t once_control = PTHREAD_ONCE_INIT;
+
 #define FUSE_MOUNT_OPT(t, p) { t, offsetof(struct mount_opts, p), 1 }
 
 static const struct fuse_opt fm_mount_opts[] = {    
@@ -146,6 +148,39 @@ static const struct fuse_opt fm_mount_opts[] = {
     FUSE_OPT_END
 };
 
+void *bg_handler(void *arg);
+
+static void init_threads(void)
+{
+    intptr_t i = 0;
+    int error = 0;
+    int *threadcount;
+    pthread_mutexattr_t attr;
+    pthread_mutexattr_init(&attr);
+    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);    
+
+    pthread_mutex_init(&dir_state.lock, &attr);
+    pthread_mutex_init(&global_work.lock, &attr);
+    pthread_cond_init(&global_work.cv, NULL);
+    bg_thread = malloc(mo.num_threads * sizeof(pthread_t));
+    if (!bg_thread)
+    {
+        MAINLOG0((logfile, "%s: Failed to malloc thread space for thread descriptors\n", __func__));
+        db_close(db_state);
+    }
+    threadcount = malloc(mo.num_threads * sizeof(int));
+    if (!threadcount)
+    {
+        MAINLOG0((logfile, "%s: Failed to malloc thread space for thread numbers\n", __func__));
+        db_close(db_state);
+    }
+    for (i = 0; i < mo.num_threads; i++)
+    {
+        threadcount[i] = i;
+        error = pthread_create(&bg_thread[i], NULL, bg_handler, &threadcount[i]);
+    }
+}
+
 static char *str_encode_state(encode_state_e state)
 {
     switch (state)
@@ -661,6 +696,7 @@ static int fm_getattr(const char *path, struct stat *stbuf)
     char *flac_path = NULL;
     int error = 0;
 
+    pthread_once(&once_control, init_threads);
     memset(stbuf, 0, sizeof(struct stat));
     if (strcmp(path, "/") == 0)
     {
@@ -721,7 +757,10 @@ static int fm_getattr(const char *path, struct stat *stbuf)
 
 static int fm_readlink(const char *path, char *buf, size_t size)
 {
-    int res = readlink(path, buf, size - 1);
+    int res = 0;
+
+    pthread_once(&once_control, init_threads);
+    res = readlink(path, buf, size - 1);
     if (res == -1)
         return -errno;
 
@@ -736,6 +775,8 @@ static int fm_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
     struct dirent *de;
     char *flac_path = NULL;
 
+    pthread_once(&once_control, init_threads);
+
     (void) offset;
     (void) fi;
 
@@ -792,6 +833,8 @@ static int fm_open(const char *path, struct fuse_file_info *fi)
     char *flac_path = NULL;
     int error = 0;
 
+    pthread_once(&once_control, init_threads);
+
     if (fi->flags & (O_RDWR|O_WRONLY))
         return -EROFS;
 
@@ -852,6 +895,9 @@ static int fm_open(const char *path, struct fuse_file_info *fi)
 static int fm_release(const char *path, struct fuse_file_info *fi)
 {
     char *flac_path = NULL;
+
+    pthread_once(&once_control, init_threads);
+
     close(fi->fh);
 
     flac_path = convert_to_base_path(path);
@@ -871,6 +917,8 @@ static int fm_read(const char *path, char *buf, size_t size, off_t offset,
 {
     int res;
 
+    pthread_once(&once_control, init_threads);
+
     (void) path;
     res = pread(fi->fh, buf, size, offset);
     if (res == -1)
@@ -885,6 +933,8 @@ static int fm_statfs(const char *path, struct statvfs *stbuf)
 {
     int res;
 
+    pthread_once(&once_control, init_threads);
+
     res = statvfs(mo.basedir, stbuf);
     if (res == -1)
         return -errno;
@@ -1010,10 +1060,6 @@ int main(int argc, char *argv[])
     intptr_t i = 0;
     int error = 0;
     struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
-    int *threadcount;
-    pthread_mutexattr_t attr;
-    pthread_mutexattr_init(&attr);
-    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK_NP);    
     umask(0);
 
     logfile = stderr;
@@ -1101,26 +1147,6 @@ int main(int argc, char *argv[])
 
     strcpy(dir_state.last, "");
     dir_state.num = 0;
-    pthread_mutex_init(&dir_state.lock, &attr);
-    pthread_mutex_init(&global_work.lock, &attr);
-    pthread_cond_init(&global_work.cv, NULL);
-    bg_thread = malloc(mo.num_threads * sizeof(pthread_t));
-    if (!bg_thread)
-    {
-        MAINLOG0((logfile, "Failed to malloc thread space for thread descriptors\n"));
-        db_close(db_state);
-    }
-    threadcount = malloc(mo.num_threads * sizeof(int));
-    if (!threadcount)
-    {
-        MAINLOG0((logfile, "Failed to malloc thread space for thread numbers\n"));
-        db_close(db_state);
-    }
-    for (i = 0; i < mo.num_threads; i++)
-    {
-        threadcount[i] = i;
-        error = pthread_create(&bg_thread[i], NULL, bg_handler, &threadcount[i]);
-    }
 
     error = fuse_main(args.argc, args.argv, &fm_oper, NULL);
     if (error)