VirtualBox

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

Last change on this file since 4715 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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