forked from enlightenment/efl
evas: Add shutdown logic on thread creation failure
Summary: In case of thread creation failure, shutdown logic will be stuck. To prevent stuck, set exit variables to make thread_shutdown working even if init fails. Also modify init logics to return init result to a caller. Reviewers: jypark, woohyun, cedric, jpeg Subscribers: cedric Differential Revision: https://phab.enlightenment.org/D4411 Note (@jpeg): I have modified the patch just a little bit. Signed-off-by: Jean-Philippe Andre <jp.andre@samsung.com>
This commit is contained in:
parent
8b9fe4adda
commit
88e1fc9613
|
@ -236,7 +236,7 @@ evas_async_events_process(void)
|
||||||
{
|
{
|
||||||
int nr, count = 0;
|
int nr, count = 0;
|
||||||
|
|
||||||
if (_fd_read == -1) return 0;
|
if (_fd_read == -1) return -1;
|
||||||
|
|
||||||
_evas_async_events_fork_handle();
|
_evas_async_events_fork_handle();
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ _evas_thread_main_loop_lock(void *target EINA_UNUSED,
|
||||||
eina_condition_free(&call->c);
|
eina_condition_free(&call->c);
|
||||||
eina_lock_free(&call->m);
|
eina_lock_free(&call->m);
|
||||||
free(call);
|
free(call);
|
||||||
}
|
}
|
||||||
|
|
||||||
EAPI int
|
EAPI int
|
||||||
evas_thread_main_loop_begin(void)
|
evas_thread_main_loop_begin(void)
|
||||||
|
|
|
@ -36,7 +36,7 @@ evas_init(void)
|
||||||
lockmax = atoi(getenv("EVAS_LOCK_DEBUG"));
|
lockmax = atoi(getenv("EVAS_LOCK_DEBUG"));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_EVIL
|
#ifdef HAVE_EVIL
|
||||||
if (!evil_init())
|
if (!evil_init())
|
||||||
return --_evas_init_count;
|
return --_evas_init_count;
|
||||||
|
@ -66,16 +66,22 @@ evas_init(void)
|
||||||
if (!evas_async_events_init())
|
if (!evas_async_events_init())
|
||||||
goto shutdown_module;
|
goto shutdown_module;
|
||||||
#ifdef EVAS_CSERVE2
|
#ifdef EVAS_CSERVE2
|
||||||
|
int cs2 = 0;
|
||||||
{
|
{
|
||||||
const char *env;
|
const char *env;
|
||||||
env = getenv("EVAS_CSERVE2");
|
env = getenv("EVAS_CSERVE2");
|
||||||
if (env && atoi(env)) evas_cserve2_init();
|
if (env && atoi(env))
|
||||||
|
{
|
||||||
|
cs2 = evas_cserve2_init();
|
||||||
|
if (!cs2) goto shutdown_async_events;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_evas_preload_thread_init();
|
_evas_preload_thread_init();
|
||||||
evas_filter_init();
|
evas_filter_init();
|
||||||
|
|
||||||
evas_thread_init();
|
if (!evas_thread_init())
|
||||||
|
goto shutdown_filter;
|
||||||
|
|
||||||
eina_log_timing(_evas_log_dom_global,
|
eina_log_timing(_evas_log_dom_global,
|
||||||
EINA_LOG_STATE_STOP,
|
EINA_LOG_STATE_STOP,
|
||||||
|
@ -83,8 +89,20 @@ evas_init(void)
|
||||||
|
|
||||||
return _evas_init_count;
|
return _evas_init_count;
|
||||||
|
|
||||||
|
shutdown_filter:
|
||||||
|
evas_filter_shutdown();
|
||||||
|
_evas_preload_thread_shutdown();
|
||||||
|
#ifdef EVAS_CSERVE2
|
||||||
|
if (cs2) evas_cserve2_shutdown();
|
||||||
|
shutdown_async_events:
|
||||||
|
#endif
|
||||||
|
evas_async_events_shutdown();
|
||||||
shutdown_module:
|
shutdown_module:
|
||||||
evas_module_shutdown();
|
evas_module_shutdown();
|
||||||
|
#ifdef BUILD_LOADER_EET
|
||||||
|
eet_shutdown();
|
||||||
|
#endif
|
||||||
|
efl_object_shutdown();
|
||||||
eina_log_domain_unregister(_evas_log_dom_global);
|
eina_log_domain_unregister(_evas_log_dom_global);
|
||||||
shutdown_eet:
|
shutdown_eet:
|
||||||
eet_shutdown();
|
eet_shutdown();
|
||||||
|
@ -450,7 +468,7 @@ EAPI void
|
||||||
evas_render_method_list_free(Eina_List *list)
|
evas_render_method_list_free(Eina_List *list)
|
||||||
{
|
{
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
EINA_LIST_FREE(list, s) eina_stringshare_del(s);
|
EINA_LIST_FREE(list, s) eina_stringshare_del(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1653,7 +1653,7 @@ evas_render_mapped(Evas_Public_Data *evas, Evas_Object *eo_obj,
|
||||||
/* We aren't sure this object will be rendered by
|
/* We aren't sure this object will be rendered by
|
||||||
normal(not proxy) drawing after, we reset this
|
normal(not proxy) drawing after, we reset this
|
||||||
only in case of normal drawing. For optmizing,
|
only in case of normal drawing. For optmizing,
|
||||||
push this object in an array then reset them
|
push this object in an array then reset them
|
||||||
in the end of the rendering.*/
|
in the end of the rendering.*/
|
||||||
if (!proxy_render_data)
|
if (!proxy_render_data)
|
||||||
evas_object_change_reset(obj2->object);
|
evas_object_change_reset(obj2->object);
|
||||||
|
@ -2541,7 +2541,7 @@ evas_render_updates_internal_loop(Evas *eo_e, Evas_Public_Data *e,
|
||||||
e->engine.func->context_clip_set(e->engine.data.output,
|
e->engine.func->context_clip_set(e->engine.data.output,
|
||||||
context,
|
context,
|
||||||
x, y, w, h);
|
x, y, w, h);
|
||||||
|
|
||||||
/* Clipper masks */
|
/* Clipper masks */
|
||||||
if (_evas_render_object_is_mask(obj->cur->clipper))
|
if (_evas_render_object_is_mask(obj->cur->clipper))
|
||||||
mask = obj->cur->clipper; // main object clipped by this mask
|
mask = obj->cur->clipper; // main object clipped by this mask
|
||||||
|
@ -2770,8 +2770,8 @@ evas_render_updates_internal(Evas *eo_e,
|
||||||
if (e->framespace.changed)
|
if (e->framespace.changed)
|
||||||
{
|
{
|
||||||
/* NB: If the framespace changes, we need to add a redraw rectangle
|
/* NB: If the framespace changes, we need to add a redraw rectangle
|
||||||
* which covers the Whole viewport. This is because 'framespace' is
|
* which covers the Whole viewport. This is because 'framespace' is
|
||||||
* defined as "the space IN the viewport which is Occupied by the
|
* defined as "the space IN the viewport which is Occupied by the
|
||||||
* window frame" */
|
* window frame" */
|
||||||
e->engine.func->output_redraws_rect_add(e->engine.data.output,
|
e->engine.func->output_redraws_rect_add(e->engine.data.output,
|
||||||
e->viewport.x, e->viewport.y,
|
e->viewport.x, e->viewport.y,
|
||||||
|
@ -3080,7 +3080,7 @@ evas_render_updates_internal(Evas *eo_e,
|
||||||
OBJS_ARRAY_CLEAN(&e->snapshot_objects);
|
OBJS_ARRAY_CLEAN(&e->snapshot_objects);
|
||||||
eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
|
eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
|
||||||
eina_array_clean(&e->clip_changes);
|
eina_array_clean(&e->clip_changes);
|
||||||
/* we should flush here and have a mempool system for this
|
/* we should flush here and have a mempool system for this
|
||||||
eina_array_flush(&e->active_objects);
|
eina_array_flush(&e->active_objects);
|
||||||
eina_array_flush(&e->render_objects);
|
eina_array_flush(&e->render_objects);
|
||||||
eina_array_flush(&e->restack_objects);
|
eina_array_flush(&e->restack_objects);
|
||||||
|
@ -3104,7 +3104,7 @@ evas_render_updates_internal(Evas *eo_e,
|
||||||
* efficiency */
|
* efficiency */
|
||||||
if ((e->delete_objects.count == 0) || (e->delete_objects.count > 1024))
|
if ((e->delete_objects.count == 0) || (e->delete_objects.count > 1024))
|
||||||
eina_array_flush(&e->delete_objects);
|
eina_array_flush(&e->delete_objects);
|
||||||
|
|
||||||
evas_module_clean();
|
evas_module_clean();
|
||||||
|
|
||||||
if (!do_async)
|
if (!do_async)
|
||||||
|
|
|
@ -14,6 +14,23 @@ static volatile int evas_thread_exited = 0;
|
||||||
static Eina_Bool exit_thread = EINA_FALSE;
|
static Eina_Bool exit_thread = EINA_FALSE;
|
||||||
static int init_count = 0;
|
static int init_count = 0;
|
||||||
|
|
||||||
|
#define SHUTDOWN_TIMEOUT_RESET (0)
|
||||||
|
#define SHUTDOWN_TIMEOUT_CHECK (1)
|
||||||
|
#define SHUTDOWN_TIMEOUT (3000)
|
||||||
|
|
||||||
|
static Eina_Bool
|
||||||
|
_shutdown_timeout(double *time, int mode, int timeout_ms)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
|
||||||
|
if ( mode == SHUTDOWN_TIMEOUT_RESET )
|
||||||
|
*time = (tv.tv_sec + tv.tv_usec / 1000000.0) * 1000.0;
|
||||||
|
return ((tv.tv_sec + tv.tv_usec / 1000000.0) * 1000.0 - (*time)) > timeout_ms ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
evas_thread_queue_append(Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flush)
|
evas_thread_queue_append(Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flush)
|
||||||
{
|
{
|
||||||
|
@ -122,32 +139,69 @@ out:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
evas_thread_init(void)
|
evas_thread_init(void)
|
||||||
{
|
{
|
||||||
if (init_count++) return;
|
if (init_count++)
|
||||||
|
return init_count;
|
||||||
|
|
||||||
eina_threads_init();
|
exit_thread = EINA_FALSE;
|
||||||
|
evas_thread_exited = 0;
|
||||||
|
|
||||||
|
if(!eina_threads_init())
|
||||||
|
{
|
||||||
|
CRI("Could not init eina threads");
|
||||||
|
goto fail_on_eina_thread_init;
|
||||||
|
}
|
||||||
|
|
||||||
eina_inarray_step_set(&evas_thread_queue, sizeof (Eina_Inarray), sizeof (Evas_Thread_Command), 128);
|
eina_inarray_step_set(&evas_thread_queue, sizeof (Eina_Inarray), sizeof (Evas_Thread_Command), 128);
|
||||||
|
|
||||||
if (!eina_lock_new(&evas_thread_queue_lock))
|
if (!eina_lock_new(&evas_thread_queue_lock))
|
||||||
CRI("Could not create draw thread lock");
|
{
|
||||||
|
CRI("Could not create draw thread lock (%m)");
|
||||||
|
goto fail_on_lock_creation;
|
||||||
|
}
|
||||||
if (!eina_condition_new(&evas_thread_queue_condition, &evas_thread_queue_lock))
|
if (!eina_condition_new(&evas_thread_queue_condition, &evas_thread_queue_lock))
|
||||||
CRI("Could not create draw thread condition");
|
{
|
||||||
|
CRI("Could not create draw thread condition (%m)");
|
||||||
|
goto fail_on_cond_creation;
|
||||||
|
}
|
||||||
|
|
||||||
if (!eina_thread_create(&evas_thread_worker, EINA_THREAD_NORMAL, -1,
|
if (!eina_thread_create(&evas_thread_worker, EINA_THREAD_NORMAL, -1,
|
||||||
evas_thread_worker_func, NULL))
|
evas_thread_worker_func, NULL))
|
||||||
CRI("Could not create draw thread");
|
{
|
||||||
|
CRI("Could not create draw thread (%m)");
|
||||||
|
goto fail_on_thread_creation;
|
||||||
|
}
|
||||||
|
|
||||||
|
return init_count;
|
||||||
|
|
||||||
|
fail_on_thread_creation:
|
||||||
|
evas_thread_worker = 0;
|
||||||
|
eina_condition_free(&evas_thread_queue_condition);
|
||||||
|
fail_on_cond_creation:
|
||||||
|
eina_lock_free(&evas_thread_queue_lock);
|
||||||
|
fail_on_lock_creation:
|
||||||
|
eina_threads_shutdown();
|
||||||
|
fail_on_eina_thread_init:
|
||||||
|
exit_thread = EINA_TRUE;
|
||||||
|
evas_thread_exited = 1;
|
||||||
|
return --init_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
evas_thread_shutdown(void)
|
evas_thread_shutdown(void)
|
||||||
{
|
{
|
||||||
assert(init_count);
|
double to = 0 ;
|
||||||
|
|
||||||
|
if (init_count <= 0)
|
||||||
|
{
|
||||||
|
ERR("Too many calls to shutdown, ignored.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (--init_count)
|
if (--init_count)
|
||||||
return;
|
return init_count;
|
||||||
|
|
||||||
eina_lock_take(&evas_thread_queue_lock);
|
eina_lock_take(&evas_thread_queue_lock);
|
||||||
|
|
||||||
|
@ -155,16 +209,27 @@ evas_thread_shutdown(void)
|
||||||
eina_condition_signal(&evas_thread_queue_condition);
|
eina_condition_signal(&evas_thread_queue_condition);
|
||||||
|
|
||||||
eina_lock_release(&evas_thread_queue_lock);
|
eina_lock_release(&evas_thread_queue_lock);
|
||||||
|
_shutdown_timeout(&to, SHUTDOWN_TIMEOUT_RESET, SHUTDOWN_TIMEOUT);
|
||||||
while (!evas_thread_exited)
|
while (!evas_thread_exited && (evas_async_events_process() != -1))
|
||||||
evas_async_events_process();
|
{
|
||||||
|
if(_shutdown_timeout(&to, SHUTDOWN_TIMEOUT_CHECK, SHUTDOWN_TIMEOUT))
|
||||||
|
{
|
||||||
|
CRI("Timeout shutdown thread. Skipping thread_join. Some resources could be leaked");
|
||||||
|
goto timeout_shutdown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eina_thread_join(evas_thread_worker);
|
eina_thread_join(evas_thread_worker);
|
||||||
|
timeout_shutdown:
|
||||||
eina_lock_free(&evas_thread_queue_lock);
|
eina_lock_free(&evas_thread_queue_lock);
|
||||||
eina_condition_free(&evas_thread_queue_condition);
|
eina_condition_free(&evas_thread_queue_condition);
|
||||||
|
|
||||||
|
evas_thread_worker = 0;
|
||||||
|
|
||||||
eina_inarray_flush(&evas_thread_queue);
|
eina_inarray_flush(&evas_thread_queue);
|
||||||
free(evas_thread_queue_cache);
|
free(evas_thread_queue_cache);
|
||||||
|
|
||||||
eina_threads_shutdown();
|
eina_threads_shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -566,7 +566,7 @@ struct _Image_Entry_Flags
|
||||||
Eina_Bool alpha_sparse : 1;
|
Eina_Bool alpha_sparse : 1;
|
||||||
Eina_Bool preload_done : 1;
|
Eina_Bool preload_done : 1;
|
||||||
Eina_Bool delete_me : 1;
|
Eina_Bool delete_me : 1;
|
||||||
|
|
||||||
Eina_Bool pending : 1;
|
Eina_Bool pending : 1;
|
||||||
Eina_Bool rotated : 1;
|
Eina_Bool rotated : 1;
|
||||||
Eina_Bool unload_cancel : 1;
|
Eina_Bool unload_cancel : 1;
|
||||||
|
@ -675,7 +675,7 @@ struct _Image_Entry
|
||||||
/* Reference to the file */
|
/* Reference to the file */
|
||||||
Eina_File *f;
|
Eina_File *f;
|
||||||
void *loader_data;
|
void *loader_data;
|
||||||
|
|
||||||
Image_Entry_Flags flags;
|
Image_Entry_Flags flags;
|
||||||
Evas_Image_Scale_Hint scale_hint;
|
Evas_Image_Scale_Hint scale_hint;
|
||||||
void *data1, *data2;
|
void *data1, *data2;
|
||||||
|
@ -1315,8 +1315,8 @@ EAPI int evas_async_events_process_blocking(void);
|
||||||
void evas_render_rendering_wait(Evas_Public_Data *evas);
|
void evas_render_rendering_wait(Evas_Public_Data *evas);
|
||||||
void evas_all_sync(void);
|
void evas_all_sync(void);
|
||||||
|
|
||||||
void evas_thread_init(void);
|
int evas_thread_init(void);
|
||||||
void evas_thread_shutdown(void);
|
int evas_thread_shutdown(void);
|
||||||
EAPI void evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data);
|
EAPI void evas_thread_cmd_enqueue(Evas_Thread_Command_Cb cb, void *data);
|
||||||
EAPI void evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data);
|
EAPI void evas_thread_queue_flush(Evas_Thread_Command_Cb cb, void *data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue