mut_pthread.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:8k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999, 2000
  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.33 2001/01/09 00:56:16 ubell 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. #define pthread_self _lwp_self
  33. #define pthread_mutex_destroy(x) 0
  34. #endif
  35. #ifdef HAVE_MUTEX_UI_THREADS
  36. #define pthread_cond_signal cond_signal
  37. #define pthread_cond_wait cond_wait
  38. #define pthread_mutex_lock mutex_lock
  39. #define pthread_mutex_trylock mutex_trylock
  40. #define pthread_mutex_unlock mutex_unlock
  41. #define pthread_self thr_self
  42. #define pthread_mutex_destroy mutex_destroy
  43. #endif
  44. #define PTHREAD_UNLOCK_ATTEMPTS 5
  45. /*
  46.  * __db_pthread_mutex_init --
  47.  * Initialize a MUTEX.
  48.  *
  49.  * PUBLIC: int __db_pthread_mutex_init __P((DB_ENV *, MUTEX *, u_int32_t));
  50.  */
  51. int
  52. __db_pthread_mutex_init(dbenv, mutexp, flags)
  53. DB_ENV *dbenv;
  54. MUTEX *mutexp;
  55. u_int32_t flags;
  56. {
  57. int ret;
  58. ret = 0;
  59. memset(mutexp, 0, sizeof(*mutexp));
  60. /*
  61.  * If this is a thread lock or the process has told us that there are
  62.  * no other processes in the environment, use thread-only locks, they
  63.  * are faster in some cases.
  64.  *
  65.  * This is where we decide to ignore locks we don't need to set -- if
  66.  * the application isn't threaded, there aren't any threads to block.
  67.  */
  68. if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) {
  69. if (!F_ISSET(dbenv, DB_ENV_THREAD)) {
  70. F_SET(mutexp, MUTEX_IGNORE);
  71. return (0);
  72. }
  73. F_SET(mutexp, MUTEX_THREAD);
  74. }
  75. #ifdef HAVE_MUTEX_PTHREADS
  76. {
  77. pthread_condattr_t condattr, *condattrp = NULL;
  78. pthread_mutexattr_t mutexattr, *mutexattrp = NULL;
  79. if (!F_ISSET(mutexp, MUTEX_THREAD)) {
  80. ret = pthread_condattr_init(&condattr);
  81. if (ret == 0)
  82. ret = pthread_condattr_setpshared(
  83.     &condattr, PTHREAD_PROCESS_SHARED);
  84. condattrp = &condattr;
  85. if (ret == 0)
  86. ret = pthread_mutexattr_init(&mutexattr);
  87. if (ret == 0)
  88. ret = pthread_mutexattr_setpshared(
  89.     &mutexattr, PTHREAD_PROCESS_SHARED);
  90. mutexattrp = &mutexattr;
  91. }
  92. if (ret == 0)
  93. ret = pthread_mutex_init(&mutexp->mutex, mutexattrp);
  94. if (mutexattrp != NULL)
  95. pthread_mutexattr_destroy(mutexattrp);
  96. if (LF_ISSET(MUTEX_SELF_BLOCK)) {
  97. if (ret == 0)
  98. ret = pthread_cond_init(&mutexp->cond, condattrp);
  99. F_SET(mutexp, MUTEX_SELF_BLOCK);
  100. if (condattrp != NULL)
  101. pthread_condattr_destroy(condattrp);
  102. }}
  103. #endif
  104. #ifdef HAVE_MUTEX_SOLARIS_LWP
  105. /*
  106.  * XXX
  107.  * Gcc complains about missing braces in the static initializations of
  108.  * lwp_cond_t and lwp_mutex_t structures because the structures contain
  109.  * sub-structures/unions and the Solaris include file that defines the
  110.  * initialization values doesn't have surrounding braces.  There's not
  111.  * much we can do.
  112.  */
  113. if (F_ISSET(mutexp, MUTEX_THREAD)) {
  114. static lwp_mutex_t mi = DEFAULTMUTEX;
  115. mutexp->mutex = mi;
  116. } else {
  117. static lwp_mutex_t mi = SHAREDMUTEX;
  118. mutexp->mutex = mi;
  119. }
  120. if (LF_ISSET(MUTEX_SELF_BLOCK)) {
  121. if (F_ISSET(mutexp, MUTEX_THREAD)) {
  122. static lwp_cond_t ci = DEFAULTCV;
  123. mutexp->cond = ci;
  124. } else {
  125. static lwp_cond_t ci = SHAREDCV;
  126. mutexp->cond = ci;
  127. }
  128. F_SET(mutexp, MUTEX_SELF_BLOCK);
  129. }
  130. #endif
  131. #ifdef HAVE_MUTEX_UI_THREADS
  132. {
  133. int type;
  134. type = F_ISSET(mutexp, MUTEX_THREAD) ? USYNC_THREAD : USYNC_PROCESS;
  135. ret = mutex_init(&mutexp->mutex, type, NULL);
  136. if (ret == 0 && LF_ISSET(MUTEX_SELF_BLOCK)) {
  137. ret = cond_init(&mutexp->cond, type, NULL);
  138. F_SET(mutexp, MUTEX_SELF_BLOCK);
  139. }}
  140. #endif
  141. mutexp->spins = __os_spin();
  142. #ifdef MUTEX_SYSTEM_RESOURCES
  143. mutexp->reg_off = INVALID_ROFF;
  144. #endif
  145. if (ret == 0)
  146. F_SET(mutexp, MUTEX_INITED);
  147. return (ret);
  148. }
  149. /*
  150.  * __db_pthread_mutex_lock
  151.  * Lock on a mutex, logically blocking if necessary.
  152.  *
  153.  * PUBLIC: int __db_pthread_mutex_lock __P((DB_ENV *, MUTEX *));
  154.  */
  155. int
  156. __db_pthread_mutex_lock(dbenv, mutexp)
  157. DB_ENV *dbenv;
  158. MUTEX *mutexp;
  159. {
  160. u_int32_t nspins;
  161. int i, ret, waited;
  162. if (!dbenv->db_mutexlocks || F_ISSET(mutexp, MUTEX_IGNORE))
  163. return (0);
  164. /* Attempt to acquire the resource for N spins. */
  165. for (nspins = mutexp->spins; nspins > 0; --nspins)
  166. if (pthread_mutex_trylock(&mutexp->mutex) == 0)
  167. break;
  168. if (nspins == 0 && (ret = pthread_mutex_lock(&mutexp->mutex)) != 0)
  169. return (ret);
  170. if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) {
  171. for (waited = 0; mutexp->locked != 0; waited = 1) {
  172. ret = pthread_cond_wait(&mutexp->cond, &mutexp->mutex);
  173. /*
  174.  * !!!
  175.  * Solaris bug workaround:
  176.  * pthread_cond_wait() sometimes returns ETIME -- out
  177.  * of sheer paranoia, check both ETIME and ETIMEDOUT.
  178.  * We believe this happens when the application uses
  179.  * SIGALRM for some purpose, e.g., the C library sleep
  180.  * call, and Solaris delivers the signal to the wrong
  181.  * LWP.
  182.  */
  183. if (ret != 0 && ret != ETIME && ret != ETIMEDOUT)
  184. return (ret);
  185. }
  186. if (waited)
  187. ++mutexp->mutex_set_wait;
  188. else
  189. ++mutexp->mutex_set_nowait;
  190. #ifdef DIAGNOSTIC
  191. mutexp->locked = (u_int32_t)pthread_self();
  192. #else
  193. mutexp->locked = 1;
  194. #endif
  195. /*
  196.  * According to HP-UX engineers contacted by Netscape,
  197.  * pthread_mutex_unlock() will occasionally return EFAULT
  198.  * for no good reason on mutexes in shared memory regions,
  199.  * and the correct caller behavior is to try again.  Do
  200.  * so, up to PTHREAD_UNLOCK_ATTEMPTS consecutive times.
  201.  * Note that we don't bother to restrict this to HP-UX;
  202.  * it should be harmless elsewhere. [#2471]
  203.  */
  204. i = PTHREAD_UNLOCK_ATTEMPTS;
  205. do {
  206. ret = pthread_mutex_unlock(&mutexp->mutex);
  207. } while (ret == EFAULT && --i > 0);
  208. if (ret != 0)
  209. return (ret);
  210. } else {
  211. if (nspins == mutexp->spins)
  212. ++mutexp->mutex_set_nowait;
  213. else
  214. ++mutexp->mutex_set_wait;
  215. #ifdef DIAGNOSTIC
  216. if (mutexp->locked) {
  217. char msgbuf[128];
  218. (void)snprintf(msgbuf,
  219.     sizeof(msgbuf), MSG1, (u_long)mutexp->locked);
  220. (void)write(STDERR_FILENO, msgbuf, strlen(msgbuf));
  221. }
  222. mutexp->locked = (u_int32_t)pthread_self();
  223. #else
  224. mutexp->locked = 1;
  225. #endif
  226. }
  227. return (0);
  228. }
  229. /*
  230.  * __db_pthread_mutex_unlock --
  231.  * Release a lock.
  232.  *
  233.  * PUBLIC: int __db_pthread_mutex_unlock __P((DB_ENV *, MUTEX *));
  234.  */
  235. int
  236. __db_pthread_mutex_unlock(dbenv, mutexp)
  237. DB_ENV *dbenv;
  238. MUTEX *mutexp;
  239. {
  240. int i, ret;
  241. if (!dbenv->db_mutexlocks || F_ISSET(mutexp, MUTEX_IGNORE))
  242. return (0);
  243. #ifdef DIAGNOSTIC
  244. if (!mutexp->locked)
  245. (void)write(STDERR_FILENO, MSG2, sizeof(MSG2) - 1);
  246. #endif
  247. if (F_ISSET(mutexp, MUTEX_SELF_BLOCK)) {
  248. if ((ret = pthread_mutex_lock(&mutexp->mutex)) != 0)
  249. return (ret);
  250. mutexp->locked = 0;
  251. if ((ret = pthread_cond_signal(&mutexp->cond)) != 0)
  252. return (ret);
  253. /* See comment above;  workaround for [#2471]. */
  254. i = PTHREAD_UNLOCK_ATTEMPTS;
  255. do {
  256. ret = pthread_mutex_unlock(&mutexp->mutex);
  257. } while (ret == EFAULT && --i > 0);
  258. if (ret != 0)
  259. return (ret);
  260. } else {
  261. mutexp->locked = 0;
  262. /* See comment above;  workaround for [#2471]. */
  263. i = PTHREAD_UNLOCK_ATTEMPTS;
  264. do {
  265. ret = pthread_mutex_unlock(&mutexp->mutex);
  266. } while (ret == EFAULT && --i > 0);
  267. if (ret != 0)
  268. return (ret);
  269. }
  270. return (0);
  271. }
  272. /*
  273.  * __db_pthread_mutex_destroy --
  274.  * Destroy a MUTEX.
  275.  *
  276.  * PUBLIC: int __db_pthread_mutex_destroy __P((MUTEX *));
  277.  */
  278. int
  279. __db_pthread_mutex_destroy(mutexp)
  280. MUTEX *mutexp;
  281. {
  282. if (F_ISSET(mutexp, MUTEX_IGNORE))
  283. return (0);
  284. return (pthread_mutex_destroy(&mutexp->mutex));
  285. }