From 1b5e73e57be6bccf1b38dda1663095e471fb5e5d Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Mon, 19 Jan 2015 21:28:08 +1100 Subject: [PATCH] Fix issues with freeing ram safely on dropping clients and converting them from disconnected to dead clients by removing their instance every time and freeing dead client ram safely when it will no longer be used by the loop. --- src/stratifier.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/stratifier.c b/src/stratifier.c index c0771cd5..c92ad794 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -858,12 +858,6 @@ static void update_base(ckpool_t *ckp, int prio) create_pthread(pth, do_update, ur); } -static void __del_disconnected(sdata_t *sdata, stratum_instance_t *client) -{ - HASH_DEL(sdata->disconnected_instances, client); - sdata->stats.disconnected--; -} - static void __add_dead(sdata_t *sdata, stratum_instance_t *client) { LL_PREPEND(sdata->dead_instances, client); @@ -876,6 +870,13 @@ static void __del_dead(sdata_t *sdata, stratum_instance_t *client) sdata->stats.dead--; } +static void __del_disconnected(sdata_t *sdata, stratum_instance_t *client) +{ + HASH_DEL(sdata->disconnected_instances, client); + sdata->stats.disconnected--; + __add_dead(sdata, client); +} + static void drop_allclients(ckpool_t *ckp) { stratum_instance_t *client, *tmp; @@ -891,7 +892,6 @@ static void drop_allclients(ckpool_t *ckp) } HASH_ITER(hh, sdata->disconnected_instances, client, tmp) { __del_disconnected(sdata, client); - __add_dead(sdata, client); } sdata->stats.users = sdata->stats.workers = 0; ck_wunlock(&sdata->instance_lock); @@ -1143,7 +1143,7 @@ static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessio /* Number is in BE but we don't swap either of them */ hex2bin(&enonce1_64, sessionid, slen); - ck_rlock(&sdata->instance_lock); + ck_wlock(&sdata->instance_lock); HASH_ITER(hh, sdata->stratum_instances, instance, tmp) { if (instance->id == id) continue; @@ -1154,10 +1154,14 @@ static uint64_t disconnected_sessionid_exists(sdata_t *sdata, const char *sessio } instance = NULL; HASH_FIND(hh, sdata->disconnected_instances, &enonce1_64, sizeof(uint64_t), instance); - if (instance) + if (instance) { + /* Delete the entry once we are going to use it since there + * will be a new instance with the enonce1_64 */ + __del_disconnected(sdata, instance); ret = enonce1_64; + } out_unlock: - ck_runlock(&sdata->instance_lock); + ck_wunlock(&sdata->instance_lock); out: return ret; } @@ -1239,7 +1243,7 @@ static void dec_worker(ckpool_t *ckp, user_instance_t *instance) static void drop_client(sdata_t *sdata, int64_t id) { - stratum_instance_t *client, *tmp; + stratum_instance_t *client, *tmp, *client_delete = NULL; user_instance_t *instance = NULL; ckpool_t *ckp = NULL; bool dec = false; @@ -1259,28 +1263,33 @@ static void drop_client(sdata_t *sdata, int64_t id) } HASH_DEL(sdata->stratum_instances, client); + if (client->user_instance) + DL_DELETE(client->user_instance->instances, client); HASH_FIND(hh, sdata->disconnected_instances, &client->enonce1_64, sizeof(uint64_t), old_client); /* Only keep around one copy of the old client in server mode */ if (!client->ckp->proxy && !old_client && client->enonce1_64 && dec) { HASH_ADD(hh, sdata->disconnected_instances, enonce1_64, sizeof(uint64_t), client); sdata->stats.disconnected++; } else { - if (client->user_instance) - DL_DELETE(client->user_instance->instances, client); __add_dead(sdata, client); } } /* Cull old unused clients lazily when there are no more reference * counts for them. */ LL_FOREACH_SAFE(sdata->dead_instances, client, tmp) { + /* We can't delete the ram safely in this loop, even if we can + * safely remove the entry from the linked list so we do it on + * the next pass through the loop. */ + dealloc(client_delete); if (!client->ref) { LOGINFO("Stratifier discarding instance %ld", client->id); __del_dead(sdata, client); free(client->workername); free(client->useragent); - free(client); + client_delete = client; } } + dealloc(client_delete); ck_wunlock(&sdata->instance_lock); /* Decrease worker count outside of instance_lock to avoid recursive