source: trunk/xcache/xc_lock.c @ 1200

Last change on this file since 1200 was 1200, checked in by moo, 23 months ago

zts build fix

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