~ubuntu-branches/ubuntu/trusty/forked-daapd/trusty

« back to all changes in this revision

Viewing changes to src/filescanner.c

  • Committer: Package Import Robot
  • Author(s): Julien BLACHE
  • Date: 2011-09-22 19:15:11 UTC
  • mfrom: (2.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20110922191511-0h4ltqz2hqtcs28t
Tags: 0.19gcd-2
Move the GCD codebase to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
#include <sys/ioctl.h>
36
36
#include <fcntl.h>
37
37
#include <dirent.h>
38
 
#include <pthread.h>
39
38
 
40
39
#include <uninorm.h>
41
40
 
46
45
# include <sys/event.h>
47
46
#endif
48
47
 
49
 
#if defined(HAVE_SYS_EVENTFD_H) && defined(HAVE_EVENTFD)
50
 
# define USE_EVENTFD
51
 
# include <sys/eventfd.h>
52
 
#endif
53
 
 
54
 
#include <event.h>
 
48
#include <dispatch/dispatch.h>
55
49
 
56
50
#include "logger.h"
57
51
#include "db.h"
63
57
 
64
58
#define F_SCAN_BULK    (1 << 0)
65
59
#define F_SCAN_RESCAN  (1 << 1)
66
 
 
67
 
struct deferred_pl {
68
 
  char *path;
69
 
  struct deferred_pl *next;
70
 
};
71
 
 
 
60
#define F_SCAN_NODUP   (1 << 2)
 
61
 
 
62
static int stop_scan;
 
63
static dispatch_group_t scanner_grp;
 
64
static dispatch_queue_t deferred_pl_sq;
 
65
static int ino_fd;
 
66
static dispatch_source_t ino_src;
 
67
 
 
68
 
 
69
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
72
70
struct stacked_dir {
73
71
  char *path;
74
72
  struct stacked_dir *next;
75
73
};
76
74
 
77
 
 
78
 
#ifdef USE_EVENTFD
79
 
static int exit_efd;
80
 
#else
81
 
static int exit_pipe[2];
82
 
#endif
83
 
static int scan_exit;
84
 
static int inofd;
85
 
static struct event_base *evbase_scan;
86
 
static struct event inoev;
87
 
static struct event exitev;
88
 
static pthread_t tid_scan;
89
 
static struct deferred_pl *playlists;
90
 
static struct stacked_dir *dirstack;
91
 
 
92
 
 
93
75
static int
94
76
push_dir(struct stacked_dir **s, char *path)
95
77
{
132
114
 
133
115
  return ret;
134
116
}
 
117
#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
135
118
 
136
119
 
137
120
static void
293
276
    normalize_fixup_tag(&mfi->composer_sort, mfi->composer);
294
277
}
295
278
 
296
 
 
 
279
/* Queue: global */
297
280
static void
298
281
process_media_file(char *file, time_t mtime, off_t size, int compilation)
299
282
{
402
385
  free_mfi(&mfi, 1);
403
386
}
404
387
 
 
388
/* Queue: global & deferred_pl_sq */
405
389
static void
406
390
process_playlist(char *file)
407
391
{
419
403
    }
420
404
}
421
405
 
422
 
/* Thread: scan */
 
406
/* Queue: global */
423
407
static void
424
408
defer_playlist(char *path)
425
409
{
426
 
  struct deferred_pl *pl;
427
 
 
428
 
  pl = (struct deferred_pl *)malloc(sizeof(struct deferred_pl));
429
 
  if (!pl)
430
 
    {
431
 
      DPRINTF(E_WARN, L_SCAN, "Out of memory for deferred playlist\n");
432
 
 
433
 
      return;
434
 
    }
435
 
 
436
 
  memset(pl, 0, sizeof(struct deferred_pl));
437
 
 
438
 
  pl->path = strdup(path);
439
 
  if (!pl->path)
440
 
    {
441
 
      DPRINTF(E_WARN, L_SCAN, "Out of memory for deferred playlist\n");
442
 
 
443
 
      free(pl);
444
 
      return;
445
 
    }
446
 
 
447
 
  pl->next = playlists;
448
 
  playlists = pl;
 
410
  char *pl_path;
 
411
 
 
412
  pl_path = strdup(path);
 
413
  if (!pl_path)
 
414
    {
 
415
      DPRINTF(E_WARN, L_SCAN, "Out of memory for deferred playlist\n");
 
416
 
 
417
      return;
 
418
    }
 
419
 
 
420
  /* Not using dispatch_group_async() on the scanner_grp as deferred playlists
 
421
   * processing is triggered by scanner_grp being empty at the end of the bulk
 
422
   * scan.
 
423
   */
 
424
  dispatch_retain(scanner_grp);
 
425
  dispatch_async(deferred_pl_sq,
 
426
                 ^{
 
427
                   int ret;
 
428
 
 
429
                   if (stop_scan)
 
430
                     {
 
431
                       free(pl_path);
 
432
                       return;
 
433
                     }
 
434
 
 
435
                   /* In case deinit() happens after the bulk scan */
 
436
                   dispatch_group_enter(scanner_grp);
 
437
 
 
438
                   ret = db_pool_get();
 
439
                   if (ret < 0)
 
440
                     {
 
441
                       DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; skipping playlist %s\n", pl_path);
 
442
 
 
443
                       free(pl_path);
 
444
                       return;
 
445
                     }
 
446
 
 
447
                   process_playlist(pl_path);
 
448
 
 
449
                   free(pl_path);
 
450
                   db_pool_release();
 
451
 
 
452
                   dispatch_group_leave(scanner_grp);
 
453
                   dispatch_release(scanner_grp);
 
454
                 });
449
455
 
450
456
  DPRINTF(E_INFO, L_SCAN, "Deferred playlist %s\n", path);
451
457
}
452
458
 
453
 
/* Thread: scan (bulk only) */
454
 
static void
455
 
process_deferred_playlists(void)
456
 
{
457
 
  struct deferred_pl *pl;
458
 
 
459
 
  while ((pl = playlists))
460
 
    {
461
 
      playlists = pl->next;
462
 
 
463
 
      process_playlist(pl->path);
464
 
 
465
 
      free(pl->path);
466
 
      free(pl);
467
 
 
468
 
      /* Run the event loop */
469
 
      event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);
470
 
 
471
 
      if (scan_exit)
472
 
        return;
473
 
    }
474
 
}
475
 
 
476
 
/* Thread: scan */
 
459
/* Queue: global */
477
460
static void
478
461
process_file(char *file, time_t mtime, off_t size, int compilation, int flags)
479
462
{
508
491
}
509
492
 
510
493
 
511
 
/* Thread: scan */
 
494
/* Queue: global */
512
495
static int
513
496
check_compilation(char *path)
514
497
{
528
511
  return 0;
529
512
}
530
513
 
531
 
/* Thread: scan */
 
514
static void
 
515
process_directory_async(char *path, int flags);
 
516
 
 
517
/* Queue: global */
532
518
static void
533
519
process_directory(char *path, int flags)
534
520
{
535
 
  struct stacked_dir *bulkstack;
536
521
  DIR *dirp;
537
522
  struct dirent buf;
538
523
  struct dirent *de;
546
531
  int compilation;
547
532
  int ret;
548
533
 
549
 
  if (flags & F_SCAN_BULK)
550
 
    {
551
 
      /* Save our directory stack so it won't get handled inside
552
 
       * the event loop - not its business, we're in bulk mode here.
553
 
       */
554
 
      bulkstack = dirstack;
555
 
      dirstack = NULL;
556
 
 
557
 
      /* Run the event loop */
558
 
      event_base_loop(evbase_scan, EVLOOP_ONCE | EVLOOP_NONBLOCK);
559
 
 
560
 
      /* Restore our directory stack */
561
 
      dirstack = bulkstack;
562
 
 
563
 
      if (scan_exit)
564
 
        return;
565
 
    }
566
 
 
567
534
  DPRINTF(E_DBG, L_SCAN, "Processing directory %s (flags = 0x%x)\n", path, flags);
568
535
 
569
536
  dirp = opendir(path);
579
546
 
580
547
  for (;;)
581
548
    {
 
549
      if (stop_scan)
 
550
        break;
 
551
 
582
552
      ret = readdir_r(dirp, &buf, &de);
583
553
      if (ret != 0)
584
554
        {
641
611
      if (S_ISREG(sb.st_mode))
642
612
        process_file(entry, sb.st_mtime, sb.st_size, compilation, flags);
643
613
      else if (S_ISDIR(sb.st_mode))
644
 
        push_dir(&dirstack, entry);
 
614
        process_directory_async(entry, flags);
645
615
      else
646
616
        DPRINTF(E_LOG, L_SCAN, "Skipping %s, not a directory, symlink nor regular file\n", entry);
647
617
    }
648
618
 
649
619
  closedir(dirp);
650
620
 
 
621
  if (stop_scan)
 
622
    return;
 
623
 
651
624
  memset(&wi, 0, sizeof(struct watch_info));
652
625
 
653
626
#if defined(__linux__)
654
627
  /* Add inotify watch */
655
 
  wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
 
628
  wi.wd = inotify_add_watch(ino_fd, path, IN_CREATE | IN_DELETE | IN_MODIFY | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
656
629
  if (wi.wd < 0)
657
630
    {
658
631
      DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));
682
655
  /* Add kevent */
683
656
  EV_SET(&kev, wi.wd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_DELETE | NOTE_WRITE | NOTE_RENAME, 0, NULL);
684
657
 
685
 
  ret = kevent(inofd, &kev, 1, NULL, 0, NULL);
 
658
  ret = kevent(ino_fd, &kev, 1, NULL, 0, NULL);
686
659
  if (ret < 0)
687
660
    {
688
661
      DPRINTF(E_WARN, L_SCAN, "Could not add kevent for %s: %s\n", path, strerror(errno));
698
671
#endif
699
672
}
700
673
 
701
 
/* Thread: scan */
 
674
/* Queue: global */
702
675
static void
703
 
process_directories(char *root, int flags)
 
676
process_directory_async(char *path, int flags)
704
677
{
705
 
  char *path;
706
 
 
707
 
  process_directory(root, flags);
708
 
 
709
 
  if (scan_exit)
710
 
    return;
711
 
 
712
 
  while ((path = pop_dir(&dirstack)))
713
 
    {
714
 
      process_directory(path, flags);
715
 
 
716
 
      free(path);
717
 
 
718
 
      if (scan_exit)
719
 
        return;
720
 
    }
 
678
  char *my_path;
 
679
 
 
680
  if (stop_scan)
 
681
    {
 
682
      if (flags & F_SCAN_NODUP)
 
683
        free(path);
 
684
 
 
685
      return;
 
686
    }
 
687
 
 
688
  if (flags & F_SCAN_NODUP)
 
689
    {
 
690
      my_path = path;
 
691
 
 
692
      flags &= ~F_SCAN_NODUP;
 
693
    }
 
694
  else
 
695
    {
 
696
      my_path = strdup(path);
 
697
      if (!my_path)
 
698
        {
 
699
          DPRINTF(E_LOG, L_SCAN, "Skipping %s, out of memory\n", path);
 
700
 
 
701
          return;
 
702
        }
 
703
    }
 
704
 
 
705
  dispatch_group_async(scanner_grp, dispatch_get_current_queue(),
 
706
                       ^{
 
707
                         int ret;
 
708
 
 
709
                         if (stop_scan)
 
710
                           {
 
711
                             free(my_path);
 
712
                             return;
 
713
                           }
 
714
 
 
715
                         ret = db_pool_get();
 
716
                         if (ret < 0)
 
717
                           {
 
718
                             DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; skipping %s\n", my_path);
 
719
 
 
720
                             free(my_path);
 
721
                             return;
 
722
                           }
 
723
 
 
724
                         process_directory(my_path, flags);
 
725
 
 
726
                         free(my_path);
 
727
                         db_pool_release();
 
728
                       });
721
729
}
722
730
 
723
 
 
724
 
/* Thread: scan */
 
731
/* Queue: global */
725
732
static void
726
733
bulk_scan(void)
727
734
{
734
741
 
735
742
  start = time(NULL);
736
743
 
737
 
  playlists = NULL;
738
 
  dirstack = NULL;
739
 
 
740
744
  lib = cfg_getsec(cfg, "library");
741
745
 
742
746
  ndirs = cfg_size(lib, "directories");
752
756
          continue;
753
757
        }
754
758
 
755
 
      process_directories(deref, F_SCAN_BULK);
756
 
 
757
 
      free(deref);
758
 
 
759
 
      if (scan_exit)
760
 
        return;
 
759
      process_directory_async(deref, F_SCAN_BULK | F_SCAN_NODUP);
761
760
    }
762
761
 
763
 
  if (playlists)
764
 
    process_deferred_playlists();
765
 
 
766
 
  if (scan_exit)
767
 
    return;
768
 
 
769
 
  if (dirstack)
770
 
    DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");
771
 
 
772
 
  DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
773
 
  db_purge_cruft(start);
 
762
  /* Wait for the scanner group to be empty, then queue db_purge_cruft()
 
763
   * on the deferred playlists queue and resume that queue.
 
764
   * In a nutshell: wait until initial bulk scan is done, then
 
765
   * process deferred playlists, then purge the database.
 
766
   */
 
767
  dispatch_retain(scanner_grp);
 
768
  dispatch_group_notify(scanner_grp, dispatch_get_current_queue(),
 
769
                        ^{
 
770
                          dispatch_async(deferred_pl_sq,
 
771
                                         ^{
 
772
                                           int ret;
 
773
 
 
774
                                           if (stop_scan)
 
775
                                             return;
 
776
 
 
777
                                           /* In case deinit() happens after the bulk scan */
 
778
                                           dispatch_group_enter(scanner_grp);
 
779
 
 
780
                                           ret = db_pool_get();
 
781
                                           if (ret < 0)
 
782
                                             {
 
783
                                               DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; DB purge aborted\n");
 
784
 
 
785
                                               return;
 
786
                                             }
 
787
 
 
788
                                           DPRINTF(E_DBG, L_SCAN, "Purging old database content\n");
 
789
                                           db_purge_cruft(start);
 
790
 
 
791
                                           db_hook_post_scan();
 
792
 
 
793
                                           db_pool_release();
 
794
 
 
795
                                           dispatch_group_leave(scanner_grp);
 
796
                                           dispatch_release(scanner_grp);
 
797
                                         });
 
798
 
 
799
                          DPRINTF(E_DBG, L_SCAN, "Now processing deferred playlists from bulk scan\n");
 
800
 
 
801
                          dispatch_resume(deferred_pl_sq);
 
802
                          dispatch_release(deferred_pl_sq);
 
803
                          deferred_pl_sq = NULL;
 
804
                        });
774
805
}
775
806
 
776
807
 
777
 
/* Thread: scan */
778
 
static void *
779
 
filescanner(void *arg)
 
808
/* Queue: global */
 
809
static void
 
810
startup_task(void *arg)
780
811
{
781
812
  int ret;
782
813
 
783
 
  ret = db_perthread_init();
 
814
  ret = db_pool_get();
784
815
  if (ret < 0)
785
816
    {
786
 
      DPRINTF(E_LOG, L_SCAN, "Error: DB init failed\n");
 
817
      DPRINTF(E_LOG, L_SCAN, "Startup failed: could not acquire database connection\n");
787
818
 
788
 
      pthread_exit(NULL);
 
819
      return;
789
820
    }
790
821
 
791
822
  ret = db_watch_clear();
793
824
    {
794
825
      DPRINTF(E_LOG, L_SCAN, "Error: could not clear old watches from DB\n");
795
826
 
796
 
      pthread_exit(NULL);
 
827
      goto startup_fail;
797
828
    }
798
829
 
799
830
  ret = db_groups_clear();
801
832
    {
802
833
      DPRINTF(E_LOG, L_SCAN, "Error: could not clear old groups from DB\n");
803
834
 
804
 
      pthread_exit(NULL);
 
835
      goto startup_fail;
805
836
    }
806
837
 
807
838
  /* Recompute all songalbumids, in case the SQLite DB got transferred
812
843
 
813
844
  bulk_scan();
814
845
 
815
 
  db_hook_post_scan();
816
 
 
817
 
  if (!scan_exit)
818
 
    {
819
 
      /* Enable inotify */
820
 
      event_add(&inoev, NULL);
821
 
 
822
 
      event_base_dispatch(evbase_scan);
823
 
    }
