extend ecore fork infra to handle pipe re-create afetr fork for
authorCarsten Haitzler <raster@rasterman.com>
Mon, 13 Aug 2012 08:52:45 +0000 (08:52 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Mon, 13 Aug 2012 08:52:45 +0000 (08:52 +0000)
ecore-evas.

SVN revision: 75194

legacy/ecore/ChangeLog
legacy/ecore/src/lib/ecore/Ecore.h
legacy/ecore/src/lib/ecore/ecore.c
legacy/ecore/src/lib/ecore_evas/ecore_evas.c

index 00b372f..d0c8610 100644 (file)
 
        * Correctly shutdown Ecore_Thread.
        * Add a way to reset Ecore_Thread internal pipe after a fork via ecore_fork_reset.
+
+2012-08-13  Carsten Haitzler (The Rasterman)
+
+        * Fix ecore fork reset function to allow for callbacks to be
+          attached so ecore-evas can reset evas async fd on fork.
+
index 7f2d043..ed9c9ab 100644 (file)
@@ -381,25 +381,6 @@ extern "C" {
 EAPI int ecore_init(void);
 EAPI int ecore_shutdown(void);
 /**
- * Reset the ecore internal state after a fork
- * 
- * Ecore maintains internal data that can be affected by the fork() system call
- * which creates a duplicate of the current process. This also duplicates
- * file descriptors which is problematic in that these file descriptors still
- * point to their original sources. This function makes ecore reset internal
- * state (e.g. pipes used for signalling between threads) so they function
- * correctly afterwards.
- * 
- * It is highly suggested that you call this function after any fork()
- * system call inside the child process if you intend to use ecore features
- * after this point and not call any exec() family functions. Not doing so
- * will cause possible misbehaviour.
- * 
- * @since 1.7
- */
-EAPI void ecore_fork_reset(void);
-
-/**
  * @}
  */
 
@@ -473,6 +454,46 @@ typedef void (*Ecore_Cb)(void *data);
 typedef void *(*Ecore_Data_Cb)(void *data);
 
 /**
+ * Add a function to be called by ecore_fork_reset()
+ * 
+ * This queues @p func to be called (and passed @p data as its argument) when
+ * ecore_fork_reset() is called. This allows other libraries and subsystems
+ * to also reset their internal state after a fork.
+ * 
+ * @since 1.7
+ */
+EAPI Eina_Bool ecore_fork_reset_callback_add(Ecore_Cb func, const void *data);
+
+/**
+ * This removes the callback specified
+ * 
+ * This deletes the callback added by ecore_fork_reset_callback_add() using
+ * the function and data pointer to specify which to remove.
+ * 
+ * @since 1.7
+ */
+EAPI Eina_Bool ecore_fork_reset_callback_del(Ecore_Cb func, const void *data);
+       
+/**
+ * Reset the ecore internal state after a fork
+ * 
+ * Ecore maintains internal data that can be affected by the fork() system call
+ * which creates a duplicate of the current process. This also duplicates
+ * file descriptors which is problematic in that these file descriptors still
+ * point to their original sources. This function makes ecore reset internal
+ * state (e.g. pipes used for signalling between threads) so they function
+ * correctly afterwards.
+ * 
+ * It is highly suggested that you call this function after any fork()
+ * system call inside the child process if you intend to use ecore features
+ * after this point and not call any exec() family functions. Not doing so
+ * will cause possible misbehaviour.
+ * 
+ * @since 1.7
+ */
+EAPI void ecore_fork_reset(void);
+
+/**
  * @brief Call callback asynchronously in the main loop.
  * @since 1.1.0
  *
index d8dc359..0df319b 100644 (file)
@@ -305,9 +305,60 @@ unlock:
      return _ecore_init_count;
 }
 
+struct _Ecore_Fork_Cb
+{
+   Ecore_Cb func;
+   void *data;
+   Eina_Bool delete_me : 1;
+};
+
+typedef struct _Ecore_Fork_Cb Ecore_Fork_Cb;
+
+static int fork_cbs_walking = 0;
+static Eina_List *fork_cbs = NULL;
+
+EAPI Eina_Bool
+ecore_fork_reset_callback_add(Ecore_Cb func, const void *data)
+{
+   Ecore_Fork_Cb *fcb;
+   
+   fcb = calloc(1, sizeof(Ecore_Fork_Cb));
+   if (!fcb) return EINA_FALSE;
+   fcb->func = func;
+   fcb->data = (void *)data;
+   fork_cbs = eina_list_append(fork_cbs, fcb);
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ecore_fork_reset_callback_del(Ecore_Cb func, const void *data)
+{
+   Eina_List *l;
+   Ecore_Fork_Cb *fcb;
+
+   EINA_LIST_FOREACH(fork_cbs, l, fcb)
+     {
+        if ((fcb->func == func) && (fcb->data == data))
+          {
+             if (!fork_cbs_walking)
+               {
+                  fork_cbs = eina_list_remove_list(fork_cbs, l);
+                  free(fcb);
+               }
+             else
+               fcb->delete_me = EINA_TRUE;
+             return EINA_TRUE;
+          }
+     }
+   return EINA_FALSE;
+}
+
 EAPI void
 ecore_fork_reset(void)
 {
+   Eina_List *l, *ln;
+   Ecore_Fork_Cb *fcb;
+   
    eina_lock_take(&_thread_safety);
 
    ecore_pipe_del(_thread_call);
@@ -316,6 +367,24 @@ ecore_fork_reset(void)
    if (_thread_cb) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
 
    eina_lock_release(&_thread_safety);
+
+   // should this be done withing the eina lock stuff?
+   
+   fork_cbs_walking++;
+   EINA_LIST_FOREACH(fork_cbs, l, fcb)
+     {
+        fcb->func(fcb->data);
+     }
+   fork_cbs_walking--;
+   
+   EINA_LIST_FOREACH_SAFE(fork_cbs, l, ln, fcb)
+     {
+        if (fcb->delete_me)
+          {
+             fork_cbs = eina_list_remove_list(fork_cbs, l);
+             free(fcb);
+          }
+     }
 }
 
 /**
index 9f3eadd..0520192 100644 (file)
@@ -218,6 +218,21 @@ ecore_evas_engine_type_supported_get(Ecore_Evas_Engine_Type engine)
      };
 }
 
+static void
+_ecore_evas_fork_cb(void *data __UNUSED__)
+{
+   int fd;
+   
+   if (_ecore_evas_async_events_fd)
+     ecore_main_fd_handler_del(_ecore_evas_async_events_fd);
+   fd = evas_async_events_fd_get();
+   if (fd >= 0)
+     _ecore_evas_async_events_fd = 
+     ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+                               _ecore_evas_async_events_fd_handler, NULL,
+                               NULL, NULL);
+}
+
 EAPI int
 ecore_evas_init(void)
 {
@@ -240,12 +255,13 @@ ecore_evas_init(void)
         goto shutdown_ecore;
      }
 
+   ecore_fork_reset_callback_add(_ecore_evas_fork_cb, NULL);
    fd = evas_async_events_fd_get();
-   if (fd > 0)
-     _ecore_evas_async_events_fd = ecore_main_fd_handler_add(fd,
-                                                             ECORE_FD_READ,
-                                                             _ecore_evas_async_events_fd_handler, NULL,
-                                                             NULL, NULL);
+   if (fd >= 0)
+     _ecore_evas_async_events_fd = 
+     ecore_main_fd_handler_add(fd, ECORE_FD_READ,
+                               _ecore_evas_async_events_fd_handler, NULL,
+                               NULL, NULL);
 
    ecore_evas_idle_enterer =
      ecore_idle_enterer_add(_ecore_evas_idle_enter, NULL);
@@ -308,6 +324,8 @@ ecore_evas_shutdown(void)
 
    if (_ecore_evas_async_events_fd)
      ecore_main_fd_handler_del(_ecore_evas_async_events_fd);
+   
+   ecore_fork_reset_callback_del(_ecore_evas_fork_cb, NULL);
 
    eina_log_domain_unregister(_ecore_evas_log_dom);
    _ecore_evas_log_dom = -1;