From f6320c7e317ba9c5e5fda1fd7d4358646060412b Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 31 Jan 2021 18:24:35 +0100 Subject: [PATCH] Wrap SDL thread functions into scrcpy-specific API The goal is to expose a consistent API for system tools, and paves the way to make the "core" independant of SDL in the future. --- app/meson.build | 3 +- app/src/controller.c | 46 +++++++------- app/src/controller.h | 9 ++- app/src/decoder.c | 2 - app/src/file_handler.c | 49 +++++++-------- app/src/file_handler.h | 9 ++- app/src/fps_counter.c | 66 ++++++++++---------- app/src/fps_counter.h | 12 ++-- app/src/input_manager.c | 1 - app/src/receiver.c | 13 ++-- app/src/receiver.h | 7 +-- app/src/recorder.c | 50 +++++++-------- app/src/recorder.h | 9 ++- app/src/scrcpy.c | 1 - app/src/screen.c | 7 +-- app/src/server.c | 45 +++++++------- app/src/server.h | 8 +-- app/src/stream.c | 8 +-- app/src/stream.h | 4 +- app/src/util/lock.h | 75 ---------------------- app/src/util/thread.c | 133 ++++++++++++++++++++++++++++++++++++++++ app/src/util/thread.h | 66 ++++++++++++++++++++ app/src/video_buffer.c | 34 +++++----- app/src/video_buffer.h | 12 ++-- 24 files changed, 395 insertions(+), 274 deletions(-) delete mode 100644 app/src/util/lock.h create mode 100644 app/src/util/thread.c create mode 100644 app/src/util/thread.h diff --git a/app/meson.build b/app/meson.build index 2dade249..1f50209e 100644 --- a/app/meson.build +++ b/app/meson.build @@ -23,7 +23,8 @@ src = [ 'src/video_buffer.c', 'src/util/net.c', 'src/util/process.c', - 'src/util/str_util.c' + 'src/util/str_util.c', + 'src/util/thread.c', ] if host_machine.system() == 'windows' diff --git a/app/src/controller.c b/app/src/controller.c index da90fbf1..38b5e702 100644 --- a/app/src/controller.c +++ b/app/src/controller.c @@ -2,25 +2,27 @@ #include -#include "util/lock.h" #include "util/log.h" bool controller_init(struct controller *controller, socket_t control_socket) { cbuf_init(&controller->queue); - if (!receiver_init(&controller->receiver, control_socket)) { + bool ok = receiver_init(&controller->receiver, control_socket); + if (!ok) { return false; } - if (!(controller->mutex = SDL_CreateMutex())) { + ok = sc_mutex_init(&controller->mutex); + if (!ok) { receiver_destroy(&controller->receiver); return false; } - if (!(controller->msg_cond = SDL_CreateCond())) { + ok = sc_cond_init(&controller->msg_cond); + if (!ok) { receiver_destroy(&controller->receiver); - SDL_DestroyMutex(controller->mutex); + sc_mutex_destroy(&controller->mutex); return false; } @@ -32,8 +34,8 @@ controller_init(struct controller *controller, socket_t control_socket) { void controller_destroy(struct controller *controller) { - SDL_DestroyCond(controller->msg_cond); - SDL_DestroyMutex(controller->mutex); + sc_cond_destroy(&controller->msg_cond); + sc_mutex_destroy(&controller->mutex); struct control_msg msg; while (cbuf_take(&controller->queue, &msg)) { @@ -46,13 +48,13 @@ controller_destroy(struct controller *controller) { bool controller_push_msg(struct controller *controller, const struct control_msg *msg) { - mutex_lock(controller->mutex); + sc_mutex_lock(&controller->mutex); bool was_empty = cbuf_is_empty(&controller->queue); bool res = cbuf_push(&controller->queue, *msg); if (was_empty) { - cond_signal(controller->msg_cond); + sc_cond_signal(&controller->msg_cond); } - mutex_unlock(controller->mutex); + sc_mutex_unlock(&controller->mutex); return res; } @@ -73,20 +75,20 @@ run_controller(void *data) { struct controller *controller = data; for (;;) { - mutex_lock(controller->mutex); + sc_mutex_lock(&controller->mutex); while (!controller->stopped && cbuf_is_empty(&controller->queue)) { - cond_wait(controller->msg_cond, controller->mutex); + sc_cond_wait(&controller->msg_cond, &controller->mutex); } if (controller->stopped) { // stop immediately, do not process further msgs - mutex_unlock(controller->mutex); + sc_mutex_unlock(&controller->mutex); break; } struct control_msg msg; bool non_empty = cbuf_take(&controller->queue, &msg); assert(non_empty); (void) non_empty; - mutex_unlock(controller->mutex); + sc_mutex_unlock(&controller->mutex); bool ok = process_msg(controller, &msg); control_msg_destroy(&msg); @@ -102,16 +104,16 @@ bool controller_start(struct controller *controller) { LOGD("Starting controller thread"); - controller->thread = SDL_CreateThread(run_controller, "controller", - controller); - if (!controller->thread) { + bool ok = sc_thread_create(&controller->thread, run_controller, + "controller", controller); + if (!ok) { LOGC("Could not start controller thread"); return false; } if (!receiver_start(&controller->receiver)) { controller_stop(controller); - SDL_WaitThread(controller->thread, NULL); + sc_thread_join(&controller->thread, NULL); return false; } @@ -120,14 +122,14 @@ controller_start(struct controller *controller) { void controller_stop(struct controller *controller) { - mutex_lock(controller->mutex); + sc_mutex_lock(&controller->mutex); controller->stopped = true; - cond_signal(controller->msg_cond); - mutex_unlock(controller->mutex); + sc_cond_signal(&controller->msg_cond); + sc_mutex_unlock(&controller->mutex); } void controller_join(struct controller *controller) { - SDL_WaitThread(controller->thread, NULL); + sc_thread_join(&controller->thread, NULL); receiver_join(&controller->receiver); } diff --git a/app/src/controller.h b/app/src/controller.h index d6fe35e2..c53d0a61 100644 --- a/app/src/controller.h +++ b/app/src/controller.h @@ -4,21 +4,20 @@ #include "common.h" #include -#include -#include #include "control_msg.h" #include "receiver.h" #include "util/cbuf.h" #include "util/net.h" +#include "util/thread.h" struct control_msg_queue CBUF(struct control_msg, 64); struct controller { socket_t control_socket; - SDL_Thread *thread; - SDL_mutex *mutex; - SDL_cond *msg_cond; + sc_thread thread; + sc_mutex mutex; + sc_cond msg_cond; bool stopped; struct control_msg_queue queue; struct receiver receiver; diff --git a/app/src/decoder.c b/app/src/decoder.c index 50c55ab2..23f9ce9d 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include #include "events.h" diff --git a/app/src/file_handler.c b/app/src/file_handler.c index 4f60a101..2b08240c 100644 --- a/app/src/file_handler.c +++ b/app/src/file_handler.c @@ -4,7 +4,6 @@ #include #include "adb.h" -#include "util/lock.h" #include "util/log.h" #define DEFAULT_PUSH_TARGET "/sdcard/" @@ -20,12 +19,14 @@ file_handler_init(struct file_handler *file_handler, const char *serial, cbuf_init(&file_handler->queue); - if (!(file_handler->mutex = SDL_CreateMutex())) { + bool ok = sc_mutex_init(&file_handler->mutex); + if (!ok) { return false; } - if (!(file_handler->event_cond = SDL_CreateCond())) { - SDL_DestroyMutex(file_handler->mutex); + ok = sc_cond_init(&file_handler->event_cond); + if (!ok) { + sc_mutex_destroy(&file_handler->mutex); return false; } @@ -33,8 +34,8 @@ file_handler_init(struct file_handler *file_handler, const char *serial, file_handler->serial = strdup(serial); if (!file_handler->serial) { LOGW("Could not strdup serial"); - SDL_DestroyCond(file_handler->event_cond); - SDL_DestroyMutex(file_handler->mutex); + sc_cond_destroy(&file_handler->event_cond); + sc_mutex_destroy(&file_handler->mutex); return false; } } else { @@ -54,8 +55,8 @@ file_handler_init(struct file_handler *file_handler, const char *serial, void file_handler_destroy(struct file_handler *file_handler) { - SDL_DestroyCond(file_handler->event_cond); - SDL_DestroyMutex(file_handler->mutex); + sc_cond_destroy(&file_handler->event_cond); + sc_mutex_destroy(&file_handler->mutex); free(file_handler->serial); struct file_handler_request req; @@ -92,13 +93,13 @@ file_handler_request(struct file_handler *file_handler, .file = file, }; - mutex_lock(file_handler->mutex); + sc_mutex_lock(&file_handler->mutex); bool was_empty = cbuf_is_empty(&file_handler->queue); bool res = cbuf_push(&file_handler->queue, req); if (was_empty) { - cond_signal(file_handler->event_cond); + sc_cond_signal(&file_handler->event_cond); } - mutex_unlock(file_handler->mutex); + sc_mutex_unlock(&file_handler->mutex); return res; } @@ -107,14 +108,14 @@ run_file_handler(void *data) { struct file_handler *file_handler = data; for (;;) { - mutex_lock(file_handler->mutex); + sc_mutex_lock(&file_handler->mutex); file_handler->current_process = PROCESS_NONE; while (!file_handler->stopped && cbuf_is_empty(&file_handler->queue)) { - cond_wait(file_handler->event_cond, file_handler->mutex); + sc_cond_wait(&file_handler->event_cond, &file_handler->mutex); } if (file_handler->stopped) { // stop immediately, do not process further events - mutex_unlock(file_handler->mutex); + sc_mutex_unlock(&file_handler->mutex); break; } struct file_handler_request req; @@ -132,7 +133,7 @@ run_file_handler(void *data) { file_handler->push_target); } file_handler->current_process = process; - mutex_unlock(file_handler->mutex); + sc_mutex_unlock(&file_handler->mutex); if (req.action == ACTION_INSTALL_APK) { if (process_check_success(process, "adb install", false)) { @@ -150,13 +151,13 @@ run_file_handler(void *data) { } } - mutex_lock(file_handler->mutex); + sc_mutex_lock(&file_handler->mutex); // Close the process (it is necessary already terminated) // Execute this call with mutex locked to avoid race conditions with // file_handler_stop() process_close(file_handler->current_process); file_handler->current_process = PROCESS_NONE; - mutex_unlock(file_handler->mutex); + sc_mutex_unlock(&file_handler->mutex); file_handler_request_destroy(&req); } @@ -167,9 +168,9 @@ bool file_handler_start(struct file_handler *file_handler) { LOGD("Starting file_handler thread"); - file_handler->thread = SDL_CreateThread(run_file_handler, "file_handler", - file_handler); - if (!file_handler->thread) { + bool ok = sc_thread_create(&file_handler->thread, run_file_handler, + "file_handler", file_handler); + if (!ok) { LOGC("Could not start file_handler thread"); return false; } @@ -179,18 +180,18 @@ file_handler_start(struct file_handler *file_handler) { void file_handler_stop(struct file_handler *file_handler) { - mutex_lock(file_handler->mutex); + sc_mutex_lock(&file_handler->mutex); file_handler->stopped = true; - cond_signal(file_handler->event_cond); + sc_cond_signal(&file_handler->event_cond); if (file_handler->current_process != PROCESS_NONE) { if (!process_terminate(file_handler->current_process)) { LOGW("Could not terminate push/install process"); } } - mutex_unlock(file_handler->mutex); + sc_mutex_unlock(&file_handler->mutex); } void file_handler_join(struct file_handler *file_handler) { - SDL_WaitThread(file_handler->thread, NULL); + sc_thread_join(&file_handler->thread, NULL); } diff --git a/app/src/file_handler.h b/app/src/file_handler.h index 193f68c3..fe1d1804 100644 --- a/app/src/file_handler.h +++ b/app/src/file_handler.h @@ -4,11 +4,10 @@ #include "common.h" #include -#include -#include #include "adb.h" #include "util/cbuf.h" +#include "util/thread.h" typedef enum { ACTION_INSTALL_APK, @@ -25,9 +24,9 @@ struct file_handler_request_queue CBUF(struct file_handler_request, 16); struct file_handler { char *serial; const char *push_target; - SDL_Thread *thread; - SDL_mutex *mutex; - SDL_cond *event_cond; + sc_thread thread; + sc_mutex mutex; + sc_cond event_cond; bool stopped; bool initialized; process_t current_process; diff --git a/app/src/fps_counter.c b/app/src/fps_counter.c index e7607409..281c58cf 100644 --- a/app/src/fps_counter.c +++ b/app/src/fps_counter.c @@ -3,25 +3,24 @@ #include #include -#include "util/lock.h" #include "util/log.h" #define FPS_COUNTER_INTERVAL_MS 1000 bool fps_counter_init(struct fps_counter *counter) { - counter->mutex = SDL_CreateMutex(); - if (!counter->mutex) { + bool ok = sc_mutex_init(&counter->mutex); + if (!ok) { return false; } - counter->state_cond = SDL_CreateCond(); - if (!counter->state_cond) { - SDL_DestroyMutex(counter->mutex); + ok = sc_cond_init(&counter->state_cond); + if (!ok) { + sc_mutex_destroy(&counter->mutex); return false; } - counter->thread = NULL; + counter->thread_started = false; atomic_init(&counter->started, 0); // no need to initialize the other fields, they are unused until started @@ -30,8 +29,8 @@ fps_counter_init(struct fps_counter *counter) { void fps_counter_destroy(struct fps_counter *counter) { - SDL_DestroyCond(counter->state_cond); - SDL_DestroyMutex(counter->mutex); + sc_cond_destroy(&counter->state_cond); + sc_mutex_destroy(&counter->mutex); } static inline bool @@ -77,10 +76,10 @@ static int run_fps_counter(void *data) { struct fps_counter *counter = data; - mutex_lock(counter->mutex); + sc_mutex_lock(&counter->mutex); while (!counter->interrupted) { while (!counter->interrupted && !is_started(counter)) { - cond_wait(counter->state_cond, counter->mutex); + sc_cond_wait(&counter->state_cond, &counter->mutex); } while (!counter->interrupted && is_started(counter)) { uint32_t now = SDL_GetTicks(); @@ -90,32 +89,35 @@ run_fps_counter(void *data) { uint32_t remaining = counter->next_timestamp - now; // ignore the reason (timeout or signaled), we just loop anyway - cond_wait_timeout(counter->state_cond, counter->mutex, remaining); + sc_cond_timedwait(&counter->state_cond, &counter->mutex, remaining); } } - mutex_unlock(counter->mutex); + sc_mutex_unlock(&counter->mutex); return 0; } bool fps_counter_start(struct fps_counter *counter) { - mutex_lock(counter->mutex); + sc_mutex_lock(&counter->mutex); counter->next_timestamp = SDL_GetTicks() + FPS_COUNTER_INTERVAL_MS; counter->nr_rendered = 0; counter->nr_skipped = 0; - mutex_unlock(counter->mutex); + sc_mutex_unlock(&counter->mutex); set_started(counter, true); - cond_signal(counter->state_cond); + sc_cond_signal(&counter->state_cond); - // counter->thread is always accessed from the same thread, no need to lock - if (!counter->thread) { - counter->thread = - SDL_CreateThread(run_fps_counter, "fps counter", counter); - if (!counter->thread) { + // counter->thread_started and counter->thread are always accessed from the + // same thread, no need to lock + if (!counter->thread_started) { + bool ok = sc_thread_create(&counter->thread, run_fps_counter, + "fps counter", counter); + if (!ok) { LOGE("Could not start FPS counter thread"); return false; } + + counter->thread_started = true; } return true; @@ -124,7 +126,7 @@ fps_counter_start(struct fps_counter *counter) { void fps_counter_stop(struct fps_counter *counter) { set_started(counter, false); - cond_signal(counter->state_cond); + sc_cond_signal(&counter->state_cond); } bool @@ -134,21 +136,21 @@ fps_counter_is_started(struct fps_counter *counter) { void fps_counter_interrupt(struct fps_counter *counter) { - if (!counter->thread) { + if (!counter->thread_started) { return; } - mutex_lock(counter->mutex); + sc_mutex_lock(&counter->mutex); counter->interrupted = true; - mutex_unlock(counter->mutex); + sc_mutex_unlock(&counter->mutex); // wake up blocking wait - cond_signal(counter->state_cond); + sc_cond_signal(&counter->state_cond); } void fps_counter_join(struct fps_counter *counter) { - if (counter->thread) { - SDL_WaitThread(counter->thread, NULL); + if (counter->thread_started) { + sc_thread_join(&counter->thread, NULL); } } @@ -158,11 +160,11 @@ fps_counter_add_rendered_frame(struct fps_counter *counter) { return; } - mutex_lock(counter->mutex); + sc_mutex_lock(&counter->mutex); uint32_t now = SDL_GetTicks(); check_interval_expired(counter, now); ++counter->nr_rendered; - mutex_unlock(counter->mutex); + sc_mutex_unlock(&counter->mutex); } void @@ -171,9 +173,9 @@ fps_counter_add_skipped_frame(struct fps_counter *counter) { return; } - mutex_lock(counter->mutex); + sc_mutex_lock(&counter->mutex); uint32_t now = SDL_GetTicks(); check_interval_expired(counter, now); ++counter->nr_skipped; - mutex_unlock(counter->mutex); + sc_mutex_unlock(&counter->mutex); } diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index 68255bb6..de252586 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -6,13 +6,15 @@ #include #include #include -#include -#include + +#include "util/thread.h" struct fps_counter { - SDL_Thread *thread; - SDL_mutex *mutex; - SDL_cond *state_cond; + sc_thread thread; + sc_mutex mutex; + sc_cond state_cond; + + bool thread_started; // atomic so that we can check without locking the mutex // if the FPS counter is disabled, we don't want to lock unnecessarily diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 432c4c83..fd780ae6 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -4,7 +4,6 @@ #include #include "event_converter.h" -#include "util/lock.h" #include "util/log.h" static const int ACTION_DOWN = 1; diff --git a/app/src/receiver.c b/app/src/receiver.c index 5b97f88b..337d2a17 100644 --- a/app/src/receiver.c +++ b/app/src/receiver.c @@ -4,12 +4,12 @@ #include #include "device_msg.h" -#include "util/lock.h" #include "util/log.h" bool receiver_init(struct receiver *receiver, socket_t control_socket) { - if (!(receiver->mutex = SDL_CreateMutex())) { + bool ok = sc_mutex_init(&receiver->mutex); + if (!ok) { return false; } receiver->control_socket = control_socket; @@ -18,7 +18,7 @@ receiver_init(struct receiver *receiver, socket_t control_socket) { void receiver_destroy(struct receiver *receiver) { - SDL_DestroyMutex(receiver->mutex); + sc_mutex_destroy(&receiver->mutex); } static void @@ -101,8 +101,9 @@ bool receiver_start(struct receiver *receiver) { LOGD("Starting receiver thread"); - receiver->thread = SDL_CreateThread(run_receiver, "receiver", receiver); - if (!receiver->thread) { + bool ok = sc_thread_create(&receiver->thread, run_receiver, "receiver", + receiver); + if (!ok) { LOGC("Could not start receiver thread"); return false; } @@ -112,5 +113,5 @@ receiver_start(struct receiver *receiver) { void receiver_join(struct receiver *receiver) { - SDL_WaitThread(receiver->thread, NULL); + sc_thread_join(&receiver->thread, NULL); } diff --git a/app/src/receiver.h b/app/src/receiver.h index 3b1cc03a..36523b62 100644 --- a/app/src/receiver.h +++ b/app/src/receiver.h @@ -4,17 +4,16 @@ #include "common.h" #include -#include -#include #include "util/net.h" +#include "util/thread.h" // receive events from the device // managed by the controller struct receiver { socket_t control_socket; - SDL_Thread *thread; - SDL_mutex *mutex; + sc_thread thread; + sc_mutex mutex; }; bool diff --git a/app/src/recorder.c b/app/src/recorder.c index 12047369..0aacb1a4 100644 --- a/app/src/recorder.c +++ b/app/src/recorder.c @@ -3,7 +3,6 @@ #include #include -#include "util/lock.h" #include "util/log.h" static const AVRational SCRCPY_TIME_BASE = {1, 1000000}; // timestamps in us @@ -69,17 +68,17 @@ recorder_init(struct recorder *recorder, return false; } - recorder->mutex = SDL_CreateMutex(); - if (!recorder->mutex) { + bool ok = sc_mutex_init(&recorder->mutex); + if (!ok) { LOGC("Could not create mutex"); free(recorder->filename); return false; } - recorder->queue_cond = SDL_CreateCond(); - if (!recorder->queue_cond) { + ok = sc_cond_init(&recorder->queue_cond); + if (!ok) { LOGC("Could not create cond"); - SDL_DestroyMutex(recorder->mutex); + sc_mutex_destroy(&recorder->mutex); free(recorder->filename); return false; } @@ -97,8 +96,8 @@ recorder_init(struct recorder *recorder, void recorder_destroy(struct recorder *recorder) { - SDL_DestroyCond(recorder->queue_cond); - SDL_DestroyMutex(recorder->mutex); + sc_cond_destroy(&recorder->queue_cond); + sc_mutex_destroy(&recorder->mutex); free(recorder->filename); } @@ -258,17 +257,17 @@ run_recorder(void *data) { struct recorder *recorder = data; for (;;) { - mutex_lock(recorder->mutex); + sc_mutex_lock(&recorder->mutex); while (!recorder->stopped && queue_is_empty(&recorder->queue)) { - cond_wait(recorder->queue_cond, recorder->mutex); + sc_cond_wait(&recorder->queue_cond, &recorder->mutex); } // if stopped is set, continue to process the remaining events (to // finish the recording) before actually stopping if (recorder->stopped && queue_is_empty(&recorder->queue)) { - mutex_unlock(recorder->mutex); + sc_mutex_unlock(&recorder->mutex); struct record_packet *last = recorder->previous; if (last) { // assign an arbitrary duration to the last packet @@ -288,7 +287,7 @@ run_recorder(void *data) { struct record_packet *rec; queue_take(&recorder->queue, next, &rec); - mutex_unlock(recorder->mutex); + sc_mutex_unlock(&recorder->mutex); // recorder->previous is only written from this thread, no need to lock struct record_packet *previous = recorder->previous; @@ -311,11 +310,11 @@ run_recorder(void *data) { if (!ok) { LOGE("Could not record packet"); - mutex_lock(recorder->mutex); + sc_mutex_lock(&recorder->mutex); recorder->failed = true; // discard pending packets recorder_queue_clear(&recorder->queue); - mutex_unlock(recorder->mutex); + sc_mutex_unlock(&recorder->mutex); break; } @@ -330,8 +329,9 @@ bool recorder_start(struct recorder *recorder) { LOGD("Starting recorder thread"); - recorder->thread = SDL_CreateThread(run_recorder, "recorder", recorder); - if (!recorder->thread) { + bool ok = sc_thread_create(&recorder->thread, run_recorder, "recorder", + recorder); + if (!ok) { LOGC("Could not start recorder thread"); return false; } @@ -341,38 +341,38 @@ recorder_start(struct recorder *recorder) { void recorder_stop(struct recorder *recorder) { - mutex_lock(recorder->mutex); + sc_mutex_lock(&recorder->mutex); recorder->stopped = true; - cond_signal(recorder->queue_cond); - mutex_unlock(recorder->mutex); + sc_cond_signal(&recorder->queue_cond); + sc_mutex_unlock(&recorder->mutex); } void recorder_join(struct recorder *recorder) { - SDL_WaitThread(recorder->thread, NULL); + sc_thread_join(&recorder->thread, NULL); } bool recorder_push(struct recorder *recorder, const AVPacket *packet) { - mutex_lock(recorder->mutex); + sc_mutex_lock(&recorder->mutex); assert(!recorder->stopped); if (recorder->failed) { // reject any new packet (this will stop the stream) - mutex_unlock(recorder->mutex); + sc_mutex_unlock(&recorder->mutex); return false; } struct record_packet *rec = record_packet_new(packet); if (!rec) { LOGC("Could not allocate record packet"); - mutex_unlock(recorder->mutex); + sc_mutex_unlock(&recorder->mutex); return false; } queue_push(&recorder->queue, next, rec); - cond_signal(recorder->queue_cond); + sc_cond_signal(&recorder->queue_cond); - mutex_unlock(recorder->mutex); + sc_mutex_unlock(&recorder->mutex); return true; } diff --git a/app/src/recorder.h b/app/src/recorder.h index 1e942110..be2b2dff 100644 --- a/app/src/recorder.h +++ b/app/src/recorder.h @@ -5,12 +5,11 @@ #include #include -#include -#include #include "coords.h" #include "scrcpy.h" #include "util/queue.h" +#include "util/thread.h" struct record_packet { AVPacket packet; @@ -26,9 +25,9 @@ struct recorder { struct size declared_frame_size; bool header_written; - SDL_Thread *thread; - SDL_mutex *mutex; - SDL_cond *queue_cond; + sc_thread thread; + sc_mutex mutex; + sc_cond queue_cond; bool stopped; // set on recorder_stop() by the stream reader bool failed; // set on packet write failure struct recorder_queue queue; diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index f1560130..747e25a6 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -26,7 +26,6 @@ #include "stream.h" #include "tiny_xpm.h" #include "video_buffer.h" -#include "util/lock.h" #include "util/log.h" #include "util/net.h" diff --git a/app/src/screen.c b/app/src/screen.c index 5bdfac2a..0f8a2226 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -8,7 +8,6 @@ #include "scrcpy.h" #include "tiny_xpm.h" #include "video_buffer.h" -#include "util/lock.h" #include "util/log.h" #define DISPLAY_MARGINS 96 @@ -454,15 +453,15 @@ update_texture(struct screen *screen, const AVFrame *frame) { bool screen_update_frame(struct screen *screen, struct video_buffer *vb) { - mutex_lock(vb->mutex); + sc_mutex_lock(&vb->mutex); const AVFrame *frame = video_buffer_consume_rendered_frame(vb); struct size new_frame_size = {frame->width, frame->height}; if (!prepare_for_frame(screen, new_frame_size)) { - mutex_unlock(vb->mutex); + sc_mutex_unlock(&vb->mutex); return false; } update_texture(screen, frame); - mutex_unlock(vb->mutex); + sc_mutex_unlock(&vb->mutex); screen_render(screen, false); return true; diff --git a/app/src/server.c b/app/src/server.c index bb08d56e..096ac18f 100644 --- a/app/src/server.c +++ b/app/src/server.c @@ -5,12 +5,10 @@ #include #include #include -#include #include #include #include "adb.h" -#include "util/lock.h" #include "util/log.h" #include "util/net.h" #include "util/str_util.h" @@ -357,18 +355,17 @@ bool server_init(struct server *server) { server->serial = NULL; server->process = PROCESS_NONE; - server->wait_server_thread = NULL; atomic_flag_clear_explicit(&server->server_socket_closed, memory_order_relaxed); - server->mutex = SDL_CreateMutex(); - if (!server->mutex) { + bool ok = sc_mutex_init(&server->mutex); + if (!ok) { return false; } - server->process_terminated_cond = SDL_CreateCond(); - if (!server->process_terminated_cond) { - SDL_DestroyMutex(server->mutex); + ok = sc_cond_init(&server->process_terminated_cond); + if (!ok) { + sc_mutex_destroy(&server->mutex); return false; } @@ -391,10 +388,10 @@ run_wait_server(void *data) { struct server *server = data; process_wait(server->process, false); // ignore exit code - mutex_lock(server->mutex); + sc_mutex_lock(&server->mutex); server->process_terminated = true; - cond_signal(server->process_terminated_cond); - mutex_unlock(server->mutex); + sc_cond_signal(&server->process_terminated_cond); + sc_mutex_unlock(&server->mutex); // no need for synchronization, server_socket is initialized before this // thread was created @@ -439,9 +436,9 @@ server_start(struct server *server, const char *serial, // things simple and multiplatform, just spawn a new thread waiting for the // server process and calling shutdown()/close() on the server socket if // necessary to wake up any accept() blocking call. - server->wait_server_thread = - SDL_CreateThread(run_wait_server, "wait-server", server); - if (!server->wait_server_thread) { + bool ok = sc_thread_create(&server->wait_server_thread, run_wait_server, + "wait-server", server); + if (!ok) { process_terminate(server->process); process_wait(server->process, true); // ignore exit code goto error2; @@ -531,33 +528,33 @@ server_stop(struct server *server) { } // Give some delay for the server to terminate properly - mutex_lock(server->mutex); - int r = 0; + sc_mutex_lock(&server->mutex); + bool signaled = false; if (!server->process_terminated) { #define WATCHDOG_DELAY_MS 1000 - r = cond_wait_timeout(server->process_terminated_cond, - server->mutex, - WATCHDOG_DELAY_MS); + signaled = sc_cond_timedwait(&server->process_terminated_cond, + &server->mutex, + WATCHDOG_DELAY_MS); } - mutex_unlock(server->mutex); + sc_mutex_unlock(&server->mutex); // After this delay, kill the server if it's not dead already. // On some devices, closing the sockets is not sufficient to wake up the // blocking calls while the device is asleep. - if (r == SDL_MUTEX_TIMEDOUT) { + if (!signaled) { // The process is terminated, but not reaped (closed) yet, so its PID // is still valid. LOGW("Killing the server..."); process_terminate(server->process); } - SDL_WaitThread(server->wait_server_thread, NULL); + sc_thread_join(&server->wait_server_thread, NULL); process_close(server->process); } void server_destroy(struct server *server) { free(server->serial); - SDL_DestroyCond(server->process_terminated_cond); - SDL_DestroyMutex(server->mutex); + sc_cond_destroy(&server->process_terminated_cond); + sc_mutex_destroy(&server->mutex); } diff --git a/app/src/server.h b/app/src/server.h index 1ac12b5f..83c528ef 100644 --- a/app/src/server.h +++ b/app/src/server.h @@ -6,21 +6,21 @@ #include #include #include -#include #include "adb.h" #include "scrcpy.h" #include "util/log.h" #include "util/net.h" +#include "util/thread.h" struct server { char *serial; process_t process; - SDL_Thread *wait_server_thread; + sc_thread wait_server_thread; atomic_flag server_socket_closed; - SDL_mutex *mutex; - SDL_cond *process_terminated_cond; + sc_mutex mutex; + sc_cond process_terminated_cond; bool process_terminated; socket_t server_socket; // only used if !tunnel_forward diff --git a/app/src/stream.c b/app/src/stream.c index e4c9f387..ba72f164 100644 --- a/app/src/stream.c +++ b/app/src/stream.c @@ -4,8 +4,6 @@ #include #include #include -#include -#include #include #include "decoder.h" @@ -279,8 +277,8 @@ bool stream_start(struct stream *stream) { LOGD("Starting stream thread"); - stream->thread = SDL_CreateThread(run_stream, "stream", stream); - if (!stream->thread) { + bool ok = sc_thread_create(&stream->thread, run_stream, "stream", stream); + if (!ok) { LOGC("Could not start stream thread"); return false; } @@ -296,5 +294,5 @@ stream_stop(struct stream *stream) { void stream_join(struct stream *stream) { - SDL_WaitThread(stream->thread, NULL); + sc_thread_join(&stream->thread, NULL); } diff --git a/app/src/stream.h b/app/src/stream.h index d308df88..784e0402 100644 --- a/app/src/stream.h +++ b/app/src/stream.h @@ -7,15 +7,15 @@ #include #include #include -#include #include "util/net.h" +#include "util/thread.h" struct video_buffer; struct stream { socket_t socket; - SDL_Thread *thread; + sc_thread thread; struct decoder *decoder; struct recorder *recorder; AVCodecContext *codec_ctx; diff --git a/app/src/util/lock.h b/app/src/util/lock.h deleted file mode 100644 index f031bd69..00000000 --- a/app/src/util/lock.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef LOCK_H -#define LOCK_H - -#include "common.h" - -#include -#include - -#include "log.h" - -static inline void -mutex_lock(SDL_mutex *mutex) { - int r = SDL_LockMutex(mutex); -#ifndef NDEBUG - if (r) { - LOGC("Could not lock mutex: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif -} - -static inline void -mutex_unlock(SDL_mutex *mutex) { - int r = SDL_UnlockMutex(mutex); -#ifndef NDEBUG - if (r) { - LOGC("Could not unlock mutex: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif -} - -static inline void -cond_wait(SDL_cond *cond, SDL_mutex *mutex) { - int r = SDL_CondWait(cond, mutex); -#ifndef NDEBUG - if (r) { - LOGC("Could not wait on condition: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif -} - -static inline int -cond_wait_timeout(SDL_cond *cond, SDL_mutex *mutex, uint32_t ms) { - int r = SDL_CondWaitTimeout(cond, mutex, ms); -#ifndef NDEBUG - if (r < 0) { - LOGC("Could not wait on condition with timeout: %s", SDL_GetError()); - abort(); - } -#endif - return r; -} - -static inline void -cond_signal(SDL_cond *cond) { - int r = SDL_CondSignal(cond); -#ifndef NDEBUG - if (r) { - LOGC("Could not signal a condition: %s", SDL_GetError()); - abort(); - } -#else - (void) r; -#endif -} - -#endif diff --git a/app/src/util/thread.c b/app/src/util/thread.c new file mode 100644 index 00000000..bb4feb62 --- /dev/null +++ b/app/src/util/thread.c @@ -0,0 +1,133 @@ +#include "thread.h" + +#include +#include + +#include "log.h" + +bool +sc_thread_create(sc_thread *thread, sc_thread_fn fn, const char *name, + void *userdata) { + SDL_Thread *sdl_thread = SDL_CreateThread(fn, name, userdata); + if (!sdl_thread) { + return false; + } + + thread->thread = sdl_thread; + return true; +} + +void +sc_thread_join(sc_thread *thread, int *status) { + SDL_WaitThread(thread->thread, status); +} + +bool +sc_mutex_init(sc_mutex *mutex) { + SDL_mutex *sdl_mutex = SDL_CreateMutex(); + if (!sdl_mutex) { + return false; + } + + mutex->mutex = sdl_mutex; + return true; +} + +void +sc_mutex_destroy(sc_mutex *mutex) { + SDL_DestroyMutex(mutex->mutex); +} + +void +sc_mutex_lock(sc_mutex *mutex) { + int r = SDL_LockMutex(mutex->mutex); +#ifndef NDEBUG + if (r) { + LOGC("Could not lock mutex: %s", SDL_GetError()); + abort(); + } +#else + (void) r; +#endif +} + +void +sc_mutex_unlock(sc_mutex *mutex) { + int r = SDL_UnlockMutex(mutex->mutex); +#ifndef NDEBUG + if (r) { + LOGC("Could not lock mutex: %s", SDL_GetError()); + abort(); + } +#else + (void) r; +#endif +} + +bool +sc_cond_init(sc_cond *cond) { + SDL_cond *sdl_cond = SDL_CreateCond(); + if (!sdl_cond) { + return false; + } + + cond->cond = sdl_cond; + return true; +} + +void +sc_cond_destroy(sc_cond *cond) { + SDL_DestroyCond(cond->cond); +} + +void +sc_cond_wait(sc_cond *cond, sc_mutex *mutex) { + int r = SDL_CondWait(cond->cond, mutex->mutex); +#ifndef NDEBUG + if (r) { + LOGC("Could not wait on condition: %s", SDL_GetError()); + abort(); + } +#else + (void) r; +#endif +} + +bool +sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, uint32_t ms) { + int r = SDL_CondWaitTimeout(cond->cond, mutex->mutex, ms); +#ifndef NDEBUG + if (r < 0) { + LOGC("Could not wait on condition with timeout: %s", SDL_GetError()); + abort(); + } +#endif + assert(r == 0 || r == SDL_MUTEX_TIMEDOUT); + return r == 0; +} + +void +sc_cond_signal(sc_cond *cond) { + int r = SDL_CondSignal(cond->cond); +#ifndef NDEBUG + if (r) { + LOGC("Could not signal a condition: %s", SDL_GetError()); + abort(); + } +#else + (void) r; +#endif +} + +void +sc_cond_broadcast(sc_cond *cond) { + int r = SDL_CondBroadcast(cond->cond); +#ifndef NDEBUG + if (r) { + LOGC("Could not broadcast a condition: %s", SDL_GetError()); + abort(); + } +#else + (void) r; +#endif +} diff --git a/app/src/util/thread.h b/app/src/util/thread.h new file mode 100644 index 00000000..5fbaf3c1 --- /dev/null +++ b/app/src/util/thread.h @@ -0,0 +1,66 @@ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include "common.h" + +#include +#include + +/* Forward declarations */ +typedef struct SDL_Thread SDL_Thread; +typedef struct SDL_mutex SDL_mutex; +typedef struct SDL_cond SDL_cond; + +typedef int sc_thread_fn(void *); + +typedef struct sc_thread { + SDL_Thread *thread; +} sc_thread; + +typedef struct sc_mutex { + SDL_mutex *mutex; +} sc_mutex; + +typedef struct sc_cond { + SDL_cond *cond; +} sc_cond; + +bool +sc_thread_create(sc_thread *thread, sc_thread_fn fn, const char *name, + void *userdata); + +void +sc_thread_join(sc_thread *thread, int *status); + +bool +sc_mutex_init(sc_mutex *mutex); + +void +sc_mutex_destroy(sc_mutex *mutex); + +void +sc_mutex_lock(sc_mutex *mutex); + +void +sc_mutex_unlock(sc_mutex *mutex); + +bool +sc_cond_init(sc_cond *cond); + +void +sc_cond_destroy(sc_cond *cond); + +void +sc_cond_wait(sc_cond *cond, sc_mutex *mutex); + +// return true on signaled, false on timeout +bool +sc_cond_timedwait(sc_cond *cond, sc_mutex *mutex, uint32_t ms); + +void +sc_cond_signal(sc_cond *cond); + +void +sc_cond_broadcast(sc_cond *cond); + +#endif diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index d656c6f4..660c6929 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -1,11 +1,9 @@ #include "video_buffer.h" #include -#include #include #include -#include "util/lock.h" #include "util/log.h" bool @@ -13,22 +11,26 @@ video_buffer_init(struct video_buffer *vb, struct fps_counter *fps_counter, bool render_expired_frames) { vb->fps_counter = fps_counter; - if (!(vb->decoding_frame = av_frame_alloc())) { + vb->decoding_frame = av_frame_alloc(); + if (!vb->decoding_frame) { goto error_0; } - if (!(vb->rendering_frame = av_frame_alloc())) { + vb->rendering_frame = av_frame_alloc(); + if (!vb->rendering_frame) { goto error_1; } - if (!(vb->mutex = SDL_CreateMutex())) { + bool ok = sc_mutex_init(&vb->mutex); + if (!ok) { goto error_2; } vb->render_expired_frames = render_expired_frames; if (render_expired_frames) { - if (!(vb->rendering_frame_consumed_cond = SDL_CreateCond())) { - SDL_DestroyMutex(vb->mutex); + ok = sc_cond_init(&vb->rendering_frame_consumed_cond); + if (!ok) { + sc_mutex_destroy(&vb->mutex); goto error_2; } // interrupted is not used if expired frames are not rendered @@ -53,9 +55,9 @@ error_0: void video_buffer_destroy(struct video_buffer *vb) { if (vb->render_expired_frames) { - SDL_DestroyCond(vb->rendering_frame_consumed_cond); + sc_cond_destroy(&vb->rendering_frame_consumed_cond); } - SDL_DestroyMutex(vb->mutex); + sc_mutex_destroy(&vb->mutex); av_frame_free(&vb->rendering_frame); av_frame_free(&vb->decoding_frame); } @@ -70,11 +72,11 @@ video_buffer_swap_frames(struct video_buffer *vb) { void video_buffer_offer_decoded_frame(struct video_buffer *vb, bool *previous_frame_skipped) { - mutex_lock(vb->mutex); + sc_mutex_lock(&vb->mutex); if (vb->render_expired_frames) { // wait for the current (expired) frame to be consumed while (!vb->rendering_frame_consumed && !vb->interrupted) { - cond_wait(vb->rendering_frame_consumed_cond, vb->mutex); + sc_cond_wait(&vb->rendering_frame_consumed_cond, &vb->mutex); } } else if (!vb->rendering_frame_consumed) { fps_counter_add_skipped_frame(vb->fps_counter); @@ -85,7 +87,7 @@ video_buffer_offer_decoded_frame(struct video_buffer *vb, *previous_frame_skipped = !vb->rendering_frame_consumed; vb->rendering_frame_consumed = false; - mutex_unlock(vb->mutex); + sc_mutex_unlock(&vb->mutex); } const AVFrame * @@ -95,7 +97,7 @@ video_buffer_consume_rendered_frame(struct video_buffer *vb) { fps_counter_add_rendered_frame(vb->fps_counter); if (vb->render_expired_frames) { // unblock video_buffer_offer_decoded_frame() - cond_signal(vb->rendering_frame_consumed_cond); + sc_cond_signal(&vb->rendering_frame_consumed_cond); } return vb->rendering_frame; } @@ -103,10 +105,10 @@ video_buffer_consume_rendered_frame(struct video_buffer *vb) { void video_buffer_interrupt(struct video_buffer *vb) { if (vb->render_expired_frames) { - mutex_lock(vb->mutex); + sc_mutex_lock(&vb->mutex); vb->interrupted = true; - mutex_unlock(vb->mutex); + sc_mutex_unlock(&vb->mutex); // wake up blocking wait - cond_signal(vb->rendering_frame_consumed_cond); + sc_cond_signal(&vb->rendering_frame_consumed_cond); } } diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 68ef8e04..fbab046b 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -4,9 +4,9 @@ #include "common.h" #include -#include #include "fps_counter.h" +#include "util/thread.h" // forward declarations typedef struct AVFrame AVFrame; @@ -14,10 +14,10 @@ typedef struct AVFrame AVFrame; struct video_buffer { AVFrame *decoding_frame; AVFrame *rendering_frame; - SDL_mutex *mutex; + sc_mutex mutex; bool render_expired_frames; bool interrupted; - SDL_cond *rendering_frame_consumed_cond; + sc_cond rendering_frame_consumed_cond; bool rendering_frame_consumed; struct fps_counter *fps_counter; }; @@ -30,16 +30,16 @@ void video_buffer_destroy(struct video_buffer *vb); // set the decoded frame as ready for rendering -// this function locks frames->mutex during its execution +// this function locks vb->mutex during its execution // the output flag is set to report whether the previous frame has been skipped void video_buffer_offer_decoded_frame(struct video_buffer *vb, bool *previous_frame_skipped); // mark the rendering frame as consumed and return it -// MUST be called with frames->mutex locked!!! +// MUST be called with vb->mutex locked!!! // the caller is expected to render the returned frame to some texture before -// unlocking frames->mutex +// unlocking vb->mutex const AVFrame * video_buffer_consume_rendered_frame(struct video_buffer *vb);