source: trunk/xcache/xc_lock.c @ 1363

Last change on this file since 1363 was 1363, checked in by moo, 16 months ago

cygwin hack unlink should be cygwin only

  • 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
155        lck->fd = fd;
156#ifdef __CYGWIN__
157        size = strlen(pathname) + 1;
158        lck->pathname = malloc(size);
159        memcpy(lck->pathname, pathname, size);
160#else
161        unlink(pathname);
162#endif
163    }
164    else {
165        zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
166        lck = NULL;
167    }
168
169    if (myname) {
170        free(myname);
171    }
172
173    return lck ? 1 : 0;
174}
175/* }}} */
176static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
177{
178    close(lck->fd);
179#ifdef __CYGWIN__
180    unlink(lck->pathname);
181    free(lck->pathname);
182#endif
183}
184/* }}} */
185static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
186{
187    if (dolock(lck, LCK_WR) < 0) {
188        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
189    }
190}
191/* }}} */
192static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
193{
194    if (dolock(lck, LCK_RD) < 0) {
195        zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
196    }
197}
198/* }}} */
199static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
200{
201    if (dolock(lck, LCK_UN) < 0) {
202        zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
203    }
204}
205/* }}} */
206#endif /* XC_LOCK_USE_FCNTL */
207
208struct _xc_lock_t {
209#ifdef XC_LOCK_USE_NOOP
210    int dummy;
211#endif
212
213#ifdef XC_LOCK_USE_TSRM
214    MUTEX_T tsrm_mutex;
215#endif
216
217#ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
218    zend_bool interprocess;
219#endif
220
221#ifdef XC_LOCK_USE_PTHREAD
222    pthread_mutex_t pthread_mutex;
223#endif
224
225#ifdef XC_LOCK_USE_FCNTL
226    xc_fcntl_lock_t fcntl_lock;
227#endif
228
229#ifndef NDEBUG
230    zend_bool locked;
231#endif
232};
233
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
240size_t xc_lock_size(void) /* {{{ */
241{
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{
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
261    lck->tsrm_mutex = tsrm_mutex_alloc();
262#endif
263
264#ifdef XC_LOCK_USE_FCNTL
265    if (XC_LOCK_INTERPROCESS) {
266        xc_fcntl_init(&lck->fcntl_lock, pathname);
267    }
268#endif
269
270#ifndef NDEBUG
271    lck->locked = 0;
272#endif
273
274    return lck;
275}
276/* }}} */
277void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
278{
279#ifdef XC_LOCK_USE_PTHREAD
280    pthread_mutex_destroy(&lck->pthread_mutex);
281#endif
282
283#ifdef XC_LOCK_USE_TSRM
284    tsrm_mutex_free(lck->tsrm_mutex);
285#endif
286
287#ifdef XC_LOCK_USE_FCNTL
288    if (XC_LOCK_INTERPROCESS) {
289        xc_fcntl_destroy(&lck->fcntl_lock);
290    }
291#endif
292}
293/* }}} */
294void xc_lock(xc_lock_t *lck) /* {{{ */
295{
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
303    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
304        zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
305    }
306#endif
307
308#ifdef XC_LOCK_USE_FCNTL
309    if (XC_LOCK_INTERPROCESS) {
310        xc_fcntl_lock(&lck->fcntl_lock);
311    }
312#endif
313
314#ifndef NDEBUG
315    assert(!lck->locked);
316    lck->locked = 1;
317    assert(lck->locked);
318#endif
319}
320/* }}} */
321void xc_rdlock(xc_lock_t *lck) /* {{{ */
322{
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
330    if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
331        zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
332    }
333#endif
334
335#ifdef XC_LOCK_USE_FCNTL
336    if (XC_LOCK_INTERPROCESS) {
337        xc_fcntl_lock(&lck->fcntl_lock);
338    }
339#endif
340
341#ifndef NDEBUG
342    assert(!lck->locked);
343    lck->locked = 1;
344    assert(lck->locked);
345#endif
346}
347/* }}} */
348void xc_unlock(xc_lock_t *lck) /* {{{ */
349{
350#ifndef NDEBUG
351    assert(lck->locked);
352    lck->locked = 0;
353    assert(!lck->locked);
354#endif
355
356#ifdef XC_LOCK_USE_FCNTL
357    if (XC_LOCK_INTERPROCESS) {
358        xc_fcntl_unlock(&lck->fcntl_lock);
359    }
360#endif
361
362#ifdef XC_LOCK_USE_TSRM
363    if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) {
364        zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
365    }
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
373}
374/* }}} */
Note: See TracBrowser for help on using the repository browser.