diff --git a/legacy/ecore/ChangeLog b/legacy/ecore/ChangeLog index 00b372f0f7..d0c8610b4a 100644 --- a/legacy/ecore/ChangeLog +++ b/legacy/ecore/ChangeLog @@ -852,3 +852,9 @@ * 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. + diff --git a/legacy/ecore/src/lib/ecore/Ecore.h b/legacy/ecore/src/lib/ecore/Ecore.h index 7f2d043a29..ed9c9ab8cc 100644 --- a/legacy/ecore/src/lib/ecore/Ecore.h +++ b/legacy/ecore/src/lib/ecore/Ecore.h @@ -380,25 +380,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); - /** * @} */ @@ -472,6 +453,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 diff --git a/legacy/ecore/src/lib/ecore/ecore.c b/legacy/ecore/src/lib/ecore/ecore.c index d8dc359bfc..0df319b593 100644 --- a/legacy/ecore/src/lib/ecore/ecore.c +++ b/legacy/ecore/src/lib/ecore/ecore.c @@ -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); + } + } } /** diff --git a/legacy/ecore/src/lib/ecore_evas/ecore_evas.c b/legacy/ecore/src/lib/ecore_evas/ecore_evas.c index 9f3eadde01..0520192372 100644 --- a/legacy/ecore/src/lib/ecore_evas/ecore_evas.c +++ b/legacy/ecore/src/lib/ecore_evas/ecore_evas.c @@ -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;