ui_bridge: Fix race condition that results in deadlock.

Fixed by waiting until the UI thread finishes processing events. Close #3541.
This commit is contained in:
Thiago de Arruda
2015-10-31 07:36:08 -03:00
parent ef1d39bbbf
commit 0dac666098
3 changed files with 23 additions and 1 deletions

View File

@@ -219,6 +219,7 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
loop_poll_events(&tui_loop, -1); loop_poll_events(&tui_loop, -1);
} }
ui_bridge_stopped(bridge);
term_input_destroy(&data->input); term_input_destroy(&data->input);
signal_watcher_stop(&data->cont_handle); signal_watcher_stop(&data->cont_handle);
signal_watcher_close(&data->cont_handle, NULL); signal_watcher_close(&data->cont_handle, NULL);

View File

@@ -74,6 +74,13 @@ UI *ui_bridge_attach(UI *ui, ui_main_fn ui_main, event_scheduler scheduler)
return &rv->bridge; return &rv->bridge;
} }
void ui_bridge_stopped(UIBridgeData *bridge)
{
uv_mutex_lock(&bridge->mutex);
bridge->stopped = true;
uv_mutex_unlock(&bridge->mutex);
}
static void ui_thread_run(void *data) static void ui_thread_run(void *data)
{ {
UIBridgeData *bridge = data; UIBridgeData *bridge = data;
@@ -82,8 +89,18 @@ static void ui_thread_run(void *data)
static void ui_bridge_stop(UI *b) static void ui_bridge_stop(UI *b)
{ {
UI_CALL(b, stop, 1, b);
UIBridgeData *bridge = (UIBridgeData *)b; UIBridgeData *bridge = (UIBridgeData *)b;
bool stopped = bridge->stopped = false;
UI_CALL(b, stop, 1, b);
for (;;) {
uv_mutex_lock(&bridge->mutex);
stopped = bridge->stopped;
uv_mutex_unlock(&bridge->mutex);
if (stopped) {
break;
}
loop_poll_events(&loop, 10);
}
uv_thread_join(&bridge->ui_thread); uv_thread_join(&bridge->ui_thread);
uv_mutex_destroy(&bridge->mutex); uv_mutex_destroy(&bridge->mutex);
uv_cond_destroy(&bridge->cond); uv_cond_destroy(&bridge->cond);

View File

@@ -22,6 +22,10 @@ struct ui_bridge_data {
// the call returns. This flag is used as a condition for the main // the call returns. This flag is used as a condition for the main
// thread to continue. // thread to continue.
bool ready; bool ready;
// When a stop request is sent from the main thread, it must wait until the UI
// thread finishes handling all events. This flag is set by the UI thread as a
// signal that it will no longer send messages to the main thread.
bool stopped;
}; };
#define CONTINUE(b) \ #define CONTINUE(b) \