VirtualBox

source: vbox/trunk/src/VBox/Runtime/misc/rand.cpp@ 3896

Last change on this file since 3896 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

  • Property svn:keywords set to Id
File size: 9.7 KB
Line 
1/* $Id: rand.cpp 2981 2007-06-01 16:01:28Z vboxsync $ */
2/** @file
3 * innotek Portable Runtime - Random Number
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <iprt/rand.h>
27#include <iprt/time.h>
28#include <iprt/asm.h>
29#include <iprt/err.h>
30#include <iprt/assert.h>
31#include <iprt/thread.h>
32#include "internal/rand.h"
33
34
35/*******************************************************************************
36* Global Variables *
37*******************************************************************************/
38/** Lazy init. */
39static volatile bool g_fInitialized = false;
40/** The context variable for the fallback path. */
41static uint32_t g_u32Ctx;
42
43
44/*******************************************************************************
45* Internal Functions *
46*******************************************************************************/
47static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx);
48
49
50/**
51 * Lazy initialization of the native and fallback random byte sources.
52 *
53 */
54static void rtRandLazyInit(void)
55{
56 /*
57 * Seed the fallback random code.
58 */
59 g_u32Ctx = (uint32_t)(ASMReadTSC() >> 8);
60
61 /*
62 * Call host specific init.
63 */
64 rtRandLazyInitNative();
65 g_fInitialized = true;
66}
67
68
69/**
70 * Internal wrapper for the native and generic random byte methods.
71 *
72 * @param pv Where to store the random bytes.
73 * @param cb Number of bytes to generate.
74 */
75static void rtRandGenBytes(void *pv, size_t cb)
76{
77 Assert(cb);
78 if (RT_UNLIKELY(!g_fInitialized))
79 rtRandLazyInit();
80
81 int rc = rtRandGenBytesNative(pv, cb);
82 if (RT_FAILURE(rc))
83 rtRandGenBytesFallback(pv, cb);
84}
85
86
87/**
88 * Fills a buffer with random bytes.
89 *
90 * @param pv Where to store the random bytes.
91 * @param cb Number of bytes to generate.
92 */
93RTDECL(void) RTRandBytes(void *pv, size_t cb)
94{
95 if (cb)
96 rtRandGenBytes(pv, cb);
97}
98
99
100/**
101 * Generate a 32-bit signed random number in the set [i32First..i32Last].
102 *
103 * @returns The random number.
104 * @param i32First First number in the set.
105 * @param i32Last Last number in the set.
106 */
107RTDECL(int32_t) RTRandS32Ex(int32_t i32First, int32_t i32Last)
108{
109 /* get 4 random bytes. */
110 union
111 {
112 uint32_t off;
113 uint8_t ab[4];
114 } u;
115 rtRandGenBytes(&u.ab, sizeof(u));
116
117
118 /* squeeze it into the requested range. */
119 uint32_t offLast = i32Last - i32First;
120 if (u.off > offLast)
121 {
122 do
123 {
124 u.off >>= 1;
125 } while (u.off > offLast);
126 }
127 return i32First + u.off;
128}
129
130
131/**
132 * Generate a 32-bit signed random number.
133 *
134 * @returns The random number.
135 */
136RTDECL(int32_t) RTRandS32(void)
137{
138 return RTRandS32Ex(INT32_MIN, INT32_MAX);
139}
140
141
142/**
143 * Generate a 32-bit unsigned random number in the set [u32First..u32Last].
144 *
145 * @returns The random number.
146 * @param u32First First number in the set.
147 * @param u32Last Last number in the set.
148 */
149RTDECL(uint32_t) RTRandU32Ex(uint32_t u32First, uint32_t u32Last)
150{
151 /* get 4 random bytes. */
152 union
153 {
154 uint32_t off;
155 uint8_t ab[4];
156 } u;
157 rtRandGenBytes(&u.ab, sizeof(u));
158
159
160 /* squeeze it into the requested range. */
161 const uint32_t offLast = u32Last - u32First;
162 if (u.off > offLast)
163 {
164 do
165 {
166 u.off >>= 1;
167 } while (u.off > offLast);
168 }
169 return u32First + u.off;
170}
171
172
173/**
174 * Generate a 32-bit unsigned random number.
175 *
176 * @returns The random number.
177 */
178RTDECL(uint32_t) RTRandU32(void)
179{
180 return RTRandU32Ex(0, UINT32_MAX);
181}
182
183
184/**
185 * Generate a 32-bit signed random number in the set [i32First..i32Last].
186 *
187 * @returns The random number.
188 * @param i32First First number in the set.
189 * @param i32Last Last number in the set.
190 */
191RTDECL(int64_t) RTRandS64Ex(int64_t i64First, int64_t i64Last)
192{
193 /* get 8 random bytes. */
194 union
195 {
196 uint64_t off;
197 uint8_t ab[8];
198 } u;
199 rtRandGenBytes(&u.ab, sizeof(u));
200
201 /* squeeze it into the requested range. */
202 uint64_t offLast = i64Last - i64First;
203 if (u.off > offLast)
204 {
205 do
206 {
207 u.off >>= 1;
208 } while (u.off > offLast);
209 }
210 return i64First + u.off;
211}
212
213
214/**
215 * Generate a 64-bit signed random number.
216 *
217 * @returns The random number.
218 */
219RTDECL(int64_t) RTRandS64(void)
220{
221 return RTRandS64Ex(INT64_MIN, INT64_MAX);
222}
223
224
225/**
226 * Generate a 64-bit unsigned random number in the set [u64First..u64Last].
227 *
228 * @returns The random number.
229 * @param u64First First number in the set.
230 * @param u64Last Last number in the set.
231 */
232RTDECL(uint64_t) RTRandU64Ex(uint64_t u64First, uint64_t u64Last)
233{
234 /* get 8 random bytes. */
235 union
236 {
237 uint64_t off;
238 uint8_t ab[8];
239 } u;
240 rtRandGenBytes(&u.ab, sizeof(u));
241
242 /* squeeze it into the requested range. */
243 const uint64_t offLast = u64Last - u64First;
244 if (u.off > offLast)
245 {
246 do
247 {
248 u.off >>= 1;
249 } while (u.off > offLast);
250 }
251 return u64First + u.off;
252}
253
254
255/**
256 * Generate a 64-bit unsigned random number.
257 *
258 * @returns The random number.
259 */
260RTDECL(uint64_t) RTRandU64(void)
261{
262 return RTRandU64Ex(0, UINT64_MAX);
263}
264
265
266/**
267 * Fallback random byte source.
268 *
269 * @param pv Where to store the random bytes.
270 * @param cb Number of bytes to generate.
271 */
272void rtRandGenBytesFallback(void *pv, size_t cb)
273{
274 uint8_t *pb = (uint8_t *)pv;
275 for (unsigned i = 0;; i++)
276 {
277 uint32_t u32 = rtRandGenBytesFallbackU31(&g_u32Ctx);
278
279 *pb++ = (uint8_t)u32;
280 if (!--cb)
281 break;
282
283 u32 >>= 8;
284 *pb++ = (uint8_t)u32;
285 if (!--cb)
286 break;
287
288 u32 >>= 8;
289 *pb++ = (uint8_t)u32;
290 if (!--cb)
291 break;
292
293 /* Is this really a good idea? */
294 if (!(i % 3))
295 {
296 if (i)
297 RTThreadYield();
298 *pb++ = (uint8_t)ASMReadTSC();
299 if (!--cb)
300 break;
301 }
302 }
303
304}
305
306
307/*-
308 * Copyright (c) 1990, 1993
309 * The Regents of the University of California. All rights reserved.
310 *
311 * Redistribution and use in source and binary forms, with or without
312 * modification, are permitted provided that the following conditions
313 * are met:
314 * 1. Redistributions of source code must retain the above copyright
315 * notice, this list of conditions and the following disclaimer.
316 * 2. Redistributions in binary form must reproduce the above copyright
317 * notice, this list of conditions and the following disclaimer in the
318 * documentation and/or other materials provided with the distribution.
319 * 4. Neither the name of the University nor the names of its contributors
320 * may be used to endorse or promote products derived from this software
321 * without specific prior written permission.
322 *
323 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
324 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
325 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
326 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
327 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
328 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
329 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
330 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
331 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
332 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
333 * SUCH DAMAGE.
334 */
335
336/* The core of:
337__FBSDID("$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/rand.c,v 1.16 2007/01/09 00:28:10 imp Exp $");
338*/
339
340/**
341 * Generates an unsigned 31 bit pseudo random number.
342 *
343 * @returns pseudo random number.
344 * @param pCtx The context.
345 */
346static uint32_t rtRandGenBytesFallbackU31(uint32_t *pCtx)
347{
348 /*
349 * Compute x = (7^5 * x) mod (2^31 - 1)
350 * without overflowing 31 bits:
351 * (2^31 - 1) = 127773 * (7^5) + 2836
352 *
353 * From "Random number generators: good ones are hard to find", Park and
354 * Miller, Communications of the ACM, vol. 31, no. 10, October 1988, p. 1195.
355 */
356 uint32_t Ctx = *pCtx;
357 if (!Ctx) /* must not be zero. */
358 Ctx = 0x20070212;
359 uint32_t Hi = Ctx / 127773;
360 uint32_t Lo = Ctx % 127773;
361 int32_t x = 16807 * Lo - 2836 * Hi;
362 if (x < 0)
363 x += INT32_MAX;
364 *pCtx = x;
365 return x % INT32_MAX;
366}
367
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette