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

« back to all changes in this revision

Viewing changes to srclib/apr/locks/unix/proc_mutex.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_strings.h"
 
19
#include "apr_arch_proc_mutex.h"
 
20
#include "apr_arch_file_io.h" /* for apr_mkstemp() */
 
21
 
 
22
APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
 
23
{
 
24
    return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup);
 
25
}
 
26
 
 
27
static apr_status_t proc_mutex_no_tryacquire(apr_proc_mutex_t *new_mutex)
 
28
{
 
29
    return APR_ENOTIMPL;
 
30
}
 
31
 
 
32
#if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \
 
33
    APR_HAS_PROC_PTHREAD_SERIALIZE || APR_HAS_SYSVSEM_SERIALIZE
 
34
static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex,
 
35
                                             apr_pool_t *cont,
 
36
                                             const char *fname)
 
37
{
 
38
    return APR_SUCCESS;
 
39
}
 
40
#endif    
 
41
 
 
42
#if APR_HAS_POSIXSEM_SERIALIZE
 
43
 
 
44
#ifndef SEM_FAILED
 
45
#define SEM_FAILED (-1)
 
46
#endif
 
47
 
 
48
static apr_status_t proc_mutex_posix_cleanup(void *mutex_)
 
49
{
 
50
    apr_proc_mutex_t *mutex = mutex_;
 
51
    
 
52
    if (sem_close(mutex->psem_interproc) < 0) {
 
53
        return errno;
 
54
    }
 
55
 
 
56
    return APR_SUCCESS;
 
57
}    
 
58
 
 
59
static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex,
 
60
                                            const char *fname)
 
61
{
 
62
    sem_t *psem;
 
63
    char semname[31];
 
64
    apr_time_t now;
 
65
    unsigned long sec;
 
66
    unsigned long usec;
 
67
    
 
68
    new_mutex->interproc = apr_palloc(new_mutex->pool,
 
69
                                      sizeof(*new_mutex->interproc));
 
70
    /*
 
71
     * This bogusness is to follow what appears to be the
 
72
     * lowest common denominator in Posix semaphore naming:
 
73
     *   - start with '/'
 
74
     *   - be at most 14 chars
 
75
     *   - be unique and not match anything on the filesystem
 
76
     *
 
77
     * Because of this, we ignore fname, and try our
 
78
     * own naming system. We tuck the name away, since it might
 
79
     * be useful for debugging. to  make this as robust as possible,
 
80
     * we initially try something larger (and hopefully more unique)
 
81
     * and gracefully fail down to the LCD above.
 
82
     *
 
83
     * NOTE: Darwin (Mac OS X) seems to be the most restrictive
 
84
     * implementation. Versions previous to Darwin 6.2 had the 14
 
85
     * char limit, but later rev's allow up to 31 characters.
 
86
     *
 
87
     * FIXME: There is a small window of opportunity where
 
88
     * instead of getting a new semaphore descriptor, we get
 
89
     * a previously obtained one. This can happen if the requests
 
90
     * are made at the "same time" and in the small span of time between
 
91
     * the sem_open and the sem_unlink. Use of O_EXCL does not
 
92
     * help here however...
 
93
     *
 
94
     */
 
95
    now = apr_time_now();
 
96
    sec = apr_time_sec(now);
 
97
    usec = apr_time_usec(now);
 
98
    apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec);
 
99
    psem = sem_open(semname, O_CREAT, 0644, 1);
 
100
    if ((psem == (sem_t *)SEM_FAILED) && (errno == ENAMETOOLONG)) {
 
101
        /* Oh well, good try */
 
102
        semname[13] = '\0';
 
103
        psem = sem_open(semname, O_CREAT, 0644, 1);
 
104
    }
 
105
 
 
106
    if (psem == (sem_t *)SEM_FAILED) {
 
107
        return errno;
 
108
    }
 
109
    /* Ahhh. The joys of Posix sems. Predelete it... */
 
110
    sem_unlink(semname);
 
111
    new_mutex->psem_interproc = psem;
 
