forked from len0rd/rockbox
lua rockev fix possible race on thread exit
report of call after free on event thread on Agptek Rocker I'm guessing its a race condition between the thread and the timer but can't say for sure without some more testing Change-Id: If11bd718b3cfa81ea13fff378df56d12afa17a7f
This commit is contained in:
parent
c0cc9aa9e8
commit
19084181a1
1 changed files with 45 additions and 25 deletions
|
@ -170,7 +170,7 @@ static void init_event_data(lua_State *L, struct event_data *ev_data)
|
||||||
//ev_data->NEWL = NULL;
|
//ev_data->NEWL = NULL;
|
||||||
/* rockbox */
|
/* rockbox */
|
||||||
ev_data->thread_id = UINT_MAX;
|
ev_data->thread_id = UINT_MAX;
|
||||||
ev_data->thread_state = THREAD_YIELD;
|
ev_data->thread_state = THREAD_YIELD | THREAD_SUSPENDMASK;
|
||||||
//ev_data->event_stack = NULL;
|
//ev_data->event_stack = NULL;
|
||||||
//ev_data->timer_ticks = 0;
|
//ev_data->timer_ticks = 0;
|
||||||
ev_data->freq_input = EV_INPUT;
|
ev_data->freq_input = EV_INPUT;
|
||||||
|
@ -316,7 +316,7 @@ static void event_thread(void)
|
||||||
lua_interrupt_set(ev_data.L, false);
|
lua_interrupt_set(ev_data.L, false);
|
||||||
ev_data.next_event = EV_TICKS;
|
ev_data.next_event = EV_TICKS;
|
||||||
rb->yield();
|
rb->yield();
|
||||||
} while(ev_data.thread_state == THREAD_YIELD || is_suspend(THREAD_SUSPENDMASK));
|
} while(ev_data.thread_state == THREAD_YIELD || is_suspend(THREAD_SUSPENDMASK >> 8));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,6 +332,8 @@ event_error:
|
||||||
|
|
||||||
/* timer interrupt callback */
|
/* timer interrupt callback */
|
||||||
static void rev_timer_isr(void)
|
static void rev_timer_isr(void)
|
||||||
|
{
|
||||||
|
if (ev_data.thread_state != THREAD_QUIT || is_suspend(THREAD_SUSPENDMASK >> 8))
|
||||||
{
|
{
|
||||||
ev_data.next_event--;
|
ev_data.next_event--;
|
||||||
ev_data.next_input--;
|
ev_data.next_input--;
|
||||||
|
@ -354,6 +356,7 @@ static void rev_timer_isr(void)
|
||||||
if (ev_data.next_event <= 0)
|
if (ev_data.next_event <= 0)
|
||||||
lua_interrupt_set(ev_data.L, true);
|
lua_interrupt_set(ev_data.L, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void create_event_thread_ref(struct event_data *ev_data)
|
static void create_event_thread_ref(struct event_data *ev_data)
|
||||||
{
|
{
|
||||||
|
@ -387,9 +390,6 @@ static void exit_event_thread(struct event_data *ev_data)
|
||||||
{
|
{
|
||||||
ev_data->thread_state = THREAD_QUIT;
|
ev_data->thread_state = THREAD_QUIT;
|
||||||
rb->thread_wait(ev_data->thread_id); /* wait for thread to exit */
|
rb->thread_wait(ev_data->thread_id); /* wait for thread to exit */
|
||||||
|
|
||||||
ev_data->thread_state = THREAD_YIELD;
|
|
||||||
ev_data->thread_id = UINT_MAX;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_event_thread(bool init, struct event_data *ev_data)
|
static void init_event_thread(bool init, struct event_data *ev_data)
|
||||||
|
@ -398,9 +398,13 @@ static void init_event_thread(bool init, struct event_data *ev_data)
|
||||||
{
|
{
|
||||||
if (!init && ev_data->thread_id != UINT_MAX)
|
if (!init && ev_data->thread_id != UINT_MAX)
|
||||||
{
|
{
|
||||||
|
ev_data->thread_state |= THREAD_SUSPENDMASK; /* suspend all events */
|
||||||
|
rb->yield();
|
||||||
exit_event_thread(ev_data);
|
exit_event_thread(ev_data);
|
||||||
destroy_event_thread_ref(ev_data);
|
destroy_event_thread_ref(ev_data);
|
||||||
lua_interrupt_set(ev_data->L, false);
|
lua_interrupt_set(ev_data->L, false);
|
||||||
|
ev_data->thread_state = THREAD_YIELD | THREAD_SUSPENDMASK;
|
||||||
|
ev_data->thread_id = UINT_MAX;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -421,16 +425,20 @@ static void init_event_thread(bool init, struct event_data *ev_data)
|
||||||
|
|
||||||
/* Timer is used to poll waiting events */
|
/* Timer is used to poll waiting events */
|
||||||
rb->timer_register(0, NULL, EV_TIMER_FREQ, rev_timer_isr IF_COP(, CPU));
|
rb->timer_register(0, NULL, EV_TIMER_FREQ, rev_timer_isr IF_COP(, CPU));
|
||||||
|
ev_data->thread_state &= ~THREAD_SUSPENDMASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void playback_event_callback(unsigned short id, void *data)
|
static void playback_event_callback(unsigned short id, void *data)
|
||||||
{
|
{
|
||||||
/* playback events are synchronous we need to return ASAP so set a flag */
|
/* playback events are synchronous we need to return ASAP so set a flag */
|
||||||
|
if (ev_data.thread_state != THREAD_QUIT && !is_suspend(THREAD_SUSPENDMASK >> 8))
|
||||||
|
{
|
||||||
ev_data.thread_state |= thread_ev_states[PLAYBKEVENT];
|
ev_data.thread_state |= thread_ev_states[PLAYBKEVENT];
|
||||||
ev_data.cb[PLAYBKEVENT]->id = id;
|
ev_data.cb[PLAYBKEVENT]->id = id;
|
||||||
ev_data.cb[PLAYBKEVENT]->data = data;
|
ev_data.cb[PLAYBKEVENT]->data = data;
|
||||||
lua_interrupt_set(ev_data.L, true);
|
lua_interrupt_set(ev_data.L, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void register_playbk_events(int flag_events,
|
static void register_playbk_events(int flag_events,
|
||||||
void (*handler)(unsigned short id, void *data))
|
void (*handler)(unsigned short id, void *data))
|
||||||
|
@ -499,11 +507,17 @@ static int rockev_gc(lua_State *L) {
|
||||||
void *d = (void *) lua_touserdata (L, 1);
|
void *d = (void *) lua_touserdata (L, 1);
|
||||||
|
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
else if (d == ev_data.event_stack) /* thread stack is gc'd kill thread */
|
else if (d == ev_data.event_stack) /* thread stack is gc'd kill thread */
|
||||||
|
{
|
||||||
init_event_thread(false, &ev_data);
|
init_event_thread(false, &ev_data);
|
||||||
|
}
|
||||||
else if (d == ev_data.cb[PLAYBKEVENT])
|
else if (d == ev_data.cb[PLAYBKEVENT])
|
||||||
|
{
|
||||||
register_playbk_events(0, &playback_event_callback);
|
register_playbk_events(0, &playback_event_callback);
|
||||||
|
}
|
||||||
|
|
||||||
for( int i= 0; i < EVENT_CT; i++)
|
for( int i= 0; i < EVENT_CT; i++)
|
||||||
{
|
{
|
||||||
|
@ -526,6 +540,9 @@ static int rockev_gc(lua_State *L) {
|
||||||
|
|
||||||
static int rockev_register(lua_State *L)
|
static int rockev_register(lua_State *L)
|
||||||
{
|
{
|
||||||
|
if (ev_data.thread_state == THREAD_QUIT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int event = luaL_checkoption(L, 1, NULL, ev_map);
|
int event = luaL_checkoption(L, 1, NULL, ev_map);
|
||||||
int ev_flag = thread_ev_states[event];
|
int ev_flag = thread_ev_states[event];
|
||||||
int playbk_events;
|
int playbk_events;
|
||||||
|
@ -562,6 +579,9 @@ static int rockev_register(lua_State *L)
|
||||||
|
|
||||||
static int rockev_suspend(lua_State *L)
|
static int rockev_suspend(lua_State *L)
|
||||||
{
|
{
|
||||||
|
if (ev_data.thread_state == THREAD_QUIT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int event; /*Arg 1 is event pass nil to suspend all */
|
int event; /*Arg 1 is event pass nil to suspend all */
|
||||||
bool suspend = luaL_optboolean(L, 2, true);
|
bool suspend = luaL_optboolean(L, 2, true);
|
||||||
int ev_flag = THREAD_SUSPENDMASK;
|
int ev_flag = THREAD_SUSPENDMASK;
|
||||||
|
@ -588,7 +608,7 @@ static int rockev_trigger(lua_State *L)
|
||||||
int ev_flag;
|
int ev_flag;
|
||||||
|
|
||||||
/* protect from invalid events */
|
/* protect from invalid events */
|
||||||
if (ev_data.cb[event] != NULL)
|
if (ev_data.cb[event] != NULL && ev_data.thread_state != THREAD_QUIT)
|
||||||
{
|
{
|
||||||
ev_flag = thread_ev_states[event];
|
ev_flag = thread_ev_states[event];
|
||||||
/* allow user to pass an id to some of the callback functions */
|
/* allow user to pass an id to some of the callback functions */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue