Use cbuf for control event queue

Replace the control_event_queue implementation by cbuf.
This commit is contained in:
Romain Vimont 2019-05-29 21:24:30 +02:00
parent b38292cd69
commit 241a3dcba5
6 changed files with 14 additions and 190 deletions

View file

@ -157,10 +157,6 @@ tests = [
['test_cbuf', [ ['test_cbuf', [
'tests/test_cbuf.c', 'tests/test_cbuf.c',
]], ]],
['test_control_event_queue', [
'tests/test_control_event_queue.c',
'src/control_event.c'
]],
['test_control_event_serialize', [ ['test_control_event_serialize', [
'tests/test_control_event_serialize.c', 'tests/test_control_event_serialize.c',
'src/control_event.c' 'src/control_event.c'

View file

@ -58,52 +58,3 @@ control_event_destroy(struct control_event *event) {
SDL_free(event->text_event.text); SDL_free(event->text_event.text);
} }
} }
bool
control_event_queue_is_empty(const struct control_event_queue *queue) {
return queue->head == queue->tail;
}
bool
control_event_queue_is_full(const struct control_event_queue *queue) {
return (queue->head + 1) % CONTROL_EVENT_QUEUE_SIZE == queue->tail;
}
bool
control_event_queue_init(struct control_event_queue *queue) {
queue->head = 0;
queue->tail = 0;
// the current implementation may not fail
return true;
}
void
control_event_queue_destroy(struct control_event_queue *queue) {
int i = queue->tail;
while (i != queue->head) {
control_event_destroy(&queue->data[i]);
i = (i + 1) % CONTROL_EVENT_QUEUE_SIZE;
}
}
bool
control_event_queue_push(struct control_event_queue *queue,
const struct control_event *event) {
if (control_event_queue_is_full(queue)) {
return false;
}
queue->data[queue->head] = *event;
queue->head = (queue->head + 1) % CONTROL_EVENT_QUEUE_SIZE;
return true;
}
bool
control_event_queue_take(struct control_event_queue *queue,
struct control_event *event) {
if (control_event_queue_is_empty(queue)) {
return false;
}
*event = queue->data[queue->tail];
queue->tail = (queue->tail + 1) % CONTROL_EVENT_QUEUE_SIZE;
return true;
}

View file

@ -9,7 +9,6 @@
#include "android/keycodes.h" #include "android/keycodes.h"
#include "common.h" #include "common.h"
#define CONTROL_EVENT_QUEUE_SIZE 64
#define CONTROL_EVENT_TEXT_MAX_LENGTH 300 #define CONTROL_EVENT_TEXT_MAX_LENGTH 300
#define CONTROL_EVENT_SERIALIZED_MAX_SIZE (3 + CONTROL_EVENT_TEXT_MAX_LENGTH) #define CONTROL_EVENT_SERIALIZED_MAX_SIZE (3 + CONTROL_EVENT_TEXT_MAX_LENGTH)
@ -54,38 +53,11 @@ struct control_event {
}; };
}; };
struct control_event_queue {
struct control_event data[CONTROL_EVENT_QUEUE_SIZE];
int head;
int tail;
};
// buf size must be at least CONTROL_EVENT_SERIALIZED_MAX_SIZE // buf size must be at least CONTROL_EVENT_SERIALIZED_MAX_SIZE
// return the number of bytes written // return the number of bytes written
size_t size_t
control_event_serialize(const struct control_event *event, unsigned char *buf); control_event_serialize(const struct control_event *event, unsigned char *buf);
bool
control_event_queue_init(struct control_event_queue *queue);
void
control_event_queue_destroy(struct control_event_queue *queue);
bool
control_event_queue_is_empty(const struct control_event_queue *queue);
bool
control_event_queue_is_full(const struct control_event_queue *queue);
// the event is "moved": the queue takes ownership of its fields
bool
control_event_queue_push(struct control_event_queue *queue,
const struct control_event *event);
bool
control_event_queue_take(struct control_event_queue *queue,
struct control_event *event);
void void
control_event_destroy(struct control_event *event); control_event_destroy(struct control_event *event);

View file

