Skip to content

Commit e911ee3

Browse files
author
Sascha Schumann
committed
Make rand.c thread-safe.
1 parent 9ac3e94 commit e911ee3

File tree

3 files changed

+47
-24
lines changed

3 files changed

+47
-24
lines changed

ext/standard/basic_functions.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,11 +363,19 @@ static int _php3_putenv_destructor(putenv_entry *pe)
363363

364364
void test_class_startup(void);
365365

366+
static void basic_globals_ctor(BLS_D)
367+
{
368+
BG(next) = NULL;
369+
BG(left) = -1;
370+
}
371+
366372
PHP_MINIT_FUNCTION(basic)
367373
{
368374
ELS_FETCH();
369375
#ifdef ZTS
370-
basic_globals_id = ts_allocate_id(sizeof(php_basic_globals), NULL, NULL);
376+
basic_globals_id = ts_allocate_id(sizeof(php_basic_globals), (ts_allocate_ctor) basic_globals_ctor, NULL);
377+
#else
378+
basic_globals_ctor(BLS_C);
371379
#endif
372380

373381
REGISTER_DOUBLE_CONSTANT("M_PI", M_PI, CONST_CS | CONST_PERSISTENT);

ext/standard/basic_functions.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ typedef unsigned int php_stat_len;
111111
typedef int php_stat_len;
112112
#endif
113113

114+
#if SIZEOF_INT == 4
115+
/* Most 32-bit and 64-bit systems have 32-bit ints */
116+
typedef unsigned int uint32;
117+
#elif SIZEOF_LONG == 4
118+
/* 16-bit systems? */
119+
typedef unsigned long uint32;
120+
#else
121+
#error Need type which holds 32 bits
122+
#endif
123+
124+
#define MT_N (624)
125+
114126
typedef struct {
115127
HashTable *user_shutdown_function_names;
116128
HashTable putenv_ht;
@@ -132,6 +144,11 @@ typedef struct {
132144
php_stat_len CurrentStatLength;
133145
struct stat sb;
134146
struct stat lsb;
147+
148+
/* rand.c */
149+
uint32 state[MT_N+1]; /* state vector + 1 extra to not violate ANSI C */
150+
uint32 *next; /* next random value is computed from here */
151+
int left; /* can *next++ this many times before reloading */
135152
} php_basic_globals;
136153

137154
#ifdef ZTS

ext/standard/rand.c

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#include "phpmath.h"
2828
#include "php_rand.h"
2929

30+
#include "basic_functions.h"
31+
3032
/*
3133
This is the ``Mersenne Twister'' random number generator MT19937, which
3234
generates pseudorandom integers uniformly distributed in 0..(2^32 - 1)
@@ -77,26 +79,20 @@
7779
uint32 must be an unsigned integer type capable of holding at least 32
7880
bits; exactly 32 should be fastest, but 64 is better on an Alpha with
7981
GCC at -O3 optimization so try your options and see what's best for you
80-
82+
8183
Melo: we should put some ifdefs here to catch those alphas...
8284
*/
8385

84-
typedef unsigned int uint32;
8586

86-
#define N (624) /* length of state vector */
87+
#define N MT_N /* length of state vector */
8788
#define M (397) /* a period parameter */
8889
#define K (0x9908B0DFU) /* a magic constant */
8990
#define hiBit(u) ((u) & 0x80000000U) /* mask all but highest bit of u */
9091
#define loBit(u) ((u) & 0x00000001U) /* mask all but lowest bit of u */
9192
#define loBits(u) ((u) & 0x7FFFFFFFU) /* mask the highest bit of u */
9293
#define mixBits(u, v) (hiBit(u)|loBits(v)) /* move hi bit of u to hi bit of v */
9394

94-
static uint32 state[N+1]; /* state vector + 1 extra to not violate ANSI C */
95-
static uint32 *next; /* next random value is computed from here */
96-
static int left = -1; /* can *next++ this many times before reloading */
97-
98-
99-
static void seedMT(uint32 seed)
95+
static void seedMT(uint32 seed BLS_DC)
10096
{
10197
/*
10298
We initialize state[0..(N-1)] via the generator
@@ -144,31 +140,31 @@ static void seedMT(uint32 seed)
144140
so-- that's why the only change I made is to restrict to odd seeds.
145141
*/
146142

147-
register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = state;
143+
register uint32 x = (seed | 1U) & 0xFFFFFFFFU, *s = BG(state);
148144
register int j;
149145

150-
for(left=0, *s++=x, j=N; --j;
146+
for(BG(left)=0, *s++=x, j=N; --j;
151147
*s++ = (x*=69069U) & 0xFFFFFFFFU);
152148
}
153149

154150

155-
static uint32 reloadMT(void)
151+
static uint32 reloadMT(BLS_D)
156152
{
157-
register uint32 *p0=state, *p2=state+2, *pM=state+M, s0, s1;
153+
register uint32 *p0=BG(state), *p2=BG(state)+2, *pM=BG(state)+M, s0, s1;
158154
register int j;
159155

160-
if(left < -1)
161-
seedMT(4357U);
156+
if(BG(left) < -1)
157+
seedMT(4357U BLS_CC);
162158

163-
left=N-1, next=state+1;
159+
BG(left)=N-1, BG(next)=BG(state)+1;
164160

165-
for(s0=state[0], s1=state[1], j=N-M+1; --j; s0=s1, s1=*p2++)
161+
for(s0=BG(state)[0], s1=BG(state)[1], j=N-M+1; --j; s0=s1, s1=*p2++)
166162
*p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
167163

168-
for(pM=state, j=M; --j; s0=s1, s1=*p2++)
164+
for(pM=BG(state), j=M; --j; s0=s1, s1=*p2++)
169165
*p0++ = *pM++ ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
170166

171-
s1=state[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
167+
s1=BG(state)[0], *p0 = *pM ^ (mixBits(s0, s1) >> 1) ^ (loBit(s1) ? K : 0U);
172168
s1 ^= (s1 >> 11);
173169
s1 ^= (s1 << 7) & 0x9D2C5680U;
174170
s1 ^= (s1 << 15) & 0xEFC60000U;
@@ -179,11 +175,12 @@ static uint32 reloadMT(void)
179175
static inline uint32 randomMT(void)
180176
{
181177
uint32 y;
178+
BLS_FETCH();
182179

183-
if(--left < 0)
184-
return(reloadMT());
180+
if(--BG(left) < 0)
181+
return(reloadMT(BLS_C));
185182

186-
y = *next++;
183+
y = *BG(next)++;
187184
y ^= (y >> 11);
188185
y ^= (y << 7) & 0x9D2C5680U;
189186
y ^= (y << 15) & 0xEFC60000U;
@@ -217,12 +214,13 @@ PHP_FUNCTION(srand)
217214
PHP_FUNCTION(mt_srand)
218215
{
219216
pval **arg;
217+
BLS_FETCH();
220218

221219
if (ARG_COUNT(ht) != 1 || getParametersEx(1, &arg) == FAILURE) {
222220
WRONG_PARAM_COUNT;
223221
}
224222
convert_to_long_ex(arg);
225-
seedMT((*arg)->value.lval);
223+
seedMT((*arg)->value.lval BLS_CC);
226224
}
227225
/* }}} */
228226

0 commit comments

Comments
 (0)