source: trunk/xcache/xc_lock.c @ 1204

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

finished improve stability on threaded env

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1#include "xc_lock.h"
2#include "xcache.h"
3#include <stdio.h>
4#include <string.h>
5#include <stdlib.h>
6#ifdef ZEND_WIN32
7#   include <process.h>
8#else
9#   include <unistd.h>
10#   include <fcntl.h>
11#   include <errno.h>
12#endif
13
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
33#ifndef ZEND_WIN32
34typedef int HANDLE;
35#   ifndef INVALID_HANDLE_VALUE
36#       define INVALID_HANDLE_VALUE -1
37#   endif
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)
47#endif
48
49typedef struct {
50    HANDLE fd;
51    char *pathname;
52} xc_fcntl_lock_t;
53
54/* {{{ fcntl lock impl */
55#ifndef ZEND_WIN32
56#   define LCK_WR F_WRLCK
57#   define LCK_RD F_RDLCK
58#   define LCK_UN F_UNLCK
59#   define LCK_NB 0
60static inline int dolock(xc_fcntl_lock_t *lck, int type)
61{
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>
83#   undef errno
84#   define errno GetLastError()
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
90static inline int dolock(xc_fcntl_lock_t *lck, int type)
91{
92    static OVERLAPPED offset = {0, 0, 0, 0, NULL};
93
94    if (type == LCK_UN) {
95        return UnlockFileEx(lck->fd, 0, 1, 0, &offset);
96    }
97    else {
98        return LockFileEx(lck->fd, type, 0, 1, 0, &offset);
99    }
100}
101#endif
102/* }}} */
103
104static zend_bool xc_fcntl_init(xc_fcntl_lock_t *lck, const char *pathname) /* {{{ */
105{
106    HANDLE fd;
107    int size;
108    char *myname;
109
110    if (pathname == NULL) {
111        static int instanceId = 0;
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;
123        myname = malloc(size);
124        snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.lock", tmpdir, DEFAULT_SLASH, (int) getuid(), (int) getpid(), ++instanceId);
125        pathname = myname;
126    }
127    else {
128        myname = NULL;
129    }
130
131    fd = open(pathname, O_RDWR|O_CREAT, 0666);
132
133    if (fd != INVALID_HANDLE_VALUE) {
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 {
144        zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
145        lck = NULL;
146    }
147
148    if (myname) {
149        free(myname);
150    }
151
152    return lck ? 1 : 0;
153}
154/* }}} */
155static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
156{
157    close(lck->fd);
158#ifdef __CYGWIN__
159    unlink(lck->pathname);
160#endif
161    free(lck->pathname);
162}
163/* }}} */
164static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
165{
166    if (dolock(lck, LCK_WR) < 0) {
167        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
168    }
169}
170/* }}} */
171static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
172{
173    if (dolock(lck, LCK_RD) < 0) {
174        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
175    }
176}
177/* }}} */
178static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
179{
180    if (dolock(lck, LCK_UN) < 0) {
181        zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
182    }
183}
184/* }}} */
185#endif /* XC_INTERPROCESS_LOCK_IMPLEMENTED */
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
195#   ifdef _POSIX_THREAD_PROCESS_SHARED
196    pthread_mutex_t pthread_mutex;
197#   endif
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
205
206#ifndef NDEBUG
207    zend_bool locked;
208#endif
209};
210
211size_t xc_lock_size(void) /* {{{ */
212{
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
220    pthread_mutexattr_t psharedm;
221    pthread_mutexattr_init(&psharedm);
222    pthread_mutexattr_setpshared(&psharedm, PTHREAD_PROCESS_SHARED);
223    pthread_mutex_init(&lck->pthread_mutex, &psharedm);
224    lck->tsrm_mutex = &lck->pthread_mutex;
225#   else
226    lck->tsrm_mutex = tsrm_mutex_alloc();
227#   endif
228#endif
229
230#ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
231#   ifdef ZTS
232    lck->use_fcntl = interprocess;
233    if (lck->use_fcntl)
234#   endif
235        xc_fcntl_init(&lck->fcntl_lock, pathname);
236#endif
237
238#ifndef NDEBUG
239    lck->locked = 0;
240#endif
241
242    return lck;
243}
244/* }}} */
245void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
246{
247#ifdef ZTS
248#   ifdef _POSIX_THREAD_PROCESS_SHARED
249    pthread_mutex_destroy(&lck->pthread_mutex);
250#   else
251    tsrm_mutex_free(lck->tsrm_mutex);
252#   endif
253    lck->tsrm_mutex = NULL;
254#endif
255
256#ifndef XC_INTERPROCESS_LOCK_IMPLEMENTED
257#   ifdef ZTS
258    if (lck->use_fcntl)
259#   endif
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
280
281#ifndef NDEBUG
282    assert(!lck->locked);
283    lck->locked = 1;
284    assert(lck->locked);
285#endif
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
304
305#ifndef NDEBUG
306    assert(!lck->locked);
307    lck->locked = 1;
308    assert(lck->locked);
309#endif
310}
311/* }}} */
312void xc_unlock(xc_lock_t *lck) /* {{{ */
313{
314#ifndef NDEBUG
315    assert(lck->locked);
316    lck->locked = 0;
317    assert(!lck->locked);
318#endif
319
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.