1 //===========================================================================
5 // ISO and POSIX 1003.1 standard random number generation functions
7 //===========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //===========================================================================
41 //#####DESCRIPTIONBEGIN####
43 // Author(s): jlarmour
46 // Purpose: Provides ISO C rand() and srand() functions, along with
47 // POSIX 1003.1 rand_r() function
48 // Description: This implements rand() and srand() of section 7.10.2.1 of
49 // the ISO C standard. Also rand_r() defined in section 8.3.8
50 // of the POSIX 1003.1 standard
53 //####DESCRIPTIONEND####
55 //===========================================================================
59 #include <pkgconf/libc_stdlib.h> // Configuration header
63 #include <cyg/infra/cyg_type.h> // Common type definitions and support
64 #include <cyg/infra/cyg_trac.h> // Tracing support
65 #include <cyg/infra/cyg_ass.h> // Assertion support
66 #include <stdlib.h> // Header for all stdlib functions
69 #ifdef CYGSEM_LIBC_PER_THREAD_RAND
70 # include <pkgconf/kernel.h> // kernel configuration
71 # include <cyg/kernel/thread.hxx> // per-thread data
72 # include <cyg/kernel/thread.inl> // per-thread data
73 # include <cyg/kernel/mutex.hxx> // mutexes
78 #if defined(CYGDBG_USE_TRACING) && defined(CYGNUM_LIBC_RAND_TRACE_LEVEL)
79 static int rand_trace = CYGNUM_LIBC_RAND_TRACE_LEVEL;
80 # define TL1 (0 < rand_trace)
88 #ifdef CYGSEM_LIBC_PER_THREAD_RAND
89 static Cyg_Thread::cyg_data_index
90 rand_data_index=CYGNUM_KERNEL_THREADS_DATA_MAX;
92 static Cyg_Mutex rand_data_mutex CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_LIBC);
94 static unsigned int cyg_libc_rand_seed = CYGNUM_LIBC_RAND_SEED;
102 unsigned int *seed_p;
105 CYG_REPORT_FUNCNAMETYPE( "rand", "returning %d" );
107 // get seed for this thread (if relevant )
108 #ifdef CYGSEM_LIBC_PER_THREAD_RAND
109 Cyg_Thread *self = Cyg_Thread::self();
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
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) {
118 // FIXME: Should use real CDL to pre-allocate a slot at compile
119 // time to ensure there are enough slots
120 rand_data_index = self->new_data_index();
121 CYG_ASSERT(rand_data_index >= 0, "failed to allocate data index" );
124 self->set_data(rand_data_index, CYGNUM_LIBC_RAND_SEED);
126 rand_data_mutex.unlock();
129 // we have a valid index now
131 seed_p = (unsigned int *)self->get_data_ptr(rand_data_index);
133 seed_p = &cyg_libc_rand_seed;
136 CYG_TRACE2( TL1, "Retrieved seed address %08x containing %d",
138 CYG_CHECK_DATA_PTR( seed_p, "Help! Returned address of seed is invalid!" );
140 retval = rand_r( seed_p );
142 CYG_REPORT_RETVAL( retval );
150 rand_r( unsigned int *seed )
154 CYG_REPORT_FUNCNAMETYPE( "rand_r", "returning %d" );
156 CYG_CHECK_DATA_PTR( seed, "pointer to seed invalid!" );
158 #if defined(CYGIMP_LIBC_RAND_SIMPLEST)
160 // This algorithm sucks in the lower bits
162 *seed = (*seed * 1103515245) + 12345; // permutate seed
164 retval = (int)( *seed & RAND_MAX );
166 #elif defined(CYGIMP_LIBC_RAND_SIMPLE1)
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
171 unsigned int s=*seed;
174 s = (s * 1103515245) + 12345; // permutate seed
175 // Only use top 11 bits
176 uret = s & 0xffe00000;
178 s = (s * 1103515245) + 12345; // permutate seed
179 // Only use top 14 bits
180 uret += (s & 0xfffc0000) >> 11;
182 s = (s * 1103515245) + 12345; // permutate seed
183 // Only use top 7 bits
184 uret += (s & 0xfe000000) >> (11+14);
186 retval = (int)(uret & RAND_MAX);
189 #elif defined(CYGIMP_LIBC_RAND_KNUTH1)
191 // This is the code supplied in Knuth Vol 2 section 3.6 p.185 bottom
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
198 *seed = AA*(*seed % QQ) - RR*(unsigned int)(*seed/QQ);
202 retval = (int)( *seed & RAND_MAX );
205 # error No valid implementation for rand()!
208 CYG_REPORT_RETVAL( retval );
216 srand( unsigned int seed )
218 CYG_REPORT_FUNCNAME( "srand" );
220 CYG_REPORT_FUNCARG1DV( (int)seed );
222 // get seed for this thread ( if relevant )
223 #ifdef CYGSEM_LIBC_PER_THREAD_RAND
224 Cyg_Thread *self = Cyg_Thread::self();
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
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) {
233 // FIXME: Should use real CDL to pre-allocate a slot at compile
234 // time to ensure there are enough slots
235 rand_data_index = self->new_data_index();
236 CYG_ASSERT(rand_data_index >= 0, "failed to allocate data index" );
238 rand_data_mutex.unlock();
241 // we have a valid index now
243 self->set_data(rand_data_index, (CYG_ADDRWORD) seed);
245 cyg_libc_rand_seed = seed;