| 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 |
|---|
| 15 | typedef 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 | |
|---|
| 30 | typedef 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 |
|---|
| 41 | static 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 |
|---|
| 71 | static 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 | |
|---|
| 85 | static 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 | /* }}} */ |
|---|
| 136 | static 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 | /* }}} */ |
|---|
| 145 | static 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 | /* }}} */ |
|---|
| 152 | static 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 | /* }}} */ |
|---|
| 159 | static 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 | |
|---|
| 181 | struct _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 | |
|---|
| 198 | xc_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 | # ifdef ZTS |
|---|
| 204 | xc_lock_t *lck = malloc(sizeof(xc_lock_t)); |
|---|
| 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 | /* }}} */ |
|---|
| 226 | void 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 | /* }}} */ |
|---|
| 244 | void 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 | /* }}} */ |
|---|
| 262 | void 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 | /* }}} */ |
|---|
| 280 | void 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 | /* }}} */ |
|---|