Fix Channel memory leak;

Channels need to be removed from the global array/map when destroyed.

Note that this exposes an infinite loop in map_remove, which will
be fixed later.

Note also that Channel's are retained if they have any messages in
them, to prevent releasing a channel while it has pending messages.
This commit is contained in:
bjorn 2019-11-11 18:33:33 -08:00
parent 8d12f0b867
commit 13136482b9
5 changed files with 21 additions and 3 deletions

View File

@ -80,6 +80,7 @@ static int l_lovrThreadGetChannel(lua_State* L) {
const char* name = luaL_checkstring(L, 1);
Channel* channel = lovrThreadGetChannel(name);
luax_pushtype(L, Channel, channel);
lovrRelease(Channel, channel);
return 1;
}

View File

@ -15,18 +15,22 @@ struct Channel {
size_t head;
uint64_t sent;
uint64_t received;
uint64_t hash;
};
Channel* lovrChannelCreate(void) {
Channel* lovrChannelCreate(uint64_t hash) {
Channel* channel = lovrAlloc(Channel);
arr_init(&channel->messages);
mtx_init(&channel->lock, mtx_plain | mtx_timed);
cnd_init(&channel->cond);
channel->hash = hash;
return channel;
}
extern void lovrThreadRemoveChannel(uint64_t hash);
void lovrChannelDestroy(void* ref) {
Channel* channel = ref;
lovrThreadRemoveChannel(channel->hash);
lovrChannelClear(channel);
arr_free(&channel->messages);
mtx_destroy(&channel->lock);

View File

@ -6,7 +6,7 @@
struct Variant;
typedef struct Channel Channel;
Channel* lovrChannelCreate(void);
Channel* lovrChannelCreate(uint64_t hash);
void lovrChannelDestroy(void* ref);
bool lovrChannelPush(Channel* channel, struct Variant* variant, double timeout, uint64_t* id);
bool lovrChannelPop(Channel* channel, struct Variant* variant, double timeout);

View File

@ -38,12 +38,23 @@ Channel* lovrThreadGetChannel(const char* name) {
if (index == MAP_NIL) {
index = state.channels.length;
map_set(&state.channelMap, hash, index);
arr_push(&state.channels, lovrChannelCreate());
arr_push(&state.channels, lovrChannelCreate(hash));
}
return state.channels.data[index];
}
void lovrThreadRemoveChannel(uint64_t hash) {
uint64_t index = map_get(&state.channelMap, hash);
if (index == MAP_NIL) {
return;
}
map_remove(&state.channelMap, hash);
arr_splice(&state.channels, index, 1);
}
Thread* lovrThreadInit(Thread* thread, int (*runner)(void*), Blob* body) {
lovrRetain(body);
thread->runner = runner;

View File

@ -1,6 +1,7 @@
#include "data/blob.h"
#include "lib/tinycthread/tinycthread.h"
#include <stdbool.h>
#include <stdint.h>
#pragma once
@ -18,6 +19,7 @@ typedef struct Thread {
bool lovrThreadModuleInit(void);
void lovrThreadModuleDestroy(void);
struct Channel* lovrThreadGetChannel(const char* name);
void lovrThreadRemoveChannel(uint64_t hash);
Thread* lovrThreadInit(Thread* thread, int (*runner)(void*), Blob* body);
#define lovrThreadCreate(...) lovrThreadInit(lovrAlloc(Thread), __VA_ARGS__)