From owner-svn-src-projects@FreeBSD.ORG Tue Feb 25 21:35:16 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 1A5B0EE9; Tue, 25 Feb 2014 21:35:16 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 055721CAE; Tue, 25 Feb 2014 21:35:16 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s1PLZF2m028710; Tue, 25 Feb 2014 21:35:15 GMT (envelope-from markm@svn.freebsd.org) Received: (from markm@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s1PLZFqe028709; Tue, 25 Feb 2014 21:35:15 GMT (envelope-from markm@svn.freebsd.org) Message-Id: <201402252135.s1PLZFqe028709@svn.freebsd.org> From: Mark Murray Date: Tue, 25 Feb 2014 21:35:15 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r262496 - projects/random_number_generator/sys/dev/random X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 25 Feb 2014 21:35:16 -0000 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); }