@ -8,9 +8,7 @@
bool bool
controller_init(struct controller *controller, socket_t video_socket) { controller_init(struct controller *controller, socket_t video_socket) {
if (!control_event_queue_init(&controller->queue)) { cbuf_init(&controller->queue);
return false;
}
if (!(controller->mutex = SDL_CreateMutex())) { if (!(controller->mutex = SDL_CreateMutex())) {
return false; return false;
@ -31,16 +29,19 @@ void
controller_destroy(struct controller *controller) { controller_destroy(struct controller *controller) {
SDL_DestroyCond(controller->event_cond); SDL_DestroyCond(controller->event_cond);
SDL_DestroyMutex(controller->mutex); SDL_DestroyMutex(controller->mutex);
control_event_queue_destroy(&controller->queue);
struct control_event event;
while (cbuf_take(&controller->queue, &event)) {
control_event_destroy(&event);
}
} }
bool bool
controller_push_event(struct controller *controller, controller_push_event(struct controller *controller,
const struct control_event *event) { const struct control_event *event) {
bool res;
mutex_lock(controller->mutex); mutex_lock(controller->mutex);
bool was_empty = control_event_queue_is_empty(&controller->queue); bool was_empty = cbuf_is_empty(&controller->queue);
res = control_event_queue_push(&controller->queue, event); bool res = cbuf_push(&controller->queue, *event);
if (was_empty) { if (was_empty) {
cond_signal(controller->event_cond); cond_signal(controller->event_cond);
} }
@ -66,8 +67,7 @@ run_controller(void *data) {
for (;;) { for (;;) {
mutex_lock(controller->mutex); mutex_lock(controller->mutex);
while (!controller->stopped while (!controller->stopped && cbuf_is_empty(&controller->queue)) {
&& control_event_queue_is_empty(&controller->queue)) {
cond_wait(controller->event_cond, controller->mutex); cond_wait(controller->event_cond, controller->mutex);
} }
if (controller->stopped) { if (controller->stopped) {
@ -76,8 +76,7 @@ run_controller(void *data) {
break; break;
} }
struct control_event event; struct control_event event;
bool non_empty = control_event_queue_take(&controller->queue, bool non_empty = cbuf_take(&controller->queue, &event);
&event);
SDL_assert(non_empty); SDL_assert(non_empty);
mutex_unlock(controller->mutex); mutex_unlock(controller->mutex);

View file

@ -1,14 +1,16 @@
#ifndef CONTROL_H #ifndef CONTROL_H
#define CONTROL_H #define CONTROL_H
#include "control_event.h"
#include <stdbool.h> #include <stdbool.h>
#include <SDL2/SDL_mutex.h> #include <SDL2/SDL_mutex.h>
#include <SDL2/SDL_thread.h> #include <SDL2/SDL_thread.h>
#include "cbuf.h"
#include "control_event.h"
#include "net.h" #include "net.h"
struct control_event_queue CBUF(struct control_event, 64);
struct controller { struct controller {
socket_t video_socket; socket_t video_socket;
SDL_Thread *thread; SDL_Thread *thread;
@ -33,7 +35,6 @@ controller_stop(struct controller *controller);
void void
controller_join(struct controller *controller); controller_join(struct controller *controller);
// expose simple API to hide control_event_queue
bool bool
controller_push_event(struct controller *controller, controller_push_event(struct controller *controller,
const struct control_event *event); const struct control_event *event);

View file

@ -1,95 +0,0 @@
#include <assert.h>
#include <string.h>
#include "control_event.h"
static void test_control_event_queue_empty(void) {
struct control_event_queue queue;
bool init_ok = control_event_queue_init(&queue);
assert(init_ok);
assert(control_event_queue_is_empty(&queue));
struct control_event dummy_event;
bool push_ok = control_event_queue_push(&queue, &dummy_event);
assert(push_ok);
assert(!control_event_queue_is_empty(&queue));
bool take_ok = control_event_queue_take(&queue, &dummy_event);
assert(take_ok);
assert(control_event_queue_is_empty(&queue));
bool take_empty_ok = control_event_queue_take(&queue, &dummy_event);
assert(!take_empty_ok); // the queue is empty
control_event_queue_destroy(&queue);
}
static void test_control_event_queue_full(void) {
struct control_event_queue queue;
bool init_ok = control_event_queue_init(&queue);
assert(init_ok);
assert(!control_event_queue_is_full(&queue));
struct control_event dummy_event;
// fill the queue
while (control_event_queue_push(&queue, &dummy_event));
bool take_ok = control_event_queue_take(&queue, &dummy_event);
assert(take_ok);
assert(!control_event_queue_is_full(&queue));
control_event_queue_destroy(&queue);
}
static void test_control_event_queue_push_take(void) {
struct control_event_queue queue;
bool init_ok = control_event_queue_init(&queue);
assert(init_ok);
struct control_event event = {
.type = CONTROL_EVENT_TYPE_KEYCODE,
.keycode_event = {
.action = AKEY_EVENT_ACTION_DOWN,
.keycode = AKEYCODE_ENTER,
.metastate = AMETA_CTRL_LEFT_ON | AMETA_CTRL_ON,
},
};
bool push1_ok = control_event_queue_push(&queue, &event);
assert(push1_ok);
event = (struct control_event) {
.type = CONTROL_EVENT_TYPE_TEXT,
.text_event = {
.text = "abc",
},
};
bool push2_ok = control_event_queue_push(&queue, &event);
assert(push2_ok);
// overwrite event
bool take1_ok = control_event_queue_take(&queue, &event);
assert(take1_ok);
assert(event.type == CONTROL_EVENT_TYPE_KEYCODE);
assert(event.keycode_event.action == AKEY_EVENT_ACTION_DOWN);
assert(event.keycode_event.keycode == AKEYCODE_ENTER);
assert(event.keycode_event.metastate == (AMETA_CTRL_LEFT_ON | AMETA_CTRL_ON));
// overwrite event
bool take2_ok = control_event_queue_take(&queue, &event);
assert(take2_ok);
assert(event.type == CONTROL_EVENT_TYPE_TEXT);
assert(!strcmp(event.text_event.text, "abc"));
control_event_queue_destroy(&queue);
}
int main(void) {
test_control_event_queue_empty();
test_control_event_queue_full();
test_control_event_queue_push_take();
return 0;
}