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;
|
||||
|
||||
if (_fd_read == -1) return 0;
|
||||
if (_fd_read == -1) return -1;
|
||||
|
||||
_evas_async_events_fork_handle();
|
||||
|
||||
|
@ -370,7 +370,7 @@ _evas_thread_main_loop_lock(void *target EINA_UNUSED,
|
|||
eina_condition_free(&call->c);
|
||||
eina_lock_free(&call->m);
|
||||
free(call);
|
||||
}
|
||||
}
|
||||
|
||||
EAPI int
|
||||
evas_thread_main_loop_begin(void)
|
||||
|
|
|
@ -36,7 +36,7 @@ evas_init(void)
|
|||
lockmax = atoi(getenv("EVAS_LOCK_DEBUG"));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_EVIL
|
||||
if (!evil_init())
|
||||
return --_evas_init_count;
|
||||
|
@ -66,16 +66,22 @@ evas_init(void)
|
|||
if (!evas_async_events_init())
|
||||
goto shutdown_module;
|
||||
#ifdef EVAS_CSERVE2
|
||||
int cs2 = 0;
|
||||
{
|
||||
const char *env;
|
||||
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
|
||||
_evas_preload_thread_init();
|
||||
evas_filter_init();
|
||||
|
||||
evas_thread_init();
|
||||
if (!evas_thread_init())
|
||||
goto shutdown_filter;
|
||||
|
||||
eina_log_timing(_evas_log_dom_global,
|
||||
EINA_LOG_STATE_STOP,
|
||||
|
@ -83,8 +89,20 @@ evas_init(void)
|
|||
|
||||
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:
|
||||
evas_module_shutdown();
|
||||
#ifdef BUILD_LOADER_EET
|
||||
eet_shutdown();
|
||||
#endif
|
||||
efl_object_shutdown();
|
||||
eina_log_domain_unregister(_evas_log_dom_global);
|
||||
shutdown_eet:
|
||||
eet_shutdown();
|
||||
|
@ -450,7 +468,7 @@ EAPI void
|
|||
evas_render_method_list_free(Eina_List *list)
|
||||
{
|
||||
const char *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
|
||||
normal(not proxy) drawing after, we reset this
|
||||
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.*/
|
||||
if (!proxy_render_data)
|
||||
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,
|
||||
context,
|
||||
x, y, w, h);
|
||||
|
||||
|
||||
/* Clipper masks */
|
||||
if (_evas_render_object_is_mask(obj->cur->clipper))
|
||||
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)
|
||||
{
|
||||
/* NB: If the framespace changes, we need to add a redraw rectangle
|
||||
* which covers the Whole viewport. This is because 'framespace' is
|
||||
* defined as "the space IN the viewport which is Occupied by the
|
||||
* which covers the Whole viewport. This is because 'framespace' is
|
||||
* defined as "the space IN the viewport which is Occupied by the
|
||||
* window frame" */
|
||||
e->engine.func->output_redraws_rect_add(e->engine.data.output,
|
||||
e->viewport.x, e->viewport.y,
|
||||
|
@ -3080,7 +3080,7 @@ evas_render_updates_internal(Evas *eo_e,
|
|||
OBJS_ARRAY_CLEAN(&e->snapshot_objects);
|
||||
eina_array_foreach(&e->clip_changes, _evas_clip_changes_free, NULL);
|
||||
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->render_objects);
|
||||
eina_array_flush(&e->restack_objects);
|
||||
|
@ -3104,7 +3104,7 @@ evas_render_updates_internal(Evas *eo_e,
|
|||
* efficiency */
|
||||
if ((e->delete_objects.count == 0) || (e->delete_objects.count > 1024))
|
||||
eina_array_flush(&e->delete_objects);
|
||||
|
||||
|
||||
evas_module_clean();
|
||||
|
||||
if (!do_async)
|
||||
|
|
|
@ -14,6 +14,23 @@ static volatile int evas_thread_exited = 0;
|
|||
static Eina_Bool exit_thread = EINA_FALSE;
|
||||
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
|
||||
evas_thread_queue_append(Evas_Thread_Command_Cb cb, void *data, Eina_Bool do_flush)
|
||||
{
|
||||
|
@ -122,32 +139,69 @@ out:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
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);
|
||||
|
||||
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))
|
||||
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,
|
||||
evas_thread_worker_func, NULL))
|
||||
CRI("Could not create draw thread");
|
||||
evas_thread_worker_func, NULL))
|
||||
{
|
||||
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)
|
||||
{
|
||||
assert(init_count);
|
||||
double to = 0 ;
|
||||
|
||||
if (init_count <= 0)
|
||||
{
|
||||
ERR("Too many calls to shutdown, ignored.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (--init_count)
|
||||
return;
|
||||
return init_count;
|
||||
|
||||
eina_lock_take(&evas_thread_queue_lock);
|
||||
|
||||
|
@ -155,16 +209,27 @@ evas_thread_shutdown(void)
|
|||
eina_condition_signal(&evas_thread_queue_condition);
|
||||
|
||||
eina_lock_release(&evas_thread_queue_lock);
|
||||
|
||||
while (!evas_thread_exited)
|
||||
evas_async_events_process();
|
||||
_shutdown_timeout(&to, SHUTDOWN_TIMEOUT_RESET, SHUTDOWN_TIMEOUT);
|
||||
while (!evas_thread_exited && (evas_async_events_process() != -1))
|
||||
{
|
||||
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);
|
||||
timeout_shutdown:
|
||||
eina_lock_free(&evas_thread_queue_lock);
|
||||
eina_condition_free(&evas_thread_queue_condition);
|
||||
|
||||
evas_thread_worker = 0;
|
||||
|
||||
eina_inarray_flush(&evas_thread_queue);
|
||||
free(evas_thread_queue_cache);
|
||||
|
||||
eina_threads_shutdown();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -566,7 +566,7 @@ struct _Image_Entry_Flags
|
|||
Eina_Bool alpha_sparse : 1;
|
||||
Eina_Bool preload_done : 1;
|
||||
Eina_Bool delete_me : 1;
|
||||
|
||||
|
||||
Eina_Bool pending : 1;
|
||||
Eina_Bool rotated : 1;
|
||||
Eina_Bool unload_cancel : 1;
|
||||
|
@ -675,7 +675,7 @@ struct _Image_Entry
|
|||
/* Reference to the file */
|
||||
Eina_File *f;
|
||||
void *loader_data;
|
||||
|
||||
|
||||
Image_Entry_Flags flags;
|
||||
Evas_Image_Scale_Hint scale_hint;
|
||||
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_all_sync(void);
|
||||
|
||||
void evas_thread_init(void);
|
||||
void evas_thread_shutdown(void);
|
||||
int evas_thread_init(void);
|
||||
int evas_thread_shutdown(void);
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue