diff --git a/libdc/include/dc/refable.h b/libdc/include/dc/refable.h index 3f5ff00..22caffd 100644 --- a/libdc/include/dc/refable.h +++ b/libdc/include/dc/refable.h @@ -6,9 +6,12 @@ typedef void (*dc_cleanup_t)(void *); typedef struct { int ref; dc_cleanup_t cleanup; + int debug; } dc_refable_t; void *dc_ref(void *); void dc_unref(void *); +void dc_ref_debug(void *); + #endif diff --git a/libdc/include/dc/session.h b/libdc/include/dc/session.h index 1978955..5fe76e5 100644 --- a/libdc/include/dc/session.h +++ b/libdc/include/dc/session.h @@ -69,12 +69,15 @@ dc_api_t dc_session_api(dc_session_t s); * access to the internal account cache */ void dc_session_add_account(dc_session_t s, dc_account_t u); +void dc_session_add_account_new(dc_session_t s, dc_account_t u); dc_account_t dc_session_account_fullname(dc_session_t s, char const *f); /** - * Adds a new channel to the internal cache. + * Adds a new channel to the internal cache. _new does the same, but doesn't + * increase the reference count. */ void dc_session_add_channel(dc_session_t s, dc_channel_t u); +void dc_session_add_channel_new(dc_session_t s, dc_channel_t u); dc_channel_t dc_session_channel_by_id(dc_session_t s, char const *snowflake); @@ -96,9 +99,11 @@ dc_channel_t dc_session_channel_recipients(dc_session_t s, dc_account_t *r, size_t sz); /** - * Add a guild to be managed by this session. + * Add a guild to be managed by this session. _new does the same, but doesn't + * ref the given reference. */ void dc_session_add_guild(dc_session_t s, dc_guild_t g); +void dc_session_add_guild_new(dc_session_t s, dc_guild_t g); GHashTable *dc_session_guilds(dc_session_t s); dc_guild_t dc_session_guild_by_name(dc_session_t s, char const *name); diff --git a/libdc/src/refable.c b/libdc/src/refable.c index 4b757f3..aacde10 100644 --- a/libdc/src/refable.c +++ b/libdc/src/refable.c @@ -11,6 +11,12 @@ void *dc_ref(void *arg) ptr = (dc_refable_t *)arg; ++ptr->ref; + if (ptr->debug) { + FILE *F = fopen("refdebug.txt", "a+"); + fprintf(F, "libdc: ref inc: %p: %d\n", ptr, ptr->ref); + fclose(F); + } + return arg; } @@ -21,7 +27,33 @@ void dc_unref(void *arg) return_if_true(arg == NULL,); ptr = (dc_refable_t *)arg; - if ((--ptr->ref) <= 0 && ptr->cleanup != NULL) { + --ptr->ref; + + if (ptr->debug) { + FILE *F = fopen("refdebug.txt", "a+"); + fprintf(F, "libdc: ref dec: %p: %d\n", + ptr, ptr->ref + ); + fclose(F); + } + + if (ptr->ref <= 0 && ptr->cleanup != NULL) { ptr->cleanup(arg); + + if (ptr->debug) { + FILE *F = fopen("refdebug.txt", "a+"); + fprintf(F, "libdc: ref dec: %p: %d: cleanup!\n", + ptr, ptr->ref + ); + fclose(F); + } } } + +void dc_ref_debug(void *arg) +{ + dc_refable_t *ptr = NULL; + return_if_true(arg == NULL,); + ptr = (dc_refable_t *)arg; + ptr->debug = true; +} diff --git a/libdc/src/session.c b/libdc/src/session.c index a467435..f602099 100644 --- a/libdc/src/session.c +++ b/libdc/src/session.c @@ -83,7 +83,7 @@ static void dc_session_handle_ready(dc_session_t s, dc_event_t e) json_t *user = NULL; json_t *relationships = NULL; json_t *presences = NULL; - size_t idx = 0, i = 0; + size_t idx = 0; json_t *c = NULL; json_t *channels = NULL; json_t *guilds = NULL; @@ -109,7 +109,7 @@ static void dc_session_handle_ready(dc_session_t s, dc_event_t e) } dc_account_add_friend(s->login, u); - dc_session_add_account(s, u); + dc_session_add_account_new(s, u); } } @@ -142,14 +142,7 @@ static void dc_session_handle_ready(dc_session_t s, dc_event_t e) json_array_foreach(guilds, idx, c) { dc_guild_t guild = dc_guild_from_json(c); continue_if_true(guild == NULL); - dc_session_add_guild(s, guild); - - /* add their channels to our own thing - */ - for (i = 0; i < dc_guild_channels(guild); i++) { - dc_channel_t chan = dc_guild_nth_channel(guild, i); - dc_session_add_channel(s, chan); - } + dc_session_add_guild_new(s, guild); } } @@ -159,14 +152,10 @@ static void dc_session_handle_ready(dc_session_t s, dc_event_t e) if (channels != NULL && json_is_array(channels)) { json_array_foreach(channels, idx, c) { dc_channel_t chan = dc_channel_from_json(c); - if (chan == NULL) { - continue; - } - + continue_if_true(chan == NULL); /* TODO: dedup recipients */ - - dc_session_add_channel(s, chan); + dc_session_add_channel_new(s, chan); } } @@ -249,6 +238,18 @@ bool dc_session_logout(dc_session_t s) s->gateway = NULL; } + if (s->accounts != NULL) { + g_hash_table_remove_all(s->accounts); + } + + if (s->guilds != NULL) { + g_hash_table_remove_all(s->guilds); + } + + if (s->channels != NULL) { + g_hash_table_remove_all(s->channels); + } + s->ready = false; return true; @@ -325,6 +326,12 @@ bool dc_session_equal_me_fullname(dc_session_t s, char const *a) } void dc_session_add_account(dc_session_t s, dc_account_t u) +{ + return_if_true(s == NULL || u == NULL,); + dc_session_add_account_new(s, dc_ref(u)); +} + +void dc_session_add_account_new(dc_session_t s, dc_account_t u) { return_if_true(s == NULL || u == NULL,); return_if_true(dc_account_id(u) == NULL,); @@ -332,7 +339,7 @@ void dc_session_add_account(dc_session_t s, dc_account_t u) char const *id = dc_account_id(u); if (!g_hash_table_contains(s->accounts, id)) { - g_hash_table_insert(s->accounts, strdup(id), dc_ref(u)); + g_hash_table_insert(s->accounts, strdup(id), u); } } @@ -362,6 +369,12 @@ dc_channel_t dc_session_channel_by_id(dc_session_t s, char const *snowflake) } void dc_session_add_channel(dc_session_t s, dc_channel_t u) +{ + return_if_true(s == NULL || u == NULL,); + dc_session_add_channel_new(s, dc_ref(u)); +} + +void dc_session_add_channel_new(dc_session_t s, dc_channel_t u) { return_if_true(s == NULL || u == NULL,); return_if_true(dc_channel_id(u) == NULL,); @@ -369,7 +382,7 @@ void dc_session_add_channel(dc_session_t s, dc_channel_t u) char const *id = dc_channel_id(u); if (!g_hash_table_contains(s->channels, id)) { - g_hash_table_insert(s->channels, strdup(id), dc_ref(u)); + g_hash_table_insert(s->channels, strdup(id), u); /* TODO: dedup for saving storage */ } @@ -392,12 +405,7 @@ dc_channel_t dc_session_make_channel(dc_session_t s, dc_account_t *r, } return_if_true(c == NULL, NULL); - dc_session_add_channel(s, c); - /* unref once to match the proper ref count after - * dc_session_add_channel() - * BUG: if dc_session_add_channel() fails this is bad - */ - dc_unref(c); + dc_session_add_channel_new(s, c); } if (dc_channel_messages(c) <= 0 && dc_channel_is_dm(c)) { @@ -453,17 +461,31 @@ GHashTable *dc_session_guilds(dc_session_t s) } void dc_session_add_guild(dc_session_t s, dc_guild_t g) +{ + return_if_true(s == NULL || g == NULL,); + dc_session_add_guild_new(s, dc_ref(g)); +} + +void dc_session_add_guild_new(dc_session_t s, dc_guild_t g) { return_if_true(s == NULL || g == NULL,); return_if_true(dc_guild_id(g) == NULL,); char const *id = dc_guild_id(g); + size_t i = 0; if (!g_hash_table_contains(s->guilds, id)) { - g_hash_table_insert(s->guilds, strdup(id), dc_ref(g)); + g_hash_table_insert(s->guilds, strdup(id), g); /* TODO: dedup for saving storage */ } + + /* add their channels to our own thing + */ + for (i = 0; i < dc_guild_channels(g); i++) { + dc_channel_t chan = dc_guild_nth_channel(g, i); + dc_session_add_channel(s, chan); + } } dc_guild_t dc_session_guild_by_name(dc_session_t s, char const *name) diff --git a/ncdc/src/login.c b/ncdc/src/login.c index e162d70..07a7ade 100644 --- a/ncdc/src/login.c +++ b/ncdc/src/login.c @@ -50,9 +50,8 @@ bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, dc_unref(current_session); current_session = dc_ref(s); - LOG(n, L"login: %ls: authentication successful, waiting for ready from websocket...", - av[1] - ); + LOG(n, L"login: %ls: authentication successful, waiting for ready " + L"from websocket...", av[1]); while (!dc_session_is_ready(current_session)) ; diff --git a/ncdc/src/mainwindow.c b/ncdc/src/mainwindow.c index 879c054..c152652 100644 --- a/ncdc/src/mainwindow.c +++ b/ncdc/src/mainwindow.c @@ -109,7 +109,7 @@ ncdc_mainwindow_t ncdc_mainwindow_new(void) ptr->focus = FOCUS_INPUT; ncdc_mainwindow_update_focus(ptr); - return ptr; + return dc_ref(ptr); } static bool diff --git a/ncdc/src/msg.c b/ncdc/src/msg.c index b8acda3..1a8aeb9 100644 --- a/ncdc/src/msg.c +++ b/ncdc/src/msg.c @@ -63,9 +63,7 @@ bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, cleanup: - dc_unref(c); dc_unref(m); - free(target); free(message);