112
    new_mutex->fname = apr_pstrdup(new_mutex->pool, semname);
 
113
    apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
 
114
                              apr_proc_mutex_cleanup, 
 
115
                              apr_pool_cleanup_null);
 
116
    return APR_SUCCESS;
 
117
}
 
118
 
 
119
static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex)
 
120
{
 
121
    if (sem_wait(mutex->psem_interproc) < 0) {
 
122
        return errno;
 
123
    }
 
124
    mutex->curr_locked = 1;
 
125
    return APR_SUCCESS;
 
126
}
 
127
 
 
128
static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
 
129
{
 
130
    mutex->curr_locked = 0;
 
131
    if (sem_post(mutex->psem_interproc) < 0) {
 
132
        /* any failure is probably fatal, so no big deal to leave
 
133
         * ->curr_locked at 0. */
 
134
        return errno;
 
135
    }
 
136
    return APR_SUCCESS;
 
137
}
 
138
 
 
139
static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
 
140
{
 
141
#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL)
 
142
    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 
143
#else
 
144
    0,
 
145
#endif
 
146
    proc_mutex_posix_create,
 
147
    proc_mutex_posix_acquire,
 
148
    proc_mutex_no_tryacquire,
 
149
    proc_mutex_posix_release,
 
150
    proc_mutex_posix_cleanup,
 
151
    proc_mutex_no_child_init,
 
152
    "posixsem"
 
153
};
 
154
 
 
155
#endif /* Posix sem implementation */
 
156
 
 
157
#if APR_HAS_SYSVSEM_SERIALIZE
 
158
 
 
159
static struct sembuf proc_mutex_op_on;
 
160
static struct sembuf proc_mutex_op_off;
 
161
 
 
162
static void proc_mutex_sysv_setup(void)
 
163
{
 
164
    proc_mutex_op_on.sem_num = 0;
 
165
    proc_mutex_op_on.sem_op = -1;
 
166
    proc_mutex_op_on.sem_flg = SEM_UNDO;
 
167
    proc_mutex_op_off.sem_num = 0;
 
168
    proc_mutex_op_off.sem_op = 1;
 
169
    proc_mutex_op_off.sem_flg = SEM_UNDO;
 
170
}
 
171
 
 
172
static apr_status_t proc_mutex_sysv_cleanup(void *mutex_)
 
173
{
 
174
    apr_proc_mutex_t *mutex=mutex_;
 
175
    union semun ick;
 
176
    
 
177
    if (mutex->interproc->filedes != -1) {
 
178
        ick.val = 0;
 
179
        semctl(mutex->interproc->filedes, 0, IPC_RMID, ick);
 
180
    }
 
181
    return APR_SUCCESS;
 
182
}    
 
183
 
 
184
static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex,
 
185
                                           const char *fname)
 
186
{
 
187
    union semun ick;
 
188
    apr_status_t rv;
 
189
    
 
190
    new_mutex->interproc = apr_palloc(new_mutex->pool, sizeof(*new_mutex->interproc));
 
191
    new_mutex->interproc->filedes = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
 
192
 
 
193
    if (new_mutex->interproc->filedes < 0) {
 
194
        rv = errno;
 
195
        proc_mutex_sysv_cleanup(new_mutex);
 
196
        return rv;
 
197
    }
 
198
    ick.val = 1;
 
199
    if (semctl(new_mutex->interproc->filedes, 0, SETVAL, ick) < 0) {
 
200
        rv = errno;
 
201
        proc_mutex_sysv_cleanup(new_mutex);
 
202
        return rv;
 
203
    }
 
204
    new_mutex->curr_locked = 0;
 
205
    apr_pool_cleanup_register(new_mutex->pool,
 
206
                              (void *)new_mutex, apr_proc_mutex_cleanup, 
 
207
                              apr_pool_cleanup_null);
 
208
    return APR_SUCCESS;
 
209
}
 
210
 
 
211
static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex)
 
212
{
 
213
    int rc;
 
214
 
 
215
    do {
 
216
        rc = semop(mutex->interproc->filedes, &proc_mutex_op_on, 1);
 
217
    } while (rc < 0 && errno == EINTR);
 
218
    if (rc < 0) {
 
219
        return errno;
 
220
    }
 
221
    mutex->curr_locked = 1;
 
222
    return APR_SUCCESS;
 
223
}
 
224
 
 
225
static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
 
226
{
 
227
    int rc;
 
228
 
 
229
    mutex->curr_locked = 0;
 
230
    do {
 
231
        rc = semop(mutex->interproc->filedes, &proc_mutex_op_off, 1);
 
232
    } while (rc < 0 && errno == EINTR);
 
233
    if (rc < 0) {
 
234
        return errno;
 
235
    }
 
236
    return APR_SUCCESS;
 
237
}
 
238
 
 
239
static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
 
240
{
 
241
#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL)
 
242
    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 
243
#else
 
244
    0,
 
245
#endif
 
246
    proc_mutex_sysv_create,
 
247
    proc_mutex_sysv_acquire,
 
248
    proc_mutex_no_tryacquire,
 
249
    proc_mutex_sysv_release,
 
250
    proc_mutex_sysv_cleanup,
 
251
    proc_mutex_no_child_init,
 
252
    "sysvsem"
 
253
};
 
254
 
 
255
#endif /* SysV sem implementation */
 
256
 
 
257
#if APR_HAS_PROC_PTHREAD_SERIALIZE
 
258
 
 
259
static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_)
 
260
{
 
261
    apr_proc_mutex_t *mutex=mutex_;
 
262
    apr_status_t rv;
 
263
 
 
264
    if (mutex->curr_locked == 1) {
 
265
        if ((rv = pthread_mutex_unlock(mutex->pthread_interproc))) {
 
266
#ifdef PTHREAD_SETS_ERRNO
 
267
            rv = errno;
 
268
#endif
 
269
            return rv;
 
270
        }
 
271
    }
 
272
    /* curr_locked is set to -1 until the mutex has been created */
 
273
    if (mutex->curr_locked != -1) {
 
274
        if ((rv = pthread_mutex_destroy(mutex->pthread_interproc))) {
 
275
#ifdef PTHREAD_SETS_ERRNO
 
276
            rv = errno;
 
277
#endif
 
278
            return rv;
 
279
        }
 
280
    }
 
281
    if (munmap((caddr_t)mutex->pthread_interproc, sizeof(pthread_mutex_t))) {
 
282
        return errno;
 
283
    }
 
284
    return APR_SUCCESS;
 
285
}
 
286
 
 
287
static apr_status_t proc_mutex_proc_pthread_create(apr_proc_mutex_t *new_mutex,
 
288
                                                   const char *fname)
 
289
{
 
290
    apr_status_t rv;
 
291
    int fd;
 
292
    pthread_mutexattr_t mattr;
 
293
 
 
294
    fd = open("/dev/zero", O_RDWR);
 
295
    if (fd < 0) {
 
296
        return errno;
 
297
    }
 
298
 
 
299
    new_mutex->pthread_interproc = (pthread_mutex_t *)mmap(
 
300
                                       (caddr_t) 0, 
 
301
                                       sizeof(pthread_mutex_t), 
 
302
                                       PROT_READ | PROT_WRITE, MAP_SHARED,
 
303
                                       fd, 0); 
 
304
    if (new_mutex->pthread_interproc == (pthread_mutex_t *) (caddr_t) -1) {
 
305
        close(fd);
 
306
        return errno;
 
307
    }
 
308
    close(fd);
 
309
 
 
310
    new_mutex->curr_locked = -1; /* until the mutex has been created */
 
311
 
 
312
    if ((rv = pthread_mutexattr_init(&mattr))) {
 
313
#ifdef PTHREAD_SETS_ERRNO
 
314
        rv = errno;
 
315
#endif
 
316
        proc_mutex_proc_pthread_cleanup(new_mutex);
 
317
        return rv;
 
318
    }
 
319
    if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) {
 
320
#ifdef PTHREAD_SETS_ERRNO
 
321
        rv = errno;
 
322
#endif
 
323
        proc_mutex_proc_pthread_cleanup(new_mutex);
 
324
        pthread_mutexattr_destroy(&mattr);
 
325
        return rv;
 
326
    }
 
327
 
 
328
#ifdef HAVE_PTHREAD_MUTEX_ROBUST
 
329
    if ((rv = pthread_mutexattr_setrobust_np(&mattr, 
 
330
                                               PTHREAD_MUTEX_ROBUST_NP))) {
 
331
#ifdef PTHREAD_SETS_ERRNO
 
332
        rv = errno;
 
333
#endif
 
334
        proc_mutex_proc_pthread_cleanup(new_mutex);
 
335
        pthread_mutexattr_destroy(&mattr);
 
336
        return rv;
 
337
    }
 
338
    if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) {
 
339
#ifdef PTHREAD_SETS_ERRNO
 
340
        rv = errno;
 
341
#endif
 
342
        proc_mutex_proc_pthread_cleanup(new_mutex);
 
343
        pthread_mutexattr_destroy(&mattr);
 
344
        return rv;
 
345
    }
 
346
#endif /* HAVE_PTHREAD_MUTEX_ROBUST */
 
347
 
 
348
    if ((rv = pthread_mutex_init(new_mutex->pthread_interproc, &mattr))) {
 
349
#ifdef PTHREAD_SETS_ERRNO
 
350
        rv = errno;
 
351
#endif
 
352
        proc_mutex_proc_pthread_cleanup(new_mutex);
 
353
        pthread_mutexattr_destroy(&mattr);
 
354
        return rv;
 
355
    }
 
356
 
 
357
    new_mutex->curr_locked = 0; /* mutex created now */
 
358
 
 
359
    if ((rv = pthread_mutexattr_destroy(&mattr))) {
 
360
#ifdef PTHREAD_SETS_ERRNO
 
361
        rv = errno;
 
362
#endif
 
363
        proc_mutex_proc_pthread_cleanup(new_mutex);
 
364
        return rv;
 
365
    }
 
366
 
 
367
    apr_pool_cleanup_register(new_mutex->pool,
 
368
                              (void *)new_mutex,
 
369
                              apr_proc_mutex_cleanup, 
 
370
                              apr_pool_cleanup_null);
 
371
    return APR_SUCCESS;
 
372
}
 
373
 
 
374
static apr_status_t proc_mutex_proc_pthread_acquire(apr_proc_mutex_t *mutex)
 
375
{
 
376
    apr_status_t rv;
 
377
 
 
378
    if ((rv = pthread_mutex_lock(mutex->pthread_interproc))) {
 
379
#ifdef PTHREAD_SETS_ERRNO
 
380
        rv = errno;
 
381
#endif
 
382
#ifdef HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP
 
383
        /* Okay, our owner died.  Let's try to make it consistent again. */
 
384
        if (rv == EOWNERDEAD) {
 
385
            pthread_mutex_consistent_np(mutex->pthread_interproc);
 
386
        }
 
387
        else
 
388
            return rv;
 
389
#else
 
390
        return rv;
 
391
#endif
 
392
    }
 
393
    mutex->curr_locked = 1;
 
394
    return APR_SUCCESS;
 
395
}
 
396
 
 
397
/* TODO: Add proc_mutex_proc_pthread_tryacquire(apr_proc_mutex_t *mutex) */
 
398
 
 
399
static apr_status_t proc_mutex_proc_pthread_release(apr_proc_mutex_t *mutex)
 
400
{
 
401
    apr_status_t rv;
 
402
 
 
403
    mutex->curr_locked = 0;
 
404
    if ((rv = pthread_mutex_unlock(mutex->pthread_interproc))) {
 
405
#ifdef PTHREAD_SETS_ERRNO
 
406
        rv = errno;
 
407
#endif
 
408
        return rv;
 
409
    }
 
410
    return APR_SUCCESS;
 
411
}
 
412
 
 
413
static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
 
414
{
 
415
    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 
416
    proc_mutex_proc_pthread_create,
 
417
    proc_mutex_proc_pthread_acquire,
 
418
    proc_mutex_no_tryacquire,
 
419
    proc_mutex_proc_pthread_release,
 
420
    proc_mutex_proc_pthread_cleanup,
 
421
    proc_mutex_no_child_init,
 
422
    "pthread"
 
423
};
 
424
 
 
425
#endif
 
426
 
 
427
#if APR_HAS_FCNTL_SERIALIZE
 
428
 
 
429
static struct flock proc_mutex_lock_it;
 
430
static struct flock proc_mutex_unlock_it;
 
431
 
 
432
static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
 
433
 
 
434
static void proc_mutex_fcntl_setup(void)
 
435
{
 
436
    proc_mutex_lock_it.l_whence = SEEK_SET;   /* from current point */
 
437
    proc_mutex_lock_it.l_start = 0;           /* -"- */
 
438
    proc_mutex_lock_it.l_len = 0;             /* until end of file */
 
439
    proc_mutex_lock_it.l_type = F_WRLCK;      /* set exclusive/write lock */
 
440
    proc_mutex_lock_it.l_pid = 0;             /* pid not actually interesting */
 
441
    proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */
 
442
    proc_mutex_unlock_it.l_start = 0;         /* -"- */
 
443
    proc_mutex_unlock_it.l_len = 0;           /* until end of file */
 
444
    proc_mutex_unlock_it.l_type = F_UNLCK;    /* set exclusive/write lock */
 
445
    proc_mutex_unlock_it.l_pid = 0;           /* pid not actually interesting */
 
446
}
 
447
 
 
448
static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_)
 
449
{
 
450
    apr_status_t status;
 
451
    apr_proc_mutex_t *mutex=mutex_;
 
452
 
 
453
    if (mutex->curr_locked == 1) {
 
454
        status = proc_mutex_fcntl_release(mutex);
 
455
        if (status != APR_SUCCESS)
 
456
            return status;
 
457
    }
 
458
        
 
459
    return apr_file_close(mutex->interproc);
 
460
}    
 
461
 
 
462
static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex,
 
463
                                            const char *fname)
 
464
{
 
465
    int rv;
 
466
 
 
467
    if (fname) {
 
468
        new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
 
469
        rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
 
470
                           APR_CREATE | APR_WRITE | APR_EXCL, 
 
471
                           APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD,
 
472
                           new_mutex->pool);
 
473
    }
 
474
    else {
 
475
        new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
 
476
        rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
 
477
                             APR_CREATE | APR_WRITE | APR_EXCL,
 
478
                             new_mutex->pool);
 
479
    }
 
480
 
 
481
    if (rv != APR_SUCCESS) {
 
482
        return rv;
 
483
    }
 
484
 
 
485
    new_mutex->curr_locked = 0;
 
486
    unlink(new_mutex->fname);
 
487
    apr_pool_cleanup_register(new_mutex->pool,
 
488
                              (void*)new_mutex,
 
489
                              apr_proc_mutex_cleanup, 
 
490
                              apr_pool_cleanup_null);
 
491
    return APR_SUCCESS; 
 
492
}
 
493
 
 
494
static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex)
 
495
{
 
496
    int rc;
 
497
 
 
498
    do {
 
499
        rc = fcntl(mutex->interproc->filedes, F_SETLKW, &proc_mutex_lock_it);
 
500
    } while (rc < 0 && errno == EINTR);
 
501
    if (rc < 0) {
 
502
        return errno;
 
503
    }
 
504
    mutex->curr_locked=1;
 
505
    return APR_SUCCESS;
 
506
}
 
507
 
 
508
static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
 
509
{
 
510
    int rc;
 
511
 
 
512
    mutex->curr_locked=0;
 
513
    do {
 
514
        rc = fcntl(mutex->interproc->filedes, F_SETLKW, &proc_mutex_unlock_it);
 
515
    } while (rc < 0 && errno == EINTR);
 
516
    if (rc < 0) {
 
517
        return errno;
 
518
    }
 
519
    return APR_SUCCESS;
 
520
}
 
521
 
 
522
static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
 
523
{
 
524
#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL)
 
525
    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 
526
#else
 
527
    0,
 
528
#endif
 
529
    proc_mutex_fcntl_create,
 
530
    proc_mutex_fcntl_acquire,
 
531
    proc_mutex_no_tryacquire,
 
532
    proc_mutex_fcntl_release,
 
533
    proc_mutex_fcntl_cleanup,
 
534
    proc_mutex_no_child_init,
 
535
    "fcntl"
 
536
};
 
537
 
 
538
#endif /* fcntl implementation */
 
539
 
 
540
#if APR_HAS_FLOCK_SERIALIZE
 
541
 
 
542
static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
 
543
 
 
544
static apr_status_t proc_mutex_flock_cleanup(void *mutex_)
 
545
{
 
546
    apr_status_t status;
 
547
    apr_proc_mutex_t *mutex=mutex_;
 
548
 
 
549
    if (mutex->curr_locked == 1) {
 
550
        status = proc_mutex_flock_release(mutex);
 
551
        if (status != APR_SUCCESS)
 
552
            return status;
 
553
    }
 
554
    if (mutex->interproc) { /* if it was opened properly */
 
555
        apr_file_close(mutex->interproc);
 
556
    }
 
557
    unlink(mutex->fname);
 
558
    return APR_SUCCESS;
 
559
}    
 
560
 
 
561
static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex,
 
562
                                            const char *fname)
 
563
{
 
564
    int rv;
 
565
 
 
566
    if (fname) {
 
567
        new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
 
568
        rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
 
569
                           APR_CREATE | APR_WRITE | APR_EXCL, 
 
570
                           APR_UREAD | APR_UWRITE,
 
571
                           new_mutex->pool);
 
572
    }
 
573
    else {
 
574
        new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
 
575
        rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
 
576
                             APR_CREATE | APR_WRITE | APR_EXCL,
 
577
                             new_mutex->pool);
 
578
    }
 
579
 
 
580
    if (rv != APR_SUCCESS) {
 
581
        proc_mutex_flock_cleanup(new_mutex);
 
582
        return errno;
 
583
    }
 
584
    new_mutex->curr_locked = 0;
 
585
    apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
 
586
                              apr_proc_mutex_cleanup,
 
587
                              apr_pool_cleanup_null);
 
588
    return APR_SUCCESS;
 
589
}
 
590
 
 
591
static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex)
 
592
{
 
593
    int rc;
 
594
 
 
595
    do {
 
596
        rc = flock(mutex->interproc->filedes, LOCK_EX);
 
597
    } while (rc < 0 && errno == EINTR);
 
598
    if (rc < 0) {
 
599
        return errno;
 
600
    }
 
601
    mutex->curr_locked = 1;
 
602
    return APR_SUCCESS;
 
603
}
 
604
 
 
605
static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
 
606
{
 
607
    int rc;
 
608
 
 
609
    mutex->curr_locked = 0;
 
610
    do {
 
611
        rc = flock(mutex->interproc->filedes, LOCK_UN);
 
612
    } while (rc < 0 && errno == EINTR);
 
613
    if (rc < 0) {
 
614
        return errno;
 
615
    }
 
616
    return APR_SUCCESS;
 
617
}
 
618
 
 
619
static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex,
 
620
                                                apr_pool_t *pool, 
 
621
                                                const char *fname)
 
622
{
 
623
    apr_proc_mutex_t *new_mutex;
 
624
    int rv;
 
625
 
 
626
    new_mutex = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t));
 
627
 
 
628
    memcpy(new_mutex, *mutex, sizeof *new_mutex);
 
629
    new_mutex->pool = pool;
 
630
    if (!fname) {
 
631
        fname = (*mutex)->fname;
 
632
    }
 
633
    new_mutex->fname = apr_pstrdup(pool, fname);
 
634
    rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
 
635
                       APR_WRITE, 0, new_mutex->pool);
 
636
    if (rv != APR_SUCCESS) {
 
637
        return rv;
 
638
    }
 
639
    *mutex = new_mutex;
 
640
    return APR_SUCCESS;
 
641
}
 
642
 
 
643
static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
 
644
{
 
645
#if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL)
 
646
    APR_PROCESS_LOCK_MECH_IS_GLOBAL,
 
647
#else
 
648
    0,
 
649
#endif
 
650
    proc_mutex_flock_create,
 
651
    proc_mutex_flock_acquire,
 
652
    proc_mutex_no_tryacquire,
 
653
    proc_mutex_flock_release,
 
654
    proc_mutex_flock_cleanup,
 
655
    proc_mutex_flock_child_init,
 
656
    "flock"
 
657
};
 
658
 
 
659
#endif /* flock implementation */
 
660
 
 
661
void apr_proc_mutex_unix_setup_lock(void)
 
662
{
 
663
    /* setup only needed for sysvsem and fnctl */
 
664
#if APR_HAS_SYSVSEM_SERIALIZE
 
665
    proc_mutex_sysv_setup();
 
666
#endif
 
667
#if APR_HAS_FCNTL_SERIALIZE
 
668
    proc_mutex_fcntl_setup();
 
669
#endif
 
670
}
 
671
 
 
672
static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech)
 
673
{
 
674
    switch (mech) {
 
675
    case APR_LOCK_FCNTL:
 
676
#if APR_HAS_FCNTL_SERIALIZE
 
677
        new_mutex->inter_meth = &mutex_fcntl_methods;
 
678
#else
 
679
        return APR_ENOTIMPL;
 
680
#endif
 
681
        break;
 
682
    case APR_LOCK_FLOCK:
 
683
#if APR_HAS_FLOCK_SERIALIZE
 
684
        new_mutex->inter_meth = &mutex_flock_methods;
 
685
#else
 
686
        return APR_ENOTIMPL;
 
687
#endif
 
688
        break;
 
689
    case APR_LOCK_SYSVSEM:
 
690
#if APR_HAS_SYSVSEM_SERIALIZE
 
691
        new_mutex->inter_meth = &mutex_sysv_methods;
 
692
#else
 
693
        return APR_ENOTIMPL;
 
694
#endif
 
695
        break;
 
696
    case APR_LOCK_POSIXSEM:
 
697
#if APR_HAS_POSIXSEM_SERIALIZE
 
698
        new_mutex->inter_meth = &mutex_posixsem_methods;
 
699
#else
 
700
        return APR_ENOTIMPL;
 
701
#endif
 
702
        break;
 
703
    case APR_LOCK_PROC_PTHREAD:
 
704
#if APR_HAS_PROC_PTHREAD_SERIALIZE
 
705
        new_mutex->inter_meth = &mutex_proc_pthread_methods;
 
706
#else
 
707
        return APR_ENOTIMPL;
 
708
#endif
 
709
        break;
 
710
    case APR_LOCK_DEFAULT:
 
711
#if APR_USE_FLOCK_SERIALIZE
 
712
        new_mutex->inter_meth = &mutex_flock_methods;
 
713
#elif APR_USE_SYSVSEM_SERIALIZE
 
714
        new_mutex->inter_meth = &mutex_sysv_methods;
 
715
#elif APR_USE_FCNTL_SERIALIZE
 
716
        new_mutex->inter_meth = &mutex_fcntl_methods;
 
717
#elif APR_USE_PROC_PTHREAD_SERIALIZE
 
718
        new_mutex->inter_meth = &mutex_proc_pthread_methods;
 
719
#elif APR_USE_POSIXSEM_SERIALIZE
 
720
        new_mutex->inter_meth = &mutex_posixsem_methods;
 
721
#else
 
722
        return APR_ENOTIMPL;
 
723
#endif
 
724
        break;
 
725
    default:
 
726
        return APR_ENOTIMPL;
 
727
    }
 
728
    return APR_SUCCESS;
 
729
}
 
730
 
 
731
APR_DECLARE(const char *) apr_proc_mutex_defname(void)
 
732
{
 
733
    apr_status_t rv;
 
734
    apr_proc_mutex_t mutex;
 
735
 
 
736
    if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT)) != APR_SUCCESS) {
 
737
        return "unknown";
 
738
    }
 
739
    mutex.meth = mutex.inter_meth;
 
740
 
 
741
    return apr_proc_mutex_name(&mutex);
 
742
}
 
743
   
 
744
static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname)
 
745
{
 
746
    apr_status_t rv;
 
747
 
 
748
    if ((rv = proc_mutex_choose_method(new_mutex, mech)) != APR_SUCCESS) {
 
749
        return rv;
 
750
    }
 
751
 
 
752
    new_mutex->meth = new_mutex->inter_meth;
 
753
 
 
754
    if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) {
 
755
        return rv;
 
756
    }
 
757
 
 
758
    return APR_SUCCESS;
 
759
}
 
760
 
 
761
APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
 
762
                                                const char *fname,
 
763
                                                apr_lockmech_e mech,
 
764
                                                apr_pool_t *pool)
 
765
{
 
766
    apr_proc_mutex_t *new_mutex;
 
767
    apr_status_t rv;
 
768
 
 
769
    new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
 
770
    new_mutex->pool = pool;
 
771
 
 
772
    if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS)
 
773
        return rv;
 
774
 
 
775
    *mutex = new_mutex;
 
776
    return APR_SUCCESS;
 
777
}
 
778
 
 
779
APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
 
780
                                                    const char *fname,
 
781
                                                    apr_pool_t *pool)
 
782
{
 
783
    return (*mutex)->meth->child_init(mutex, pool, fname);
 
784
}
 
785
 
 
786
APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
 
787
{
 
788
    return mutex->meth->acquire(mutex);
 
789
}
 
790
 
 
791
APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
 
792
{
 
793
    return mutex->meth->tryacquire(mutex);
 
794
}
 
795
 
 
796
APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
 
797
{
 
798
    return mutex->meth->release(mutex);
 
799
}
 
800
 
 
801
APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
 
802
{
 
803
    return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
 
804
}
 
805
 
 
806
APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
 
807
{
 
808
    return mutex->meth->name;
 
809
}
 
810
 
 
811
APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
 
812
{
 
813
    /* POSIX sems use the fname field but don't use a file,
 
814
     * so be careful. */
 
815
#if APR_HAS_FLOCK_SERIALIZE
 
816
    if (mutex->meth == &mutex_flock_methods) {
 
817
        return mutex->fname;
 
818
    }
 
819
#endif
 
820
#if APR_HAS_FCNTL_SERIALIZE
 
821
    if (mutex->meth == &mutex_fcntl_methods) {
 
822
        return mutex->fname;
 
823
    }
 
824
#endif
 
825
    return NULL;
 
826
}
 
827
 
 
828
APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
 
829
 
 
830
/* Implement OS-specific accessors defined in apr_portable.h */
 
831
 
 
832
APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
 
833
                                                apr_proc_mutex_t *pmutex)
 
834
{
 
835
#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE
 
836
    ospmutex->crossproc = pmutex->interproc->filedes;
 
837
#endif
 
838
#if APR_HAS_PROC_PTHREAD_SERIALIZE
 
839
    ospmutex->pthread_interproc = pmutex->pthread_interproc;
 
840
#endif
 
841
    return APR_SUCCESS;
 
842
}
 
843
 
 
844
APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
 
845
                                                apr_os_proc_mutex_t *ospmutex,
 
846
                                                apr_pool_t *pool)
 
847
{
 
848
    if (pool == NULL) {
 
849
        return APR_ENOPOOL;
 
850
    }
 
851
    if ((*pmutex) == NULL) {
 
852
        (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool,
 
853
                                                    sizeof(apr_proc_mutex_t));
 
854
        (*pmutex)->pool = pool;
 
855
    }
 
856
#if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE
 
857
    apr_os_file_put(&(*pmutex)->interproc, &ospmutex->crossproc, 0, pool);
 
858
#endif
 
859
#if APR_HAS_PROC_PTHREAD_SERIALIZE
 
860
    (*pmutex)->pthread_interproc = ospmutex->pthread_interproc;
 
861
#endif
 
862
    return APR_SUCCESS;
 
863
}
 
864