~ubuntu-branches/ubuntu/feisty/apache2/feisty

« back to all changes in this revision

Viewing changes to srclib/apr/atomic/unix/apr_atomic.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Barth
  • Date: 2006-12-09 21:05:45 UTC
  • mfrom: (0.6.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20061209210545-h70s0xaqc2v8vqr2
Tags: 2.2.3-3.2
* Non-maintainer upload.
* 043_ajp_connection_reuse: Patch from upstream Bugzilla, fixing a critical
  issue with regard to connection reuse in mod_proxy_ajp.
  Closes: #396265

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
 
2
 * applicable.
 
3
 *
 
4
 * Licensed under the Apache License, Version 2.0 (the "License");
 
5
 * you may not use this file except in compliance with the License.
 
6
 * You may obtain a copy of the License at
 
7
 *
 
8
 *     http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
10
 * Unless required by applicable law or agreed to in writing, software
 
11
 * distributed under the License is distributed on an "AS IS" BASIS,
 
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
13
 * See the License for the specific language governing permissions and
 
14
 * limitations under the License.
 
15
 */
 
16
 
 
17
#include "apr.h"
 
18
#include "apr_atomic.h"
 
19
#include "apr_thread_mutex.h"
 
20
 
 
21
#include "apr_private.h"
 
22
 
 
23
#include <stdlib.h>
 
24
 
 
25
#if defined(__GNUC__) && defined(__STRICT_ANSI__) && !defined(USE_GENERIC_ATOMICS)
 
26
/* force use of generic atomics if building e.g. with -std=c89, which
 
27
 * doesn't allow inline asm */
 
28
#define USE_GENERIC_ATOMICS
 
29
#endif
 
30
 
 
31
#if (defined(__i386__) || defined(__x86_64__)) \
 
32
    && defined(__GNUC__) && !defined(USE_GENERIC_ATOMICS)
 
33
 
 
34
APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem, 
 
35
                                           apr_uint32_t with,
 
36
                                           apr_uint32_t cmp)
 
37
{
 
38
    apr_uint32_t prev;
 
39
 
 
40
    asm volatile ("lock; cmpxchgl %1, %2"             
 
41
                  : "=a" (prev)               
 
42
                  : "r" (with), "m" (*(mem)), "0"(cmp) 
 
43
                  : "memory", "cc");
 
44
    return prev;
 
45
}
 
46
#define APR_OVERRIDE_ATOMIC_CAS32
 
47
 
 
48
static apr_uint32_t inline intel_atomic_add32(volatile apr_uint32_t *mem, 
 
49
                                              apr_uint32_t val)
 
50
{
 
51
    asm volatile ("lock; xaddl %0,%1"
 
52
                  : "=r"(val), "=m"(*mem) /* outputs */
 
53
                  : "0"(val), "m"(*mem)   /* inputs */
 
54
                  : "memory", "cc");
 
55
    return val;
 
56
}
 
57
 
 
58
APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem, 
 
59
                                           apr_uint32_t val)
 
60
{
 
61
    return intel_atomic_add32(mem, val);
 
62
}
 
63
#define APR_OVERRIDE_ATOMIC_ADD32
 
64
 
 
65
APR_DECLARE(void) apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
66
{
 
67
    asm volatile ("lock; subl %1, %0"
 
68
                  :
 
69
                  : "m" (*(mem)), "r" (val)
 
70
                  : "memory", "cc");
 
71
}
 
72
#define APR_OVERRIDE_ATOMIC_SUB32
 
73
 
 
74
APR_DECLARE(int) apr_atomic_dec32(volatile apr_uint32_t *mem)
 
75
{
 
76
    unsigned char prev;
 
77
 
 
78
    asm volatile ("lock; decl %1;\n\t"
 
79
                  "setnz %%al"
 
80
                  : "=a" (prev)
 
81
                  : "m" (*(mem))
 
82
                  : "memory", "cc");
 
83
    return prev;
 
84
}
 
85
#define APR_OVERRIDE_ATOMIC_DEC32
 
86
 
 
87
APR_DECLARE(apr_uint32_t) apr_atomic_inc32(volatile apr_uint32_t *mem)
 
88
{
 
89
    return intel_atomic_add32(mem, 1);
 
90
}
 
91
#define APR_OVERRIDE_ATOMIC_INC32
 
92
 
 
93
APR_DECLARE(void) apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
94
{
 
95
    *mem = val;
 
96
}
 
