-LRN: use signal pipe instead of a semaphore
authorChristian Grothoff <christian@grothoff.org>
Sat, 14 Jan 2012 23:18:52 +0000 (23:18 +0000)
committerChristian Grothoff <christian@grothoff.org>
Sat, 14 Jan 2012 23:18:52 +0000 (23:18 +0000)
src/fs/fs_dirmetascan.c

index 6af1863479745ad39582df9805c106ff0f66ec03..fd8ab15c44488b2f4dfe3da3352d6a8b1c08b6dc 100644 (file)
@@ -102,6 +102,26 @@ struct MetaCounter
   struct MetaCounter *next;\r
 };\r
 \r
+struct AddDirContext;\r
+\r
+/**\r
+ * A structure used to hold a pointer to the tree item that is being\r
+ * processed.\r
+ * Needed to avoid changing the context for every recursive call.\r
+ */\r
+struct AddDirStack\r
+{\r
+  /**\r
+   * Context pointer\r
+   */\r
+  struct AddDirContext *adc;\r
+\r
+  /**\r
+   * Parent directory\r
+   */\r
+  struct ShareTreeItem *parent;\r
+};\r
+\r
 /**\r
  * Execution context for 'add_dir'\r
  * Owned by the initiator thread.\r
@@ -109,13 +129,11 @@ struct MetaCounter
 struct AddDirContext\r
 {\r
   /**\r
-   * Parent directory (used to access keyword and metadata counters,\r
-   * and the like).\r
    * After the scan is finished, it will contain a pointer to the\r
    * top-level directory entry in the directory tree built by the\r
    * scanner.\r
    */\r
-  struct ShareTreeItem *parent;\r
+  struct ShareTreeItem *toplevel;\r
 \r
   /**\r
    * Expanded filename (as given by the scan initiator).\r
@@ -124,15 +142,10 @@ struct AddDirContext
   char *filename_expanded;\r
 \r
   /**\r
-   * A synchronization privitive. Whenever its state is altered,\r
-   * it means that the initiator wants the scanner to wrap up.\r
-   * It is owned by the initiator thread.\r
+   * A pipe end to read signals from.\r
+   * Owned by the initiator thread.\r
    */\r
