diff --git a/app/backend.cpp b/app/backend.cpp index cd5d82f..5d893a4 100644 --- a/app/backend.cpp +++ b/app/backend.cpp @@ -30,6 +30,8 @@ void Backend::vanillaEventHandler() emit vibrate(*event.data); break; } + + vanilla_free_event(&event); } } diff --git a/lib/gamepad/gamepad.c b/lib/gamepad/gamepad.c index cf8f5b9..2afea5e 100644 --- a/lib/gamepad/gamepad.c +++ b/lib/gamepad/gamepad.c @@ -3,6 +3,7 @@ #include "gamepad.h" #include +#include #include #include #include @@ -31,18 +32,21 @@ uint16_t PORT_AUD; uint16_t PORT_HID; uint16_t PORT_CMD; +#define EVENT_BUFFER_SIZE 65536 +#define EVENT_BUFFER_ARENA_SIZE VANILLA_MAX_EVENT_COUNT * 2 +uint8_t *EVENT_BUFFER_ARENA[EVENT_BUFFER_ARENA_SIZE] = {0}; + void send_to_console(int fd, const void *data, size_t data_size, int port) { struct sockaddr_in address; address.sin_family = AF_INET; address.sin_addr.s_addr = SERVER_ADDRESS; address.sin_port = htons((uint16_t) (port - 100)); - - char ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &address.sin_addr, ip, INET_ADDRSTRLEN); ssize_t sent = sendto(fd, data, data_size, 0, (const struct sockaddr *) &address, sizeof(address)); if (sent == -1) { + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &address.sin_addr, ip, INET_ADDRSTRLEN); print_info("Failed to send to Wii U socket: address: %s, fd: %d, port: %d, errno: %i", ip, fd, port - 100, errno); } } @@ -286,12 +290,19 @@ int is_stop_code(const char *data, size_t data_length) int push_event(event_loop_t *loop, int type, const void *data, size_t size) { - pthread_mutex_lock(&loop->mutex); vanilla_event_t *ev = &loop->events[loop->new_index % VANILLA_MAX_EVENT_COUNT]; - if (size <= sizeof(ev->data)) { + if (size <= EVENT_BUFFER_SIZE) { + assert(!ev->data); + + ev->data = get_event_buffer(); + if (!ev->data) { + print_info("OUT OF MEMORY FOR NEW EVENTS"); + return VANILLA_ERROR; + } + ev->type = type; memcpy(ev->data, data, size); ev->size = size; @@ -300,13 +311,14 @@ int push_event(event_loop_t *loop, int type, const void *data, size_t size) // Prevent rollover by skipping oldest event if necessary if (loop->new_index > loop->used_index + VANILLA_MAX_EVENT_COUNT) { + vanilla_free_event(&loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT]); print_info("SKIPPED EVENT TO PREVENT ROLLOVER (%lu > %lu + %lu)", loop->new_index, loop->used_index, VANILLA_MAX_EVENT_COUNT); loop->used_index++; } pthread_cond_broadcast(&loop->waitcond); } else { - print_info("FAILED TO PUSH EVENT: wanted %lu, only had %lu. This is a bug, please report to developers.\n", size, sizeof(ev->data)); + print_info("FAILED TO PUSH EVENT: wanted %lu, only had %lu. This is a bug, please report to developers.\n", size, EVENT_BUFFER_SIZE); } pthread_mutex_unlock(&loop->mutex); @@ -330,9 +342,11 @@ int get_event(event_loop_t *loop, vanilla_event_t *event, int wait) vanilla_event_t *pull_event = &loop->events[loop->used_index % VANILLA_MAX_EVENT_COUNT]; event->type = pull_event->type; - memcpy(event->data, pull_event->data, pull_event->size); + event->data = pull_event->data; event->size = pull_event->size; + pull_event->data = NULL; + loop->used_index++; ret = 1; } @@ -341,4 +355,52 @@ int get_event(event_loop_t *loop, vanilla_event_t *event, int wait) pthread_mutex_unlock(&loop->mutex); return ret; +} + +void *get_event_buffer() +{ + void *buf = NULL; + + for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) { + if (EVENT_BUFFER_ARENA[i]) { + buf = EVENT_BUFFER_ARENA[i]; + EVENT_BUFFER_ARENA[i] = NULL; + break; + } + } + + return buf; +} + +void release_event_buffer(void *buffer) +{ + for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) { + if (!EVENT_BUFFER_ARENA[i]) { + EVENT_BUFFER_ARENA[i] = buffer; + break; + } + } +} + +void init_event_buffer_arena() +{ + for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) { + if (!EVENT_BUFFER_ARENA[i]) { + EVENT_BUFFER_ARENA[i] = malloc(EVENT_BUFFER_SIZE); + } else { + print_info("CRITICAL: Buffer wasn't returned to the arena"); + } + } +} + +void free_event_buffer_arena() +{ + for (size_t i = 0; i < EVENT_BUFFER_ARENA_SIZE; i++) { + if (EVENT_BUFFER_ARENA[i]) { + free(EVENT_BUFFER_ARENA[i]); + EVENT_BUFFER_ARENA[i] = NULL; + } else { + print_info("CRITICAL: Buffer wasn't returned to the arena"); + } + } } \ No newline at end of file diff --git a/lib/gamepad/gamepad.h b/lib/gamepad/gamepad.h index 6a376f4..8cc914e 100644 --- a/lib/gamepad/gamepad.h +++ b/lib/gamepad/gamepad.h @@ -42,4 +42,9 @@ int is_stop_code(const char *data, size_t data_length); int push_event(event_loop_t *loop, int type, const void *data, size_t size); int get_event(event_loop_t *loop, vanilla_event_t *event, int wait); +void init_event_buffer_arena(); +void free_event_buffer_arena(); +void *get_event_buffer(); +void release_event_buffer(void *buffer); + #endif // VANILLA_GAMEPAD_H \ No newline at end of file diff --git a/lib/vanilla.c b/lib/vanilla.c index 543ae26..3bd59a5 100644 --- a/lib/vanilla.c +++ b/lib/vanilla.c @@ -30,9 +30,13 @@ void *start_gamepad(void *arg) struct gamepad_data_t *data = (struct gamepad_data_t *) arg; pthread_mutex_lock(&event_loop.mutex); + init_event_buffer_arena(); event_loop.active = 1; event_loop.new_index = 0; event_loop.used_index = 0; + for (int i = 0; i < VANILLA_MAX_EVENT_COUNT; i++) { + event_loop.events[i].data = NULL; + } pthread_cond_broadcast(&event_loop.waitcond); pthread_mutex_unlock(&event_loop.mutex); @@ -42,6 +46,7 @@ void *start_gamepad(void *arg) pthread_mutex_lock(&event_loop.mutex); event_loop.active = 0; + free_event_buffer_arena(); pthread_cond_broadcast(&event_loop.waitcond); pthread_mutex_unlock(&event_loop.mutex); @@ -170,4 +175,12 @@ int vanilla_poll_event(vanilla_event_t *event) int vanilla_wait_event(vanilla_event_t *event) { return get_event(&event_loop, event, 1); +} + +int vanilla_free_event(vanilla_event_t *event) +{ + if (event->data) { + release_event_buffer(event->data); + event->data = NULL; + } } \ No newline at end of file diff --git a/lib/vanilla.h b/lib/vanilla.h index 4f77e93..e5d1280 100644 --- a/lib/vanilla.h +++ b/lib/vanilla.h @@ -98,7 +98,7 @@ static const uint8_t VANILLA_PPS_PARAMS[] = { typedef struct { int type; - uint8_t data[65536]; + uint8_t *data; size_t size; } vanilla_event_t; @@ -110,6 +110,7 @@ int vanilla_sync(uint16_t code, uint32_t server_address); int vanilla_poll_event(vanilla_event_t *event); int vanilla_wait_event(vanilla_event_t *event); +int vanilla_free_event(vanilla_event_t *event); /** * Attempt to stop the current action diff --git a/rpi/main.c b/rpi/main.c index 12349c1..0057d2e 100644 --- a/rpi/main.c +++ b/rpi/main.c @@ -105,23 +105,25 @@ static SDL_mutex *decode_loop_mutex; static SDL_cond *decode_loop_cond; static int decode_loop_running = 0; static int decode_pkt_ready = 0; -static vanilla_event_t decode_event; +static uint8_t decode_data[65536]; +static size_t decode_size = 0; int decode_loop(void *) { - vanilla_event_t our_pkt; + uint8_t our_data[65536]; + size_t our_data_size = 0; SDL_LockMutex(decode_loop_mutex); while (decode_loop_running) { while (!decode_pkt_ready) { SDL_CondWait(decode_loop_cond, decode_loop_mutex); } - - our_pkt = decode_event; - decode_pkt_ready = 0; + + memcpy(our_data, decode_data, decode_size); + our_data_size = decode_size; SDL_UnlockMutex(decode_loop_mutex); - decode(our_pkt.data, our_pkt.size); + decode(our_data, decode_size); SDL_LockMutex(decode_loop_mutex); } @@ -153,7 +155,8 @@ int run_backend(void *data) while (vanilla_wait_event(&event)) { if (event.type == VANILLA_EVENT_VIDEO) { SDL_LockMutex(decode_loop_mutex); - decode_event = event; + memcpy(decode_data, event.data, event.size); + decode_size = event.size; decode_pkt_ready = 1; SDL_CondBroadcast(decode_loop_cond); SDL_UnlockMutex(decode_loop_mutex); @@ -167,6 +170,8 @@ int run_backend(void *data) } else if (event.type == VANILLA_EVENT_VIBRATE) { vibrate = event.data[0]; } + + vanilla_free_event(&event); } SDL_LockMutex(decode_loop_mutex);