From 6003243ef3622395513da90919c225a4a9cfe2a8 Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Thu, 11 Apr 2013 04:22:22 +0200 Subject: [PATCH] util: introduce kernel utils for pseudorandom number generation Currently there are two generators. The fast one is the same one the scheduler is using. The standard one is the same algorithm libroot's rand() uses. Should there be a need for more cryptographically PRNG MD4 or MD5 might be a good candidates. --- headers/private/kernel/util/Random.h | 69 ++++++++++++++++++++++++++++ src/system/kernel/util/Jamfile | 1 + src/system/kernel/util/Random.cpp | 54 ++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 headers/private/kernel/util/Random.h create mode 100644 src/system/kernel/util/Random.cpp diff --git a/headers/private/kernel/util/Random.h b/headers/private/kernel/util/Random.h new file mode 100644 index 0000000000..7ca4f05312 --- /dev/null +++ b/headers/private/kernel/util/Random.h @@ -0,0 +1,69 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef KERNEL_UTIL_RANDOM_H +#define KERNEL_UTIL_RANDOM_H + + +#include +#include + + +#define MAX_FAST_RANDOM_VALUE 0x7fff +#define MAX_RANDOM_VALUE 0x7fffffffu + +const int kFastRandomShift = 15; +const int kRandomShift = 31; + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned int fast_random_value(void); +unsigned int random_value(void); + +#ifdef __cplusplus +} +#endif + + +#ifdef __cplusplus + +template +T +fast_get_random() +{ + size_t shift = 0; + T random = 0; + while (shift < sizeof(T) * 8) { + random |= (T)fast_random_value() << shift; + shift += kFastRandomShift; + } + + return random; +} + + +template +T +get_random() +{ + size_t shift = 0; + T random = 0; + while (shift < sizeof(T) * 8) { + random |= (T)random_value() << shift; + shift += kRandomShift; + } + + return random; +} + + +#endif // __cplusplus + +#endif // KERNEL_UTIL_RANDOM_H + diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index 02ce7ce690..a8f49b9d2a 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -14,6 +14,7 @@ KernelMergeObject kernel_util.o : queue.cpp ring_buffer.cpp RadixBitmap.cpp + Random.cpp : $(TARGET_KERNEL_PIC_CCFLAGS) -DUSING_LIBGCC ; diff --git a/src/system/kernel/util/Random.cpp b/src/system/kernel/util/Random.cpp new file mode 100644 index 0000000000..417abe7324 --- /dev/null +++ b/src/system/kernel/util/Random.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2013 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include + +#include + + +static uint32 fast_last = 0; +static uint32 last = 0; + +// In the following functions there are race conditions when many threads +// attempt to update static variable last. However, since such conflicts +// are non-deterministic it is not a big problem. + + +// A simple linear congruential generator +unsigned int +fast_random_value() +{ + if (fast_last == 0) + fast_last = system_time(); + + uint32 random = fast_last * 1103515245 + 12345; + fast_last = random; + return (random >> 16) & 0x7fff; +} + + +// Taken from "Random number generators: good ones are hard to find", +// Park and Miller, Communications of the ACM, vol. 31, no. 10, +// October 1988, p. 1195. +unsigned int +random_value() +{ + if (last == 0) + last = system_time(); + + uint32 hi = last / 127773; + uint32 lo = last % 127773; + + int32 random = 16807 * lo - 2836 * hi; + if (random <= 0) + random += MAX_RANDOM_VALUE; + last = random; + return random % (MAX_RANDOM_VALUE + 1); +} +