Date: Tue, 25 Feb 2014 21:35:15 +0000 (UTC) From: Mark Murray <markm@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r262496 - projects/random_number_generator/sys/dev/random Message-ID: <201402252135.s1PLZFqe028709@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: markm Date: Tue Feb 25 21:35:15 2014 New Revision: 262496 URL: http://svnweb.freebsd.org/changeset/base/262496 Log: More ring-buffer tweeking. Still haven't had the nerve to actually run this properly. Modified: projects/random_number_generator/sys/dev/random/random_harvestq.c Modified: projects/random_number_generator/sys/dev/random/random_harvestq.c ============================================================================== --- projects/random_number_generator/sys/dev/random/random_harvestq.c Tue Feb 25 21:07:18 2014 (r262495) +++ projects/random_number_generator/sys/dev/random/random_harvestq.c Tue Feb 25 21:35:15 2014 (r262496) @@ -76,6 +76,14 @@ static struct mtx harvest_mtx; * the buffer is empty. * If (ring_in + 1) == ring_out (MOD RANDOM_FIFO_MAX), * the buffer is full. + * + * The ring_in variable needs locking as there are multiple + * sources to the ring. Only the sources may change ring_in, + * but the consumer may examine it. + * + * The ring_out variable does not need locking as there is + * only one consumer. Only the consumer may change ring_out, + * but the sources may examine it. */ static struct entropyfifo { struct harvest_event ring[RANDOM_FIFO_MAX]; @@ -111,40 +119,44 @@ random_kthread(void *arg __unused) { u_int maxloop; - /* Process until told to stop */ - mtx_lock_spin(&harvest_mtx); - for (; random_kthread_control >= 0;) { + /* + * Process until told to stop. + * + * Locking is not needed as this is the only place we modify ring_out, and + * we only examine ring_in without changing it. Both of these are volatile, + * and this is a unique thread. + */ + while (random_kthread_control >= 0) { /* Deal with events, if any. Restrict the number we do in one go. */ maxloop = RANDOM_FIFO_MAX; - while ((entropyfifo.ring_out != entropyfifo.ring_in) && maxloop--) { + while (entropyfifo.ring_out != entropyfifo.ring_in) { + /* Modifying ring_out here ONLY. */ entropyfifo.ring_out = (entropyfifo.ring_out + 1)%RANDOM_FIFO_MAX; - mtx_unlock_spin(&harvest_mtx); harvest_process_event(entropyfifo.ring + entropyfifo.ring_out); - mtx_lock_spin(&harvest_mtx); + /* The ring may be filled quickly so don't loop forever. */ + if (--maxloop) + break; } /* * Give the fast hardware sources a go */ - mtx_unlock_spin(&harvest_mtx); live_entropy_sources_feed(); - mtx_lock_spin(&harvest_mtx); /* * If a queue flush was commanded, it has now happened, * and we can mark this by resetting the command. + * A negative value, however, terminates the thread. */ if (random_kthread_control == 1) random_kthread_control = 0; /* Work done, so don't belabour the issue */ - msleep_spin_sbt(&random_kthread_control, &harvest_mtx, - "-", SBT_1S/10, 0, C_PREL(1)); + tsleep_sbt(&random_kthread_control, 0, "-", SBT_1S/10, 0, C_PREL(1)); } - mtx_unlock_spin(&harvest_mtx); randomdev_set_wakeup_exit(&random_kthread_control); /* NOTREACHED */ @@ -334,7 +346,6 @@ random_harvestq_internal(const void *ent enum random_entropy_source origin) { struct harvest_event *event; - size_t c; u_int ring_in; KASSERT(origin >= RANDOM_START && origin < ENTROPYSOURCE, @@ -344,24 +355,26 @@ random_harvestq_internal(const void *ent if (!(harvest_source_mask & (1U << origin))) return; - /* Lockless check to avoid lock operations if queue is full. */ + /* Lock ring_in against multi-thread contention */ + /* XXX: Fix? Go critical instead of locking? */ + mtx_lock_spin(&harvest_mtx); ring_in = (entropyfifo.ring_in + 1)%RANDOM_FIFO_MAX; - if (ring_in == entropyfifo.ring_out) + if (ring_in == entropyfifo.ring_out) { + /* The ring is full; unlock and leave. */ + mtx_unlock_spin(&harvest_mtx); return; - - mtx_lock_spin(&harvest_mtx); - + } entropyfifo.ring_in = ring_in; - event = entropyfifo.ring + entropyfifo.ring_in; + event = entropyfifo.ring + ring_in; + mtx_unlock_spin(&harvest_mtx); + /* Stash the harvested stuff in the *event buffer */ + count = MIN(count, HARVESTSIZE); event->he_somecounter = get_cyclecount(); event->he_size = count; event->he_bits = bits; event->he_source = origin; event->he_destination = harvest_destination[origin]++; - c = MIN(count, HARVESTSIZE); - memcpy(event->he_entropy, entropy, c); - memset(event->he_entropy + c, 0, HARVESTSIZE - c); - - mtx_unlock_spin(&harvest_mtx); + memcpy(event->he_entropy, entropy, count); + memset(event->he_entropy + count, 0, HARVESTSIZE - count); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402252135.s1PLZFqe028709>