Simplify cleanup

The cleanup is not linear: for example, the server must be stopped and
its sockets must be shutdown after the stream and controller are stopped
(so that they don't continue processing garbage), but before they are
joined, to avoid a deadlock if they are blocked on a socket read.

Simplify the spaghetti-cleanup by keeping trace of initialization at
runtime.
This commit is contained in:
Romain Vimont 2019-05-30 11:18:54 +02:00
parent 0dee9b04b2
commit bfb86ca2c2

View file

@ -280,20 +280,24 @@ scrcpy(const struct scrcpy_options *options) {
show_touches_waited = false; show_touches_waited = false;
} }
bool ret = true; bool ret = false;
bool video_buffer_initialized = false;
bool file_handler_initialized = false;
bool recorder_initialized = false;
bool stream_started = false;
bool controller_initialized = false;
bool controller_started = false;
bool display = !options->no_display; bool display = !options->no_display;
bool control = !options->no_control; bool control = !options->no_control;
if (!sdl_init_and_configure(display)) { if (!sdl_init_and_configure(display)) {
ret = false; goto end;
goto finally_destroy_server;
} }
if (!server_connect_to(&server)) { if (!server_connect_to(&server)) {
server_stop(&server); goto end;
ret = false;
goto finally_destroy_server;
} }
socket_t device_socket = server.device_socket; socket_t device_socket = server.device_socket;
@ -305,23 +309,21 @@ scrcpy(const struct scrcpy_options *options) {
// change therefore, we transmit the screen size before the video stream, // change therefore, we transmit the screen size before the video stream,
// to be able to init the window immediately // to be able to init the window immediately
if (!device_read_info(device_socket, device_name, &frame_size)) { if (!device_read_info(device_socket, device_name, &frame_size)) {
server_stop(&server); goto end;
ret = false;
goto finally_destroy_server;
} }
struct decoder *dec = NULL; struct decoder *dec = NULL;
if (display) { if (display) {
if (!video_buffer_init(&video_buffer)) { if (!video_buffer_init(&video_buffer)) {
server_stop(&server); goto end;
ret = false;
goto finally_destroy_server;
} }
video_buffer_initialized = true;
if (control && !file_handler_init(&file_handler, server.serial)) { if (control) {
ret = false; if (!file_handler_init(&file_handler, server.serial)) {
server_stop(&server); goto end;
goto finally_destroy_video_buffer; }
file_handler_initialized = true;
} }
decoder_init(&decoder, &video_buffer); decoder_init(&decoder, &video_buffer);
@ -334,11 +336,10 @@ scrcpy(const struct scrcpy_options *options) {
options->record_filename, options->record_filename,
options->record_format, options->record_format,
frame_size)) { frame_size)) {
ret = false; goto end;
server_stop(&server);
goto finally_destroy_file_handler;
} }
rec = &recorder; rec = &recorder;
recorder_initialized = true;
} }
av_log_set_callback(av_log_callback); av_log_set_callback(av_log_callback);
@ -348,28 +349,24 @@ scrcpy(const struct scrcpy_options *options) {
// now we consumed the header values, the socket receives the video stream // now we consumed the header values, the socket receives the video stream
// start the stream // start the stream
if (!stream_start(&stream)) { if (!stream_start(&stream)) {
ret = false; goto end;
server_stop(&server);
goto finally_destroy_recorder;
} }
stream_started = true;
if (display) { if (display) {
if (control) { if (control) {
if (!controller_init(&controller, device_socket)) { if (!controller_init(&controller, device_socket)) {
ret = false; goto end;
goto finally_stop_stream;
} }
if (!controller_start(&controller)) { if (!controller_start(&controller)) {
ret = false; goto end;
goto finally_destroy_controller;
} }
} }
if (!screen_init_rendering(&screen, device_name, frame_size, if (!screen_init_rendering(&screen, device_name, frame_size,
options->always_on_top)) { options->always_on_top)) {
ret = false; goto end;
goto finally_stop_and_join_controller;
} }
if (options->fullscreen) { if (options->fullscreen) {
@ -387,35 +384,47 @@ scrcpy(const struct scrcpy_options *options) {
screen_destroy(&screen); screen_destroy(&screen);
finally_stop_and_join_controller: end:
if (display && control) { // stop stream and controller so that they don't continue once their socket
// is shutdown
if (stream_started) {
stream_stop(&stream);
}
if (controller_started) {
controller_stop(&controller); controller_stop(&controller);
}
if (file_handler_initialized) {
file_handler_stop(&file_handler);
}
// shutdown the sockets and kill the server
server_stop(&server);
// now that the sockets are shutdown, the stream and controller are
// interrupted, we can join them
if (stream_started) {
stream_join(&stream);
}
if (controller_started) {
controller_join(&controller); controller_join(&controller);
} }
finally_destroy_controller: if (controller_initialized) {
if (display && control) {
controller_destroy(&controller); controller_destroy(&controller);
} }
finally_stop_stream:
stream_stop(&stream); if (recorder_initialized) {
// stop the server before stream_join() to wake up the stream
server_stop(&server);
stream_join(&stream);
finally_destroy_recorder:
if (record) {
recorder_destroy(&recorder); recorder_destroy(&recorder);
} }
finally_destroy_file_handler:
if (display && control) { if (file_handler_initialized) {
file_handler_stop(&file_handler);
file_handler_join(&file_handler); file_handler_join(&file_handler);
file_handler_destroy(&file_handler); file_handler_destroy(&file_handler);
} }
finally_destroy_video_buffer:
if (display) { if (video_buffer_initialized) {
video_buffer_destroy(&video_buffer); video_buffer_destroy(&video_buffer);
} }
finally_destroy_server:
if (options->show_touches) { if (options->show_touches) {
if (!show_touches_waited) { if (!show_touches_waited) {
// wait the process which enabled "show touches" // wait the process which enabled "show touches"