source: trunk/xcache/xc_lock.c @ 1204

Last change on this file since 1204 was 1204, checked in by moo, 20 months ago

finished improve stability on threaded env

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