commit 2fe6f86096157085c12ddd4460cf50293f95437c
parent 6a944967b1e5fa96e9728392e95d4049b8f78dae
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 6 Feb 2017 18:47:45 +0100
Add and test the ssp_rng_proxy_<read|write> functions
Diffstat:
5 files changed, 242 insertions(+), 51 deletions(-)
diff --git a/src/ssp.h b/src/ssp.h
@@ -232,6 +232,16 @@ ssp_rng_proxy_create_from_rng
struct ssp_rng_proxy** proxy);
SSP_API res_T
+ssp_rng_proxy_read
+ (struct ssp_rng_proxy* proxy,
+ FILE* stream);
+
+SSP_API res_T
+ssp_rng_proxy_write
+ (const struct ssp_rng_proxy* proxy,
+ FILE* stream);
+
+SSP_API res_T
ssp_rng_proxy_ref_get
(struct ssp_rng_proxy* proxy);
diff --git a/src/ssp_rng.c b/src/ssp_rng.c
@@ -378,7 +378,7 @@ rng_cxx_init<aes_T>(struct mem_allocator* allocator, void* data)
{
(void) allocator;
if (!haveAESNI()) {
- // AES-NI instructions not available on this hardware
+ /* AES-NI instructions not available on this hardware */
return RES_BAD_OP;
}
ASSERT(data);
diff --git a/src/ssp_rng_proxy.c b/src/ssp_rng_proxy.c
@@ -33,6 +33,7 @@
#include <rsys/mutex.h>
#include <rsys/ref_count.h>
+#include <rsys/signal.h>
#include <rsys/stretchy_array.h>
#include <limits.h>
@@ -45,6 +46,13 @@ struct rng_state_cache {
long head, tail; /* Position onto the head/tail `states' stream */
};
+CLBK(rng_proxy_cb_T, ARG1(const struct ssp_rng_proxy*));
+
+enum rng_proxy_sig {
+ RNG_PROXY_SIG_READ,
+ RNG_PROXY_SIGS_COUNT__
+};
+
/* A proxy manages a list of N independent RNGs of the same type named buckets.
* One ensure that each bucket have independent `infinite' random numbers by
* partitioning a unique random sequence in N random pools, each containing
@@ -69,6 +77,8 @@ struct ssp_rng_proxy {
struct ssp_rng** pools; /* `type' RNGs wrapped by bucket RNGs */
struct rng_state_cache* states; /* Cache of `type' RNG states */
+ signal_T signals[RNG_PROXY_SIGS_COUNT__];
+
struct mutex* mutex;
struct mem_allocator* allocator;
ref_T ref;
@@ -161,8 +171,20 @@ struct rng_bucket {
struct ssp_rng_proxy* proxy; /* The RNG proxy */
size_t name; /* Unique bucket identifier in [0, #buckets) */
size_t count; /* Remaining unique random numbers in `pool' */
+ rng_proxy_cb_T cb_on_proxy_read;
};
+static void
+rng_bucket_on_proxy_read(const struct ssp_rng_proxy* proxy, void* ctx)
+{
+ struct rng_bucket* rng = (struct rng_bucket*)ctx;
+ ASSERT(proxy && ctx && rng->proxy == proxy);
+ (void)proxy;
+ /* Reset bucket */
+ rng->count = 0;
+ rng->pool = NULL;
+}
+
static INLINE void
rng_bucket_next_ran_pool(struct rng_bucket* rng)
{
@@ -221,6 +243,7 @@ rng_bucket_release(void* data)
struct rng_bucket* rng = (struct rng_bucket*)data;
ASSERT(data && rng->proxy);
ATOMIC_SET(&rng->proxy->buckets[rng->name], 0);
+ CLBK_DISCONNECT(&rng->cb_on_proxy_read);
SSP(rng_proxy_ref_put(rng->proxy));
}
@@ -363,6 +386,7 @@ ssp_rng_proxy_create
{
struct mem_allocator* allocator = NULL;
struct ssp_rng_proxy* proxy = NULL;
+ size_t i;
res_T res = RES_OK;
if(!type || !out_proxy || !nbuckets) {
@@ -390,6 +414,10 @@ ssp_rng_proxy_create
goto error;
}
+ FOR_EACH(i, 0, RNG_PROXY_SIGS_COUNT__) {
+ SIG_INIT(proxy->signals + i);
+ }
+
res = rng_proxy_setup(proxy, nbuckets);
if(res != RES_OK) goto error;
@@ -415,6 +443,7 @@ ssp_rng_proxy_create_from_rng
struct ssp_rng_proxy* proxy = NULL;
struct ssp_rng_type type;
FILE* stream = NULL;
+ size_t i;
res_T res = RES_OK;
if(!rng || !out_proxy || !nbuckets) {
@@ -458,6 +487,10 @@ ssp_rng_proxy_create_from_rng
goto error;
}
+ FOR_EACH(i, 0, RNG_PROXY_SIGS_COUNT__) {
+ SIG_INIT(proxy->signals + i);
+ }
+
res = rng_proxy_setup(proxy, nbuckets);
if(res != RES_OK) goto error;
@@ -474,6 +507,34 @@ error:
}
res_T
+ssp_rng_proxy_read(struct ssp_rng_proxy* proxy, FILE* stream)
+{
+ res_T res = RES_OK;
+ if(!proxy || !stream) return RES_BAD_ARG;
+
+ mutex_lock(proxy->mutex);
+ res = ssp_rng_read(proxy->rng, stream);
+ mutex_unlock(proxy->mutex);
+ if(res != RES_OK) return res;
+
+ SIG_BROADCAST(proxy->signals+RNG_PROXY_SIG_READ, rng_proxy_cb_T, ARG1(proxy));
+ return RES_OK;
+}
+
+res_T
+ssp_rng_proxy_write(const struct ssp_rng_proxy* proxy, FILE* stream)
+{
+ res_T res = RES_OK;
+
+ if(!proxy || !stream) return RES_BAD_ARG;
+
+ mutex_lock(proxy->mutex);
+ res = ssp_rng_write(proxy->rng, stream);
+ mutex_unlock(proxy->mutex);
+ return res;
+}
+
+res_T
ssp_rng_proxy_ref_get(struct ssp_rng_proxy* proxy)
{
if(!proxy) return RES_BAD_ARG;
@@ -497,6 +558,7 @@ ssp_rng_proxy_create_rng
{
struct ssp_rng* rng = NULL;
struct ssp_rng_type type = RNG_BUCKET_NULL;
+ struct rng_bucket* bucket = NULL;
res_T res = RES_OK;
if(!proxy || ibucket >= sa_size(proxy->buckets) || !out_rng) {
@@ -516,10 +578,17 @@ ssp_rng_proxy_create_rng
res = ssp_rng_create(proxy->allocator, &type, &rng);
if(res != RES_OK) goto error;
- ((struct rng_bucket*)rng->state)->name = ibucket;
- ((struct rng_bucket*)rng->state)->proxy = proxy;
+ bucket = (struct rng_bucket*)rng->state;
+ bucket->name = ibucket;
+ bucket->proxy = proxy;
SSP(rng_proxy_ref_get(proxy));
+ /* The bucket RNG listens the "write" signal of the proxy to reset its
+ * internal RNs counter on "write" invocation. */
+ CLBK_INIT(&bucket->cb_on_proxy_read);
+ CLBK_SETUP(&bucket->cb_on_proxy_read, rng_bucket_on_proxy_read, bucket);
+ SIG_CONNECT_CLBK(proxy->signals+RNG_PROXY_SIG_READ, &bucket->cb_on_proxy_read);
+
exit:
if(out_rng) *out_rng = rng;
return res;
diff --git a/src/test_ssp_rng_proxy.c b/src/test_ssp_rng_proxy.c
@@ -31,20 +31,14 @@
#include "ssp.h"
#include "test_ssp_utils.h"
-int
-main(int argc, char** argv)
+#define NRANDS 2000000
+#define COUNT 4605307
+
+static void
+test_creation(void)
{
- struct ssp_rng_type type;
struct ssp_rng_proxy* proxy;
- struct ssp_rng_proxy* proxy1, *proxy2;
- struct ssp_rng* rng[4];
- struct ssp_rng* rng1[4], * rng2[4];
- struct ssp_rng* rng3;
- struct mem_allocator allocator;
- size_t i = 0;
- (void)argc, (void)argv;
-
- mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+ struct ssp_rng_type type;
CHECK(ssp_rng_proxy_create(NULL, NULL, 0, NULL), RES_BAD_ARG);
CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 0, NULL), RES_BAD_ARG);
@@ -69,7 +63,23 @@ main(int argc, char** argv)
CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
- CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_mt19937_64, 4, &proxy), RES_OK);
+ CHECK(ssp_rng_proxy_create
+ (&mem_default_allocator, &ssp_rng_threefry, 1, &proxy), RES_OK);
+ CHECK(ssp_rng_proxy_get_type(proxy, &type), RES_OK);
+ CHECK(ssp_rng_type_eq(&type, &ssp_rng_threefry), 1);
+ CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
+}
+
+static void
+test_rng_from_proxy(void)
+{
+ struct ssp_rng_type type;
+ struct ssp_rng_proxy* proxy;
+ struct ssp_rng* rng[4];
+ uint64_t r[4];
+ size_t i, j, k;
+
+ CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy), RES_OK);
CHECK(ssp_rng_proxy_create_rng(NULL, 0, NULL), RES_BAD_ARG);
CHECK(ssp_rng_proxy_create_rng(proxy, 0, NULL), RES_BAD_ARG);
@@ -79,9 +89,8 @@ main(int argc, char** argv)
CHECK(ssp_rng_ref_put(rng[0]), RES_OK);
CHECK(ssp_rng_proxy_create_rng(proxy, 4, &rng[0]), RES_BAD_ARG);
- FOR_EACH(i, 0, 4) {
- CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK);
- }
+
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK);
CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
CHECK(ssp_rng_get_type(rng[0], &type), RES_OK);
@@ -91,35 +100,56 @@ main(int argc, char** argv)
CHECK(ssp_rng_type_eq(&type, &type2), 1);
}
- FOR_EACH(i, 0, 2000000) {
- uint64_t r[4];
- int j;
+ FOR_EACH(i, 0, NRANDS) {
FOR_EACH(j, 0, 4) {
- int k;
r[j] = ssp_rng_get(rng[j]);
- FOR_EACH(k, 0, j)
- NCHECK(r[k], r[j]);
+ FOR_EACH(k, 0, j) NCHECK(r[k], r[j]);
}
}
- CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 1, &proxy1), RES_OK);
- CHECK(ssp_rng_proxy_create(&allocator, &ssp_rng_threefry, 1, &proxy2), RES_OK);
- CHECK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1[0]), RES_OK);
- CHECK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2[0]), RES_OK);
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK);
+}
+
+static void
+test_multi_proxies(void)
+{
+ struct ssp_rng_proxy* proxy1;
+ struct ssp_rng_proxy* proxy2;
+ struct ssp_rng* rng1;
+ struct ssp_rng* rng2;
+ struct ssp_rng* rng3;
+ size_t i;
+
+ CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_threefry, 1, &proxy1), RES_OK);
+ CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_threefry, 1, &proxy2), RES_OK);
+
+ CHECK(ssp_rng_proxy_create_rng(proxy1, 0, &rng1), RES_OK);
+ CHECK(ssp_rng_proxy_create_rng(proxy2, 0, &rng2), RES_OK);
ssp_rng_create(NULL, &ssp_rng_threefry, &rng3);
+
CHECK(ssp_rng_proxy_ref_put(proxy1), RES_OK);
CHECK(ssp_rng_proxy_ref_put(proxy2), RES_OK);
-#define COUNT 4605307
- ssp_rng_discard(rng1[0], COUNT);
+
+ ssp_rng_discard(rng1, COUNT);
ssp_rng_discard(rng3, COUNT+1);
- FOR_EACH(i, 0, COUNT) ssp_rng_get(rng2[0]);
- CHECK(ssp_rng_get(rng1[0]), ssp_rng_get(rng2[0]));
- CHECK(ssp_rng_get(rng1[0]), ssp_rng_get(rng3));
+ FOR_EACH(i, 0, COUNT) ssp_rng_get(rng2);
- FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK);
- CHECK(ssp_rng_ref_put(rng1[0]), RES_OK);
- CHECK(ssp_rng_ref_put(rng2[0]), RES_OK);
+ CHECK(ssp_rng_get(rng1), ssp_rng_get(rng2));
+ CHECK(ssp_rng_get(rng1), ssp_rng_get(rng3));
+
+ CHECK(ssp_rng_ref_put(rng1), RES_OK);
+ CHECK(ssp_rng_ref_put(rng2), RES_OK);
CHECK(ssp_rng_ref_put(rng3), RES_OK);
+}
+
+static void
+test_proxy_from_rng(void)
+{
+ struct ssp_rng_proxy* proxy;
+ struct ssp_rng* rng[4];
+ struct ssp_rng_type type;
+ uint64_t r[4];
+ size_t i, j, k;
CHECK(ssp_rng_create(NULL, &ssp_rng_threefry, &rng[0]), RES_OK);
CHECK(ssp_rng_discard(rng[0], COUNT), RES_OK);
@@ -137,17 +167,13 @@ main(int argc, char** argv)
CHECK(ssp_rng_proxy_create_rng(proxy, 1, &rng[2]), RES_BAD_ARG);
CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1]));
- CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1]));
- CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1]));
- CHECK(ssp_rng_get(rng[0]), ssp_rng_get(rng[1]));
CHECK(ssp_rng_ref_put(rng[1]), RES_OK);
CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
CHECK(ssp_rng_proxy_create_from_rng(NULL, rng[0], 4, &proxy), RES_OK);
CHECK(ssp_rng_ref_put(rng[0]), RES_OK);
- FOR_EACH(i, 0, 4)
- CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK);
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng[i]), RES_OK);
CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
CHECK(ssp_rng_get_type(rng[0], &type), RES_OK);
@@ -157,20 +183,106 @@ main(int argc, char** argv)
CHECK(ssp_rng_type_eq(&type, &type2), 1);
}
- FOR_EACH(i, 0, 2000000) {
- uint64_t r[4];
- int j;
+ FOR_EACH(i, 0, NRANDS) {
FOR_EACH(j, 0, 4) {
- int k;
r[j] = ssp_rng_get(rng[j]);
- FOR_EACH(k, 0, j)
- NCHECK(r[k], r[j]);
+ FOR_EACH(k, 0, j) NCHECK(r[k], r[j]);
}
}
FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng[i]), RES_OK);
+}
+
+static void
+test_read(void)
+{
+ struct ssp_rng_proxy* proxy;
+ struct ssp_rng* rng;
+ struct ssp_rng* rng1[4];
+ FILE* stream;
+ uint64_t r[4];
+ size_t i, j, k;
+
+ CHECK(ssp_rng_create(NULL, &ssp_rng_mt19937_64, &rng), RES_OK);
+ CHECK(ssp_rng_discard(rng, COUNT), RES_OK);
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+ CHECK(ssp_rng_write(rng, stream), RES_OK);
+ rewind(stream);
+
+ CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_mt19937_64, 4, &proxy), RES_OK);
+ CHECK(ssp_rng_proxy_read(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_proxy_read(proxy, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_proxy_read(NULL, stream), RES_BAD_ARG);
+ CHECK(ssp_rng_proxy_read(proxy, stream), RES_OK);
+
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_proxy_create_rng(proxy, i, &rng1[i]), RES_OK);
+
+ r[0] = ssp_rng_get(rng);
+ CHECK(r[0], ssp_rng_get(rng1[0]));
+ NCHECK(r[0], ssp_rng_get(rng1[1]));
+ NCHECK(r[0], ssp_rng_get(rng1[2]));
+ NCHECK(r[0], ssp_rng_get(rng1[3]));
+
+ FOR_EACH(i, 0, NRANDS) {
+ FOR_EACH(j, 0, 4) {
+ r[j] = ssp_rng_get(rng1[j]);
+ FOR_EACH(k, 0, j) NCHECK(r[k], r[j]);
+ }
+ }
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
+ CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
+ CHECK(ssp_rng_ref_put(rng), RES_OK);
+ FOR_EACH(i, 0, 4) CHECK(ssp_rng_ref_put(rng1[i]), RES_OK);
+ fclose(stream);
+}
+
+static void
+test_write(void)
+{
+ struct ssp_rng_proxy* proxy;
+ struct ssp_rng* rng0;
+ struct ssp_rng* rng1;
+ FILE* stream;
+ uint64_t r;
+
+ stream = tmpfile();
+ NCHECK(stream, NULL);
+
+ CHECK(ssp_rng_proxy_create(NULL, &ssp_rng_ranlux48, 1, &proxy), RES_OK);
+ CHECK(ssp_rng_proxy_create_rng(proxy, 0, &rng0), RES_OK);
+
+ CHECK(ssp_rng_proxy_write(NULL, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_proxy_write(proxy, NULL), RES_BAD_ARG);
+ CHECK(ssp_rng_proxy_write(NULL, stream), RES_BAD_ARG);
+ CHECK(ssp_rng_proxy_write(proxy, stream), RES_OK);
+
+ CHECK(ssp_rng_create(NULL, &ssp_rng_ranlux48, &rng1), RES_OK);
+ r = ssp_rng_get(rng0);
+ CHECK(r, ssp_rng_get(rng1));
+
+ rewind(stream);
+ CHECK(ssp_rng_read(rng1, stream), RES_OK);
+ CHECK(r, ssp_rng_get(rng1));
+ CHECK(ssp_rng_get(rng0), ssp_rng_get(rng1));
+
+ CHECK(ssp_rng_proxy_ref_put(proxy), RES_OK);
+ CHECK(ssp_rng_ref_put(rng0), RES_OK);
+ CHECK(ssp_rng_ref_put(rng1), RES_OK);
+
+ fclose(stream);
+}
+
+int
+main(int argc, char** argv)
+{
+ (void)argc, (void)argv;
+ test_creation();
+ test_rng_from_proxy();
+ test_multi_proxies();
+ test_proxy_from_rng();
+ test_read();
+ test_write();
CHECK(mem_allocated_size(), 0);
return 0;
}
diff --git a/src/test_ssp_utils.h b/src/test_ssp_utils.h
@@ -32,7 +32,7 @@
#include <rsys/mem_allocator.h>
#include <stdio.h>
-static void
+static INLINE void
check_memory_allocator(struct mem_allocator* allocator)
{
if(MEM_ALLOCATED_SIZE(allocator)) {