proc_mutex.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "apr.h"
  17. #include "apr_strings.h"
  18. #include "apr_arch_proc_mutex.h"
  19. #include "apr_arch_file_io.h" /* for apr_mkstemp() */
  20. #include "apr_hash.h"
  21. APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
  22. {
  23. return apr_pool_cleanup_run(mutex->pool, mutex, apr_proc_mutex_cleanup);
  24. }
  25. #if APR_HAS_POSIXSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || \
  26. APR_HAS_PROC_PTHREAD_SERIALIZE || APR_HAS_SYSVSEM_SERIALIZE
  27. static apr_status_t proc_mutex_no_child_init(apr_proc_mutex_t **mutex,
  28. apr_pool_t *cont,
  29. const char *fname)
  30. {
  31. return APR_SUCCESS;
  32. }
  33. #endif
  34. #if APR_HAS_POSIXSEM_SERIALIZE
  35. #ifndef SEM_FAILED
  36. #define SEM_FAILED (-1)
  37. #endif
  38. static apr_status_t proc_mutex_posix_cleanup(void *mutex_)
  39. {
  40. apr_proc_mutex_t *mutex = mutex_;
  41. if (sem_close(mutex->psem_interproc) < 0) {
  42. return errno;
  43. }
  44. return APR_SUCCESS;
  45. }
  46. static unsigned int rshash (char *p) {
  47. /* hash function from Robert Sedgwicks 'Algorithms in C' book */
  48. unsigned int b = 378551;
  49. unsigned int a = 63689;
  50. unsigned int retval = 0;
  51. for( ; *p; p++)
  52. {
  53. retval = retval * a + (*p);
  54. a *= b;
  55. }
  56. return retval;
  57. }
  58. static apr_status_t proc_mutex_posix_create(apr_proc_mutex_t *new_mutex,
  59. const char *fname)
  60. {
  61. #define APR_POSIXSEM_NAME_MIN 13
  62. sem_t *psem;
  63. char semname[32];
  64. new_mutex->interproc = apr_palloc(new_mutex->pool,
  65. sizeof(*new_mutex->interproc));
  66. /*
  67. * This bogusness is to follow what appears to be the
  68. * lowest common denominator in Posix semaphore naming:
  69. * - start with '/'
  70. * - be at most 14 chars
  71. * - be unique and not match anything on the filesystem
  72. *
  73. * Because of this, we use fname to generate a (unique) hash
  74. * and use that as the name of the semaphore. If no filename was
  75. * given, we create one based on the time. We tuck the name
  76. * away, since it might be useful for debugging. We use 2 hashing
  77. * functions to try to avoid collisions.
  78. *
  79. * To make this as robust as possible, we initially try something
  80. * larger (and hopefully more unique) and gracefully fail down to the
  81. * LCD above.
  82. *
  83. * NOTE: Darwin (Mac OS X) seems to be the most restrictive
  84. * implementation. Versions previous to Darwin 6.2 had the 14
  85. * char limit, but later rev's allow up to 31 characters.
  86. *
  87. */
  88. if (fname) {
  89. apr_ssize_t flen = strlen(fname);
  90. char *p = apr_pstrndup(new_mutex->pool, fname, strlen(fname));
  91. unsigned int h1, h2;
  92. h1 = apr_hashfunc_default((const char *)p, &flen);
  93. h2 = rshash(p);
  94. apr_snprintf(semname, sizeof(semname), "/ApR.%xH%x", h1, h2);
  95. } else {
  96. apr_time_t now;
  97. unsigned long sec;
  98. unsigned long usec;
  99. now = apr_time_now();
  100. sec = apr_time_sec(now);
  101. usec = apr_time_usec(now);
  102. apr_snprintf(semname, sizeof(semname), "/ApR.%lxZ%lx", sec, usec);
  103. }
  104. psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
  105. if (psem == (sem_t *)SEM_FAILED) {
  106. if (errno == ENAMETOOLONG) {
  107. /* Oh well, good try */
  108. semname[APR_POSIXSEM_NAME_MIN] = '\0';
  109. } else {
  110. return errno;
  111. }
  112. psem = sem_open(semname, O_CREAT | O_EXCL, 0644, 1);
  113. }
  114. if (psem == (sem_t *)SEM_FAILED) {
  115. return errno;
  116. }
  117. /* Ahhh. The joys of Posix sems. Predelete it... */
  118. sem_unlink(semname);
  119. new_mutex->psem_interproc = psem;
  120. new_mutex->fname = apr_pstrdup(new_mutex->pool, semname);
  121. apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
  122. apr_proc_mutex_cleanup,
  123. apr_pool_cleanup_null);
  124. return APR_SUCCESS;
  125. }
  126. static apr_status_t proc_mutex_posix_acquire(apr_proc_mutex_t *mutex)
  127. {
  128. if (sem_wait(mutex->psem_interproc) < 0) {
  129. return errno;
  130. }
  131. mutex->curr_locked = 1;
  132. return APR_SUCCESS;
  133. }
  134. static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex)
  135. {
  136. if (sem_trywait(mutex->psem_interproc) < 0) {
  137. if (errno == EAGAIN) {
  138. return APR_EBUSY;
  139. }
  140. return errno;
  141. }
  142. mutex->curr_locked = 1;
  143. return APR_SUCCESS;
  144. }
  145. static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
  146. {
  147. mutex->curr_locked = 0;
  148. if (sem_post(mutex->psem_interproc) < 0) {
  149. /* any failure is probably fatal, so no big deal to leave
  150. * ->curr_locked at 0. */
  151. return errno;
  152. }
  153. return APR_SUCCESS;
  154. }
  155. static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
  156. {
  157. #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(POSIXSEM_IS_GLOBAL)
  158. APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  159. #else
  160. 0,
  161. #endif
  162. proc_mutex_posix_create,
  163. proc_mutex_posix_acquire,
  164. proc_mutex_posix_tryacquire,
  165. proc_mutex_posix_release,
  166. proc_mutex_posix_cleanup,
  167. proc_mutex_no_child_init,
  168. "posixsem"
  169. };
  170. #endif /* Posix sem implementation */
  171. #if APR_HAS_SYSVSEM_SERIALIZE
  172. static struct sembuf proc_mutex_op_on;
  173. static struct sembuf proc_mutex_op_try;
  174. static struct sembuf proc_mutex_op_off;
  175. static void proc_mutex_sysv_setup(void)
  176. {
  177. proc_mutex_op_on.sem_num = 0;
  178. proc_mutex_op_on.sem_op = -1;
  179. proc_mutex_op_on.sem_flg = SEM_UNDO;
  180. proc_mutex_op_try.sem_num = 0;
  181. proc_mutex_op_try.sem_op = -1;
  182. proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT;
  183. proc_mutex_op_off.sem_num = 0;
  184. proc_mutex_op_off.sem_op = 1;
  185. proc_mutex_op_off.sem_flg = SEM_UNDO;
  186. }
  187. static apr_status_t proc_mutex_sysv_cleanup(void *mutex_)
  188. {
  189. apr_proc_mutex_t *mutex=mutex_;
  190. union semun ick;
  191. if (mutex->interproc->filedes != -1) {
  192. ick.val = 0;
  193. semctl(mutex->interproc->filedes, 0, IPC_RMID, ick);
  194. }
  195. return APR_SUCCESS;
  196. }
  197. static apr_status_t proc_mutex_sysv_create(apr_proc_mutex_t *new_mutex,
  198. const char *fname)
  199. {
  200. union semun ick;
  201. apr_status_t rv;
  202. new_mutex->interproc = apr_palloc(new_mutex->pool, sizeof(*new_mutex->interproc));
  203. new_mutex->interproc->filedes = semget(IPC_PRIVATE, 1, IPC_CREAT | 0600);
  204. if (new_mutex->interproc->filedes < 0) {
  205. rv = errno;
  206. proc_mutex_sysv_cleanup(new_mutex);
  207. return rv;
  208. }
  209. ick.val = 1;
  210. if (semctl(new_mutex->interproc->filedes, 0, SETVAL, ick) < 0) {
  211. rv = errno;
  212. proc_mutex_sysv_cleanup(new_mutex);
  213. return rv;
  214. }
  215. new_mutex->curr_locked = 0;
  216. apr_pool_cleanup_register(new_mutex->pool,
  217. (void *)new_mutex, apr_proc_mutex_cleanup,
  218. apr_pool_cleanup_null);
  219. return APR_SUCCESS;
  220. }
  221. static apr_status_t proc_mutex_sysv_acquire(apr_proc_mutex_t *mutex)
  222. {
  223. int rc;
  224. do {
  225. rc = semop(mutex->interproc->filedes, &proc_mutex_op_on, 1);
  226. } while (rc < 0 && errno == EINTR);
  227. if (rc < 0) {
  228. return errno;
  229. }
  230. mutex->curr_locked = 1;
  231. return APR_SUCCESS;
  232. }
  233. static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex)
  234. {
  235. int rc;
  236. do {
  237. rc = semop(mutex->interproc->filedes, &proc_mutex_op_try, 1);
  238. } while (rc < 0 && errno == EINTR);
  239. if (rc < 0) {
  240. if (errno == EAGAIN) {
  241. return APR_EBUSY;
  242. }
  243. return errno;
  244. }
  245. mutex->curr_locked = 1;
  246. return APR_SUCCESS;
  247. }
  248. static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
  249. {
  250. int rc;
  251. mutex->curr_locked = 0;
  252. do {
  253. rc = semop(mutex->interproc->filedes, &proc_mutex_op_off, 1);
  254. } while (rc < 0 && errno == EINTR);
  255. if (rc < 0) {
  256. return errno;
  257. }
  258. return APR_SUCCESS;
  259. }
  260. static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
  261. {
  262. #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(SYSVSEM_IS_GLOBAL)
  263. APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  264. #else
  265. 0,
  266. #endif
  267. proc_mutex_sysv_create,
  268. proc_mutex_sysv_acquire,
  269. proc_mutex_sysv_tryacquire,
  270. proc_mutex_sysv_release,
  271. proc_mutex_sysv_cleanup,
  272. proc_mutex_no_child_init,
  273. "sysvsem"
  274. };
  275. #endif /* SysV sem implementation */
  276. #if APR_HAS_PROC_PTHREAD_SERIALIZE
  277. static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_)
  278. {
  279. apr_proc_mutex_t *mutex=mutex_;
  280. apr_status_t rv;
  281. if (mutex->curr_locked == 1) {
  282. if ((rv = pthread_mutex_unlock(mutex->pthread_interproc))) {
  283. #ifdef HAVE_ZOS_PTHREADS
  284. rv = errno;
  285. #endif
  286. return rv;
  287. }
  288. }
  289. /* curr_locked is set to -1 until the mutex has been created */
  290. if (mutex->curr_locked != -1) {
  291. if ((rv = pthread_mutex_destroy(mutex->pthread_interproc))) {
  292. #ifdef HAVE_ZOS_PTHREADS
  293. rv = errno;
  294. #endif
  295. return rv;
  296. }
  297. }
  298. if (munmap((caddr_t)mutex->pthread_interproc, sizeof(pthread_mutex_t))) {
  299. return errno;
  300. }
  301. return APR_SUCCESS;
  302. }
  303. static apr_status_t proc_mutex_proc_pthread_create(apr_proc_mutex_t *new_mutex,
  304. const char *fname)
  305. {
  306. apr_status_t rv;
  307. int fd;
  308. pthread_mutexattr_t mattr;
  309. fd = open("/dev/zero", O_RDWR);
  310. if (fd < 0) {
  311. return errno;
  312. }
  313. new_mutex->pthread_interproc = (pthread_mutex_t *)mmap(
  314. (caddr_t) 0,
  315. sizeof(pthread_mutex_t),
  316. PROT_READ | PROT_WRITE, MAP_SHARED,
  317. fd, 0);
  318. if (new_mutex->pthread_interproc == (pthread_mutex_t *) (caddr_t) -1) {
  319. close(fd);
  320. return errno;
  321. }
  322. close(fd);
  323. new_mutex->curr_locked = -1; /* until the mutex has been created */
  324. if ((rv = pthread_mutexattr_init(&mattr))) {
  325. #ifdef HAVE_ZOS_PTHREADS
  326. rv = errno;
  327. #endif
  328. proc_mutex_proc_pthread_cleanup(new_mutex);
  329. return rv;
  330. }
  331. if ((rv = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED))) {
  332. #ifdef HAVE_ZOS_PTHREADS
  333. rv = errno;
  334. #endif
  335. proc_mutex_proc_pthread_cleanup(new_mutex);
  336. pthread_mutexattr_destroy(&mattr);
  337. return rv;
  338. }
  339. #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  340. if ((rv = pthread_mutexattr_setrobust_np(&mattr,
  341. PTHREAD_MUTEX_ROBUST_NP))) {
  342. #ifdef HAVE_ZOS_PTHREADS
  343. rv = errno;
  344. #endif
  345. proc_mutex_proc_pthread_cleanup(new_mutex);
  346. pthread_mutexattr_destroy(&mattr);
  347. return rv;
  348. }
  349. if ((rv = pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT))) {
  350. #ifdef HAVE_ZOS_PTHREADS
  351. rv = errno;
  352. #endif
  353. proc_mutex_proc_pthread_cleanup(new_mutex);
  354. pthread_mutexattr_destroy(&mattr);
  355. return rv;
  356. }
  357. #endif /* HAVE_PTHREAD_MUTEX_ROBUST */
  358. if ((rv = pthread_mutex_init(new_mutex->pthread_interproc, &mattr))) {
  359. #ifdef HAVE_ZOS_PTHREADS
  360. rv = errno;
  361. #endif
  362. proc_mutex_proc_pthread_cleanup(new_mutex);
  363. pthread_mutexattr_destroy(&mattr);
  364. return rv;
  365. }
  366. new_mutex->curr_locked = 0; /* mutex created now */
  367. if ((rv = pthread_mutexattr_destroy(&mattr))) {
  368. #ifdef HAVE_ZOS_PTHREADS
  369. rv = errno;
  370. #endif
  371. proc_mutex_proc_pthread_cleanup(new_mutex);
  372. return rv;
  373. }
  374. apr_pool_cleanup_register(new_mutex->pool,
  375. (void *)new_mutex,
  376. apr_proc_mutex_cleanup,
  377. apr_pool_cleanup_null);
  378. return APR_SUCCESS;
  379. }
  380. static apr_status_t proc_mutex_proc_pthread_acquire(apr_proc_mutex_t *mutex)
  381. {
  382. apr_status_t rv;
  383. if ((rv = pthread_mutex_lock(mutex->pthread_interproc))) {
  384. #ifdef HAVE_ZOS_PTHREADS
  385. rv = errno;
  386. #endif
  387. #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  388. /* Okay, our owner died. Let's try to make it consistent again. */
  389. if (rv == EOWNERDEAD) {
  390. pthread_mutex_consistent_np(mutex->pthread_interproc);
  391. }
  392. else
  393. return rv;
  394. #else
  395. return rv;
  396. #endif
  397. }
  398. mutex->curr_locked = 1;
  399. return APR_SUCCESS;
  400. }
  401. static apr_status_t proc_mutex_proc_pthread_tryacquire(apr_proc_mutex_t *mutex)
  402. {
  403. apr_status_t rv;
  404. if ((rv = pthread_mutex_trylock(mutex->pthread_interproc))) {
  405. #ifdef HAVE_ZOS_PTHREADS
  406. rv = errno;
  407. #endif
  408. if (rv == EBUSY) {
  409. return APR_EBUSY;
  410. }
  411. #ifdef HAVE_PTHREAD_MUTEX_ROBUST
  412. /* Okay, our owner died. Let's try to make it consistent again. */
  413. if (rv == EOWNERDEAD) {
  414. pthread_mutex_consistent_np(mutex->pthread_interproc);
  415. rv = APR_SUCCESS;
  416. }
  417. else
  418. return rv;
  419. #else
  420. return rv;
  421. #endif
  422. }
  423. mutex->curr_locked = 1;
  424. return rv;
  425. }
  426. static apr_status_t proc_mutex_proc_pthread_release(apr_proc_mutex_t *mutex)
  427. {
  428. apr_status_t rv;
  429. mutex->curr_locked = 0;
  430. if ((rv = pthread_mutex_unlock(mutex->pthread_interproc))) {
  431. #ifdef HAVE_ZOS_PTHREADS
  432. rv = errno;
  433. #endif
  434. return rv;
  435. }
  436. return APR_SUCCESS;
  437. }
  438. static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
  439. {
  440. APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  441. proc_mutex_proc_pthread_create,
  442. proc_mutex_proc_pthread_acquire,
  443. proc_mutex_proc_pthread_tryacquire,
  444. proc_mutex_proc_pthread_release,
  445. proc_mutex_proc_pthread_cleanup,
  446. proc_mutex_no_child_init,
  447. "pthread"
  448. };
  449. #endif
  450. #if APR_HAS_FCNTL_SERIALIZE
  451. static struct flock proc_mutex_lock_it;
  452. static struct flock proc_mutex_unlock_it;
  453. static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *);
  454. static void proc_mutex_fcntl_setup(void)
  455. {
  456. proc_mutex_lock_it.l_whence = SEEK_SET; /* from current point */
  457. proc_mutex_lock_it.l_start = 0; /* -"- */
  458. proc_mutex_lock_it.l_len = 0; /* until end of file */
  459. proc_mutex_lock_it.l_type = F_WRLCK; /* set exclusive/write lock */
  460. proc_mutex_lock_it.l_pid = 0; /* pid not actually interesting */
  461. proc_mutex_unlock_it.l_whence = SEEK_SET; /* from current point */
  462. proc_mutex_unlock_it.l_start = 0; /* -"- */
  463. proc_mutex_unlock_it.l_len = 0; /* until end of file */
  464. proc_mutex_unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */
  465. proc_mutex_unlock_it.l_pid = 0; /* pid not actually interesting */
  466. }
  467. static apr_status_t proc_mutex_fcntl_cleanup(void *mutex_)
  468. {
  469. apr_status_t status;
  470. apr_proc_mutex_t *mutex=mutex_;
  471. if (mutex->curr_locked == 1) {
  472. status = proc_mutex_fcntl_release(mutex);
  473. if (status != APR_SUCCESS)
  474. return status;
  475. }
  476. return apr_file_close(mutex->interproc);
  477. }
  478. static apr_status_t proc_mutex_fcntl_create(apr_proc_mutex_t *new_mutex,
  479. const char *fname)
  480. {
  481. int rv;
  482. if (fname) {
  483. new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
  484. rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
  485. APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
  486. APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD,
  487. new_mutex->pool);
  488. }
  489. else {
  490. new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
  491. rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
  492. APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
  493. new_mutex->pool);
  494. }
  495. if (rv != APR_SUCCESS) {
  496. return rv;
  497. }
  498. new_mutex->curr_locked = 0;
  499. unlink(new_mutex->fname);
  500. apr_pool_cleanup_register(new_mutex->pool,
  501. (void*)new_mutex,
  502. apr_proc_mutex_cleanup,
  503. apr_pool_cleanup_null);
  504. return APR_SUCCESS;
  505. }
  506. static apr_status_t proc_mutex_fcntl_acquire(apr_proc_mutex_t *mutex)
  507. {
  508. int rc;
  509. do {
  510. rc = fcntl(mutex->interproc->filedes, F_SETLKW, &proc_mutex_lock_it);
  511. } while (rc < 0 && errno == EINTR);
  512. if (rc < 0) {
  513. return errno;
  514. }
  515. mutex->curr_locked=1;
  516. return APR_SUCCESS;
  517. }
  518. static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex)
  519. {
  520. int rc;
  521. do {
  522. rc = fcntl(mutex->interproc->filedes, F_SETLK, &proc_mutex_lock_it);
  523. } while (rc < 0 && errno == EINTR);
  524. if (rc < 0) {
  525. #if FCNTL_TRYACQUIRE_EACCES
  526. if (errno == EACCES) {
  527. #else
  528. if (errno == EAGAIN) {
  529. #endif
  530. return APR_EBUSY;
  531. }
  532. return errno;
  533. }
  534. mutex->curr_locked = 1;
  535. return APR_SUCCESS;
  536. }
  537. static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
  538. {
  539. int rc;
  540. mutex->curr_locked=0;
  541. do {
  542. rc = fcntl(mutex->interproc->filedes, F_SETLKW, &proc_mutex_unlock_it);
  543. } while (rc < 0 && errno == EINTR);
  544. if (rc < 0) {
  545. return errno;
  546. }
  547. return APR_SUCCESS;
  548. }
  549. static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
  550. {
  551. #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FCNTL_IS_GLOBAL)
  552. APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  553. #else
  554. 0,
  555. #endif
  556. proc_mutex_fcntl_create,
  557. proc_mutex_fcntl_acquire,
  558. proc_mutex_fcntl_tryacquire,
  559. proc_mutex_fcntl_release,
  560. proc_mutex_fcntl_cleanup,
  561. proc_mutex_no_child_init,
  562. "fcntl"
  563. };
  564. #endif /* fcntl implementation */
  565. #if APR_HAS_FLOCK_SERIALIZE
  566. static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *);
  567. static apr_status_t proc_mutex_flock_cleanup(void *mutex_)
  568. {
  569. apr_status_t status;
  570. apr_proc_mutex_t *mutex=mutex_;
  571. if (mutex->curr_locked == 1) {
  572. status = proc_mutex_flock_release(mutex);
  573. if (status != APR_SUCCESS)
  574. return status;
  575. }
  576. if (mutex->interproc) { /* if it was opened properly */
  577. apr_file_close(mutex->interproc);
  578. }
  579. unlink(mutex->fname);
  580. return APR_SUCCESS;
  581. }
  582. static apr_status_t proc_mutex_flock_create(apr_proc_mutex_t *new_mutex,
  583. const char *fname)
  584. {
  585. int rv;
  586. if (fname) {
  587. new_mutex->fname = apr_pstrdup(new_mutex->pool, fname);
  588. rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
  589. APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
  590. APR_UREAD | APR_UWRITE,
  591. new_mutex->pool);
  592. }
  593. else {
  594. new_mutex->fname = apr_pstrdup(new_mutex->pool, "/tmp/aprXXXXXX");
  595. rv = apr_file_mktemp(&new_mutex->interproc, new_mutex->fname,
  596. APR_FOPEN_CREATE | APR_FOPEN_WRITE | APR_FOPEN_EXCL,
  597. new_mutex->pool);
  598. }
  599. if (rv != APR_SUCCESS) {
  600. proc_mutex_flock_cleanup(new_mutex);
  601. return errno;
  602. }
  603. new_mutex->curr_locked = 0;
  604. apr_pool_cleanup_register(new_mutex->pool, (void *)new_mutex,
  605. apr_proc_mutex_cleanup,
  606. apr_pool_cleanup_null);
  607. return APR_SUCCESS;
  608. }
  609. static apr_status_t proc_mutex_flock_acquire(apr_proc_mutex_t *mutex)
  610. {
  611. int rc;
  612. do {
  613. rc = flock(mutex->interproc->filedes, LOCK_EX);
  614. } while (rc < 0 && errno == EINTR);
  615. if (rc < 0) {
  616. return errno;
  617. }
  618. mutex->curr_locked = 1;
  619. return APR_SUCCESS;
  620. }
  621. static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex)
  622. {
  623. int rc;
  624. do {
  625. rc = flock(mutex->interproc->filedes, LOCK_EX | LOCK_NB);
  626. } while (rc < 0 && errno == EINTR);
  627. if (rc < 0) {
  628. if (errno == EWOULDBLOCK || errno == EAGAIN) {
  629. return APR_EBUSY;
  630. }
  631. return errno;
  632. }
  633. mutex->curr_locked = 1;
  634. return APR_SUCCESS;
  635. }
  636. static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
  637. {
  638. int rc;
  639. mutex->curr_locked = 0;
  640. do {
  641. rc = flock(mutex->interproc->filedes, LOCK_UN);
  642. } while (rc < 0 && errno == EINTR);
  643. if (rc < 0) {
  644. return errno;
  645. }
  646. return APR_SUCCESS;
  647. }
  648. static apr_status_t proc_mutex_flock_child_init(apr_proc_mutex_t **mutex,
  649. apr_pool_t *pool,
  650. const char *fname)
  651. {
  652. apr_proc_mutex_t *new_mutex;
  653. int rv;
  654. new_mutex = (apr_proc_mutex_t *)apr_palloc(pool, sizeof(apr_proc_mutex_t));
  655. memcpy(new_mutex, *mutex, sizeof *new_mutex);
  656. new_mutex->pool = pool;
  657. if (!fname) {
  658. fname = (*mutex)->fname;
  659. }
  660. new_mutex->fname = apr_pstrdup(pool, fname);
  661. rv = apr_file_open(&new_mutex->interproc, new_mutex->fname,
  662. APR_FOPEN_WRITE, 0, new_mutex->pool);
  663. if (rv != APR_SUCCESS) {
  664. return rv;
  665. }
  666. *mutex = new_mutex;
  667. return APR_SUCCESS;
  668. }
  669. static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
  670. {
  671. #if APR_PROCESS_LOCK_IS_GLOBAL || !APR_HAS_THREADS || defined(FLOCK_IS_GLOBAL)
  672. APR_PROCESS_LOCK_MECH_IS_GLOBAL,
  673. #else
  674. 0,
  675. #endif
  676. proc_mutex_flock_create,
  677. proc_mutex_flock_acquire,
  678. proc_mutex_flock_tryacquire,
  679. proc_mutex_flock_release,
  680. proc_mutex_flock_cleanup,
  681. proc_mutex_flock_child_init,
  682. "flock"
  683. };
  684. #endif /* flock implementation */
  685. void apr_proc_mutex_unix_setup_lock(void)
  686. {
  687. /* setup only needed for sysvsem and fnctl */
  688. #if APR_HAS_SYSVSEM_SERIALIZE
  689. proc_mutex_sysv_setup();
  690. #endif
  691. #if APR_HAS_FCNTL_SERIALIZE
  692. proc_mutex_fcntl_setup();
  693. #endif
  694. }
  695. static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech)
  696. {
  697. switch (mech) {
  698. case APR_LOCK_FCNTL:
  699. #if APR_HAS_FCNTL_SERIALIZE
  700. new_mutex->inter_meth = &mutex_fcntl_methods;
  701. #else
  702. return APR_ENOTIMPL;
  703. #endif
  704. break;
  705. case APR_LOCK_FLOCK:
  706. #if APR_HAS_FLOCK_SERIALIZE
  707. new_mutex->inter_meth = &mutex_flock_methods;
  708. #else
  709. return APR_ENOTIMPL;
  710. #endif
  711. break;
  712. case APR_LOCK_SYSVSEM:
  713. #if APR_HAS_SYSVSEM_SERIALIZE
  714. new_mutex->inter_meth = &mutex_sysv_methods;
  715. #else
  716. return APR_ENOTIMPL;
  717. #endif
  718. break;
  719. case APR_LOCK_POSIXSEM:
  720. #if APR_HAS_POSIXSEM_SERIALIZE
  721. new_mutex->inter_meth = &mutex_posixsem_methods;
  722. #else
  723. return APR_ENOTIMPL;
  724. #endif
  725. break;
  726. case APR_LOCK_PROC_PTHREAD:
  727. #if APR_HAS_PROC_PTHREAD_SERIALIZE
  728. new_mutex->inter_meth = &mutex_proc_pthread_methods;
  729. #else
  730. return APR_ENOTIMPL;
  731. #endif
  732. break;
  733. case APR_LOCK_DEFAULT:
  734. #if APR_USE_FLOCK_SERIALIZE
  735. new_mutex->inter_meth = &mutex_flock_methods;
  736. #elif APR_USE_SYSVSEM_SERIALIZE
  737. new_mutex->inter_meth = &mutex_sysv_methods;
  738. #elif APR_USE_FCNTL_SERIALIZE
  739. new_mutex->inter_meth = &mutex_fcntl_methods;
  740. #elif APR_USE_PROC_PTHREAD_SERIALIZE
  741. new_mutex->inter_meth = &mutex_proc_pthread_methods;
  742. #elif APR_USE_POSIXSEM_SERIALIZE
  743. new_mutex->inter_meth = &mutex_posixsem_methods;
  744. #else
  745. return APR_ENOTIMPL;
  746. #endif
  747. break;
  748. default:
  749. return APR_ENOTIMPL;
  750. }
  751. return APR_SUCCESS;
  752. }
  753. APR_DECLARE(const char *) apr_proc_mutex_defname(void)
  754. {
  755. apr_status_t rv;
  756. apr_proc_mutex_t mutex;
  757. if ((rv = proc_mutex_choose_method(&mutex, APR_LOCK_DEFAULT)) != APR_SUCCESS) {
  758. return "unknown";
  759. }
  760. mutex.meth = mutex.inter_meth;
  761. return apr_proc_mutex_name(&mutex);
  762. }
  763. static apr_status_t proc_mutex_create(apr_proc_mutex_t *new_mutex, apr_lockmech_e mech, const char *fname)
  764. {
  765. apr_status_t rv;
  766. if ((rv = proc_mutex_choose_method(new_mutex, mech)) != APR_SUCCESS) {
  767. return rv;
  768. }
  769. new_mutex->meth = new_mutex->inter_meth;
  770. if ((rv = new_mutex->meth->create(new_mutex, fname)) != APR_SUCCESS) {
  771. return rv;
  772. }
  773. return APR_SUCCESS;
  774. }
  775. APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
  776. const char *fname,
  777. apr_lockmech_e mech,
  778. apr_pool_t *pool)
  779. {
  780. apr_proc_mutex_t *new_mutex;
  781. apr_status_t rv;
  782. new_mutex = apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
  783. new_mutex->pool = pool;
  784. if ((rv = proc_mutex_create(new_mutex, mech, fname)) != APR_SUCCESS)
  785. return rv;
  786. *mutex = new_mutex;
  787. return APR_SUCCESS;
  788. }
  789. APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
  790. const char *fname,
  791. apr_pool_t *pool)
  792. {
  793. return (*mutex)->meth->child_init(mutex, pool, fname);
  794. }
  795. APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
  796. {
  797. return mutex->meth->acquire(mutex);
  798. }
  799. APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
  800. {
  801. return mutex->meth->tryacquire(mutex);
  802. }
  803. APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
  804. {
  805. return mutex->meth->release(mutex);
  806. }
  807. APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
  808. {
  809. return ((apr_proc_mutex_t *)mutex)->meth->cleanup(mutex);
  810. }
  811. APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
  812. {
  813. return mutex->meth->name;
  814. }
  815. APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
  816. {
  817. /* POSIX sems use the fname field but don't use a file,
  818. * so be careful. */
  819. #if APR_HAS_FLOCK_SERIALIZE
  820. if (mutex->meth == &mutex_flock_methods) {
  821. return mutex->fname;
  822. }
  823. #endif
  824. #if APR_HAS_FCNTL_SERIALIZE
  825. if (mutex->meth == &mutex_fcntl_methods) {
  826. return mutex->fname;
  827. }
  828. #endif
  829. return NULL;
  830. }
  831. APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
  832. /* Implement OS-specific accessors defined in apr_portable.h */
  833. APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
  834. apr_proc_mutex_t *pmutex)
  835. {
  836. #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE
  837. ospmutex->crossproc = pmutex->interproc->filedes;
  838. #endif
  839. #if APR_HAS_PROC_PTHREAD_SERIALIZE
  840. ospmutex->pthread_interproc = pmutex->pthread_interproc;
  841. #endif
  842. return APR_SUCCESS;
  843. }
  844. APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
  845. apr_os_proc_mutex_t *ospmutex,
  846. apr_pool_t *pool)
  847. {
  848. if (pool == NULL) {
  849. return APR_ENOPOOL;
  850. }
  851. if ((*pmutex) == NULL) {
  852. (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool,
  853. sizeof(apr_proc_mutex_t));
  854. (*pmutex)->pool = pool;
  855. }
  856. #if APR_HAS_SYSVSEM_SERIALIZE || APR_HAS_FCNTL_SERIALIZE || APR_HAS_FLOCK_SERIALIZE || APR_HAS_POSIXSEM_SERIALIZE
  857. apr_os_file_put(&(*pmutex)->interproc, &ospmutex->crossproc, 0, pool);
  858. #endif
  859. #if APR_HAS_PROC_PTHREAD_SERIALIZE
  860. (*pmutex)->pthread_interproc = ospmutex->pthread_interproc;
  861. #endif
  862. return APR_SUCCESS;
  863. }