mut_pthread.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:9k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999-2002
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: mut_pthread.c,v 11.53 2002/08/13 19:56:47 sue Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #endif
  16. #include "db_int.h"
  17. #ifdef DIAGNOSTIC
  18. #undef MSG1
  19. #define MSG1 "mutex_lock: ERROR: lock currently in use: pid: %lu.n"
  20. #undef MSG2
  21. #define MSG2 "mutex_unlock: ERROR: lock already unlockedn"
  22. #ifndef STDERR_FILENO
  23. #define STDERR_FILENO 2
  24. #endif
  25. #endif
  26. #ifdef HAVE_MUTEX_SOLARIS_LWP
  27. #define pthread_cond_signal _lwp_cond_signal
  28. #define pthread_cond_wait _lwp_cond_wait
  29. #define pthread_mutex_lock _lwp_mutex_lock
  30. #define pthread_mutex_trylock _lwp_mutex_trylock
  31. #define pthread_mutex_unlock _lwp_mutex_unlock
  32. /*
  33.  * _lwp_self returns the LWP process ID which isn't a unique per-thread
  34.  * identifier.  Use pthread_self instead, it appears to work even if we
  35.  * are not a pthreads application.
  36.  */
  37. #define pthread_mutex_destroy(x) 0
  38. #endif
  39. #ifdef HAVE_MUTEX_UI_THREADS
  40. #define pthread_cond_signal cond_signal
  41. #define pthread_cond_wait cond_wait
  42. #define pthread_mutex_lock mutex_lock
  43. #define pthread_mutex_trylock mutex_trylock
  44. #define pthread_mutex_unlock mutex_unlock
  45. #define pthread_self thr_self
  46. #define pthread_mutex_destroy mutex_destroy
  47. #endif
  48. #define PTHREAD_UNLOCK_ATTEMPTS 5
  49. /*
  50.  * __db_pthread_mutex_init --
  51.  * Initialize a DB_MUTEX.
  52.  *
  53.  * PUBLIC: int __db_pthread_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t));
  54.  */
  55. int
  56. __db_pthread_mutex_init(dbenv, mutexp, flags)
  57. DB_ENV *dbenv;
  58. DB_MUTEX *mutexp;
  59. u_int32_t flags;
  60. {
  61. u_int32_t save;
  62. int ret;
  63. ret = 0;
  64. /*
  65.  * The only setting/checking of the MUTEX_MPOOL flags is in the mutex
  66.  * mutex allocation code (__db_mutex_alloc/free).  Preserve only that
  67.  * flag.  This is safe because even if this flag was never explicitly
  68.  * set, but happened to be set in memory, it will never be checked or
  69.  * acted upon.
  70.  */
  71. save = F_ISSET(mutexp, MUTEX_MPOOL);
  72. memset(mutexp, 0, sizeof(*mutexp));
  73. F_SET(mutexp, save);
  74. /*
  75.  * If this is a thread lock or the process has told us that there are
  76.  * no other processes in the environment, use thread-only locks, they
  77.  * are faster in some cases.
  78.  *
  79.  * This is where we decide to ignore locks we don't need to set -- if
  80.  * the application isn't threaded, there aren't any threads to block.
  81.  */
  82. if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) {
  83. if (!F_ISSET(dbenv, DB_ENV_THREAD)) {
  84. F_SET(mutexp, MUTEX_IGNORE);
  85. return (0);
  86. }
  87. }
  88. #ifdef HAVE_MUTEX_PTHREADS
  89. {
  90. pthread_condattr_t condattr, *condattrp = NULL;
  91. pthread_mutexattr_t mutexattr, *mutexattrp = NULL;
  92. if (!LF_ISSET(MUTEX_THREAD)) {
  93. ret = pthread_mutexattr_init(&mutexattr);
  94. #ifndef HAVE_MUTEX_THREAD_ONLY
  95. if (ret == 0)
  96. ret = pthread_mutexattr_setpshared(
  97.     &mutexattr, PTHREAD_PROCESS_SHARED);
  98. #endif
  99. mutexattrp = &mutexattr;
  100. }
  101. if (ret == 0)
  102. ret = pthread_mutex_init(&mutexp->mutex, mutexattrp);
  103. if (mutexattrp != NULL)
  104. pthread_mutexattr_destroy(mutexattrp);
  105. if (ret == 0 && LF_ISSET(MUTEX_SELF_BLOCK)) {
  106. if (!LF_ISSET(MUTEX_THREAD)) {
  107. ret = pthread_condattr_init(&condattr);
  108. #ifndef HAVE_MUTEX_THREAD_ONLY
  109. if (ret == 0) {
  110. condattrp = &condattr;
  111. ret = pthread_condattr_setpshared(
  112.     &condattr, PTHREAD_PROCESS_SHARED);
  113. }
  114. #endif
  115. }
  116. if (ret == 0)
  117. ret = pthread_cond_init(&mutexp->cond, condattrp);
  118. F_SET(mutexp, MUTEX_SELF_BLOCK);
  119. if (condattrp != NULL)
  120. (void)pthread_condattr_destroy(condattrp);
  121. }
  122. }
  123. #endif
  124. #ifdef HAVE_MUTEX_SOLARIS_LWP
  125. /*
  126.  * XXX
  127.  * Gcc complains about missing braces in the static initializations of
  128.  * lwp_cond_t and lwp_mutex_t structures because the structures contain
  129.  * sub-structures/unions and the Solaris include file that defines the
  130.  * initialization values doesn't have surrounding braces.  There's not
  131.  * much we can do.
  132.  */
  133. if (LF_ISSET(MUTEX_THREAD)) {
  134. static lwp_mutex_t mi = DEFAULTMUTEX;
  135. mutexp->mutex = mi;
  136. } else {
  137. static lwp_mutex_t mi = SHAREDMUTEX;
  138. mutexp->mutex = mi;
  139. }
  140. if (LF_ISSET(MUTEX_SELF_BLOCK)) {
  141. if (LF_ISSET(MUTEX_THREAD)) {
  142. static lwp_cond_t ci = DEFAULTCV;
  143. mutexp->cond = ci;
  144. } else {
  145. static lwp_cond_t ci = SHAREDCV;
  146. mutexp->cond = ci;
  147. }
  148. F_SET(mutexp, MUTEX_SELF_BLOCK);
  149. }
  150. #endif
  151. #ifdef HAVE_MUTEX_UI_THREADS
  152. {
  153. int type;
  154. type = LF_ISSET(MUTEX_THREAD) ? USYNC_THREAD : USYNC_PROCESS;
  155. ret = mutex_init(&mutexp->mutex, type, NULL);
  156. if (ret == 0 && LF_ISSET(MUTEX_SELF_BLOCK)) {
  157. ret = cond_init(&mutexp->cond, type, NULL);
  158. F_SET(mutexp, MUTEX_SELF_BLOCK);
  159. }}
  160. #endif
  161. mutexp->spins = __os_spin(dbenv);
  162. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  163. mutexp->reg_off = INVALID_ROFF;
  164. #endif
  165. if (ret == 0)
  166. F_SET(mutexp, MUTEX_INITED);
  167. else
  168. __db_err(dbenv,
  169.     "unable to initialize mutex: %s", strerror(ret));
  170. return (ret);
  171. }
  172. /*
  173.  * __db_pthread_mutex_lock
  174.  * Lock on a mutex, logically blocking if necessary.
  175.  *
  176.  * PUBLIC: int __db_pthread_mutex_lock __P((DB_ENV *, DB_MUTEX *));
  177.  */
  178. int
  179. __db_pthread_mutex_lock(dbenv, mutexp)
  180. DB_ENV *dbenv;
  181. DB_MUTEX *mutexp;
  182. {
  183. u_int32_t nspins;
  184. int i, ret, waited;
  185. if (F_ISSET(dbenv, DB_ENV_NOLOCKING) || F_ISSET(mutexp, MUTEX_IGNORE))
  186. return (0);
  187. /* Attempt to acquire the resource for N spins. */
  188. for (nspins = mutexp->spins; nspins > 0; --nspins)
  189. if (pthread_mutex_trylock(&mutexp->mutex) == 0)
  190. break;
  191. if (nspins == 0 && (ret = pthread_mutex_lock(&mutexp->mutex)) != 0)
  192. goto err;
  193. if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) {
  194. for (waited = 0; mutexp->locked != 0; waited = 1) {
  195. ret = pthread_cond_wait(&mutexp->cond, &mutexp->mutex);
  196. /*
  197.  * !!!
  198.  * Solaris bug workaround:
  199.  * pthread_cond_wait() sometimes returns ETIME -- out
  200.  * of sheer paranoia, check both ETIME and ETIMEDOUT.
  201.  * We believe this happens when the application uses
  202.  * SIGALRM for some purpose, e.g., the C library sleep
  203.  * call, and Solaris delivers the signal to the wrong
  204.  * LWP.
  205.  */
  206. if (ret != 0 && ret != EINTR &&
  207. #ifdef ETIME
  208.     ret != ETIME &&
  209. #endif
  210.     ret != ETIMEDOUT) {
  211. (void)pthread_mutex_unlock(&mutexp->mutex);
  212. return (ret);
  213. }
  214. }
  215. if (waited)
  216. ++mutexp->mutex_set_wait;
  217. else
  218. ++mutexp->mutex_set_nowait;
  219. #ifdef DIAGNOSTIC
  220. mutexp->locked = (u_int32_t)pthread_self();
  221. #else
  222. mutexp->locked = 1;
  223. #endif
  224. /*
  225.  * According to HP-UX engineers contacted by Netscape,
  226.  * pthread_mutex_unlock() will occasionally return EFAULT
  227.  * for no good reason on mutexes in shared memory regions,
  228.  * and the correct caller behavior is to try again.  Do
  229.  * so, up to PTHREAD_UNLOCK_ATTEMPTS consecutive times.
  230.  * Note that we don't bother to restrict this to HP-UX;
  231.  * it should be harmless elsewhere. [#2471]
  232.  */
  233. i = PTHREAD_UNLOCK_ATTEMPTS;
  234. do {
  235. ret = pthread_mutex_unlock(&mutexp->mutex);
  236. } while (ret == EFAULT && --i > 0);
  237. if (ret != 0)
  238. goto err;
  239. } else {
  240. if (nspins == mutexp->spins)
  241. ++mutexp->mutex_set_nowait;
  242. else if (nspins > 0) {
  243. ++mutexp->mutex_set_spin;
  244. mutexp->mutex_set_spins += mutexp->spins - nspins;
  245. } else
  246. ++mutexp->mutex_set_wait;
  247. #ifdef DIAGNOSTIC
  248. if (mutexp->locked) {
  249. char msgbuf[128];
  250. (void)snprintf(msgbuf,
  251.     sizeof(msgbuf), MSG1, (u_long)mutexp->locked);
  252. (void)write(STDERR_FILENO, msgbuf, strlen(msgbuf));
  253. }
  254. mutexp->locked = (u_int32_t)pthread_self();
  255. #else
  256. mutexp->locked = 1;
  257. #endif
  258. }
  259. return (0);
  260. err: __db_err(dbenv, "unable to lock mutex: %s", strerror(ret));
  261. return (ret);
  262. }
  263. /*
  264.  * __db_pthread_mutex_unlock --
  265.  * Release a lock.
  266.  *
  267.  * PUBLIC: int __db_pthread_mutex_unlock __P((DB_ENV *, DB_MUTEX *));
  268.  */
  269. int
  270. __db_pthread_mutex_unlock(dbenv, mutexp)
  271. DB_ENV *dbenv;
  272. DB_MUTEX *mutexp;
  273. {
  274. int i, ret;
  275. if (F_ISSET(dbenv, DB_ENV_NOLOCKING) || F_ISSET(mutexp, MUTEX_IGNORE))
  276. return (0);
  277. #ifdef DIAGNOSTIC
  278. if (!mutexp->locked)
  279. (void)write(STDERR_FILENO, MSG2, sizeof(MSG2) - 1);
  280. #endif
  281. if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) {
  282. if ((ret = pthread_mutex_lock(&mutexp->mutex)) != 0)
  283. goto err;
  284. mutexp->locked = 0;
  285. if ((ret = pthread_cond_signal(&mutexp->cond)) != 0)
  286. return (ret);
  287. } else
  288. mutexp->locked = 0;
  289. /* See comment above;  workaround for [#2471]. */
  290. i = PTHREAD_UNLOCK_ATTEMPTS;
  291. do {
  292. ret = pthread_mutex_unlock(&mutexp->mutex);
  293. } while (ret == EFAULT && --i > 0);
  294. return (ret);
  295. err: __db_err(dbenv, "unable to unlock mutex: %s", strerror(ret));
  296. return (ret);
  297. }
  298. /*
  299.  * __db_pthread_mutex_destroy --
  300.  * Destroy a DB_MUTEX.
  301.  *
  302.  * PUBLIC: int __db_pthread_mutex_destroy __P((DB_MUTEX *));
  303.  */
  304. int
  305. __db_pthread_mutex_destroy(mutexp)
  306. DB_MUTEX *mutexp;
  307. {
  308. int ret;
  309. if (F_ISSET(mutexp, MUTEX_IGNORE))
  310. return (0);
  311. if ((ret = pthread_mutex_destroy(&mutexp->mutex)) != 0)
  312. __db_err(NULL, "unable to destroy mutex: %s", strerror(ret));
  313. return (ret);
  314. }