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:
Wonki Kim 2016-11-22 14:33:48 +09:00 committed by Jean-Philippe Andre
parent 8b9fe4adda
commit 88e1fc9613
5 changed files with 112 additions and 29 deletions

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

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