-#if WINDOWS\r
-  HANDLE stop;\r
-#else\r
-  sem_t *stop;\r
-#endif\r
+  const struct GNUNET_DISK_FileHandle *stop_read;\r
 \r
   /**\r
    * 1 if the scanner should stop, 0 otherwise. Set in response\r
@@ -164,15 +177,17 @@ struct AddDirContext
  */\r
 struct GNUNET_FS_DirScanner\r
 {\r
- /**\r
-  * A synchronization privitive that is used to signal the scanner to stop.\r
-  * Owned by the initiator thread.\r
-  */\r
-#if WINDOWS\r
-  HANDLE stop;\r
-#else\r
-  sem_t *stop;\r
-#endif\r
+  /**\r
+   * A pipe end to read signals from.\r
+   * Owned by the initiator thread.\r
+   */\r
+  const struct GNUNET_DISK_FileHandle *stop_write;\r
+  \r
+  /**\r
+   * A pipe transfer signals to the scanner.\r
+   * Owned by the initiator thread.\r
+   */\r
+  struct GNUNET_DISK_PipeHandle *stop_pipe;\r
 \r
  /**\r
   * A thread object for the scanner thread.\r
@@ -312,21 +327,14 @@ struct ProcessMetadataContext
 static int\r
 should_stop (struct AddDirContext *adc)\r
 {\r
-#if WINDOWS\r
-  if (WaitForSingleObject (adc->stop, 0) == WAIT_TIMEOUT)\r
-    return 0;\r
-  adc->do_stop = 1;\r
-  return 1;\r
-#else\r
-  int value;\r
-  sem_getvalue(adc->stop, &value);  \r
-  if (value > 0)\r
+  errno = 0;\r
+  char c;\r
+  if (GNUNET_DISK_file_read_non_blocking (adc->stop_read, &c, 1) == 1\r
+      || errno != EAGAIN)\r
   {\r
     adc->do_stop = 1;\r
-    return 1;\r
   }\r
-  return 0;\r
-#endif\r
+  return adc->do_stop;\r
 }\r
 \r
 /**\r
@@ -535,19 +543,19 @@ make_item (struct ShareTreeItem *parent)
  * @param filename name of the file to process\r
  */\r
 static void\r
-extract_file (struct AddDirContext *adc, const char *filename)\r
+extract_file (struct AddDirStack *ads, const char *filename)\r
 {\r
   struct ShareTreeItem *item;\r
   const char *short_fn;\r
 \r
-  item = make_item (adc->parent);\r
+  item = make_item (ads->parent);\r
 \r
   GNUNET_DISK_file_size (filename, &item->file_size, GNUNET_YES);\r
   item->is_directory = GNUNET_NO;\r
 \r
   item->meta = GNUNET_CONTAINER_meta_data_create ();\r
   GNUNET_FS_meta_data_extract_from_file (item->meta, filename,\r
-      adc->plugins);\r
+      ads->adc->plugins);\r
   GNUNET_CONTAINER_meta_data_delete (item->meta, EXTRACTOR_METATYPE_FILENAME,\r
       NULL, 0);\r
   short_fn = GNUNET_STRINGS_get_short_name (filename);\r
@@ -725,13 +733,14 @@ process_keywords_and_metadata (struct ProcessMetadataStackItem *stack,
  * scan.\r
  * TODO: find a way to make it non-recursive.\r
  *\r
- * @param cls the 'struct AddDirContext*' we're in\r
+ * @param cls the 'struct AddDirStack *' we're in\r
  * @param filename file or directory to scan\r
  */\r
 static int\r
 scan_directory (void *cls, const char *filename)\r
 {\r
-  struct AddDirContext *adc = cls, recurse_adc;\r
+  struct AddDirStack *ads = cls, recurse_ads;\r
+  struct AddDirContext *adc = ads->adc;\r
   struct stat sbuf;\r
   struct ShareTreeItem *item;\r
   const char *short_fn;\r
@@ -763,33 +772,31 @@ scan_directory (void *cls, const char *filename)
   }\r
 \r
   if (!S_ISDIR (sbuf.st_mode))\r
-    extract_file (adc, filename);\r
+    extract_file (ads, filename);\r
   else\r
   {\r
-    item = make_item (adc->parent);\r
+    item = make_item (ads->parent);\r
     item->meta = GNUNET_CONTAINER_meta_data_create ();\r
 \r
     item->is_directory = GNUNET_YES;\r
 \r
-    /* copy fields from adc */\r
-    recurse_adc = *adc;\r
-    /* replace recurse_adc contents with the ones for this directory */\r
-    recurse_adc.parent = item;\r
+    recurse_ads.adc = adc;\r
+    recurse_ads.parent = item;\r
 \r
     /* recurse into directory */\r
-    GNUNET_DISK_directory_scan (filename, &scan_directory, &recurse_adc);\r
+    GNUNET_DISK_directory_scan (filename, &scan_directory, &recurse_ads);\r
 \r
     short_fn = GNUNET_STRINGS_get_short_name (filename);\r
 \r
     item->filename = GNUNET_strdup (filename);\r
     item->short_filename = GNUNET_strdup (short_fn);\r
 \r
-    if (adc->parent == NULL)\r
+    if (ads->parent == NULL)\r
     {\r
       /* we're finished with the scan, make sure caller gets the top-level\r
        * directory pointer\r
        */\r
-      adc->parent = item;\r
+      adc->toplevel = item;\r
     }\r
   }\r
   return GNUNET_OK;\r
@@ -809,11 +816,9 @@ void
 GNUNET_FS_directory_scan_finish (struct GNUNET_FS_DirScanner *ds,\r
     int close_pipe)\r
 {\r
-#if WINDOWS\r
-  SetEvent (ds->stop);\r
-#else\r
-  sem_post (&ds->stop);\r
-#endif\r
+  char c = 1;\r
+  GNUNET_DISK_file_write (ds->stop_write, &c, 1);\r
+\r
   if (close_pipe)\r
   {\r
     if (ds->progress_read_task != GNUNET_SCHEDULER_NO_TASK)\r
@@ -845,16 +850,15 @@ GNUNET_FS_directory_scan_cleanup (struct GNUNET_FS_DirScanner *ds)
   GNUNET_FS_directory_scan_finish (ds, GNUNET_YES);\r
 #if WINDOWS\r
   WaitForSingleObject (ds->thread, INFINITE);\r
-  CloseHandle (ds->stop);\r
   CloseHandle (ds->thread);\r
 #else\r
   pthread_join (ds->thread, NULL);\r
-  sem_destroy (&ds->stop);\r
   pthread_detach (ds->thread);\r
 #endif\r
 \r
+  GNUNET_DISK_pipe_close (ds->stop_pipe);\r
   GNUNET_DISK_pipe_close (ds->progress_pipe);\r
-  result = ds->adc->parent;\r
+  result = ds->adc->toplevel;\r
   GNUNET_free (ds->adc);\r
   GNUNET_free (ds);\r
   return result;\r
@@ -870,7 +874,10 @@ static int
 #endif\r
 run_directory_scan_thread (struct AddDirContext *adc)\r
 {\r
-  scan_directory (adc, adc->filename_expanded);\r
+  struct AddDirStack ads;\r
+  ads.adc = adc;\r
+  ads.parent = NULL;\r
+  scan_directory (&ads, adc->filename_expanded);\r
   GNUNET_free (adc->filename_expanded);\r
   if (adc->plugins != NULL)\r
     EXTRACTOR_plugin_remove_all (adc->plugins);\r
@@ -1060,15 +1067,8 @@ GNUNET_FS_directory_scan_start (const char *filename,
 \r
   ds->adc = adc;\r
 \r
-#if WINDOWS\r
-  ds->stop = CreateEvent (NULL, TRUE, FALSE, NULL);\r
-  adc->stop = ds->stop;\r
-  ok = ds->stop != INVALID_HANDLE_VALUE;\r
-#else\r
-  ok = !sem_init (&ds->stop, 0, 0);\r
-  adc = &ds->stop;\r
-#endif\r
-  if (!ok)\r
+  ds->stop_pipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);\r
+  if (ds->stop_pipe == NULL)\r
   {\r
     GNUNET_free (adc);\r
     GNUNET_free (ds);\r
@@ -1076,6 +1076,10 @@ GNUNET_FS_directory_scan_start (const char *filename,
     GNUNET_DISK_pipe_close (progress_pipe);\r
     return NULL;\r
   }\r
+  ds->stop_write = GNUNET_DISK_pipe_handle (ds->stop_pipe,\r
+      GNUNET_DISK_PIPE_END_WRITE);\r
+  adc->stop_read = GNUNET_DISK_pipe_handle (ds->stop_pipe,\r
+      GNUNET_DISK_PIPE_END_READ);\r
 \r
   adc->plugins = NULL;\r
   if (!disable_extractor)\r