|
0
|
1 //=========================================================================== |
|
|
2 // |
|
|
3 // rand.cxx |
|
|
4 // |
|
2
|
5 // ISO and POSIX 1003.1 standard random number generation functions |
|
0
|
6 // |
|
|
7 //=========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
2
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
0
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //=========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
2
|
32 // Author(s): jlarmour |
|
|
33 // Contributors: jlarmour |
|
|
34 // Date: 1990-01-20 |
|
|
35 // Purpose: Provides ISO C rand() and srand() functions, along with |
|
|
36 // POSIX 1003.1 rand_r() function |
|
|
37 // Description: This implements rand() and srand() of section 7.10.2.1 of |
|
|
38 // the ISO C standard. Also rand_r() defined in section 8.3.8 |
|
|
39 // of the POSIX 1003.1 standard |
|
0
|
40 // Usage: |
|
|
41 // |
|
|
42 //####DESCRIPTIONEND#### |
|
|
43 // |
|
|
44 //=========================================================================== |
|
|
45 |
|
|
46 // CONFIGURATION |
|
|
47 |
|
|
48 #include <pkgconf/libc.h> // Configuration header |
|
|
49 |
|
|
50 // INCLUDES |
|
|
51 |
|
|
52 #include <cyg/infra/cyg_type.h> // Common type definitions and support |
|
|
53 #include <cyg/infra/cyg_trac.h> // Tracing support |
|
|
54 #include <cyg/infra/cyg_ass.h> // Assertion support |
|
|
55 #include <stdlib.h> // Header for all stdlib functions |
|
|
56 // (like this one) |
|
|
57 #include "clibincl/stdlibsupp.hxx" // Support for stdlib functions |
|
2
|
58 |
|
|
59 #ifdef CYGSEM_LIBC_PER_THREAD_RAND |
|
|
60 # include <pkgconf/kernel.h> // kernel configuration |
|
|
61 # include <cyg/kernel/thread.hxx> // per-thread data |
|
|
62 # include <cyg/kernel/thread.inl> // per-thread data |
|
|
63 # include <cyg/kernel/mutex.hxx> // mutexes |
|
|
64 #endif |
|
0
|
65 |
|
|
66 // TRACE |
|
|
67 |
|
|
68 #if defined(CYGDBG_USE_TRACING) && defined(CYGNUM_LIBC_RAND_TRACE_LEVEL) |
|
|
69 static int rand_trace = CYGNUM_LIBC_RAND_TRACE_LEVEL; |
|
|
70 # define TL1 (0 < rand_trace) |
|
|
71 #else |
|
|
72 # define TL1 (0) |
|
|
73 #endif |
|
|
74 |
|
|
75 |
|
|
76 // EXPORTED SYMBOLS |
|
|
77 |
|
|
78 externC int |
|
2
|
79 rand( void ) CYGBLD_ATTRIB_WEAK_ALIAS(_rand); |
|
0
|
80 |
|
|
81 externC int |
|
2
|
82 rand_r( unsigned int *seed ) CYGBLD_ATTRIB_WEAK_ALIAS(_rand_r); |
|
0
|
83 |
|
|
84 externC void |
|
2
|
85 srand( unsigned int seed ) CYGBLD_ATTRIB_WEAK_ALIAS(_srand); |
|
|
86 |
|
|
87 |
|
|
88 // STATICS |
|
0
|
89 |
|
2
|
90 #ifdef CYGSEM_LIBC_PER_THREAD_RAND |
|
|
91 static cyg_ucount32 rand_data_index=CYGNUM_KERNEL_THREADS_DATA_MAX; |
|
|
92 static Cyg_Mutex rand_data_mutex CYG_INIT_PRIORITY(LIBC); |
|
|
93 #else |
|
|
94 static unsigned int cyg_libc_rand_seed = CYGNUM_LIBC_RAND_SEED; |
|
|
95 #endif |
|
0
|
96 |
|
|
97 // FUNCTIONS |
|
|
98 |
|
|
99 int |
|
|
100 _rand( void ) |
|
|
101 { |
|
2
|
102 unsigned int *seed_p; |
|
0
|
103 int retval; |
|
|
104 |
|
|
105 CYG_REPORT_FUNCNAMETYPE( "_rand", "returning %d" ); |
|
|
106 |
|
2
|
107 // get seed for this thread (if relevant ) |
|
|
108 #ifdef CYGSEM_LIBC_PER_THREAD_RAND |
|
|
109 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
110 |
|
|
111 // Get a per-thread data slot if we haven't got one already |
|
|
112 // Do a simple test before locking and retrying test, as this is a |
|
|
113 // rare situation |
|
|
114 if (CYGNUM_KERNEL_THREADS_DATA_MAX==rand_data_index) { |
|
|
115 rand_data_mutex.lock(); |
|
|
116 if (CYGNUM_KERNEL_THREADS_DATA_MAX==rand_data_index) { |
|
0
|
117 |
|
2
|
118 // the kernel just throws an assert if this doesn't work |
|
|
119 // FIXME: Should use real CDL to pre-allocate a slot at compile |
|
|
120 // time to ensure there are enough slots |
|
|
121 rand_data_index = self->new_data_index(); |
|
|
122 |
|
|
123 // Initialize seed |
|
|
124 self->set_data(rand_data_index, CYGNUM_LIBC_RAND_SEED); |
|
|
125 } |
|
|
126 rand_data_mutex.unlock(); |
|
|
127 } // if |
|
|
128 |
|
|
129 // we have a valid index now |
|
|
130 |
|
|
131 seed_p = (unsigned int *)self->get_data_ptr(rand_data_index); |
|
|
132 #else |
|
|
133 seed_p = &cyg_libc_rand_seed; |
|
|
134 #endif |
|
0
|
135 |
|
|
136 CYG_TRACE2( TL1, "Retrieved seed address %08x containing %d", |
|
|
137 seed_p, *seed_p ); |
|
2
|
138 CYG_CHECK_DATA_PTR( seed_p, "Help! Returned address of seed is invalid!" ); |
|
0
|
139 |
|
2
|
140 retval = _rand_r( seed_p ); |
|
0
|
141 |
|
|
142 CYG_REPORT_RETVAL( retval ); |
|
|
143 |
|
|
144 return retval; |
|
|
145 |
|
|
146 } // _rand() |
|
|
147 |
|
|
148 |
|
|
149 int |
|
|
150 _rand_r( unsigned int *seed ) |
|
|
151 { |
|
|
152 int retval; |
|
|
153 |
|
|
154 CYG_REPORT_FUNCNAMETYPE( "_rand_r", "returning %d" ); |
|
|
155 |
|
|
156 CYG_CHECK_DATA_PTR( seed, "pointer to seed invalid!" ); |
|
|
157 |
|
2
|
158 #if defined(CYGIMP_LIBC_RAND_SIMPLEST) |
|
|
159 |
|
|
160 // This algorithm sucks in the lower bits |
|
|
161 |
|
0
|
162 *seed = (*seed * 1103515245) + 12345; // permutate seed |
|
|
163 |
|
|
164 retval = (int)( *seed & RAND_MAX ); |
|
|
165 |
|
2
|
166 #elif defined(CYGIMP_LIBC_RAND_SIMPLE1) |
|
|
167 |
|
|
168 // The above algorithm sucks in the lower bits, so we shave them off |
|
|
169 // and repeat a couple of times to make it up |
|
|
170 |
|
|
171 unsigned int s=*seed; |
|
|
172 unsigned int uret; |
|
|
173 |
|
|
174 s = (s * 1103515245) + 12345; // permutate seed |
|
|
175 // Only use top 11 bits |
|
|
176 uret = s & 0xffe00000; |
|
|
177 |
|
|
178 s = (s * 1103515245) + 12345; // permutate seed |
|
|
179 // Only use top 14 bits |
|
|
180 uret += (s & 0xfffc0000) >> 11; |
|
|
181 |
|
|
182 s = (s * 1103515245) + 12345; // permutate seed |
|
|
183 // Only use top 7 bits |
|
|
184 uret += (s & 0xfe000000) >> (11+14); |
|
|
185 |
|
|
186 retval = (int)(uret & RAND_MAX); |
|
|
187 *seed = s; |
|
|
188 |
|
|
189 #elif defined(CYGIMP_LIBC_RAND_KNUTH1) |
|
|
190 |
|
|
191 // This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom |
|
|
192 |
|
|
193 #define MM 2147483647 // a Mersenne prime |
|
|
194 #define AA 48271 // this does well in the spectral test |
|
|
195 #define QQ 44488 // (long)(MM/AA) |
|
|
196 #define RR 3399 // MM % AA; it is important that RR<QQ |
|
|
197 |
|
|
198 *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ); |
|
|
199 if (*seed < 0) |
|
|
200 *seed += MM; |
|
|
201 |
|
|
202 retval = (int)( *seed & RAND_MAX ); |
|
|
203 |
|
|
204 #else |
|
|
205 # error No valid implementation for rand()! |
|
|
206 #endif |
|
|
207 |
|
0
|
208 CYG_REPORT_RETVAL( retval ); |
|
|
209 |
|
|
210 return retval; |
|
|
211 |
|
|
212 } // _rand_r() |
|
|
213 |
|
|
214 |
|
|
215 void |
|
|
216 _srand( unsigned int seed ) |
|
|
217 { |
|
2
|
218 CYG_REPORT_FUNCNAME( "_srand" ); |
|
0
|
219 |
|
|
220 CYG_REPORT_FUNCARG1DV( (int)seed ); |
|
|
221 |
|
2
|
222 // get seed for this thread ( if relevant ) |
|
|
223 #ifdef CYGSEM_LIBC_PER_THREAD_RAND |
|
|
224 Cyg_Thread *self = Cyg_Thread::self(); |
|
0
|
225 |
|
2
|
226 // Get a per-thread data slot if we haven't got one already |
|
|
227 // Do a simple test before locking and retrying test, as this is a |
|
|
228 // rare situation |
|
|
229 if (CYGNUM_KERNEL_THREADS_DATA_MAX==rand_data_index) { |
|
|
230 rand_data_mutex.lock(); |
|
|
231 if (CYGNUM_KERNEL_THREADS_DATA_MAX==rand_data_index) { |
|
0
|
232 |
|
2
|
233 // the kernel just throws an assert if this doesn't work |
|
|
234 // FIXME: Should use real CDL to pre-allocate a slot at compile |
|
|
235 // time to ensure there are enough slots |
|
|
236 rand_data_index = self->new_data_index(); |
|
0
|
237 |
|
2
|
238 } |
|
|
239 rand_data_mutex.unlock(); |
|
|
240 } // if |
|
|
241 |
|
|
242 // we have a valid index now |
|
|
243 |
|
|
244 self->set_data(rand_data_index, (CYG_ADDRWORD) seed); |
|
|
245 #else |
|
|
246 cyg_libc_rand_seed = seed; |
|
|
247 #endif |
|
0
|
248 |
|
|
249 CYG_REPORT_RETURN(); |
|
|
250 |
|
|
251 } // _srand() |
|
|
252 |
|
|
253 // EOF rand.cxx |