97
#define APR_OVERRIDE_ATOMIC_SET32
 
98
 
 
99
APR_DECLARE(apr_uint32_t) apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
100
{
 
101
    apr_uint32_t prev = val;
 
102
 
 
103
    asm volatile ("lock; xchgl %0, %1"
 
104
                  : "=r" (prev)
 
105
                  : "m" (*(mem)), "0"(prev)
 
106
                  : "memory");
 
107
    return prev;
 
108
}
 
109
#define APR_OVERRIDE_ATOMIC_XCHG32
 
110
 
 
111
/*#define apr_atomic_init(pool)        APR_SUCCESS*/
 
112
 
 
113
#endif /* (__linux__ || __EMX__ || __FreeBSD__) && __i386__ */
 
114
 
 
115
#if (defined(__PPC__) || defined(__ppc__)) && defined(__GNUC__) \
 
116
    && !defined(USE_GENERIC_ATOMICS)
 
117
 
 
118
APR_DECLARE(apr_uint32_t) apr_atomic_cas32(volatile apr_uint32_t *mem,
 
119
                                           apr_uint32_t swap,
 
120
                                           apr_uint32_t cmp)
 
121
{
 
122
    apr_uint32_t prev;
 
123
                                                                                
 
124
    asm volatile ("0:\n\t"                   /* retry local label     */
 
125
                  "lwarx  %0,0,%1\n\t"       /* load prev and reserve */
 
126
                  "cmpw   %0,%3\n\t"         /* does it match cmp?    */
 
127
                  "bne-   1f\n\t"            /* ...no, bail out       */
 
128
                  "stwcx. %2,0,%1\n\t"       /* ...yes, conditionally
 
129
                                                store swap            */
 
130
                  "bne-   0b\n\t"            /* start over if we lost
 
131
                                                the reservation       */
 
132
                  "1:"                       /* exit local label      */
 
133
 
 
134
                  : "=&r"(prev)                        /* output      */
 
135
                  : "b" (mem), "r" (swap), "r"(cmp)    /* inputs      */
 
136
                  : "memory", "cc");                   /* clobbered   */
 
137
    return prev;
 
138
}
 
139
#define APR_OVERRIDE_ATOMIC_CAS32
 
140
 
 
141
APR_DECLARE(apr_uint32_t) apr_atomic_add32(volatile apr_uint32_t *mem,
 
142
                                           apr_uint32_t delta)
 
143
{
 
144
    apr_uint32_t prev, temp;
 
145
                                                                                
 
146
    asm volatile ("0:\n\t"                   /* retry local label     */
 
147
                  "lwarx  %0,0,%2\n\t"       /* load prev and reserve */
 
148
                  "add    %1,%0,%3\n\t"      /* temp = prev + delta   */
 
149
                  "stwcx. %1,0,%2\n\t"       /* conditionally store   */
 
150
                  "bne-   0b"                /* start over if we lost
 
151
                                                the reservation       */
 
152
 
 
153
                  /*XXX find a cleaner way to define the temp         
 
154
                   *    it's not an output
 
155
                   */
 
156
                  : "=&r" (prev), "=&r" (temp)        /* output, temp */
 
157
                  : "b" (mem), "r" (delta)            /* inputs       */
 
158
                  : "memory", "cc");                  /* clobbered    */
 
159
    return prev;
 
160
}
 
161
#define APR_OVERRIDE_ATOMIC_ADD32
 
162
 
 
163
#endif /* __PPC__ && __GNUC__ */
 
164
 
 
165
#if !defined(APR_OVERRIDE_ATOMIC_INIT)
 
166
 
 
167
#if APR_HAS_THREADS
 
168
#define NUM_ATOMIC_HASH 7
 
169
/* shift by 2 to get rid of alignment issues */
 
170
#define ATOMIC_HASH(x) (unsigned int)(((unsigned long)(x)>>2)%(unsigned int)NUM_ATOMIC_HASH)
 
171
static apr_thread_mutex_t **hash_mutex;
 
172
#endif /* APR_HAS_THREADS */
 
173
 
 
174
apr_status_t apr_atomic_init(apr_pool_t *p)
 
175
{
 
176
#if APR_HAS_THREADS
 
177
    int i;
 
178
    apr_status_t rv;
 
179
    hash_mutex = apr_palloc(p, sizeof(apr_thread_mutex_t*) * NUM_ATOMIC_HASH);
 
180
 
 
181
    for (i = 0; i < NUM_ATOMIC_HASH; i++) {
 
182
        rv = apr_thread_mutex_create(&(hash_mutex[i]),
 
183
                                     APR_THREAD_MUTEX_DEFAULT, p);
 
184
        if (rv != APR_SUCCESS) {
 
185
           return rv;
 
186
        }
 
187
    }
 
188
#endif /* APR_HAS_THREADS */
 
189
    return APR_SUCCESS;
 
190
}
 
191
#endif /* !defined(APR_OVERRIDE_ATOMIC_INIT) */
 
192
 
 
193
/* abort() if 'x' does not evaluate to APR_SUCCESS. */
 
194
#define CHECK(x) do { if ((x) != APR_SUCCESS) abort(); } while (0)
 
195
 
 
196
#if !defined(APR_OVERRIDE_ATOMIC_ADD32)
 
197
#if defined(APR_OVERRIDE_ATOMIC_CAS32)
 
198
apr_uint32_t apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
199
{
 
200
    apr_uint32_t old_value, new_value;
 
201
    
 
202
    do {
 
203
        old_value = *mem;
 
204
        new_value = old_value + val;
 
205
    } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
 
206
    return old_value;
 
207
}
 
208
#else
 
209
apr_uint32_t apr_atomic_add32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
210
{
 
211
    apr_uint32_t old_value;
 
212
 
 
213
#if APR_HAS_THREADS
 
214
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
215
       
 
216
    CHECK(apr_thread_mutex_lock(lock));
 
217
    old_value = *mem;
 
218
    *mem += val;
 
219
    CHECK(apr_thread_mutex_unlock(lock));
 
220
#else
 
221
    old_value = *mem;
 
222
    *mem += val;
 
223
#endif /* APR_HAS_THREADS */
 
224
    return old_value;
 
225
}
 
226
#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
 
227
#endif /* !defined(APR_OVERRIDE_ATOMIC_ADD32) */
 
228
 
 
229
#if !defined(APR_OVERRIDE_ATOMIC_SUB32)
 
230
#if defined(APR_OVERRIDE_ATOMIC_CAS32)
 
231
void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
232
{
 
233
    apr_uint32_t old_value, new_value;
 
234
    
 
235
    do {
 
236
        old_value = *mem;
 
237
        new_value = old_value - val;
 
238
    } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
 
239
}
 
240
#else
 
241
void apr_atomic_sub32(volatile apr_uint32_t *mem, apr_uint32_t val) 
 
242
{
 
243
#if APR_HAS_THREADS
 
244
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
245
       
 
246
    CHECK(apr_thread_mutex_lock(lock));
 
247
    *mem -= val;
 
248
    CHECK(apr_thread_mutex_unlock(lock));
 
249
#else
 
250
    *mem -= val;
 
251
#endif /* APR_HAS_THREADS */
 
252
}
 
253
#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
 
254
#endif /* !defined(APR_OVERRIDE_ATOMIC_SUB32) */
 
255
 
 
256
#if !defined(APR_OVERRIDE_ATOMIC_SET32)
 
257
void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val) 
 
258
{
 
259
#if APR_HAS_THREADS
 
260
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
261
 
 
262
    CHECK(apr_thread_mutex_lock(lock));
 
263
    *mem = val;
 
264
    CHECK(apr_thread_mutex_unlock(lock));
 
265
#else
 
266
    *mem = val;
 
267
#endif /* APR_HAS_THREADS */
 
268
}
 
269
#endif /* !defined(APR_OVERRIDE_ATOMIC_SET32) */
 
270
 
 
271
#if !defined(APR_OVERRIDE_ATOMIC_INC32)
 
272
apr_uint32_t apr_atomic_inc32(volatile apr_uint32_t *mem) 
 
273
{
 
274
    return apr_atomic_add32(mem, 1);
 
275
}
 
276
#endif /* !defined(APR_OVERRIDE_ATOMIC_INC32) */
 
277
 
 
278
#if !defined(APR_OVERRIDE_ATOMIC_DEC32)
 
279
#if defined(APR_OVERRIDE_ATOMIC_CAS32)
 
280
int apr_atomic_dec32(volatile apr_uint32_t *mem)
 
281
{
 
282
    apr_uint32_t old_value, new_value;
 
283
    
 
284
    do {
 
285
        old_value = *mem;
 
286
        new_value = old_value - 1;
 
287
    } while (apr_atomic_cas32(mem, new_value, old_value) != old_value);
 
288
    return old_value != 1;
 
289
}
 
