From 24e362a595fed7bdf6cd9cc310c19bfb4e6a4df5 Mon Sep 17 00:00:00 2001 From: Elliu <elliu@hashi.re> Date: Wed, 22 Dec 2021 22:50:25 +0100 Subject: [PATCH] Moving C code in headers to .c files to allow includes from C++ --- CMakeLists.txt | 2 + inc/lektor/common.h | 2 +- inc/lektor/lib/strv.h | 297 +++---------------- inc/lektor/net.h | 4 +- inc/lektor/queue.h | 101 +------ src/base/os.c | 2 +- src/database/queue.c | 108 +++++++ src/lib/strv.c | 262 ++++++++++++++++ src/main/server.c | 2 + src/module/module_qt_window.c | 24 +- src/module/module_qt_window.h | 31 ++ src/module/qt_window/mpvwidget.hh | 2 + src/module/qt_window/mpvwidget_interface.cpp | 18 +- src/module/qt_window/mpvwidget_interface.h | 10 +- src/module/thread.c | 81 +++++ src/module/thread.h | 87 +----- 16 files changed, 591 insertions(+), 442 deletions(-) create mode 100644 src/lib/strv.c create mode 100644 src/module/module_qt_window.h create mode 100644 src/module/thread.c diff --git a/CMakeLists.txt b/CMakeLists.txt index d9d8d8d2..4e9cfd55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,6 +139,7 @@ set(lektor_db_SOURCES src/database/open.c src/database/update.c src/database/upgrade.c + src/lib/strv.c ) set(lektor_module_SOURCES @@ -150,6 +151,7 @@ set(lektor_module_SOURCES src/module/qt_window/mpvwidget.cpp src/module/qt_window/mpvwidget_interface.cpp src/module/qt_window/qthelper.cpp + src/module/thread.c ) set(lektor_mkv_SOURCES diff --git a/inc/lektor/common.h b/inc/lektor/common.h index e1a4706b..01b985a8 100644 --- a/inc/lektor/common.h +++ b/inc/lektor/common.h @@ -207,7 +207,7 @@ void ___lkt_print(const char *section, const char *format, ...); #define BUFFER_OUT_MAX 16 /* At most 16 messages per client */ #define MPD_VERSION "0.21.16" -typedef volatile enum { +typedef enum { MPD_IDLE_NONE = 0, MPD_IDLE_DATABASE = (1 << 1), diff --git a/inc/lektor/lib/strv.h b/inc/lektor/lib/strv.h index 151c64fc..d0b84a63 100644 --- a/inc/lektor/lib/strv.h +++ b/inc/lektor/lib/strv.h @@ -16,7 +16,7 @@ struct strv { #define STRV_FMT "%.*s" /* Format string for a string view */ #define STRV_ARG(sv) ((sv).count), ((sv).data) /* Unpack the string view */ -#define STRV_DEF __attribute__((unused)) static +#define STRV_DEF __attribute__((unused)) /* Create a string view from a slice or a C string. */ STRV_DEF struct strv strv_from_slice(const char *data, int count); @@ -58,265 +58,54 @@ STRV_DEF _Bool strv_equal_nocase(struct strv a, struct strv b); /* Private implementation of some functions to not include some headers */ -static inline char -strv_ctoupper(char s) -{ - return (('a' <= s) && (s <= 'z')) ? 'A' + (s - 'a') : s; -} - -static inline char -strv_ctolower(char s) -{ - return (('A' <= s) && (s <= 'Z')) ? 'a' + (s - 'A') : s; -} - -static inline _Bool -strv_memcmp(const void *ptr2, const void *ptr1, int count) -{ - register const unsigned char *s1 = (const unsigned char *)ptr1; - register const unsigned char *s2 = (const unsigned char *)ptr2; - - while (count-- > 0) { - if (*s1++ != *s2++) - return (_Bool)0; - } +char strv_ctoupper(char s); - return (_Bool)1; -} - -static inline _Bool -strv_isspace(char x) -{ - return x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '\v' || x == '\f'; -} - -static inline int -strv_strlen(const char *str) -{ - int len = 0; - while (str[len]) { - len += 1; - - /* Try to avoid overflows */ - if (len == __INT_MAX__) - return 0; - } - return len; -} +char strv_ctolower(char s); + +_Bool strv_memcmp(const void *ptr2, const void *ptr1, int count); + +_Bool strv_isspace(char x); + +int strv_strlen(const char *str); /* Implementation of the functions */ -static struct strv -strv_from_slice(const char *data, int count) -{ - struct strv sv; - sv.count = count; - sv.data = data; - return sv; -} - -static struct strv -strv_from_str(const char *cstr) -{ - return strv_from_slice(cstr, strv_strlen(cstr)); -} - -static _Bool -strv_as_str(const struct strv sv, char *data, int len) -{ - if (sv.count >= len) - return (_Bool)0; - - for (int i = 0; i < sv.count; ++i) - data[i] = sv.data[i]; - data[sv.count] = '\0'; - - return (_Bool)1; -} - -static struct strv -strv_trim_l(struct strv sv) -{ - int i = 0; - while ((i < sv.count) && strv_isspace(sv.data[i])) - i += 1; - return strv_from_slice(sv.data + i, sv.count - i); -} - -static struct strv -strv_trim_r(struct strv sv) -{ - int i = 0; - while ((i < sv.count) && strv_isspace(sv.data[sv.count - 1 - i])) - i += 1; - return strv_from_slice(sv.data, sv.count - i); -} - -static struct strv -strv_trim(struct strv sv) -{ - return strv_trim_r(strv_trim_l(sv)); -} - -static struct strv -strv_chop_left(struct strv *sv, int n) -{ - if (n > sv->count) - n = sv->count; - - struct strv result = strv_from_slice(sv->data, n); - sv->data += n; - sv->count -= n; - return result; -} - -static struct strv -strv_chop_right(struct strv *sv, int n) -{ - if (n > sv->count) - n = sv->count; - - struct strv result = strv_from_slice(sv->data + sv->count - n, n); - sv->count -= n; - return result; -} - -static _Bool -strv_index_of(struct strv sv, char c, int *index) -{ - int i = 0; - while (i < sv.count && sv.data[i] != c) - i += 1; - - if (i < sv.count) { - if (index) - *index = i; - return (_Bool)1; - } +struct strv strv_from_slice(const char *data, int count); - else - return (_Bool)0; -} - -static _Bool -strv_try_chop_by_delim(struct strv *sv, char delim, struct strv *chunk) -{ - int i = 0; - while (i < sv->count && sv->data[i] != delim) - i += 1; - - struct strv result = strv_from_slice(sv->data, i); - - if (i < sv->count) { - i += 1; - sv->count -= i; - sv->data += i; - if (chunk) - *chunk = result; - return (_Bool)1; - } +struct strv strv_from_str(const char *cstr); - return (_Bool)0; -} - -static struct strv -strv_chop_by_delim(struct strv *sv, char delim) -{ - int i = 0; - while (i < sv->count && sv->data[i] != delim) - i += 1; - - const struct strv result = strv_from_slice(sv->data, i); - i += (i < sv->count); - sv->count -= i; - sv->data += i; - - return result; -} - -static _Bool -strv_starts_with(struct strv sv, struct strv expected_prefix) -{ - if (expected_prefix.count <= sv.count) { - const struct strv actual_prefix = strv_from_slice(sv.data, expected_prefix.count); - return strv_equal(expected_prefix, actual_prefix); - } +_Bool strv_as_str(const struct strv sv, char *data, int len); - return (_Bool)0; -} +struct strv strv_trim_l(struct strv sv); -static _Bool -strv_ends_with(struct strv sv, struct strv expected_suffix) -{ - if (expected_suffix.count <= sv.count) { - const struct strv actual_suffix = - strv_from_slice(sv.data + sv.count - expected_suffix.count, expected_suffix.count); - return strv_equal(expected_suffix, actual_suffix); - } +struct strv strv_trim_r(struct strv sv); - return (_Bool)0; -} - -static _Bool -strv_equal(struct strv a, struct strv b) -{ - return (a.count != b.count) ? (_Bool)0 : strv_memcmp(a.data, b.data, a.count); -} - -static _Bool -strv_equal_nocase(struct strv a, struct strv b) -{ - if (a.count != b.count) - return (_Bool)0; - for (int i = 0; i < a.count; ++i) { - if (strv_ctoupper(a.data[i]) != strv_ctoupper(b.data[i])) - return (_Bool)0; - } - return (_Bool)1; -} - -static struct strv -strv_chop_left_while(struct strv *sv, _Bool (*cb)(char)) -{ - int i = 0; - while ((i < sv->count) && cb(sv->data[i])) - i += 1; - return strv_chop_left(sv, i); -} - -static struct strv -strv_take_left_while(struct strv sv, _Bool (*cb)(char)) -{ - int i = 0; - while ((i < sv.count) && cb(sv.data[i])) - i += 1; - return strv_from_slice(sv.data, i); -} - -static int -strv_len(struct strv sv) -{ - return sv.count; -} - -static struct strv -strv_copy(const struct strv sv) -{ - return (struct strv){ .data = sv.data, .count = sv.count }; -} - -static int -strv_to_int(const struct strv sv_init) -{ - if (strv_len(sv_init) == 0) - return 0; - - int total = 0; - struct strv sv = strv_copy(sv_init); - const _Bool negative = strv_chop_left(&sv, 1).data[0] == '-'; - - for (int i = 0; i < sv.count; ++i) - total = (total * 10) + (sv.data[i] - '0'); - - return (negative) ? -1 * total : total; -} +struct strv strv_trim(struct strv sv); + +struct strv strv_chop_left(struct strv *sv, int n); + +struct strv strv_chop_right(struct strv *sv, int n); + +_Bool strv_index_of(struct strv sv, char c, int *index); + +_Bool strv_try_chop_by_delim(struct strv *sv, char delim, struct strv *chunk); + +struct strv strv_chop_by_delim(struct strv *sv, char delim); + +_Bool strv_starts_with(struct strv sv, struct strv expected_prefix); + +_Bool strv_ends_with(struct strv sv, struct strv expected_suffix); + +_Bool strv_equal(struct strv a, struct strv b); + +_Bool strv_equal_nocase(struct strv a, struct strv b); + +struct strv strv_chop_left_while(struct strv *sv, _Bool (*cb)(char)); + +struct strv strv_take_left_while(struct strv sv, _Bool (*cb)(char)); + +int strv_len(struct strv sv); + +struct strv strv_copy(const struct strv sv); + +int strv_to_int(const struct strv sv_init); diff --git a/inc/lektor/net.h b/inc/lektor/net.h index 82d31f00..3005f427 100644 --- a/inc/lektor/net.h +++ b/inc/lektor/net.h @@ -37,8 +37,8 @@ struct lkt_message; /* Create a message structure. */ struct lkt_message *lkt_message_new(void); -struct lkt_message *lkt_message_new_str(const char *restrict msg); -struct lkt_message *lkt_message_new_fmt(const char *restrict fmt, ...); +struct lkt_message *lkt_message_new_str(const char * msg); +struct lkt_message *lkt_message_new_fmt(const char * fmt, ...); struct lkt_message *lkt_message_clone(struct lkt_message *msg); /* Destruct a message structure. */ diff --git a/inc/lektor/queue.h b/inc/lektor/queue.h index 508cdb99..2d395149 100644 --- a/inc/lektor/queue.h +++ b/inc/lektor/queue.h @@ -72,110 +72,21 @@ struct queue { /* Initialize the queue. Can't fail if the passed argument is not NULL. * WARN: In case of out of memory this function will abort the process. */ -PRIVATE_FUNCTION int -lkt_queue_new(struct queue *ret) -{ - if (!ret) - return 1; - - pthread_mutex_t mxt = PTHREAD_MUTEX_INITIALIZER; - struct queue _ret = { - .contents = LKT_ALLOC_ARRAY(lkt_event, LKT_DEFAULT_LIST_SIZE), - .size = LKT_DEFAULT_LIST_SIZE, - .last = 0, - .available = 0, - .lock = mxt, - }; - - *ret = _ret; - return 0; -} +int lkt_queue_new(struct queue *ret); /* Free the queue. Can't fail. */ -PRIVATE_FUNCTION void -lkt_queue_free(struct queue *queue) -{ - pthread_mutex_lock(&queue->lock); - if (queue && queue->contents) - free((void *)queue->contents); - pthread_mutex_unlock(&queue->lock); -} +void lkt_queue_free(struct queue *queue); /* Is an event of the following type present in the queue? * Returns 0 if the type is not present, 1 otherwise. */ -PRIVATE_FUNCTION bool -lkt_queue_has_event(struct queue *queue, LKT_EVENT_TYPE type) -{ - bool ret = false; - pthread_mutex_lock(&queue->lock); - for (size_t i = 0; i < queue->last; ++i) { - if (queue->contents[i].type & type) { - ret = true; - break; - } - } - pthread_mutex_unlock(&queue->lock); - return ret; -} +bool lkt_queue_has_event(struct queue *queue, LKT_EVENT_TYPE type); /* Send an event into the queue */ -PRIVATE_FUNCTION void -lkt_queue_send(struct queue *queue, LKT_EVENT_TYPE _type, void *_attr) -{ - pthread_mutex_lock(&queue->lock); - GOTO_UNLESS(queue, "Invalid argument", end) - - volatile lkt_event *new; - if (queue->size == queue->last) { - new = realloc((void *)queue->contents, queue->size * 2 * sizeof(lkt_event)); - - if (NULL == new) - goto end; - - queue->contents = new; - queue->size *= 2; - } - - lkt_event evt = { - .type = _type, - .attr = _attr, - }; - queue->contents[(queue->last)++] = evt; - - if (!(_type & (unsigned int)queue->available)) - LOG_WARN("QUEUE", "The event %d is not available, push it anyway", _type); -end: - pthread_mutex_unlock(&queue->lock); -} +void lkt_queue_send(struct queue *queue, LKT_EVENT_TYPE _type, void *_attr); -PRIVATE_FUNCTION lkt_event -lkt_queue_handle(struct queue *queue) -{ - pthread_mutex_lock(&queue->lock); - lkt_event ret = { 0 }; - if (!queue || !queue->last) - goto end; - if (!(queue->contents[0].type & (unsigned int)queue->available) && queue->contents[0].type) { - LOG_WARN("QUEUE", "Event %d is not available", queue->contents[0].type); - goto end; - } - - ret = queue->contents[0]; - for (size_t i = 1; i < queue->last; ++i) - queue->contents[i - 1] = queue->contents[i]; - queue->last -= 1; -end: - pthread_mutex_unlock(&queue->lock); - return ret; -} +lkt_event lkt_queue_handle(struct queue *queue); -PRIVATE_FUNCTION void -lkt_queue_make_available(struct queue *queue, LKT_EVENT_TYPE type) -{ - pthread_mutex_lock(&queue->lock); - queue->available |= type; - pthread_mutex_unlock(&queue->lock); -} +void lkt_queue_make_available(struct queue *queue, LKT_EVENT_TYPE type); #if defined(__cplusplus) } diff --git a/src/base/os.c b/src/base/os.c index a18c9bad..9c91f2e4 100644 --- a/src/base/os.c +++ b/src/base/os.c @@ -22,7 +22,7 @@ lkt_thread_set_name(const char *name) { const size_t len = strlen(name); if (len >= 16) { - LOG_FATAL("The name should at least be a 15 character string! Here the length is %zu", len); + LOG_FATAL("The name should at most be a 15 character string! Here the length is %zu", len); } #if defined(__linux__) diff --git a/src/database/queue.c b/src/database/queue.c index 6d3fce9b..b8f5007d 100644 --- a/src/database/queue.c +++ b/src/database/queue.c @@ -1,3 +1,4 @@ +#include <lektor/queue.h> #include <lektor/common.h> #include <lektor/database.h> #include <lektor/mkv.h> @@ -1176,3 +1177,110 @@ error: SQLITE_DO_ROLLBACK(db); return false; } + +/* Initialize the queue. Can't fail if the passed argument is not NULL. + * WARN: In case of out of memory this function will abort the process. */ +int +lkt_queue_new(struct queue *ret) +{ + if (!ret) + return 1; + + pthread_mutex_t mxt = PTHREAD_MUTEX_INITIALIZER; + struct queue _ret = { + .contents = LKT_ALLOC_ARRAY(lkt_event, LKT_DEFAULT_LIST_SIZE), + .size = LKT_DEFAULT_LIST_SIZE, + .last = 0, + .available = 0, + .lock = mxt, + }; + + *ret = _ret; + return 0; +} + +/* Free the queue. Can't fail. */ +void +lkt_queue_free(struct queue *queue) +{ + pthread_mutex_lock(&queue->lock); + if (queue && queue->contents) + free((void *)queue->contents); + pthread_mutex_unlock(&queue->lock); +} + +/* Is an event of the following type present in the queue? + * Returns 0 if the type is not present, 1 otherwise. */ +bool +lkt_queue_has_event(struct queue *queue, LKT_EVENT_TYPE type) +{ + bool ret = false; + pthread_mutex_lock(&queue->lock); + for (size_t i = 0; i < queue->last; ++i) { + if (queue->contents[i].type & type) { + ret = true; + break; + } + } + pthread_mutex_unlock(&queue->lock); + return ret; +} + +/* Send an event into the queue */ +void +lkt_queue_send(struct queue *queue, LKT_EVENT_TYPE _type, void *_attr) +{ + pthread_mutex_lock(&queue->lock); + GOTO_UNLESS(queue, "Invalid argument", end) + + volatile lkt_event *new; + if (queue->size == queue->last) { + new = realloc((void *)queue->contents, queue->size * 2 * sizeof(lkt_event)); + + if (NULL == new) + goto end; + + queue->contents = new; + queue->size *= 2; + } + + lkt_event evt = { + .type = _type, + .attr = _attr, + }; + queue->contents[(queue->last)++] = evt; + + if (!(_type & (unsigned int)queue->available)) + LOG_WARN("QUEUE", "The event %d is not available, push it anyway", _type); +end: + pthread_mutex_unlock(&queue->lock); +} + +lkt_event +lkt_queue_handle(struct queue *queue) +{ + pthread_mutex_lock(&queue->lock); + lkt_event ret = { 0 }; + if (!queue || !queue->last) + goto end; + if (!(queue->contents[0].type & (unsigned int)queue->available) && queue->contents[0].type) { + LOG_WARN("QUEUE", "Event %d is not available", queue->contents[0].type); + goto end; + } + + ret = queue->contents[0]; + for (size_t i = 1; i < queue->last; ++i) + queue->contents[i - 1] = queue->contents[i]; + queue->last -= 1; +end: + pthread_mutex_unlock(&queue->lock); + return ret; +} + +void +lkt_queue_make_available(struct queue *queue, LKT_EVENT_TYPE type) +{ + pthread_mutex_lock(&queue->lock); + queue->available |= type; + pthread_mutex_unlock(&queue->lock); +} diff --git a/src/lib/strv.c b/src/lib/strv.c new file mode 100644 index 00000000..818350da --- /dev/null +++ b/src/lib/strv.c @@ -0,0 +1,262 @@ +#include <lektor/lib/strv.h> + +char +strv_ctoupper(char s) +{ + return (('a' <= s) && (s <= 'z')) ? 'A' + (s - 'a') : s; +} + +char +strv_ctolower(char s) +{ + return (('A' <= s) && (s <= 'Z')) ? 'a' + (s - 'A') : s; +} + +_Bool +strv_memcmp(const void *ptr2, const void *ptr1, int count) +{ + register const unsigned char *s1 = (const unsigned char *)ptr1; + register const unsigned char *s2 = (const unsigned char *)ptr2; + + while (count-- > 0) { + if (*s1++ != *s2++) + return (_Bool)0; + } + + return (_Bool)1; +} + +_Bool +strv_isspace(char x) +{ + return x == ' ' || x == '\t' || x == '\n' || x == '\r' || x == '\v' || x == '\f'; +} + +int +strv_strlen(const char *str) +{ + int len = 0; + while (str[len]) { + len += 1; + + /* Try to avoid overflows */ + if (len == __INT_MAX__) + return 0; + } + return len; +} + +struct strv +strv_from_slice(const char *data, int count) +{ + struct strv sv; + sv.count = count; + sv.data = data; + return sv; +} + +struct strv +strv_from_str(const char *cstr) +{ + return strv_from_slice(cstr, strv_strlen(cstr)); +} + +_Bool +strv_as_str(const struct strv sv, char *data, int len) +{ + if (sv.count >= len) + return (_Bool)0; + + for (int i = 0; i < sv.count; ++i) + data[i] = sv.data[i]; + data[sv.count] = '\0'; + + return (_Bool)1; +} + +struct strv +strv_trim_l(struct strv sv) +{ + int i = 0; + while ((i < sv.count) && strv_isspace(sv.data[i])) + i += 1; + return strv_from_slice(sv.data + i, sv.count - i); +} + +struct strv +strv_trim_r(struct strv sv) +{ + int i = 0; + while ((i < sv.count) && strv_isspace(sv.data[sv.count - 1 - i])) + i += 1; + return strv_from_slice(sv.data, sv.count - i); +} + +struct strv +strv_trim(struct strv sv) +{ + return strv_trim_r(strv_trim_l(sv)); +} + +struct strv +strv_chop_left(struct strv *sv, int n) +{ + if (n > sv->count) + n = sv->count; + + struct strv result = strv_from_slice(sv->data, n); + sv->data += n; + sv->count -= n; + return result; +} + +struct strv +strv_chop_right(struct strv *sv, int n) +{ + if (n > sv->count) + n = sv->count; + + struct strv result = strv_from_slice(sv->data + sv->count - n, n); + sv->count -= n; + return result; +} + +_Bool +strv_index_of(struct strv sv, char c, int *index) +{ + int i = 0; + while (i < sv.count && sv.data[i] != c) + i += 1; + + if (i < sv.count) { + if (index) + *index = i; + return (_Bool)1; + } + + else + return (_Bool)0; +} + +_Bool +strv_try_chop_by_delim(struct strv *sv, char delim, struct strv *chunk) +{ + int i = 0; + while (i < sv->count && sv->data[i] != delim) + i += 1; + + struct strv result = strv_from_slice(sv->data, i); + + if (i < sv->count) { + i += 1; + sv->count -= i; + sv->data += i; + if (chunk) + *chunk = result; + return (_Bool)1; + } + + return (_Bool)0; +} + +struct strv +strv_chop_by_delim(struct strv *sv, char delim) +{ + int i = 0; + while (i < sv->count && sv->data[i] != delim) + i += 1; + + const struct strv result = strv_from_slice(sv->data, i); + i += (i < sv->count); + sv->count -= i; + sv->data += i; + + return result; +} + +_Bool +strv_starts_with(struct strv sv, struct strv expected_prefix) +{ + if (expected_prefix.count <= sv.count) { + const struct strv actual_prefix = strv_from_slice(sv.data, expected_prefix.count); + return strv_equal(expected_prefix, actual_prefix); + } + + return (_Bool)0; +} + +_Bool +strv_ends_with(struct strv sv, struct strv expected_suffix) +{ + if (expected_suffix.count <= sv.count) { + const struct strv actual_suffix = + strv_from_slice(sv.data + sv.count - expected_suffix.count, expected_suffix.count); + return strv_equal(expected_suffix, actual_suffix); + } + + return (_Bool)0; +} + +_Bool +strv_equal(struct strv a, struct strv b) +{ + return (a.count != b.count) ? (_Bool)0 : strv_memcmp(a.data, b.data, a.count); +} + +_Bool +strv_equal_nocase(struct strv a, struct strv b) +{ + if (a.count != b.count) + return (_Bool)0; + for (int i = 0; i < a.count; ++i) { + if (strv_ctoupper(a.data[i]) != strv_ctoupper(b.data[i])) + return (_Bool)0; + } + return (_Bool)1; +} + +struct strv +strv_chop_left_while(struct strv *sv, _Bool (*cb)(char)) +{ + int i = 0; + while ((i < sv->count) && cb(sv->data[i])) + i += 1; + return strv_chop_left(sv, i); +} + +struct strv +strv_take_left_while(struct strv sv, _Bool (*cb)(char)) +{ + int i = 0; + while ((i < sv.count) && cb(sv.data[i])) + i += 1; + return strv_from_slice(sv.data, i); +} + +int +strv_len(struct strv sv) +{ + return sv.count; +} + +struct strv +strv_copy(const struct strv sv) +{ + return (struct strv){ .data = sv.data, .count = sv.count }; +} + +int +strv_to_int(const struct strv sv_init) +{ + if (strv_len(sv_init) == 0) + return 0; + + int total = 0; + struct strv sv = strv_copy(sv_init); + const _Bool negative = strv_chop_left(&sv, 1).data[0] == '-'; + + for (int i = 0; i < sv.count; ++i) + total = (total * 10) + (sv.data[i] - '0'); + + return (negative) ? -1 * total : total; +} diff --git a/src/main/server.c b/src/main/server.c index 71bf99dd..6891835c 100644 --- a/src/main/server.c +++ b/src/main/server.c @@ -17,6 +17,7 @@ #if defined(LKT_STATIC_MODULE) REG_DECLARE(sdl2_reg) +REG_DECLARE(qt_window_reg) REG_DECLARE(repo_reg) #endif @@ -39,6 +40,7 @@ main(int argc, char *argv[]) #if defined(LKT_STATIC_MODULE) REG_REGISTER("repo", repo_reg) REG_REGISTER("sdl2", sdl2_reg) + REG_REGISTER("qt_window", qt_window_reg) #endif REG_END() diff --git a/src/module/module_qt_window.c b/src/module/module_qt_window.c index 0284b0ed..b542f099 100644 --- a/src/module/module_qt_window.c +++ b/src/module/module_qt_window.c @@ -1,10 +1,13 @@ #define __LKT_MODULE_MAIN_SOURCE__ +#include "module_qt_window.h" #include <lektor/lktmodule.h> -#include "qt_window/mpvwidget_interface.h" -struct module_qt_window_s { - MpvWidget* mpv_widget; -}; +#include "mpv.h" +#include "thread.h" + +#include <sched.h> + +#include "qt_window/mpvwidget_interface.h" /************************ * Function definitions * @@ -88,13 +91,22 @@ module_qt_window_new(struct module_qt_window_s **win, struct queue *queue, lkt_d (void)mod_free; (void)mod_close; RETURN_UNLESS(win, "Invalid arguments", false); + struct poller_thread_arg *arg; if (*win == NULL) { - *win = (struct module_qt_window_s*)calloc(1, sizeof(struct module_qt_window_s)); + *win = calloc(1, sizeof(struct module_qt_window_s)); RETURN_UNLESS(*win, "Out of memory", false); memset(*win, 0, sizeof(struct module_qt_window_s)); - (*win)->mpv_widget = ___create_mpv_widget(queue, db); + (*win)->queue = queue; + (*win)->db = db; + (*win)->is_in_preparation = true; + + arg = LKT_ALLOC_STRUCT(poller_thread_arg); + RETURN_UNLESS(arg, "Out of memory", false); + arg->args = *win; + RETURN_IF(poller_new(&(*win)->self, ___create_mpv_widget, arg), "Failed to launch the SDL thread", + false); } return true; diff --git a/src/module/module_qt_window.h b/src/module/module_qt_window.h new file mode 100644 index 00000000..acdd44d9 --- /dev/null +++ b/src/module/module_qt_window.h @@ -0,0 +1,31 @@ +#ifndef __LKT_MODULE_QT_WINDOW_H__ +#define __LKT_MODULE_QT_WINDOW_H__ + +#if defined( __cplusplus) +extern "C" { +class MpvWidget; +#else +typedef struct MpvWidget MpvWidget; +#endif + +#include <lektor/common.h> +#include "thread.h" + +struct module_qt_window_s { + MpvWidget* mpv_widget; + + /* Thread related */ + struct poller_thread self; + volatile int launched; /* SDL you sucks */ + volatile bool is_in_preparation; /* Inside the MPV & SDL init */ + volatile bool has_preparation_failed; /* The init failed */ + + /* Things from the server */ + struct queue *queue; + lkt_db *db; +}; + +#if defined(__cplusplus) +} +#endif +#endif // __LKT_MODULE_QT_WINDOW_H__ diff --git a/src/module/qt_window/mpvwidget.hh b/src/module/qt_window/mpvwidget.hh index 54a1f997..92b2ab99 100644 --- a/src/module/qt_window/mpvwidget.hh +++ b/src/module/qt_window/mpvwidget.hh @@ -6,7 +6,9 @@ #include <mpv/render_gl.h> #include <QtGui> +extern "C" { #include <lektor/common.h> +} class MpvWidget Q_DECL_FINAL: public QOpenGLWidget { diff --git a/src/module/qt_window/mpvwidget_interface.cpp b/src/module/qt_window/mpvwidget_interface.cpp index 5c6cd9c8..a257c610 100644 --- a/src/module/qt_window/mpvwidget_interface.cpp +++ b/src/module/qt_window/mpvwidget_interface.cpp @@ -1,7 +1,19 @@ #include "mpvwidget_interface.h" #include "mpvwidget.hh" -MpvWidget* -___create_mpv_widget(struct queue *queue, lkt_db* db){ - return new MpvWidget(queue, db); +#include <QApplication> + +void* +___create_mpv_widget(struct poller_thread_arg *arg){ + lkt_thread_set_name("lektord/qt-win"); + + struct module_qt_window_s* qt_window = (struct module_qt_window_s*)arg->args; + + int argc = 0; + QApplication a(argc, NULL); + setlocale(LC_NUMERIC, "C"); + qt_window->mpv_widget = new MpvWidget(qt_window->queue, qt_window->db); + qt_window->mpv_widget->show(); + a.exec(); + return NULL; } diff --git a/src/module/qt_window/mpvwidget_interface.h b/src/module/qt_window/mpvwidget_interface.h index fa62dd73..2d85855e 100644 --- a/src/module/qt_window/mpvwidget_interface.h +++ b/src/module/qt_window/mpvwidget_interface.h @@ -3,16 +3,14 @@ #if defined( __cplusplus) extern "C" { -class MpvWidget; -#else -typedef struct MpvWidget MpvWidget; #endif #include <lektor/common.h> +#include "../module_qt_window.h" -MpvWidget* ___create_mpv_widget(struct queue *queue, lkt_db* db); +void * ___create_mpv_widget(struct poller_thread_arg *arg); -#ifdef __cplusplus +#if defined(__cplusplus) } #endif -#endif +#endif // __LKT_MODULE_QT_WINDOW_MPVWIDGET_INTERFACE_H__ diff --git a/src/module/thread.c b/src/module/thread.c new file mode 100644 index 00000000..ce4086b8 --- /dev/null +++ b/src/module/thread.c @@ -0,0 +1,81 @@ +#include "thread.h" + +void * +___poller_thread_start(void *args__) +{ + struct ___poller_thread_args *args = (struct ___poller_thread_args *)args__; + void *(*start)(struct poller_thread_arg *) = args->start; + struct poller_thread_arg *arg = args->arg; + free(args__); + return start(arg); +} + +UNUSED int +poller_new(struct poller_thread *th, void *(*func)(struct poller_thread_arg *), void *args) +{ + pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_t mtx2 = PTHREAD_MUTEX_INITIALIZER; + struct poller_thread th_ = { + .input_lock = mtx1, + .output_lock = mtx2, + }; + + stack_new(&th_.input); + stack_new(&th_.output); + + struct ___poller_thread_args *__args; + *th = th_; + __args = LKT_ALLOC_STRUCT(___poller_thread_args); + __args->start = func; + __args->arg = args; + __args->arg->self = th; + + if (pthread_create(&(th->th), NULL, ___poller_thread_start, __args)) { + LOG_ERROR("THREAD", "Failed to create a poller thread"); + return 1; + } + + LOG_INFO("THREAD", "Create a new poller thread"); + return 0; +} + +UNUSED int +poller_join(struct poller_thread *th, void **ret) +{ + int sta = pthread_join(th->th, ret); + LOG_ERROR_IF(sta, "THREAD", "Failed to join thread"); + + stack_free(&th->input); + stack_free(&th->output); + LOG_WARN("THREAD", "Thread joined"); + + memset(th, 0, sizeof(struct poller_thread)); + return sta; +} + +UNUSED int +th_append(struct stack *lst, pthread_mutex_t *lock, void *ptr) +{ + DO_WITH_LOCK(*lock, error, { stack_push(lst, ptr); }); + return 0; +error: + return 1; +} + +UNUSED int +th_pop(struct stack *lst, pthread_mutex_t *lock, void **ptr) +{ + RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1); + int ret = stack_pop(lst, ptr); + RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1); + return ret; +} + +UNUSED int +th_head(struct stack *lst, pthread_mutex_t *lock, void **ptr) +{ + RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1); + int ret = stack_head(lst, ptr); + RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1); + return ret; +} diff --git a/src/module/thread.h b/src/module/thread.h index 5d20cbec..537ac63a 100644 --- a/src/module/thread.h +++ b/src/module/thread.h @@ -1,6 +1,10 @@ #if !defined(__LKT_THREAD_H__) #define __LKT_THREAD_H__ +#if defined( __cplusplus) +extern "C" { +#endif + #include <lektor/lktmodule.h> #include <lektor/common.h> #include <sys/types.h> @@ -28,85 +32,17 @@ struct ___poller_thread_args { struct poller_thread_arg *arg; }; -static void * -___poller_thread_start(void *args__) -{ - struct ___poller_thread_args *args = (struct ___poller_thread_args *)args__; - void *(*start)(struct poller_thread_arg *) = args->start; - struct poller_thread_arg *arg = args->arg; - free(args__); - return start(arg); -} - -UNUSED static int -poller_new(struct poller_thread *th, void *(*func)(struct poller_thread_arg *), void *args) -{ - pthread_mutex_t mtx1 = PTHREAD_MUTEX_INITIALIZER; - pthread_mutex_t mtx2 = PTHREAD_MUTEX_INITIALIZER; - struct poller_thread th_ = { - .input_lock = mtx1, - .output_lock = mtx2, - }; - - stack_new(&th_.input); - stack_new(&th_.output); +void * ___poller_thread_start(void *args__); - struct ___poller_thread_args *__args; - *th = th_; - __args = LKT_ALLOC_STRUCT(___poller_thread_args); - __args->start = func; - __args->arg = args; - __args->arg->self = th; +UNUSED int poller_new(struct poller_thread *th, void *(*func)(struct poller_thread_arg *), void *args); - if (pthread_create(&(th->th), NULL, ___poller_thread_start, __args)) { - LOG_ERROR("THREAD", "Failed to create a poller thread"); - return 1; - } - - LOG_INFO("THREAD", "Create a new poller thread"); - return 0; -} +UNUSED int poller_join(struct poller_thread *th, void **ret); -UNUSED static int -poller_join(struct poller_thread *th, void **ret) -{ - int sta = pthread_join(th->th, ret); - LOG_ERROR_IF(sta, "THREAD", "Failed to join thread"); +UNUSED int th_append(struct stack *lst, pthread_mutex_t *lock, void *ptr); - stack_free(&th->input); - stack_free(&th->output); - LOG_WARN("THREAD", "Thread joined"); +UNUSED int th_pop(struct stack *lst, pthread_mutex_t *lock, void **ptr); - memset(th, 0, sizeof(struct poller_thread)); - return sta; -} - -UNUSED static int -th_append(struct stack *lst, pthread_mutex_t *lock, void *ptr) -{ - DO_WITH_LOCK(*lock, error, { stack_push(lst, ptr); }); - return 0; -error: - return 1; -} - -UNUSED static int -th_pop(struct stack *lst, pthread_mutex_t *lock, void **ptr) -{ - RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1); - int ret = stack_pop(lst, ptr); - RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1); - return ret; -} - -UNUSED static int -th_head(struct stack *lst, pthread_mutex_t *lock, void **ptr) -{ - RETURN_IF(pthread_mutex_lock(lock), "Failed to lock", 1); - int ret = stack_head(lst, ptr); - RETURN_IF(pthread_mutex_unlock(lock), "Failed to lock", 1); - return ret; -} +UNUSED int th_head(struct stack *lst, pthread_mutex_t *lock, void **ptr); #define __POLLER_ATOMICS_DEFINE(operation, inout, level) \ UNUSED static int poller_##operation##inout(struct poller_thread *th, void level ptr) \ @@ -123,4 +59,7 @@ __POLLER_ATOMICS_DEFINE(head, output, **) // clang-format on #undef __POLLER_ATOMICS_DEFINE +#if defined(__cplusplus) +} +#endif #endif /* __LKT_THREAD_H__ */ -- GitLab