824
 
 
825
 
  if (!scan_exit)
826
 
    DPRINTF(E_FATAL, L_SCAN, "Scan event loop terminated ahead of time!\n");
827
 
 
828
 
  db_perthread_deinit();
829
 
 
830
 
  pthread_exit(NULL);
 
846
 startup_fail:
 
847
  db_pool_release();
831
848
}
832
849
 
833
850
 
834
851
#if defined(__linux__)
835
 
/* Thread: scan */
 
852
#define process_fs_events() inotify_fs_events()
 
853
 
 
854
/* Queue: global */
836
855
static void
837
856
process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
838
857
{
866
885
 
867
886
          while ((db_watch_enum_fetchwd(&we, &rm_wd) == 0) && (rm_wd))
868
887
            {
869
 
              inotify_rm_watch(inofd, rm_wd);
 
888
              inotify_rm_watch(ino_fd, rm_wd);
870
889
            }
871
890
 
872
891
          db_watch_enum_end(&we);
886
905
           * and we can't tell where it's going
887
906
           */
888
907
 
889
 
          inotify_rm_watch(inofd, ie->wd);
 
908
          inotify_rm_watch(ino_fd, ie->wd);
890
909
          db_watch_delete_bywd(ie->wd);
891
910
 
892
911
          memset(&we, 0, sizeof(struct watch_enum));
899
918
 
900
919
          while ((db_watch_enum_fetchwd(&we, &rm_wd) == 0) && (rm_wd))
901
920
            {
902
 
              inotify_rm_watch(inofd, rm_wd);
 
921
              inotify_rm_watch(ino_fd, rm_wd);
903
922
            }
904
923
 
905
924
          db_watch_enum_end(&we);
935
954
    }
936
955
 
937
956
  if (ie->mask & IN_CREATE)
938
 
    {
939
 
      process_directories(path, flags);
940
 
 
941
 
      if (dirstack)
942
 
        DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");
943
 
    }
 
957
    process_directory_async(path, flags);
944
958
}
945
959
 
946
 
/* Thread: scan */
 
960
/* Queue: global */
947
961
static void
948
962
process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie)
949
963
{
1032
1046
    }
1033
1047
}
1034
1048
 
1035
 
/* Thread: scan */
 
1049
/* Queue: global */
1036
1050
static void
1037
 
inotify_cb(int fd, short event, void *arg)
 
1051
inotify_fs_events(void)
1038
1052
{
1039
1053
  struct inotify_event *buf;
1040
1054
  struct inotify_event *ie;
1045
1059
  int ret;
1046
1060
 
1047
1061
  /* Determine the size of the inotify queue */
1048
 
  ret = ioctl(fd, FIONREAD, &qsize);
 
1062
  ret = ioctl(ino_fd, FIONREAD, &qsize);
1049
1063
  if (ret < 0)
1050
1064
    {
1051
1065
      DPRINTF(E_LOG, L_SCAN, "Could not determine inotify queue size: %s\n", strerror(errno));
1061
1075
      return;
1062
1076
    }
1063
1077
 
1064
 
  ret = read(fd, buf, qsize);
 
1078
  ret = read(ino_fd, buf, qsize);
1065
1079
  if (ret < 0)
1066
1080
    {
1067
1081
      DPRINTF(E_LOG, L_SCAN, "inotify read failed: %s\n", strerror(errno));
1139
1153
    }
1140
1154
 
1141
1155
  free(buf);
1142
 
 
1143
 
  event_add(&inoev, NULL);
1144
1156
}
1145
1157
#endif /* __linux__ */
1146
1158
 
1147
1159
 
1148
1160
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1149
 
/* Thread: scan */
 
1161
#define process_fs_events() kqueue_fs_events()
 
1162
 
 
1163
/* Queue: global */
1150
1164
static void
1151
 
kqueue_cb(int fd, short event, void *arg)
 
1165
kqueue_fs_events(void)
1152
1166
{
1153
1167
  struct kevent kev;
1154
1168
  struct timespec ts;
1179
1193
   * deleted or changed. We don't get directory/file names when directories/files
1180
1194
   * are created/deleted/renamed in the directory, so we have to rescan.
1181
1195
   */
1182
 
  while (kevent(fd, NULL, 0, &kev, 1, &ts) > 0)
 
1196
  while (kevent(ino_fd, NULL, 0, &kev, 1, &ts) > 0)
1183
1197
    {
1184
1198
      /* This should not happen, and if it does, we'll end up in
1185
1199
       * an infinite loop.
1314
1328
    }
1315
1329
 
1316
1330
  while ((path = pop_dir(&rescan)))
1317
 
    {
1318
 
      process_directories(path, 0);
1319
 
 
1320
 
      free(path);
1321
 
 
1322
 
      if (rescan)
1323
 
        DPRINTF(E_LOG, L_SCAN, "WARNING: unhandled leftover directories\n");
1324
 
    }
1325
 
 
1326
 
  event_add(&inoev, NULL);
 
1331
    process_directory_async(path, F_SCAN_NODUP);
1327
1332
}
1328
1333
#endif /* __FreeBSD__ || __FreeBSD_kernel__ */
1329
1334
 
1330
1335
 
1331
 
/* Thread: scan */
1332
 
static void
1333
 
exit_cb(int fd, short event, void *arg)
1334
 
{
1335
 
  event_base_loopbreak(evbase_scan);
1336
 
 
1337
 
  scan_exit = 1;
1338
 
}
1339
 
 
1340
 
 
1341
1336
/* Thread: main */
1342
1337
int
1343
1338
filescanner_init(void)
1344
1339
{
1345
 
  int ret;
1346
 
 
1347
 
  scan_exit = 0;
1348
 
 
1349
 
  evbase_scan = event_base_new();
1350
 
  if (!evbase_scan)
 
1340
  dispatch_queue_t global_q;
 
1341
 
 
1342
  stop_scan = 0;
 
1343
 
 
1344
  scanner_grp = dispatch_group_create();
 
1345
  if (!scanner_grp)
1351
1346
    {
1352
 
      DPRINTF(E_FATAL, L_SCAN, "Could not create an event base\n");
 
1347
      DPRINTF(E_FATAL, L_SCAN, "Could not create dispatch group\n");
1353
1348
 
1354
1349
      return -1;
1355
1350
    }
1356
1351
 
1357
 
#ifdef USE_EVENTFD
1358
 
  exit_efd = eventfd(0, EFD_CLOEXEC);
1359
 
  if (exit_efd < 0)
1360
 
    {
1361
 
      DPRINTF(E_FATAL, L_SCAN, "Could not create eventfd: %s\n", strerror(errno));
1362
 
 
1363
 
      goto pipe_fail;
1364
 
    }
1365
 
#else
1366
 
# if defined(__linux__)
1367
 
  ret = pipe2(exit_pipe, O_CLOEXEC);
1368
 
# else
1369
 
  ret = pipe(exit_pipe);
1370
 
# endif
1371
 
  if (ret < 0)
1372
 
    {
1373
 
      DPRINTF(E_FATAL, L_SCAN, "Could not create pipe: %s\n", strerror(errno));
1374
 
 
1375
 
      goto pipe_fail;
1376
 
    }
1377
 
#endif /* USE_EVENTFD */
 
1352
  deferred_pl_sq = dispatch_queue_create("org.forked-daapd.deferred-pl", NULL);
 
1353
  if (!deferred_pl_sq)
 
1354
    {
 
1355
      DPRINTF(E_FATAL, L_SCAN, "Could not create dispatch queue for deferred playlists\n");
 
1356
 
 
1357
      goto queue_fail;
 
1358
    }
 
1359
 
 
1360
  dispatch_suspend(deferred_pl_sq);
1378
1361
 
1379
1362
#if defined(__linux__)
1380
 
  inofd = inotify_init1(IN_CLOEXEC);
1381
 
  if (inofd < 0)
 
1363
  ino_fd = inotify_init1(IN_CLOEXEC | IN_NONBLOCK);
 
1364
  if (ino_fd < 0)
1382
1365
    {
1383
1366
      DPRINTF(E_FATAL, L_SCAN, "Could not create inotify fd: %s\n", strerror(errno));
1384
1367
 
1385
1368
      goto ino_fail;
1386
1369
    }
1387
 
 
1388
 
  event_set(&inoev, inofd, EV_READ, inotify_cb, NULL);
1389
 
 
1390
1370
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1391
1371
 
1392
 
  inofd = kqueue();
1393
 
  if (inofd < 0)
 
1372
  ino_fd = kqueue();
 
1373
  if (ino_fd < 0)
1394
1374
    {
1395
1375
      DPRINTF(E_FATAL, L_SCAN, "Could not create kqueue: %s\n", strerror(errno));
1396
1376
 
1397
1377
      goto ino_fail;
1398
1378
    }
1399
 
 
1400
 
  event_set(&inoev, inofd, EV_READ, kqueue_cb, NULL);
1401
 
#endif
1402
 
 
1403
 
  event_base_set(evbase_scan, &inoev);
1404
 
 
1405
 
#ifdef USE_EVENTFD
1406
 
  event_set(&exitev, exit_efd, EV_READ, exit_cb, NULL);
1407
 
#else
1408
 
  event_set(&exitev, exit_pipe[0], EV_READ, exit_cb, NULL);
1409
 
#endif
1410
 
  event_base_set(evbase_scan, &exitev);
1411
 
  event_add(&exitev, NULL);
1412
 
 
1413
 
  ret = pthread_create(&tid_scan, NULL, filescanner, NULL);
1414
 
  if (ret != 0)
1415
 
    {
1416
 
      DPRINTF(E_FATAL, L_SCAN, "Could not spawn filescanner thread: %s\n", strerror(errno));
1417
 
 
1418
 
      goto thread_fail;
1419
 
    }
 
1379
#endif
 
1380
 
 
1381
  global_q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 
1382
  if (!global_q)
 
1383
    {
 
1384
      DPRINTF(E_FATAL, L_SCAN, "Could not get global dispatch queue\n");
 
1385
 
 
1386
      goto source_fail;
 
1387
    }
 
1388
 
 
1389
  ino_src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, ino_fd, 0, global_q);
 
1390
  if (!ino_src)
 
1391
    {
 
1392
      DPRINTF(E_FATAL, L_SCAN, "Could not create dispatch source for inotify\n");
 
1393
 
 
1394
      goto source_fail;
 
1395
    }
 
1396
 
 
1397
  dispatch_source_set_event_handler(ino_src,
 
1398
                                    ^{
 
1399
                                      int ret;
 
1400
 
 
1401
                                      dispatch_group_enter(scanner_grp);
 
1402
 
 
1403
                                      if (stop_scan)
 
1404
                                        {
 
1405
                                          dispatch_group_leave(scanner_grp);
 
1406
                                          return;
 
1407
                                        }
 
1408
 
 
1409
                                      ret = db_pool_get();
 
1410
                                      if (ret < 0)
 
1411
                                        {
 
1412
                                          DPRINTF(E_LOG, L_SCAN, "Could not acquire database connection; inotify event aborted\n");
 
1413
 
 
1414
                                          dispatch_group_leave(scanner_grp);
 
1415
                                          return;
 
1416
                                        }
 
1417
 
 
1418
                                      process_fs_events();
 
1419
 
 
1420
                                      db_pool_release();
 
1421
                                      dispatch_group_leave(scanner_grp);
 
1422
                                    });
 
1423
 
 
1424
  dispatch_source_set_cancel_handler(ino_src,
 
1425
                                     ^{
 
1426
                                       close(ino_fd);
 
1427
                                     });
 
1428
 
 
1429
  dispatch_resume(ino_src);
 
1430
 
 
1431
  dispatch_group_async_f(scanner_grp, global_q, NULL, startup_task);
1420
1432
 
1421
1433
  return 0;
1422
1434
 
1423
 
 thread_fail:
1424
 
  close(inofd);
 
1435
 source_fail:
 
1436
  close(ino_fd);
1425
1437
 ino_fail:
1426
 
#ifdef USE_EVENTFD
1427
 
  close(exit_efd);
1428
 
#else
1429
 
  close(exit_pipe[0]);
1430
 
  close(exit_pipe[1]);
1431
 
#endif
1432
 
 pipe_fail:
1433
 
  event_base_free(evbase_scan);
 
1438
  dispatch_release(deferred_pl_sq);
 
1439
 queue_fail:
 
1440
  dispatch_release(scanner_grp);
1434
1441
 
1435
1442
  return -1;
1436
1443
}
1439
1446
void
1440
1447
filescanner_deinit(void)
1441
1448
{
1442
 
  int ret;
1443
 
 
1444
 
#ifdef USE_EVENTFD
1445
 
  ret = eventfd_write(exit_efd, 1);
1446
 
  if (ret < 0)
1447
 
    {
1448
 
      DPRINTF(E_FATAL, L_SCAN, "Could not send exit event: %s\n", strerror(errno));
1449
 
 
1450
 
      return;
1451
 
    }
1452
 
#else
1453
 
  int dummy = 42;
1454
 
 
1455
 
  ret = write(exit_pipe[1], &dummy, sizeof(dummy));
1456
 
  if (ret != sizeof(dummy))
1457
 
    {
1458
 
      DPRINTF(E_FATAL, L_SCAN, "Could not write to exit fd: %s\n", strerror(errno));
1459
 
 
1460
 
      return;
1461
 
    }
1462
 
#endif
1463
 
 
1464
 
  ret = pthread_join(tid_scan, NULL);
 
1449
  long ret;
 
1450
 
 
1451
  dispatch_source_cancel(ino_src);
 
1452
  dispatch_release(ino_src);
 
1453
 
 
1454
  stop_scan = 1;
 
1455
 
 
1456
  DPRINTF(E_INFO, L_SCAN, "Waiting for filescanner jobs to finish...\n");
 
1457
 
 
1458
  ret = dispatch_group_wait(scanner_grp, DISPATCH_TIME_FOREVER);
 
1459
  dispatch_release(scanner_grp);
 
1460
 
1465
1461
  if (ret != 0)
1466
 
    {
1467
 
      DPRINTF(E_FATAL, L_SCAN, "Could not join filescanner thread: %s\n", strerror(errno));
1468
 
 
1469
 
      return;
1470
 
    }
1471
 
 
1472
 
  event_del(&inoev);
1473
 
 
1474
 
#ifdef USE_EVENTFD
1475
 
  close(exit_efd);
1476
 
#else
1477
 
  close(exit_pipe[0]);
1478
 
  close(exit_pipe[1]);
1479
 
#endif
1480
 
  close(inofd);
1481
 
  event_base_free(evbase_scan);
 
1462
    DPRINTF(E_LOG, L_SCAN, "Error waiting for dispatch group\n");
 
1463
 
 
1464
  /* deferred_pl_sq resumed & released after completion of the bulk scan */
1482
1465
}