source: trunk/xcache/xc_lock.c @ 1365

Last change on this file since 1365 was 1365, checked in by moo, 13 months ago

ws fix

  • 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)
[1245]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;
[1363]69#ifdef __CYGWIN__
70    /* store the path for unlink() later */
[1]71    char *pathname;
[1363]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        lck->fd = fd;
[1363]155#ifdef __CYGWIN__
[1]156        size = strlen(pathname) + 1;
157        lck->pathname = malloc(size);
158        memcpy(lck->pathname, pathname, size);
[1363]159#else
160        unlink(pathname);
161#endif
[1]162    }
163    else {
[928]164        zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
[62]165        lck = NULL;
[1]166    }
[62]167
168    if (myname) {
[282]169        free(myname);
[62]170    }
171
[1199]172    return lck ? 1 : 0;
[1]173}
174/* }}} */
[1199]175static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
[1198]176{
[928]177    close(lck->fd);
[1]178#ifdef __CYGWIN__
179    unlink(lck->pathname);
[1363]180    free(lck->pathname);
[1]181#endif
182}
183/* }}} */
[1199]184static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
[1198]185{
[1]186    if (dolock(lck, LCK_WR) < 0) {
[928]187        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
[1]188    }
189}
190/* }}} */
[1199]191static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
[1198]192{
[1]193    if (dolock(lck, LCK_RD) < 0) {
[928]194        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
[1]195    }
196}
197/* }}} */
[1199]198static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
[1198]199{
[1]200    if (dolock(lck, LCK_UN) < 0) {
[928]201        zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
[1]202    }
203}
204/* }}} */
[1206]205#endif /* XC_LOCK_USE_FCNTL */
[1199]206
207struct _xc_lock_t {
[1206]208#ifdef XC_LOCK_USE_NOOP
[1199]209    int dummy;
[1206]210#endif
211
212#ifdef XC_LOCK_USE_TSRM
[1199]213    MUTEX_T tsrm_mutex;
[1206]214#endif
[1199]215
[1206]216#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
217    zend_bool interprocess;
218#endif
219
220#ifdef XC_LOCK_USE_PTHREAD
[1204]221    pthread_mutex_t pthread_mutex;
[1206]222#endif
223
224#ifdef XC_LOCK_USE_FCNTL
[1199]225    xc_fcntl_lock_t fcntl_lock;
226#endif
[1204]227
228#ifndef NDEBUG
229    zend_bool locked;
230#endif
[1199]231};
232
[1206]233#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
234#   define XC_LOCK_INTERPROCESS (lck->interprocess)
235#else
236#   define XC_LOCK_INTERPROCESS 1
237#endif
238
[1204]239size_t xc_lock_size(void) /* {{{ */
[1199]240{
[1204]241    return sizeof(xc_lock_t);
242}
243/* }}} */
244xc_lock_t *xc_lock_init(xc_lock_t *lck, const char *pathname, unsigned char interprocess) /* {{{ */
245{
[1206]246#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
247    lck->interprocess = interprocess;
248#endif
249
250#ifdef XC_LOCK_USE_PTHREAD
251    {
252        pthread_mutexattr_t psharedm;
253        pthread_mutexattr_init(&psharedm);
254        pthread_mutexattr_setpshared(&psharedm, XC_LOCK_INTERPROCESS ? PTHREAD_PROCESS_PRIVATE : PTHREAD_PROCESS_SHARED);
255        pthread_mutex_init(&lck->pthread_mutex, &psharedm);
256    }
257#endif
258
259#ifdef XC_LOCK_USE_TSRM
[1199]260    lck->tsrm_mutex = tsrm_mutex_alloc();
[1204]261#endif
262
[1206]263#ifdef XC_LOCK_USE_FCNTL
264    if (XC_LOCK_INTERPROCESS) {
[1199]265        xc_fcntl_init(&lck->fcntl_lock, pathname);
[1206]266    }
[1204]267#endif
268
269#ifndef NDEBUG
270    lck->locked = 0;
271#endif
272
[1199]273    return lck;
274}
275/* }}} */
276void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
277{
[1206]278#ifdef XC_LOCK_USE_PTHREAD
[1204]279    pthread_mutex_destroy(&lck->pthread_mutex);
[1206]280#endif
281
282#ifdef XC_LOCK_USE_TSRM
[1199]283    tsrm_mutex_free(lck->tsrm_mutex);
[1204]284#endif
285
[1206]286#ifdef XC_LOCK_USE_FCNTL
287    if (XC_LOCK_INTERPROCESS) {
[1199]288        xc_fcntl_destroy(&lck->fcntl_lock);
[1206]289    }
[1199]290#endif
291}
292/* }}} */
293void xc_lock(xc_lock_t *lck) /* {{{ */
294{
[1206]295#ifdef XC_LOCK_USE_PTHREAD
296    if (pthread_mutex_lock(&lck->pthread_mutex) < 0) {
297        zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
298    }
299#endif
300
301#ifdef XC_LOCK_USE_TSRM
[1199]302    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
303        zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
304    }
[1206]305#endif
306
307#ifdef XC_LOCK_USE_FCNTL
308    if (XC_LOCK_INTERPROCESS) {
[1199]309        xc_fcntl_lock(&lck->fcntl_lock);
[1206]310    }
[1199]311#endif
[1204]312
313#ifndef NDEBUG
314    assert(!lck->locked);
315    lck->locked = 1;
316    assert(lck->locked);
317#endif
[1199]318}
319/* }}} */
320void xc_rdlock(xc_lock_t *lck) /* {{{ */
321{
[1206]322#ifdef XC_LOCK_USE_PTHREAD
323    if (pthread_mutex_lock(&lck->pthread_mutex) < 0) {
324        zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
325    }
326#endif
327
328#ifdef XC_LOCK_USE_TSRM
[1199]329    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
330        zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
331    }
[1206]332#endif
333
334#ifdef XC_LOCK_USE_FCNTL
335    if (XC_LOCK_INTERPROCESS) {
[1199]336        xc_fcntl_lock(&lck->fcntl_lock);
[1206]337    }
[1199]338#endif
[1204]339
340#ifndef NDEBUG
341    assert(!lck->locked);
342    lck->locked = 1;
343    assert(lck->locked);
344#endif
[1199]345}
346/* }}} */
347void xc_unlock(xc_lock_t *lck) /* {{{ */
348{
[1204]349#ifndef NDEBUG
350    assert(lck->locked);
351    lck->locked = 0;
352    assert(!lck->locked);
353#endif
354
[1206]355#ifdef XC_LOCK_USE_FCNTL
356    if (XC_LOCK_INTERPROCESS) {
[1199]357        xc_fcntl_unlock(&lck->fcntl_lock);
[1206]358    }
[1199]359#endif
[1206]360
361#ifdef XC_LOCK_USE_TSRM
[1199]362    if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) {
363        zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
364    }
[1206]365#endif
366
367#ifdef XC_LOCK_USE_PTHREAD
368    if (pthread_mutex_unlock(&lck->pthread_mutex) < 0) {
369        zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
370    }
371#endif
[1199]372}
373/* }}} */
Note: See TracBrowser for help on using the repository browser.