290
#else
 
291
int apr_atomic_dec32(volatile apr_uint32_t *mem) 
 
292
{
 
293
#if APR_HAS_THREADS
 
294
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
295
    apr_uint32_t new;
 
296
 
 
297
    CHECK(apr_thread_mutex_lock(lock));
 
298
    (*mem)--;
 
299
    new = *mem;
 
300
    CHECK(apr_thread_mutex_unlock(lock));
 
301
    return new;
 
302
#else
 
303
    (*mem)--;
 
304
    return *mem; 
 
305
#endif /* APR_HAS_THREADS */
 
306
}
 
307
#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
 
308
#endif /* !defined(APR_OVERRIDE_ATOMIC_DEC32) */
 
309
 
 
310
#if !defined(APR_OVERRIDE_ATOMIC_CAS32)
 
311
apr_uint32_t apr_atomic_cas32(volatile apr_uint32_t *mem, apr_uint32_t with,
 
312
                              apr_uint32_t cmp)
 
313
{
 
314
    apr_uint32_t prev;
 
315
#if APR_HAS_THREADS
 
316
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
317
 
 
318
    CHECK(apr_thread_mutex_lock(lock));
 
319
    prev = *mem;
 
320
    if (prev == cmp) {
 
321
        *mem = with;
 
322
    }
 
323
    CHECK(apr_thread_mutex_unlock(lock));
 
324
#else
 
325
    prev = *mem;
 
326
    if (prev == cmp) {
 
327
        *mem = with;
 
328
    }
 
329
#endif /* APR_HAS_THREADS */
 
330
    return prev;
 
331
}
 
332
#endif /* !defined(APR_OVERRIDE_ATOMIC_CAS32) */
 
333
 
 
334
#if !defined(APR_OVERRIDE_ATOMIC_XCHG32)
 
335
#if defined(APR_OVERRIDE_ATOMIC_CAS32)
 
336
apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
337
{
 
338
    apr_uint32_t prev;
 
339
    do {
 
340
        prev = *mem;
 
341
    } while (apr_atomic_cas32(mem, val, prev) != prev);
 
342
    return prev;
 
343
}
 
344
#else
 
345
apr_uint32_t apr_atomic_xchg32(volatile apr_uint32_t *mem, apr_uint32_t val)
 
346
{
 
347
    apr_uint32_t prev;
 
348
#if APR_HAS_THREADS
 
349
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
350
 
 
351
    CHECK(apr_thread_mutex_lock(lock));
 
352
    prev = *mem;
 
353
    *mem = val;
 
354
    CHECK(apr_thread_mutex_unlock(lock));
 
355
#else
 
356
    prev = *mem;
 
357
    *mem = val;
 
358
#endif /* APR_HAS_THREADS */
 
359
    return prev;
 
360
}
 
361
#endif /* defined(APR_OVERRIDE_ATOMIC_CAS32) */
 
362
#endif /* !defined(APR_OVERRIDE_ATOMIC_XCHG32) */
 
363
 
 
364
#if !defined(APR_OVERRIDE_ATOMIC_CASPTR)
 
365
void *apr_atomic_casptr(volatile void **mem, void *with, const void *cmp)
 
366
{
 
367
    void *prev;
 
368
#if APR_HAS_THREADS
 
369
    apr_thread_mutex_t *lock = hash_mutex[ATOMIC_HASH(mem)];
 
370
 
 
371
    CHECK(apr_thread_mutex_lock(lock));
 
372
    prev = *(void **)mem;
 
373
    if (prev == cmp) {
 
374
        *mem = with;
 
375
    }
 
376
    CHECK(apr_thread_mutex_unlock(lock));
 
377
#else
 
378
    prev = *(void **)mem;
 
379
    if (prev == cmp) {
 
380
        *mem = with;
 
381
    }
 
382
#endif /* APR_HAS_THREADS */
 
383
    return prev;
 
384
}
 
385
#endif /* !defined(APR_OVERRIDE_ATOMIC_CASPTR) */
 
386
 
 
387
#if !defined(APR_OVERRIDE_ATOMIC_READ32)
 
388
APR_DECLARE(apr_uint32_t) apr_atomic_read32(volatile apr_uint32_t *mem)
 
389
{
 
390
    return *mem;
 
391
}
 
392
#endif
 
393