source: trunk/xcache/xc_lock.c @ 1365

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

ws fix

  • Property svn:eol-style set to native
File size: 7.4 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 type of lock is needed */
15#ifdef ZTS
16#   define XC_LOCK_NEED_TS
17#endif
18
19#ifndef ZEND_WIN32
20#   define XC_LOCK_NEED_INTERPROCESS
21#endif
22
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
26#endif
27/* }}} */
28
29/* {{{ detect which lock is needed */
30#if defined(XC_LOCK_NEED_TS) && defined(XC_LOCK_NEED_INTERPROCESS)
31#   ifdef PTHREADS
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/* }}} */
48
49/* {{{ fcntl lock impl */
50#ifdef XC_LOCK_USE_FCNTL
51#ifndef ZEND_WIN32
52typedef int HANDLE;
53#   ifndef INVALID_HANDLE_VALUE
54#       define INVALID_HANDLE_VALUE -1
55#   endif
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)
65#endif
66
67typedef struct {
68    HANDLE fd;
69#ifdef __CYGWIN__
70    /* store the path for unlink() later */
71    char *pathname;
72#endif
73} xc_fcntl_lock_t;
74
75#ifndef ZEND_WIN32
76#   define LCK_WR F_WRLCK
77#   define LCK_RD F_RDLCK
78#   define LCK_UN F_UNLCK
79#   define LCK_NB 0
80static inline int dolock(xc_fcntl_lock_t *lck, int type)
81{
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>
103#   undef errno
104#   define errno GetLastError()
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
110static inline int dolock(xc_fcntl_lock_t *lck, int type)
111{
112    static OVERLAPPED offset = {0, 0, 0, 0, NULL};
113
114    if (type == LCK_UN) {
115        return UnlockFileEx(lck->fd, 0, 1, 0, &offset);
116    }
117    else {
118        return LockFileEx(lck->fd, type, 0, 1, 0, &offset);
119    }
120}
121#endif
122/* }}} */
123
124static zend_bool xc_fcntl_init(xc_fcntl_lock_t *lck, const char *pathname) /* {{{ */
125{
126    HANDLE fd;
127    int size;
128    char *myname;
129
130    if (pathname == NULL) {
131        static int instanceId = 0;
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;
143        myname = malloc(size);
144        snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.lock", tmpdir, DEFAULT_SLASH, (int) getuid(), (int) getpid(), ++instanceId);
145        pathname = myname;
146    }
147    else {
148        myname = NULL;
149    }
150
151    fd = open(pathname, O_RDWR|O_CREAT, 0666);
152
153    if (fd != INVALID_HANDLE_VALUE) {
154        lck->fd = fd;
155#ifdef __CYGWIN__
156        size = strlen(pathname) + 1;
157        lck->pathname = malloc(size);
158        memcpy(lck->pathname, pathname, size);
159#else
160        unlink(pathname);
161#endif
162    }
163    else {
164        zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
165        lck = NULL;
166    }
167
168    if (myname) {
169        free(myname);
170    }
171
172    return lck ? 1 : 0;
173}
174/* }}} */
175static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
176{
177    close(lck->fd);
178#ifdef __CYGWIN__
179    unlink(lck->pathname);
180    free(lck->pathname);
181#endif
182}
183/* }}} */
184static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
185{
186    if (dolock(lck, LCK_WR) < 0) {
187        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
188    }
189}
190/* }}} */
191static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
192{
193    if (dolock(lck, LCK_RD) < 0) {
194        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
195    }
196}
197/* }}} */
198static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
199{
200    if (dolock(lck, LCK_UN) < 0) {
201        zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
202    }
203}
204/* }}} */
205#endif /* XC_LOCK_USE_FCNTL */
206
207struct _xc_lock_t {
208#ifdef XC_LOCK_USE_NOOP
209    int dummy;
210#endif
211
212#ifdef XC_LOCK_USE_TSRM
213    MUTEX_T tsrm_mutex;
214#endif
215
216#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
217    zend_bool interprocess;
218#endif
219
220#ifdef XC_LOCK_USE_PTHREAD
221    pthread_mutex_t pthread_mutex;
222#endif
223
224#ifdef XC_LOCK_USE_FCNTL
225    xc_fcntl_lock_t fcntl_lock;
226#endif
227
228#ifndef NDEBUG
229    zend_bool locked;
230#endif
231};
232
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
239size_t xc_lock_size(void) /* {{{ */
240{
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{
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
260    lck->tsrm_mutex = tsrm_mutex_alloc();
261#endif
262
263#ifdef XC_LOCK_USE_FCNTL
264    if (XC_LOCK_INTERPROCESS) {
265        xc_fcntl_init(&lck->fcntl_lock, pathname);
266    }
267#endif
268
269#ifndef NDEBUG
270    lck->locked = 0;
271#endif
272
273    return lck;
274}
275/* }}} */
276void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
277{
278#ifdef XC_LOCK_USE_PTHREAD
279    pthread_mutex_destroy(&lck->pthread_mutex);
280#endif
281
282#ifdef XC_LOCK_USE_TSRM
283    tsrm_mutex_free(lck->tsrm_mutex);
284#endif
285
286#ifdef XC_LOCK_USE_FCNTL
287    if (XC_LOCK_INTERPROCESS) {
288        xc_fcntl_destroy(&lck->fcntl_lock);
289    }
290#endif
291}
292/* }}} */
293void xc_lock(xc_lock_t *lck) /* {{{ */
294{
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
302    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
303        zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
304    }
305#endif
306
307#ifdef XC_LOCK_USE_FCNTL
308    if (XC_LOCK_INTERPROCESS) {
309        xc_fcntl_lock(&lck->fcntl_lock);
310    }
311#endif
312
313#ifndef NDEBUG
314    assert(!lck->locked);
315    lck->locked = 1;
316    assert(lck->locked);
317#endif
318}
319/* }}} */
320void xc_rdlock(xc_lock_t *lck) /* {{{ */
321{
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
329    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
330        zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
331    }
332#endif
333
334#ifdef XC_LOCK_USE_FCNTL
335    if (XC_LOCK_INTERPROCESS) {
336        xc_fcntl_lock(&lck->fcntl_lock);
337    }
338#endif
339
340#ifndef NDEBUG
341    assert(!lck->locked);
342    lck->locked = 1;
343    assert(lck->locked);
344#endif
345}
346/* }}} */
347void xc_unlock(xc_lock_t *lck) /* {{{ */
348{
349#ifndef NDEBUG
350    assert(lck->locked);
351    lck->locked = 0;
352    assert(!lck->locked);
353#endif
354
355#ifdef XC_LOCK_USE_FCNTL
356    if (XC_LOCK_INTERPROCESS) {
357        xc_fcntl_unlock(&lck->fcntl_lock);
358    }
359#endif
360
361#ifdef XC_LOCK_USE_TSRM
362    if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) {
363        zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
364    }
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
372}
373/* }}} */
Note: See TracBrowser for help on using the repository browser.