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 <d...@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 _______________________________________________ Pkg-perl-cvs-commits mailing list Pkg-perl-cvs-commits@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-perl-cvs-commits