]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/language/c/libc/stdlib/v2_0/src/rand.cxx
Initial revision
[karo-tx-redboot.git] / packages / language / c / libc / stdlib / v2_0 / src / rand.cxx
1 //===========================================================================
2 //
3 //      rand.cxx
4 //
5 //      ISO and POSIX 1003.1 standard random number generation functions
6 //
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.
12 //
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.
16 //
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
20 // for more details.
21 //
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.
25 //
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.
32 //
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.
35 //
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####
42 //
43 // Author(s):     jlarmour
44 // Contributors:  
45 // Date:          2000-04-30
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
51 // Usage:       
52 //
53 //####DESCRIPTIONEND####
54 //
55 //===========================================================================
56
57 // CONFIGURATION
58
59 #include <pkgconf/libc_stdlib.h>   // Configuration header
60
61 // INCLUDES
62
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
67                                    // (like this one)
68
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
74 #endif
75
76 // TRACE
77
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)
81 #else
82 # define TL1 (0)
83 #endif
84
85
86 // STATICS
87
88 #ifdef CYGSEM_LIBC_PER_THREAD_RAND
89 static Cyg_Thread::cyg_data_index
90 rand_data_index=CYGNUM_KERNEL_THREADS_DATA_MAX;
91
92 static Cyg_Mutex rand_data_mutex CYGBLD_ATTRIB_INIT_PRI(CYG_INIT_LIBC);
93 #else
94 static unsigned int cyg_libc_rand_seed = CYGNUM_LIBC_RAND_SEED;
95 #endif
96
97 // FUNCTIONS
98
99 int
100 rand( void )
101 {
102     unsigned int *seed_p;
103     int retval;
104
105     CYG_REPORT_FUNCNAMETYPE( "rand", "returning %d" );
106
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) {
117
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" );
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
135
136     CYG_TRACE2( TL1, "Retrieved seed address %08x containing %d",
137                 seed_p, *seed_p );
138     CYG_CHECK_DATA_PTR( seed_p, "Help! Returned address of seed is invalid!" );
139
140     retval = rand_r( seed_p );
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
158 #if defined(CYGIMP_LIBC_RAND_SIMPLEST)
159
160     // This algorithm sucks in the lower bits
161
162     *seed = (*seed * 1103515245) + 12345; // permutate seed
163     
164     retval = (int)( *seed & RAND_MAX );
165
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
208     CYG_REPORT_RETVAL( retval );
209
210     return retval;
211    
212 } // rand_r()
213
214
215 void
216 srand( unsigned int seed )
217 {
218     CYG_REPORT_FUNCNAME( "srand" );
219
220     CYG_REPORT_FUNCARG1DV( (int)seed );
221
222     // get seed for this thread ( if relevant )
223 #ifdef CYGSEM_LIBC_PER_THREAD_RAND
224     Cyg_Thread *self = Cyg_Thread::self();
225
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) {
232
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" );
237         }
238         rand_data_mutex.unlock();
239     } // if
240
241     // we have a valid index now
242
243     self->set_data(rand_data_index, (CYG_ADDRWORD) seed);
244 #else
245     cyg_libc_rand_seed = seed;
246 #endif
247
248     CYG_REPORT_RETURN();
249
250 } // srand()
251
252 // EOF rand.cxx