summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1085/pgm/rand.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/openpgm-svn-r1085/pgm/rand.c')
-rw-r--r--3rdparty/openpgm-svn-r1085/pgm/rand.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1085/pgm/rand.c b/3rdparty/openpgm-svn-r1085/pgm/rand.c
new file mode 100644
index 0000000..91b71eb
--- /dev/null
+++ b/3rdparty/openpgm-svn-r1085/pgm/rand.c
@@ -0,0 +1,137 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable weak pseudo-random generator.
+ *
+ * Copyright (c) 2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _WIN32
+# include <errno.h>
+# include <stdio.h>
+#endif
+#include <impl/framework.h>
+
+
+//#define RAND_DEBUG
+
+
+/* locals */
+
+static pgm_rand_t global_rand = { .seed = 0 };
+static volatile uint32_t rand_ref_count = 0;
+static pgm_mutex_t rand_mutex;
+
+
+void
+pgm_rand_init (void)
+{
+ if (pgm_atomic_exchange_and_add32 (&rand_ref_count, 1) > 0)
+ return;
+
+ pgm_mutex_init (&rand_mutex);
+}
+
+void
+pgm_rand_shutdown (void)
+{
+ pgm_return_if_fail (pgm_atomic_read32 (&rand_ref_count) > 0);
+
+ if (pgm_atomic_exchange_and_add32 (&rand_ref_count, (uint32_t)-1) != 1)
+ return;
+
+ pgm_mutex_free (&rand_mutex);
+}
+
+void
+pgm_rand_create (
+ pgm_rand_t* new_rand
+ )
+{
+/* pre-conditions */
+ pgm_assert (NULL != new_rand);
+
+#ifndef _WIN32
+/* attempt to read seed from kernel
+ */
+ FILE* fp;
+ do {
+ fp = fopen ("/dev/urandom", "rb");
+ } while (PGM_UNLIKELY(EINTR == errno));
+ if (fp) {
+ size_t items_read;
+ do {
+ items_read = fread (&new_rand->seed, sizeof(new_rand->seed), 1, fp);
+ } while (PGM_UNLIKELY(EINTR == errno));
+ fclose (fp);
+ if (1 == items_read)
+ return;
+ }
+#endif /* !_WIN32 */
+ const pgm_time_t now = pgm_time_update_now();
+ new_rand->seed = (uint32_t)pgm_to_msecs (now);
+}
+
+/* derived from POSIX.1-2001 example implementation of rand()
+ */
+
+uint32_t
+pgm_rand_int (
+ pgm_rand_t* r
+ )
+{
+/* pre-conditions */
+ pgm_assert (NULL != r);
+
+ r->seed = r->seed * 1103515245 + 12345;
+ return r->seed;
+}
+
+int32_t
+pgm_rand_int_range (
+ pgm_rand_t* r,
+ int32_t begin,
+ int32_t end
+ )
+{
+/* pre-conditions */
+ pgm_assert (NULL != r);
+
+ return begin + pgm_rand_int (r) % (end - begin);
+}
+
+uint32_t
+pgm_random_int (void)
+{
+ pgm_mutex_lock (&rand_mutex);
+ if (PGM_UNLIKELY(!global_rand.seed))
+ pgm_rand_create (&global_rand);
+ const uint32_t rand_value = pgm_rand_int (&global_rand);
+ pgm_mutex_unlock (&rand_mutex);
+ return rand_value;
+}
+
+int32_t
+pgm_random_int_range (
+ int32_t begin,
+ int32_t end
+ )
+{
+ const uint32_t rand_value = pgm_random_int();
+ return begin + rand_value % (end - begin);
+}
+
+/* eof */