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