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', [
'tests/test_cbuf.c',
]],
['test_control_event_queue', [
'tests/test_control_event_queue.c',
'src/control_event.c'
]],
['test_control_event_serialize', [
'tests/test_control_event_serialize.c',
'src/control_event.c'

View file

@ -58,52 +58,3 @@ control_event_destroy(struct control_event *event) {
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 "common.h"
#define CONTROL_EVENT_QUEUE_SIZE 64
#define CONTROL_EVENT_TEXT_MAX_LENGTH 300
#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
// return the number of bytes written
size_t
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
control_event_destroy(struct control_event *event);

View file

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

View file

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