diff --git a/src/stratifier.c b/src/stratifier.c index 6936df87..4b0266b9 100644 --- a/src/stratifier.c +++ b/src/stratifier.c @@ -7108,6 +7108,35 @@ static void upstream_workers(ckpool_t *ckp, user_instance_t *user) send_proc(ckp->connector, buf); } + +/* To iterate over all users, if user is initially NULL, this will return the first entry, + * otherwise it will return the entry after user, and NULL if there are no more entries. + * Allows us to grab and drop the lock on each iteration. */ +static user_instance_t *next_user(sdata_t *sdata, user_instance_t *user) +{ + ck_rlock(&sdata->instance_lock); + if (unlikely(!user)) + user = sdata->user_instances; + else + user = user->hh.next; + ck_runlock(&sdata->instance_lock); + + return user; +} + +/* Ditto for worker */ +static worker_instance_t *next_worker(sdata_t *sdata, user_instance_t *user, worker_instance_t *worker) +{ + ck_rlock(&sdata->instance_lock); + if (!worker) + worker = user->worker_instances; + else + worker = worker->next; + ck_runlock(&sdata->instance_lock); + + return worker; +} + static void *statsupdate(void *arg) { ckpool_t *ckp = (ckpool_t *)arg; @@ -7126,9 +7155,9 @@ static void *statsupdate(void *arg) char suffix1[16], suffix5[16], suffix15[16], suffix60[16], cdfield[64]; char suffix360[16], suffix1440[16], suffix10080[16]; log_entry_t *log_entries = NULL; - user_instance_t *user, *tmpuser; char_entry_t *char_list = NULL; stratum_instance_t *client; + user_instance_t *user; int idle_workers = 0; char *fname, *s, *sp; tv_t now, diff; @@ -7148,6 +7177,7 @@ static void *statsupdate(void *arg) ck_wunlock(&sdata->instance_lock); while (client) { + tv_time(&now); /* Look for clients that may have been dropped which the * stratifier has not been informed about and ask the * connector if they still exist */ @@ -7188,17 +7218,20 @@ static void *statsupdate(void *arg) ck_wunlock(&sdata->instance_lock); } - /* Drop and regain lock to minimise lock hold time */ - ck_rlock(&sdata->instance_lock); - HASH_ITER(hh, sdata->user_instances, user, tmpuser) { + user = NULL; + + while ((user = next_user(sdata, user)) != NULL) { worker_instance_t *worker; bool idle = false; if (!user->authorised) continue; + worker = NULL; + tv_time(&now); + /* Decay times per worker */ - DL_FOREACH(user->worker_instances, worker) { + while ((worker = next_worker(sdata, user, worker)) != NULL) { per_tdiff = tvdiff(&now, &worker->last_share); if (per_tdiff > 60) { decay_worker(worker, 0, &now); @@ -7287,7 +7320,6 @@ static void *statsupdate(void *arg) if (ckp->remote) upstream_workers(ckp, user); } - ck_runlock(&sdata->instance_lock); /* Dump log entries out of instance_lock */ dump_log_entries(&log_entries);