[libmath-prime-util-perl] 08/16: Thread safety
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:44:34 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.08
in repository libmath-prime-util-perl.
commit fc1e8c6b29e38f36d629b3174d8c17cb654d3106
Author: Dana Jacobsen <dana at acm.org>
Date: Tue Jun 19 18:32:17 2012 -0600
Thread safety
---
Changes | 2 +-
XS.xs | 8 +++++---
cache.c | 21 ++++++++++++++-------
cache.h | 26 +++++++++++++++++++++-----
lib/Math/Prime/Util.pm | 6 ++----
sieve.c | 1 +
util.c | 45 +++++++++++++++++++++++++++++++--------------
7 files changed, 75 insertions(+), 34 deletions(-)
diff --git a/Changes b/Changes
index cf964d2..4687a08 100644
--- a/Changes
+++ b/Changes
@@ -1,7 +1,7 @@
Revision history for Perl extension Math::Prime::Util.
0.08 20 June 2012
- - Added thread scaffolding.
+ - Added thread safety, though with poor concurrency.
- Accuracy improvement and measurements for math functions.
- Remove simple sieve -- it wasn't being used, and was just around for
performance comparisons.
diff --git a/XS.xs b/XS.xs
index f7a76c9..929a76d 100644
--- a/XS.xs
+++ b/XS.xs
@@ -73,7 +73,7 @@ prev_prime(IN UV n)
UV
_get_prime_cache_size()
CODE:
- RETVAL = get_prime_cache_size();
+ RETVAL = get_prime_cache(0, 0);
OUTPUT:
RETVAL
@@ -93,6 +93,7 @@ sieve_primes(IN UV low, IN UV high)
CODE:
if (low <= high) {
if (get_prime_cache(high, &sieve) < high) {
+ release_prime_cache(sieve);
croak("Could not generate sieve for %"UVuf, high);
} else {
if ((low <= 2) && (high >= 2)) { av_push(av, newSVuv( 2 )); }
@@ -102,6 +103,7 @@ sieve_primes(IN UV low, IN UV high)
START_DO_FOR_EACH_SIEVE_PRIME( sieve, low, high ) {
av_push(av,newSVuv(p));
} END_DO_FOR_EACH_SIEVE_PRIME
+ release_prime_cache(sieve);
}
}
RETVAL = newRV_noinc( (SV*) av );
@@ -166,7 +168,7 @@ segment_primes(IN UV low, IN UV high);
/* Sieve from startd*30+1 to endd*30+29. */
if (sieve_segment(sieve, low_d, seghigh_d) == 0) {
- free_prime_segment(sieve);
+ release_prime_segment(sieve);
croak("Could not segment sieve from %"UVuf" to %"UVuf, segbase+1, seghigh);
}
@@ -177,7 +179,7 @@ segment_primes(IN UV low, IN UV high);
low_d += range_d;
low = seghigh+2;
}
- free_prime_segment(sieve);
+ release_prime_segment(sieve);
}
RETVAL = newRV_noinc( (SV*) av );
OUTPUT:
diff --git a/cache.c b/cache.c
index e0730f4..cebfde4 100644
--- a/cache.c
+++ b/cache.c
@@ -17,8 +17,8 @@
*
* Since we're trying to be thread-safe (and ideally allow a good deal
* of concurrency), it is imperative these be used correctly. You need
- * to call the get method, do your stuff, then call free. Do *not* return
- * out of your function or croak without calling free.
+ * to call the get method, do your stuff, then call release. Do *not* return
+ * out of your function or croak without calling release.
*/
static int mutex_init = 0;
@@ -30,9 +30,6 @@ static perl_mutex primary_mutex;
static unsigned char* prime_cache_sieve = 0;
static UV prime_cache_size = 0;
-/* Get the maximum sieved value of the cached prime sieve. */
-UV get_prime_cache_size(void) { return prime_cache_size; }
-
/*
* Get the size and a pointer to the cached prime sieve.
* Returns the maximum sieved value in the sieve.
@@ -42,6 +39,8 @@ UV get_prime_cache_size(void) { return prime_cache_size; }
*/
UV get_prime_cache(UV n, const unsigned char** sieve)
{
+ MUTEX_LOCK(&primary_mutex);
+
if (prime_cache_size < n) {
if (prime_cache_sieve != 0)
@@ -62,10 +61,18 @@ UV get_prime_cache(UV n, const unsigned char** sieve)
prime_cache_size = n;
}
- if (sieve != 0)
+ if (sieve == 0) {
+ MUTEX_UNLOCK(&primary_mutex);
+ } else {
*sieve = prime_cache_sieve;
+ }
+
return prime_cache_size;
}
+void release_prime_cache(const unsigned char* mem) {
+ /* Thanks for letting us know you're done. */
+ MUTEX_UNLOCK(&primary_mutex);
+}
@@ -85,7 +92,7 @@ unsigned char* get_prime_segment(UV *size) {
*size = SEGMENT_CHUNK_SIZE;
return prime_segment;
}
-void free_prime_segment(unsigned char* mem) {
+void release_prime_segment(unsigned char* mem) {
/* Thanks for letting us know you're done. */
MUTEX_UNLOCK(&segment_mutex);
}
diff --git a/cache.h b/cache.h
index b7a6da3..97592ca 100644
--- a/cache.h
+++ b/cache.h
@@ -4,14 +4,30 @@
#include "EXTERN.h"
#include "perl.h"
-extern UV get_prime_cache_size(void);
-extern UV get_prime_cache(UV n, const unsigned char** sieve);
-extern void free_prime_cache(unsigned char* sieve);
-
+ /* Sieve from 0 to x and store in primary cache */
extern void prime_precalc(UV x);
+ /* Release all extra memory -- go back to initial amounts */
extern void prime_memfree(void);
+ /* Get the primary cache. Returns the size. Tries to make it
+ * at least size n. Sets sieve* to the cache, unless given 0.
+ *
+ * Ex: just give me the current size:
+ * UV cache_size = get_prime_cache(0, 0);
+ *
+ * Ex: give me the current cache and size:
+ * UV cache_size = get_prime_cache(0, &sieve);
+ *
+ * Ex: give me the cache at least size n:
+ * UV cache_size = get_prime_cache(n, &sieve);
+ */
+extern UV get_prime_cache(UV n, const unsigned char** sieve);
+ /* Inform the system we're done using the primary cache if we got a ptr. */
+extern void release_prime_cache(const unsigned char* sieve);
+
+ /* Get the segment cache. Set size to its size. */
extern unsigned char* get_prime_segment(UV* size);
-extern void free_prime_segment(unsigned char* segment);
+ /* Inform the system we're done using the segment cache. */
+extern void release_prime_segment(unsigned char* segment);
#endif
diff --git a/lib/Math/Prime/Util.pm b/lib/Math/Prime/Util.pm
index c83c531..378fdf7 100644
--- a/lib/Math/Prime/Util.pm
+++ b/lib/Math/Prime/Util.pm
@@ -749,10 +749,8 @@ Perl versions earlier than 5.8.0 have issues with 64-bit. The test suite will
try to determine if your Perl is broken. This will show up in factoring tests.
Perl 5.6.2 32-bit works fine, as do later versions with 32-bit and 64-bit.
-Because static caches are used, many functions are not threadsafe. If you
-use C<prime_precalc> and all calls have inputs smaller than that number,
-then only C<nth_prime> is problematic. This will be addressed in a later
-implementation.
+The module is thread-safe, but will not currently allow much concurrency. This
+is being worked on.
=head1 PERFORMANCE
diff --git a/sieve.c b/sieve.c
index 61931b4..4372b9d 100644
--- a/sieve.c
+++ b/sieve.c
@@ -250,5 +250,6 @@ int sieve_segment(unsigned char* mem, UV startd, UV endd)
}
END_DO_FOR_EACH_SIEVE_PRIME;
+ release_prime_cache(sieve);
return 1;
}
diff --git a/util.c b/util.c
index 6b7e728..9556180 100644
--- a/util.c
+++ b/util.c
@@ -91,6 +91,7 @@ int is_prime(UV n)
UV d, m;
unsigned char mtab;
const unsigned char* sieve;
+ int isprime;
if ( n < (NPRIME_IS_SMALL*8))
return ((prime_is_small[n/8] >> (n%8)) & 1) ? 2 : 0;
@@ -103,10 +104,12 @@ int is_prime(UV n)
if (mtab == 0)
return 0;
- if (n <= get_prime_cache(0, &sieve))
- return ((sieve[d] & mtab) == 0) ? 2 : 0;
+ isprime = (n <= get_prime_cache(0, &sieve))
+ ? 2*((sieve[d] & mtab) == 0)
+ : -1;
+ release_prime_cache(sieve);
- return _is_prime7(n);
+ return (isprime >= 0) ? isprime : _is_prime7(n);
}
/* Shortcut, asking for a very quick response of 1 = prime, 0 = dunno.
@@ -117,6 +120,7 @@ int is_definitely_prime(UV n)
UV d, m;
unsigned char mtab;
const unsigned char* sieve;
+ int isprime;
if ( n < (NPRIME_IS_SMALL*8))
return ((prime_is_small[n/8] >> (n%8)) & 1);
@@ -129,8 +133,11 @@ int is_definitely_prime(UV n)
if (mtab == 0)
return 0;
- if (n <= get_prime_cache(0, &sieve))
- return ((sieve[d] & mtab) == 0);
+ isprime = (n <= get_prime_cache(0, &sieve))
+ ? ((sieve[d] & mtab) == 0)
+ : -1;
+ release_prime_cache(sieve);
+ if (isprime >= 0) return isprime;
if (n > MPU_PROB_PRIME_BEST)
return (is_prob_prime(n) == 2);
@@ -182,11 +189,12 @@ UV next_prime(UV n)
sieve_size = get_prime_cache(0, &sieve);
if (n < sieve_size) {
START_DO_FOR_EACH_SIEVE_PRIME(sieve, n+1, sieve_size)
- return p;
+ { release_prime_cache(sieve); return p; }
END_DO_FOR_EACH_SIEVE_PRIME;
/* Not found, so must be larger than the cache size */
n = sieve_size;
}
+ release_prime_cache(sieve);
d = n/30;
m = n - d*30;
@@ -216,11 +224,15 @@ UV prev_prime(UV n)
sieve_size = get_prime_cache(0, &sieve);
if (n < sieve_size) {
do {
- m = prevwheel30[m]; if (m==29) { if (d == 0) return 0; d--; }
+ m = prevwheel30[m];
+ if (m==29) { MPUassert(d>0, "d 0 in prev_prime"); d--; }
} while (sieve[d] & masktab30[m]);
+ release_prime_cache(sieve);
} else {
+ release_prime_cache(sieve);
do {
- m = prevwheel30[m]; if (m==29) { if (d == 0) return 0; d--; }
+ m = prevwheel30[m];
+ if (m==29) { MPUassert(d>0, "d 0 in prev_prime"); d--; }
} while (!_is_prime7(d*30+m));
}
return(d*30+m);
@@ -535,6 +547,7 @@ UV prime_count(UV low, UV high)
if (segment_size < high_d) {
/* Expand sieve to sqrt(n) */
UV endp = (high_d >= (UV_MAX/30)) ? UV_MAX-2 : 30*high_d+29;
+ release_prime_cache(cache_sieve);
segment_size = get_prime_cache( sqrt(endp) + 1 , &cache_sieve) / 30;
}
@@ -542,13 +555,16 @@ UV prime_count(UV low, UV high)
/* Count all the primes in the primary cache in our range */
count += count_segment_ranged(cache_sieve, segment_size, low, high);
- if (high_d <= segment_size)
+ if (high_d <= segment_size) {
+ release_prime_cache(cache_sieve);
return count;
+ }
low_d = segment_size;
}
+ release_prime_cache(cache_sieve);
- /* More primes needed. Repeatedly segment sieve */
+ /* More primes needed. Repeatedly segment sieve. */
segment = get_prime_segment(&segment_size);
if (segment == 0)
croak("Could not get segment memory");
@@ -563,7 +579,7 @@ UV prime_count(UV low, UV high)
UV seghigh = (seghigh_d == high_d) ? high : (seghigh_d*30+29);
if (sieve_segment(segment, low_d, seghigh_d) == 0) {
- free_prime_segment(segment);
+ release_prime_segment(segment);
croak("Could not segment sieve from %"UVuf" to %"UVuf, low_d*30+1, 30*seghigh_d+29);
}
@@ -571,7 +587,7 @@ UV prime_count(UV low, UV high)
low_d += range_d;
}
- free_prime_segment(segment);
+ release_prime_segment(segment);
return count;
}
@@ -748,6 +764,7 @@ UV nth_prime(UV n)
/* Count up everything in the cached sieve. */
count += count_segment_maxcount(cache_sieve, segment_size, target, &p);
+ release_prime_cache(cache_sieve);
if (count == target)
return p;
@@ -764,7 +781,7 @@ UV nth_prime(UV n)
/* Do the actual sieving in the range */
if (sieve_segment(segment, segbase, segbase + segment_size-1) == 0) {
- free_prime_segment(segment);
+ release_prime_segment(segment);
croak("Could not segment sieve from %"UVuf" to %"UVuf, 30*segbase+1, 30*(segbase+segment_size)+29);
}
@@ -774,7 +791,7 @@ UV nth_prime(UV n)
if (count < target)
segbase += segment_size;
}
- free_prime_segment(segment);
+ release_prime_segment(segment);
MPUassert(count == target, "nth_prime got incorrect count");
return ( (segbase*30) + p );
}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git
More information about the Pkg-perl-cvs-commits
mailing list