forked from enlightenment/efl
Fix events when using recursive main loops.
If an event handler/filter created a recursive main loop (just called ecore_main_loop_begin()), then this recursive main loop should continue to process events/handlers/filters from there and on, thus event_current/event_filter_current/event_handler_current were added. When going back from recursion, the current iterator should be updated properly. The following test case used to crash but not anymore: #include <Ecore.h> #include <Eina.h> static int _log_dom; #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__) static Ecore_Event_Handler *handle; static int cb2(void *data, int type, void *event) { INF("cb2 - delete cb1 handle"); ecore_event_handler_del(handle); ecore_main_loop_quit(); /* quits inner main loop */ return 0; } static int cb1(void *data, int type, void *event) { Ecore_Event *e; INF("cb1: begin"); INF(" add cb2"); type = ecore_event_type_new(); ecore_event_handler_add(type, cb2, NULL); e = ecore_event_add(type, NULL, NULL, NULL); INF(" add event to trigger cb2: event=%p", e); INF(" inner main loop begin (recurse)"); ecore_main_loop_begin(); /* will it crash due * ecore_event_handler_del(handle) inside * cb2()? It used to! */ INF("cb1: end"); ecore_main_loop_quit(); /* quits outer main loop */ return 0; } int main(void) { Ecore_Event *e; int type; ecore_init(); _log_dom = eina_log_domain_register("test", EINA_COLOR_CYAN); /* * Creating a new main loop from inside an event callback, and inside * this new (inner) main loop deleting the caller callback used to * crash since the handle would be effectively free()d, but when the * recursion is over the pointer would be used. */ type = ecore_event_type_new(); INF("main: begin"); handle = ecore_event_handler_add(type, cb1, NULL); e = ecore_event_add(type, NULL, NULL, NULL); INF(" add event to trigger cb1: event=%p", e); INF(" main loop begin"); ecore_main_loop_begin(); INF("main: end"); return 0; } SVN revision: 46419
This commit is contained in:
parent
b9c3b58561
commit
50d0af9d5e
|
@ -51,13 +51,16 @@ struct _Ecore_Event
|
|||
|
||||
static int events_num = 0;
|
||||
static Ecore_Event *events = NULL;
|
||||
static Ecore_Event *event_current = NULL;
|
||||
|
||||
static Ecore_Event_Handler **event_handlers = NULL;
|
||||
static Ecore_Event_Handler *event_handler_current = NULL;
|
||||
static int event_handlers_num = 0;
|
||||
static int event_handlers_alloc_num = 0;
|
||||
static Eina_List *event_handlers_delete_list = NULL;
|
||||
|
||||
static Ecore_Event_Filter *event_filters = NULL;
|
||||
static Ecore_Event_Filter *event_filter_current = NULL;
|
||||
static int event_filters_delete_me = 0;
|
||||
static int event_id_max = ECORE_EVENT_COUNT;
|
||||
static int ecore_raw_event_type = ECORE_EVENT_NONE;
|
||||
|
@ -65,6 +68,7 @@ static void *ecore_raw_event_event = NULL;
|
|||
|
||||
|
||||
static void _ecore_event_purge_deleted(void);
|
||||
static void *_ecore_event_del(Ecore_Event *event);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -334,7 +338,8 @@ _ecore_event_shutdown(void)
|
|||
Ecore_Event_Handler *eh;
|
||||
Ecore_Event_Filter *ef;
|
||||
|
||||
_ecore_event_purge_deleted();
|
||||
while (events) _ecore_event_del(events);
|
||||
event_current = NULL;
|
||||
for (i = 0; i < event_handlers_num; i++)
|
||||
{
|
||||
while ((eh = event_handlers[i]))
|
||||
|
@ -357,6 +362,7 @@ _ecore_event_shutdown(void)
|
|||
free(ef);
|
||||
}
|
||||
event_filters_delete_me = 0;
|
||||
event_filter_current = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -414,41 +420,72 @@ _ecore_event_purge_deleted(void)
|
|||
void
|
||||
_ecore_event_call(void)
|
||||
{
|
||||
Ecore_Event *e;
|
||||
Ecore_Event_Filter *ef;
|
||||
Ecore_Event_Handler *eh;
|
||||
Eina_List *l, *l_next;
|
||||
Ecore_Event_Handler *eh;
|
||||
|
||||
EINA_INLIST_FOREACH(event_filters, ef)
|
||||
if (!event_filter_current)
|
||||
{
|
||||
/* regular main loop, start from head */
|
||||
event_filter_current = event_filters;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* recursive main loop, continue from where we were */
|
||||
event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next;
|
||||
}
|
||||
|
||||
while (event_filter_current)
|
||||
{
|
||||
Ecore_Event_Filter *ef = event_filter_current;
|
||||
|
||||
if (!ef->delete_me)
|
||||
{
|
||||
ef->references++;
|
||||
|
||||
if (ef->func_start)
|
||||
ef->loop_data = ef->func_start(ef->data);
|
||||
EINA_INLIST_FOREACH(events, e)
|
||||
|
||||
if (!event_current)
|
||||
{
|
||||
/* regular main loop, start from head */
|
||||
event_current = events;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* recursive main loop, continue from where we were */
|
||||
event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next;
|
||||
}
|
||||
|
||||
while (event_current)
|
||||
{
|
||||
Ecore_Event *e = event_current;
|
||||
|
||||
if (!ef->func_filter(ef->loop_data, ef->data,
|
||||
e->type, e->event))
|
||||
{
|
||||
// printf("FILTER SAID TO DEL ev %p\n", e->event);
|
||||
ecore_event_del(e);
|
||||
}
|
||||
|
||||
if (event_current) /* may have changed in recursive main loops */
|
||||
event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next;
|
||||
}
|
||||
if (ef->func_end)
|
||||
ef->func_end(ef->data, ef->loop_data);
|
||||
|
||||
ef->references--;
|
||||
}
|
||||
|
||||
if (event_filter_current) /* may have changed in recursive main loops */
|
||||
event_filter_current = (Ecore_Event_Filter *)EINA_INLIST_GET(event_filter_current)->next;
|
||||
}
|
||||
if (event_filters_delete_me)
|
||||
{
|
||||
int deleted_in_use = 0;
|
||||
Ecore_Event_Filter *l;
|
||||
EINA_INLIST_FOREACH(event_filters, l)
|
||||
for (l = event_filters; l;)
|
||||
{
|
||||
ef = l;
|
||||
Ecore_Event_Filter *ef = l;
|
||||
l = (Ecore_Event_Filter *) EINA_INLIST_GET(l)->next;
|
||||
if (ef->delete_me)
|
||||
{
|
||||
|
@ -466,19 +503,43 @@ _ecore_event_call(void)
|
|||
if (!deleted_in_use)
|
||||
event_filters_delete_me = 0;
|
||||
}
|
||||
|
||||
// printf("EVENT BATCH...\n");
|
||||
EINA_INLIST_FOREACH(events, e)
|
||||
|
||||
if (!event_current)
|
||||
{
|
||||
/* regular main loop, start from head */
|
||||
event_current = events;
|
||||
event_handler_current = NULL;
|
||||
}
|
||||
|
||||
while (event_current)
|
||||
{
|
||||
Ecore_Event *e = event_current;
|
||||
|
||||
if (!e->delete_me)
|
||||
{
|
||||
int handle_count = 0;
|
||||
ecore_raw_event_type = e->type;
|
||||
ecore_raw_event_event = e->event;
|
||||
e->references++;
|
||||
// printf("HANDLE ev type %i, %p\n", e->type, e->event);
|
||||
if ((e->type >= 0) && (e->type < event_handlers_num))
|
||||
{
|
||||
EINA_INLIST_FOREACH(event_handlers[e->type], eh)
|
||||
if (!event_handler_current)
|
||||
{
|
||||
/* regular main loop, start from head */
|
||||
event_handler_current = event_handlers[e->type];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* recursive main loop, continue from where we were */
|
||||
event_handler_current= (Ecore_Event_Handler *)EINA_INLIST_GET(event_handler_current)->next;
|
||||
}
|
||||
|
||||
while ((event_handler_current) && (!e->delete_me))
|
||||
{
|
||||
Ecore_Event_Handler *eh = event_handler_current;
|
||||
if (!eh->delete_me)
|
||||
{
|
||||
int ret;
|
||||
|
@ -490,15 +551,24 @@ _ecore_event_call(void)
|
|||
eh->references--;
|
||||
|
||||
if (!ret)
|
||||
{
|
||||
event_handler_current = NULL;
|
||||
break; /* 0 == "call no further handlers" */
|
||||
}
|
||||
}
|
||||
if (event_handler_current) /* may have changed in recursive main loops */
|
||||
event_handler_current= (Ecore_Event_Handler *)EINA_INLIST_GET(event_handler_current)->next;
|
||||
}
|
||||
}
|
||||
/* if no handlers were set for EXIT signal - then default is */
|
||||
/* to quit the main loop */
|
||||
if ((e->type == ECORE_EVENT_SIGNAL_EXIT) && (handle_count == 0))
|
||||
ecore_main_loop_quit();
|
||||
e->references--;
|
||||
}
|
||||
|
||||
if (event_current) /* may have changed in recursive main loops */
|
||||
event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next;
|
||||
}
|
||||
// printf("EVENT BATCH DONE\n");
|
||||
ecore_raw_event_type = ECORE_EVENT_NONE;
|
||||
|
|
Loading…
Reference in New Issue