| [1027] | 1 | #include "xc_lock.h" |
|---|
| 2 | #include "xcache.h" |
|---|
| [1] | 3 | #include <stdio.h> |
|---|
| 4 | #include <string.h> |
|---|
| [36] | 5 | #include <stdlib.h> |
|---|
| [1186] | 6 | #ifdef ZEND_WIN32 |
|---|
| 7 | # include <process.h> |
|---|
| [1199] | 8 | #else |
|---|
| 9 | # include <unistd.h> |
|---|
| 10 | # include <fcntl.h> |
|---|
| 11 | # include <errno.h> |
|---|
| [1186] | 12 | #endif |
|---|
| [1] | 13 | |
|---|
| [1206] | 14 | /* {{{ detect what type of lock is needed */ |
|---|
| 15 | #ifdef ZTS |
|---|
| 16 | # define XC_LOCK_NEED_TS |
|---|
| 17 | #endif |
|---|
| [1204] | 18 | |
|---|
| [1206] | 19 | #ifndef ZEND_WIN32 |
|---|
| 20 | # define XC_LOCK_NEED_INTERPROCESS |
|---|
| [1204] | 21 | #endif |
|---|
| 22 | |
|---|
| [1206] | 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 |
|---|
| [1204] | 26 | #endif |
|---|
| 27 | /* }}} */ |
|---|
| 28 | |
|---|
| [1206] | 29 | /* {{{ detect which lock is needed */ |
|---|
| 30 | #if defined(XC_LOCK_NEED_TS) && defined(XC_LOCK_NEED_INTERPROCESS) |
|---|
| 31 | # ifdef PTHREAD |
|---|
| 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 | /* }}} */ |
|---|
| [1204] | 48 | |
|---|
| [1206] | 49 | /* {{{ fcntl lock impl */ |
|---|
| 50 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| [1] | 51 | #ifndef ZEND_WIN32 |
|---|
| 52 | typedef int HANDLE; |
|---|
| [62] | 53 | # ifndef INVALID_HANDLE_VALUE |
|---|
| 54 | # define INVALID_HANDLE_VALUE -1 |
|---|
| 55 | # endif |
|---|
| [928] | 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) |
|---|
| [1] | 65 | #endif |
|---|
| 66 | |
|---|
| [1199] | 67 | typedef struct { |
|---|
| [1] | 68 | HANDLE fd; |
|---|
| 69 | char *pathname; |
|---|
| [1199] | 70 | } xc_fcntl_lock_t; |
|---|
| [1] | 71 | |
|---|
| 72 | #ifndef ZEND_WIN32 |
|---|
| [11] | 73 | # define LCK_WR F_WRLCK |
|---|
| 74 | # define LCK_RD F_RDLCK |
|---|
| 75 | # define LCK_UN F_UNLCK |
|---|
| 76 | # define LCK_NB 0 |
|---|
| [1199] | 77 | static inline int dolock(xc_fcntl_lock_t *lck, int type) |
|---|
| [1198] | 78 | { |
|---|
| [1] | 79 | int ret; |
|---|
| 80 | struct flock lock; |
|---|
| 81 | |
|---|
| 82 | lock.l_type = type; |
|---|
| 83 | lock.l_start = 0; |
|---|
| 84 | lock.l_whence = SEEK_SET; |
|---|
| 85 | lock.l_len = 1; |
|---|
| 86 | lock.l_pid = 0; |
|---|
| 87 | |
|---|
| 88 | do { |
|---|
| 89 | ret = fcntl(lck->fd, F_SETLKW, &lock); |
|---|
| 90 | } while (ret < 0 && errno == EINTR); |
|---|
| 91 | return ret; |
|---|
| 92 | } |
|---|
| 93 | #else |
|---|
| 94 | |
|---|
| 95 | # include <win32/flock.h> |
|---|
| 96 | # include <io.h> |
|---|
| 97 | # include <fcntl.h> |
|---|
| 98 | # include <sys/types.h> |
|---|
| 99 | # include <sys/stat.h> |
|---|
| [928] | 100 | # undef errno |
|---|
| 101 | # define errno GetLastError() |
|---|
| [11] | 102 | # define getuid() 0 |
|---|
| 103 | # define LCK_WR LOCKFILE_EXCLUSIVE_LOCK |
|---|
| 104 | # define LCK_RD 0 |
|---|
| 105 | # define LCK_UN 0 |
|---|
| 106 | # define LCK_NB LOCKFILE_FAIL_IMMEDIATELY |
|---|
| [1199] | 107 | static inline int dolock(xc_fcntl_lock_t *lck, int type) |
|---|
| [1198] | 108 | { |
|---|
| [1] | 109 | static OVERLAPPED offset = {0, 0, 0, 0, NULL}; |
|---|
| 110 | |
|---|
| 111 | if (type == LCK_UN) { |
|---|
| [1204] | 112 | return UnlockFileEx(lck->fd, 0, 1, 0, &offset); |
|---|
| [1] | 113 | } |
|---|
| 114 | else { |
|---|
| [1204] | 115 | return LockFileEx(lck->fd, type, 0, 1, 0, &offset); |
|---|
| [1] | 116 | } |
|---|
| 117 | } |
|---|
| [1199] | 118 | #endif |
|---|
| [1] | 119 | /* }}} */ |
|---|
| 120 | |
|---|
| [1199] | 121 | static zend_bool xc_fcntl_init(xc_fcntl_lock_t *lck, const char *pathname) /* {{{ */ |
|---|
| [1] | 122 | { |
|---|
| 123 | HANDLE fd; |
|---|
| [62] | 124 | int size; |
|---|
| 125 | char *myname; |
|---|
| [1] | 126 | |
|---|
| 127 | if (pathname == NULL) { |
|---|
| [1154] | 128 | static int instanceId = 0; |
|---|
| [62] | 129 | const char default_tmpdir[] = { DEFAULT_SLASH, 't', 'm', 'p', '\0' }; |
|---|
| 130 | const char *tmpdir; |
|---|
| 131 | |
|---|
| 132 | tmpdir = getenv("TEMP"); |
|---|
| 133 | if (!tmpdir) { |
|---|
| 134 | tmpdir = getenv("TMP"); |
|---|
| 135 | if (!tmpdir) { |
|---|
| 136 | tmpdir = default_tmpdir; |
|---|
| 137 | } |
|---|
| 138 | } |
|---|
| 139 | size = strlen(tmpdir) + sizeof("/.xcache.lock") - 1 + 3 * 10 + 100; |
|---|
| [282] | 140 | myname = malloc(size); |
|---|
| [1154] | 141 | snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.lock", tmpdir, DEFAULT_SLASH, (int) getuid(), (int) getpid(), ++instanceId); |
|---|
| [1] | 142 | pathname = myname; |
|---|
| 143 | } |
|---|
| [62] | 144 | else { |
|---|
| 145 | myname = NULL; |
|---|
| 146 | } |
|---|
| [1] | 147 | |
|---|
| [928] | 148 | fd = open(pathname, O_RDWR|O_CREAT, 0666); |
|---|
| [1] | 149 | |
|---|
| [62] | 150 | if (fd != INVALID_HANDLE_VALUE) { |
|---|
| [1] | 151 | |
|---|
| 152 | #ifndef __CYGWIN__ |
|---|
| 153 | unlink(pathname); |
|---|
| 154 | #endif |
|---|
| 155 | lck->fd = fd; |
|---|
| 156 | size = strlen(pathname) + 1; |
|---|
| 157 | lck->pathname = malloc(size); |
|---|
| 158 | memcpy(lck->pathname, pathname, size); |
|---|
| 159 | } |
|---|
| 160 | else { |
|---|
| [928] | 161 | zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname); |
|---|
| [62] | 162 | lck = NULL; |
|---|
| [1] | 163 | } |
|---|
| [62] | 164 | |
|---|
| 165 | if (myname) { |
|---|
| [282] | 166 | free(myname); |
|---|
| [62] | 167 | } |
|---|
| 168 | |
|---|
| [1199] | 169 | return lck ? 1 : 0; |
|---|
| [1] | 170 | } |
|---|
| 171 | /* }}} */ |
|---|
| [1199] | 172 | static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */ |
|---|
| [1198] | 173 | { |
|---|
| [928] | 174 | close(lck->fd); |
|---|
| [1] | 175 | #ifdef __CYGWIN__ |
|---|
| 176 | unlink(lck->pathname); |
|---|
| 177 | #endif |
|---|
| 178 | free(lck->pathname); |
|---|
| 179 | } |
|---|
| 180 | /* }}} */ |
|---|
| [1199] | 181 | static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */ |
|---|
| [1198] | 182 | { |
|---|
| [1] | 183 | if (dolock(lck, LCK_WR) < 0) { |
|---|
| [928] | 184 | zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno); |
|---|
| [1] | 185 | } |
|---|
| 186 | } |
|---|
| 187 | /* }}} */ |
|---|
| [1199] | 188 | static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */ |
|---|
| [1198] | 189 | { |
|---|
| [1] | 190 | if (dolock(lck, LCK_RD) < 0) { |
|---|
| [928] | 191 | zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno); |
|---|
| [1] | 192 | } |
|---|
| 193 | } |
|---|
| 194 | /* }}} */ |
|---|
| [1199] | 195 | static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */ |
|---|
| [1198] | 196 | { |
|---|
| [1] | 197 | if (dolock(lck, LCK_UN) < 0) { |
|---|
| [928] | 198 | zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno); |
|---|
| [1] | 199 | } |
|---|
| 200 | } |
|---|
| 201 | /* }}} */ |
|---|
| [1206] | 202 | #endif /* XC_LOCK_USE_FCNTL */ |
|---|
| [1199] | 203 | |
|---|
| 204 | struct _xc_lock_t { |
|---|
| [1206] | 205 | #ifdef XC_LOCK_USE_NOOP |
|---|
| [1199] | 206 | int dummy; |
|---|
| [1206] | 207 | #endif |
|---|
| 208 | |
|---|
| 209 | #ifdef XC_LOCK_USE_TSRM |
|---|
| [1199] | 210 | MUTEX_T tsrm_mutex; |
|---|
| [1206] | 211 | #endif |
|---|
| [1199] | 212 | |
|---|
| [1206] | 213 | #ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH |
|---|
| 214 | zend_bool interprocess; |
|---|
| 215 | #endif |
|---|
| 216 | |
|---|
| 217 | #ifdef XC_LOCK_USE_PTHREAD |
|---|
| [1204] | 218 | pthread_mutex_t pthread_mutex; |
|---|
| [1206] | 219 | #endif |
|---|
| 220 | |
|---|
| 221 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| [1199] | 222 | xc_fcntl_lock_t fcntl_lock; |
|---|
| 223 | #endif |
|---|
| [1204] | 224 | |
|---|
| 225 | #ifndef NDEBUG |
|---|
| 226 | zend_bool locked; |
|---|
| 227 | #endif |
|---|
| [1199] | 228 | }; |
|---|
| 229 | |
|---|
| [1206] | 230 | #ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH |
|---|
| 231 | # define XC_LOCK_INTERPROCESS (lck->interprocess) |
|---|
| 232 | #else |
|---|
| 233 | # define XC_LOCK_INTERPROCESS 1 |
|---|
| 234 | #endif |
|---|
| 235 | |
|---|
| [1204] | 236 | size_t xc_lock_size(void) /* {{{ */ |
|---|
| [1199] | 237 | { |
|---|
| [1204] | 238 | return sizeof(xc_lock_t); |
|---|
| 239 | } |
|---|
| 240 | /* }}} */ |
|---|
| 241 | xc_lock_t *xc_lock_init(xc_lock_t *lck, const char *pathname, unsigned char interprocess) /* {{{ */ |
|---|
| 242 | { |
|---|
| [1206] | 243 | #ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH |
|---|
| 244 | lck->interprocess = interprocess; |
|---|
| 245 | #endif |
|---|
| 246 | |
|---|
| 247 | #ifdef XC_LOCK_USE_PTHREAD |
|---|
| 248 | { |
|---|
| 249 | pthread_mutexattr_t psharedm; |
|---|
| 250 | pthread_mutexattr_init(&psharedm); |
|---|
| 251 | pthread_mutexattr_setpshared(&psharedm, XC_LOCK_INTERPROCESS ? PTHREAD_PROCESS_PRIVATE : PTHREAD_PROCESS_SHARED); |
|---|
| 252 | pthread_mutex_init(&lck->pthread_mutex, &psharedm); |
|---|
| 253 | } |
|---|
| 254 | #endif |
|---|
| 255 | |
|---|
| 256 | #ifdef XC_LOCK_USE_TSRM |
|---|
| [1199] | 257 | lck->tsrm_mutex = tsrm_mutex_alloc(); |
|---|
| [1204] | 258 | #endif |
|---|
| 259 | |
|---|
| [1206] | 260 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| 261 | if (XC_LOCK_INTERPROCESS) { |
|---|
| [1199] | 262 | xc_fcntl_init(&lck->fcntl_lock, pathname); |
|---|
| [1206] | 263 | } |
|---|
| [1204] | 264 | #endif |
|---|
| 265 | |
|---|
| 266 | #ifndef NDEBUG |
|---|
| 267 | lck->locked = 0; |
|---|
| 268 | #endif |
|---|
| 269 | |
|---|
| [1199] | 270 | return lck; |
|---|
| 271 | } |
|---|
| 272 | /* }}} */ |
|---|
| 273 | void xc_lock_destroy(xc_lock_t *lck) /* {{{ */ |
|---|
| 274 | { |
|---|
| [1206] | 275 | #ifdef XC_LOCK_USE_PTHREAD |
|---|
| [1204] | 276 | pthread_mutex_destroy(&lck->pthread_mutex); |
|---|
| [1206] | 277 | #endif |
|---|
| 278 | |
|---|
| 279 | #ifdef XC_LOCK_USE_TSRM |
|---|
| [1199] | 280 | tsrm_mutex_free(lck->tsrm_mutex); |
|---|
| [1204] | 281 | lck->tsrm_mutex = NULL; |
|---|
| 282 | #endif |
|---|
| 283 | |
|---|
| [1206] | 284 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| 285 | if (XC_LOCK_INTERPROCESS) { |
|---|
| [1199] | 286 | xc_fcntl_destroy(&lck->fcntl_lock); |
|---|
| [1206] | 287 | } |
|---|
| [1199] | 288 | #endif |
|---|
| 289 | } |
|---|
| 290 | /* }}} */ |
|---|
| 291 | void xc_lock(xc_lock_t *lck) /* {{{ */ |
|---|
| 292 | { |
|---|
| [1206] | 293 | #ifdef XC_LOCK_USE_PTHREAD |
|---|
| 294 | if (pthread_mutex_lock(&lck->pthread_mutex) < 0) { |
|---|
| 295 | zend_error(E_ERROR, "xc_lock failed errno:%d", errno); |
|---|
| 296 | } |
|---|
| 297 | #endif |
|---|
| 298 | |
|---|
| 299 | #ifdef XC_LOCK_USE_TSRM |
|---|
| [1199] | 300 | if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) { |
|---|
| 301 | zend_error(E_ERROR, "xc_lock failed errno:%d", errno); |
|---|
| 302 | } |
|---|
| [1206] | 303 | #endif |
|---|
| 304 | |
|---|
| 305 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| 306 | if (XC_LOCK_INTERPROCESS) { |
|---|
| [1199] | 307 | xc_fcntl_lock(&lck->fcntl_lock); |
|---|
| [1206] | 308 | } |
|---|
| [1199] | 309 | #endif |
|---|
| [1204] | 310 | |
|---|
| 311 | #ifndef NDEBUG |
|---|
| 312 | assert(!lck->locked); |
|---|
| 313 | lck->locked = 1; |
|---|
| 314 | assert(lck->locked); |
|---|
| 315 | #endif |
|---|
| [1199] | 316 | } |
|---|
| 317 | /* }}} */ |
|---|
| 318 | void xc_rdlock(xc_lock_t *lck) /* {{{ */ |
|---|
| 319 | { |
|---|
| [1206] | 320 | #ifdef XC_LOCK_USE_PTHREAD |
|---|
| 321 | if (pthread_mutex_lock(&lck->pthread_mutex) < 0) { |
|---|
| 322 | zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno); |
|---|
| 323 | } |
|---|
| 324 | #endif |
|---|
| 325 | |
|---|
| 326 | #ifdef XC_LOCK_USE_TSRM |
|---|
| [1199] | 327 | if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) { |
|---|
| 328 | zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno); |
|---|
| 329 | } |
|---|
| [1206] | 330 | #endif |
|---|
| 331 | |
|---|
| 332 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| 333 | if (XC_LOCK_INTERPROCESS) { |
|---|
| [1199] | 334 | xc_fcntl_lock(&lck->fcntl_lock); |
|---|
| [1206] | 335 | } |
|---|
| [1199] | 336 | #endif |
|---|
| [1204] | 337 | |
|---|
| 338 | #ifndef NDEBUG |
|---|
| 339 | assert(!lck->locked); |
|---|
| 340 | lck->locked = 1; |
|---|
| 341 | assert(lck->locked); |
|---|
| 342 | #endif |
|---|
| [1199] | 343 | } |
|---|
| 344 | /* }}} */ |
|---|
| 345 | void xc_unlock(xc_lock_t *lck) /* {{{ */ |
|---|
| 346 | { |
|---|
| [1204] | 347 | #ifndef NDEBUG |
|---|
| 348 | assert(lck->locked); |
|---|
| 349 | lck->locked = 0; |
|---|
| 350 | assert(!lck->locked); |
|---|
| 351 | #endif |
|---|
| 352 | |
|---|
| [1206] | 353 | #ifdef XC_LOCK_USE_FCNTL |
|---|
| 354 | if (XC_LOCK_INTERPROCESS) { |
|---|
| [1199] | 355 | xc_fcntl_unlock(&lck->fcntl_lock); |
|---|
| [1206] | 356 | } |
|---|
| [1199] | 357 | #endif |
|---|
| [1206] | 358 | |
|---|
| 359 | #ifdef XC_LOCK_USE_TSRM |
|---|
| [1199] | 360 | if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) { |
|---|
| 361 | zend_error(E_ERROR, "xc_unlock failed errno:%d", errno); |
|---|
| 362 | } |
|---|
| [1206] | 363 | #endif |
|---|
| 364 | |
|---|
| 365 | #ifdef XC_LOCK_USE_PTHREAD |
|---|
| 366 | if (pthread_mutex_unlock(&lck->pthread_mutex) < 0) { |
|---|
| 367 | zend_error(E_ERROR, "xc_unlock failed errno:%d", errno); |
|---|
| 368 | } |
|---|
| 369 | #endif |
|---|
| [1199] | 370 | } |
|---|
| 371 | /* }}} */ |
|---|