source: branches/3.0/xcache/xc_lock.c @ 1364

Last change on this file since 1364 was 1364, checked in by moo, 15 months ago

merge [1363] from trunk: cygwin hack unlink should be cygwin only

  • Property svn:eol-style set to native
File size: 7.4 KB
RevLine 
[1027]1#include "xc_lock.h"
2#include "xcache.h"
[1]3#include <stdio.h>
4#include <string.h>
[36]5#include <stdlib.h>
[1186]6#ifdef ZEND_WIN32
7#   include <process.h>
[1199]8#else
9#   include <unistd.h>
10#   include <fcntl.h>
11#   include <errno.h>
[1186]12#endif
[1]13
[1206]14/* {{{ detect what type of lock is needed */
15#ifdef ZTS
16#   define XC_LOCK_NEED_TS
17#endif
[1204]18
[1206]19#ifndef ZEND_WIN32
20#   define XC_LOCK_NEED_INTERPROCESS
[1204]21#endif
22
[1206]23#if defined(XC_LOCK_NEED_TS) && defined(XC_LOCK_NEED_INTERPROCESS)
24/* allow switching off interprocess support */
25#   define XC_LOCK_HAVE_INTERPROCESS_SWITCH
[1204]26#endif
27/* }}} */
28
[1206]29/* {{{ detect which lock is needed */
30#if defined(XC_LOCK_NEED_TS) && defined(XC_LOCK_NEED_INTERPROCESS)
[1246]31#   ifdef PTHREADS
[1206]32#       define XC_LOCK_USE_PTHREAD
33#       ifndef _POSIX_THREAD_PROCESS_SHARED
34#           define XC_LOCK_USE_FCNTL
35#       endif
36#   else
37#       define XC_LOCK_USE_TSRM
38#       define XC_LOCK_USE_FCNTL
39#   endif
40#elif defined(XC_LOCK_NEED_TS)
41#   define XC_LOCK_USE_TSRM
42#elif defined(XC_LOCK_NEED_INTERPROCESS)
43#   define XC_LOCK_USE_FCNTL
44#else
45#   define XC_LOCK_USE_NOOP
46#endif
47/* }}} */
[1204]48
[1206]49/* {{{ fcntl lock impl */
50#ifdef XC_LOCK_USE_FCNTL
[1]51#ifndef ZEND_WIN32
52typedef int HANDLE;
[62]53#   ifndef INVALID_HANDLE_VALUE
54#       define INVALID_HANDLE_VALUE -1
55#   endif
[928]56#else
57#   define close(h) CloseHandle(h)
58#   define open(filename, mode, permission) CreateFile(filename, \
59        GENERIC_READ | GENERIC_WRITE, \
60        FILE_SHARE_READ | FILE_SHARE_WRITE, \
61        NULL, \
62        OPEN_ALWAYS, \
63        FILE_ATTRIBUTE_NORMAL, \
64        NULL)
[1]65#endif
66
[1199]67typedef struct {
[1]68    HANDLE fd;
[1364]69#ifdef __CYGWIN__
70    /* store the path for unlink() later */
[1]71    char *pathname;
[1364]72#endif
[1199]73} xc_fcntl_lock_t;
[1]74
75#ifndef ZEND_WIN32
[11]76#   define LCK_WR F_WRLCK
77#   define LCK_RD F_RDLCK
78#   define LCK_UN F_UNLCK
79#   define LCK_NB 0
[1199]80static inline int dolock(xc_fcntl_lock_t *lck, int type)
[1198]81{
[1]82    int ret;
83    struct flock lock;
84
85    lock.l_type = type;
86    lock.l_start = 0;
87    lock.l_whence = SEEK_SET;
88    lock.l_len = 1;
89    lock.l_pid = 0;
90
91    do {
92        ret = fcntl(lck->fd, F_SETLKW, &lock);
93    } while (ret < 0 && errno == EINTR);
94    return ret;
95}
96#else
97
98#   include <win32/flock.h>
99#   include <io.h>
100#   include <fcntl.h>
101#   include <sys/types.h>
102#   include <sys/stat.h>
[928]103#   undef errno
104#   define errno GetLastError()
[11]105#   define getuid() 0
106#   define LCK_WR LOCKFILE_EXCLUSIVE_LOCK
107#   define LCK_RD 0
108#   define LCK_UN 0
109#   define LCK_NB LOCKFILE_FAIL_IMMEDIATELY
[1199]110static inline int dolock(xc_fcntl_lock_t *lck, int type)
[1198]111{
[1]112    static OVERLAPPED offset = {0, 0, 0, 0, NULL};
113
114    if (type == LCK_UN) {
[1204]115        return UnlockFileEx(lck->fd, 0, 1, 0, &offset);
[1]116    }
117    else {
[1204]118        return LockFileEx(lck->fd, type, 0, 1, 0, &offset);
[1]119    }
120}
[1199]121#endif
[1]122/* }}} */
123
[1199]124static zend_bool xc_fcntl_init(xc_fcntl_lock_t *lck, const char *pathname) /* {{{ */
[1]125{
126    HANDLE fd;
[62]127    int size;
128    char *myname;
[1]129
130    if (pathname == NULL) {
[1154]131        static int instanceId = 0;
[62]132        const char default_tmpdir[] = { DEFAULT_SLASH, 't', 'm', 'p', '\0' };
133        const char *tmpdir;
134
135        tmpdir = getenv("TEMP");
136        if (!tmpdir) {
137            tmpdir = getenv("TMP");
138            if (!tmpdir) {
139                tmpdir = default_tmpdir;
140            }
141        }
142        size = strlen(tmpdir) + sizeof("/.xcache.lock") - 1 + 3 * 10 + 100;
[282]143        myname = malloc(size);
[1154]144        snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.lock", tmpdir, DEFAULT_SLASH, (int) getuid(), (int) getpid(), ++instanceId);
[1]145        pathname = myname;
146    }
[62]147    else {
148        myname = NULL;
149    }
[1]150
[928]151    fd = open(pathname, O_RDWR|O_CREAT, 0666);
[1]152
[62]153    if (fd != INVALID_HANDLE_VALUE) {
[1]154
155        lck->fd = fd;
[1364]156#ifdef __CYGWIN__
[1]157        size = strlen(pathname) + 1;
158        lck->pathname = malloc(size);
159        memcpy(lck->pathname, pathname, size);
[1364]160#else
161        unlink(pathname);
162#endif
[1]163    }
164    else {
[928]165        zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
[62]166        lck = NULL;
[1]167    }
[62]168
169    if (myname) {
[282]170        free(myname);
[62]171    }
172
[1199]173    return lck ? 1 : 0;
[1]174}
175/* }}} */
[1199]176static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
[1198]177{
[928]178    close(lck->fd);
[1]179#ifdef __CYGWIN__
180    unlink(lck->pathname);
[1364]181    free(lck->pathname);
[1]182#endif
183}
184/* }}} */
[1199]185static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
[1198]186{
[1]187    if (dolock(lck, LCK_WR) < 0) {
[928]188        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
[1]189    }
190}
191/* }}} */
[1199]192static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
[1198]193{
[1]194    if (dolock(lck, LCK_RD) < 0) {
[928]195        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
[1]196    }
197}
198/* }}} */
[1199]199static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
[1198]200{
[1]201    if (dolock(lck, LCK_UN) < 0) {
[928]202        zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
[1]203    }
204}
205/* }}} */
[1206]206#endif /* XC_LOCK_USE_FCNTL */
[1199]207
208struct _xc_lock_t {
[1206]209#ifdef XC_LOCK_USE_NOOP
[1199]210    int dummy;
[1206]211#endif
212
213#ifdef XC_LOCK_USE_TSRM
[1199]214    MUTEX_T tsrm_mutex;
[1206]215#endif
[1199]216
[1206]217#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
218    zend_bool interprocess;
219#endif
220
221#ifdef XC_LOCK_USE_PTHREAD
[1204]222    pthread_mutex_t pthread_mutex;
[1206]223#endif
224
225#ifdef XC_LOCK_USE_FCNTL
[1199]226    xc_fcntl_lock_t fcntl_lock;
227#endif
[1204]228
229#ifndef NDEBUG
230    zend_bool locked;
231#endif
[1199]232};
233
[1206]234#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
235#   define XC_LOCK_INTERPROCESS (lck->interprocess)
236#else
237#   define XC_LOCK_INTERPROCESS 1
238#endif
239
[1204]240size_t xc_lock_size(void) /* {{{ */
[1199]241{
[1204]242    return sizeof(xc_lock_t);
243}
244/* }}} */
245xc_lock_t *xc_lock_init(xc_lock_t *lck, const char *pathname, unsigned char interprocess) /* {{{ */
246{
[1206]247#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
248    lck->interprocess = interprocess;
249#endif
250
251#ifdef XC_LOCK_USE_PTHREAD
252    {
253        pthread_mutexattr_t psharedm;
254        pthread_mutexattr_init(&psharedm);
255        pthread_mutexattr_setpshared(&psharedm, XC_LOCK_INTERPROCESS ? PTHREAD_PROCESS_PRIVATE : PTHREAD_PROCESS_SHARED);
256        pthread_mutex_init(&lck->pthread_mutex, &psharedm);
257    }
258#endif
259
260#ifdef XC_LOCK_USE_TSRM
[1199]261    lck->tsrm_mutex = tsrm_mutex_alloc();
[1204]262#endif
263
[1206]264#ifdef XC_LOCK_USE_FCNTL
265    if (XC_LOCK_INTERPROCESS) {
[1199]266        xc_fcntl_init(&lck->fcntl_lock, pathname);
[1206]267    }
[1204]268#endif
269
270#ifndef NDEBUG
271    lck->locked = 0;
272#endif
273
[1199]274    return lck;
275}
276/* }}} */
277void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
278{
[1206]279#ifdef XC_LOCK_USE_PTHREAD
[1204]280    pthread_mutex_destroy(&lck->pthread_mutex);
[1206]281#endif
282
283#ifdef XC_LOCK_USE_TSRM
[1199]284    tsrm_mutex_free(lck->tsrm_mutex);
[1204]285#endif
286
[1206]287#ifdef XC_LOCK_USE_FCNTL
288    if (XC_LOCK_INTERPROCESS) {
[1199]289        xc_fcntl_destroy(&lck->fcntl_lock);
[1206]290    }
[1199]291#endif
292}
293/* }}} */
294void xc_lock(xc_lock_t *lck) /* {{{ */
295{
[1206]296#ifdef XC_LOCK_USE_PTHREAD
297    if (pthread_mutex_lock(&lck->pthread_mutex) < 0) {
298        zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
299    }
300#endif
301
302#ifdef XC_LOCK_USE_TSRM
[1199]303    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
304        zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
305    }
[1206]306#endif
307
308#ifdef XC_LOCK_USE_FCNTL
309    if (XC_LOCK_INTERPROCESS) {
[1199]310        xc_fcntl_lock(&lck->fcntl_lock);
[1206]311    }
[1199]312#endif
[1204]313
314#ifndef NDEBUG
315    assert(!lck->locked);
316    lck->locked = 1;
317    assert(lck->locked);
318#endif
[1199]319}
320/* }}} */
321void xc_rdlock(xc_lock_t *lck) /* {{{ */
322{
[1206]323#ifdef XC_LOCK_USE_PTHREAD
324    if (pthread_mutex_lock(&lck->pthread_mutex) < 0) {
325        zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
326    }
327#endif
328
329#ifdef XC_LOCK_USE_TSRM
[1199]330    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
331        zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
332    }
[1206]333#endif
334
335#ifdef XC_LOCK_USE_FCNTL
336    if (XC_LOCK_INTERPROCESS) {
[1199]337        xc_fcntl_lock(&lck->fcntl_lock);
[1206]338    }
[1199]339#endif
[1204]340
341#ifndef NDEBUG
342    assert(!lck->locked);
343    lck->locked = 1;
344    assert(lck->locked);
345#endif
[1199]346}
347/* }}} */
348void xc_unlock(xc_lock_t *lck) /* {{{ */
349{
[1204]350#ifndef NDEBUG
351    assert(lck->locked);
352    lck->locked = 0;
353    assert(!lck->locked);
354#endif
355
[1206]356#ifdef XC_LOCK_USE_FCNTL
357    if (XC_LOCK_INTERPROCESS) {
[1199]358        xc_fcntl_unlock(&lck->fcntl_lock);
[1206]359    }
[1199]360#endif
[1206]361
362#ifdef XC_LOCK_USE_TSRM
[1199]363    if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) {
364        zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
365    }
[1206]366#endif
367
368#ifdef XC_LOCK_USE_PTHREAD
369    if (pthread_mutex_unlock(&lck->pthread_mutex) < 0) {
370        zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
371    }
372#endif
[1199]373}
374/* }}} */
Note: See TracBrowser for help on using the repository browser.