extend ecore fork infra to handle pipe re-create afetr fork for

ecore-evas.



SVN revision: 75194
This commit is contained in:
Carsten Haitzler 2012-08-13 08:52:45 +00:00
parent b51f30b082
commit fe00bc661a
4 changed files with 138 additions and 24 deletions

View File

@ -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.

View File

@ -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

View 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);
}
}
}
/**

View 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;