mutex.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: mutex.c,v 11.37 2002/05/31 19:37:46 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #if defined(MUTEX_NO_MALLOC_LOCKS) || defined(HAVE_MUTEX_SYSTEM_RESOURCES)
  17. #include "dbinc/db_shash.h"
  18. #include "dbinc/lock.h"
  19. #include "dbinc/log.h"
  20. #include "dbinc/mp.h"
  21. #include "dbinc/txn.h"
  22. #endif
  23. static int __db_mutex_alloc_int __P((DB_ENV *, REGINFO *, DB_MUTEX **));
  24. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  25. static REGMAINT * __db_mutex_maint __P((DB_ENV *, REGINFO *));
  26. #endif
  27. /*
  28.  * __db_mutex_setup --
  29.  * External interface to allocate, and/or initialize, record
  30.  * mutexes.
  31.  *
  32.  * PUBLIC: int __db_mutex_setup __P((DB_ENV *, REGINFO *, void *, u_int32_t));
  33.  */
  34. int
  35. __db_mutex_setup(dbenv, infop, ptr, flags)
  36. DB_ENV *dbenv;
  37. REGINFO *infop;
  38. void *ptr;
  39. u_int32_t flags;
  40. {
  41. DB_MUTEX *mutex;
  42. REGMAINT *maint;
  43. u_int32_t iflags, offset;
  44. int ret;
  45. ret = 0;
  46. /*
  47.  * If they indicated the region is not locked, then lock it.
  48.  * This is only needed when we have unusual mutex resources.
  49.  * (I.e. MUTEX_NO_MALLOC_LOCKS or HAVE_MUTEX_SYSTEM_RESOURCES)
  50.  */
  51. #if defined(MUTEX_NO_MALLOC_LOCKS) || defined(HAVE_MUTEX_SYSTEM_RESOURCES)
  52. if (!LF_ISSET(MUTEX_NO_RLOCK))
  53. R_LOCK(dbenv, infop);
  54. #endif
  55. /*
  56.  * Allocate the mutex if they asked us to.
  57.  */
  58. mutex = NULL;
  59. if (LF_ISSET(MUTEX_ALLOC)) {
  60. if ((ret = __db_mutex_alloc_int(dbenv, infop, ptr)) != 0)
  61. goto err;
  62. mutex = *(DB_MUTEX **)ptr;
  63. } else
  64. mutex = (DB_MUTEX *)ptr;
  65. /*
  66.  * Set up to initialize the mutex.
  67.  */
  68. iflags = LF_ISSET(MUTEX_THREAD | MUTEX_SELF_BLOCK);
  69. switch (infop->type) {
  70. case REGION_TYPE_LOCK:
  71. offset = P_TO_UINT32(mutex) + DB_FCNTL_OFF_LOCK;
  72. break;
  73. case REGION_TYPE_MPOOL:
  74. offset = P_TO_UINT32(mutex) + DB_FCNTL_OFF_MPOOL;
  75. break;
  76. default:
  77. offset = P_TO_UINT32(mutex) + DB_FCNTL_OFF_GEN;
  78. break;
  79. }
  80. maint = NULL;
  81. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  82. if (!LF_ISSET(MUTEX_NO_RECORD))
  83. maint = (REGMAINT *)__db_mutex_maint(dbenv, infop);
  84. #endif
  85. ret = __db_mutex_init(dbenv, mutex, offset, iflags, infop, maint);
  86. err:
  87. #if defined(MUTEX_NO_MALLOC_LOCKS) || defined(HAVE_MUTEX_SYSTEM_RESOURCES)
  88. if (!LF_ISSET(MUTEX_NO_RLOCK))
  89. R_UNLOCK(dbenv, infop);
  90. #endif
  91. /*
  92.  * If we allocated the mutex but had an error on init'ing,
  93.  * then we must free it before returning.
  94.  * !!!
  95.  * Free must be done after releasing region lock.
  96.  */
  97. if (ret != 0 && LF_ISSET(MUTEX_ALLOC) && mutex != NULL) {
  98. __db_mutex_free(dbenv, infop, mutex);
  99. *(DB_MUTEX **)ptr = NULL;
  100. }
  101. return (ret);
  102. }
  103. /*
  104.  * __db_mutex_alloc_int --
  105.  * Allocate and initialize a mutex.
  106.  */
  107. static int
  108. __db_mutex_alloc_int(dbenv, infop, storep)
  109. DB_ENV *dbenv;
  110. REGINFO *infop;
  111. DB_MUTEX **storep;
  112. {
  113. int ret;
  114. /*
  115.  * If the architecture supports mutexes in heap memory, use heap memory.
  116.  * If it doesn't, we have to allocate space in a region.  If allocation
  117.  * in the region fails, fallback to allocating from the mpool region,
  118.  * because it's big, it almost always exists and if it's entirely dirty,
  119.  * we can free buffers until memory is available.
  120.  */
  121. #if defined(MUTEX_NO_MALLOC_LOCKS) || defined(HAVE_MUTEX_SYSTEM_RESOURCES)
  122. ret = __db_shalloc(infop->addr, sizeof(DB_MUTEX), MUTEX_ALIGN, storep);
  123. if (ret == ENOMEM && MPOOL_ON(dbenv)) {
  124. DB_MPOOL *dbmp;
  125. dbmp = dbenv->mp_handle;
  126. if ((ret = __memp_alloc(dbmp,
  127.     dbmp->reginfo, NULL, sizeof(DB_MUTEX), NULL, storep)) == 0)
  128. (*storep)->flags = MUTEX_MPOOL;
  129. } else
  130. (*storep)->flags = 0;
  131. #else
  132. COMPQUIET(dbenv, NULL);
  133. COMPQUIET(infop, NULL);
  134. ret = __os_calloc(dbenv, 1, sizeof(DB_MUTEX), storep);
  135. #endif
  136. if (ret != 0)
  137. __db_err(dbenv, "Unable to allocate memory for mutex");
  138. return (ret);
  139. }
  140. /*
  141.  * __db_mutex_free --
  142.  * Free a mutex.
  143.  *
  144.  * PUBLIC: void __db_mutex_free __P((DB_ENV *, REGINFO *, DB_MUTEX *));
  145.  */
  146. void
  147. __db_mutex_free(dbenv, infop, mutexp)
  148. DB_ENV *dbenv;
  149. REGINFO *infop;
  150. DB_MUTEX *mutexp;
  151. {
  152. #if defined(MUTEX_NO_MALLOC_LOCKS) || defined(HAVE_MUTEX_SYSTEM_RESOURCES)
  153. R_LOCK(dbenv, infop);
  154. #if defined(HAVE_MUTEX_SYSTEM_RESOURCES)
  155. if (F_ISSET(mutexp, MUTEX_INITED))
  156. __db_shlocks_clear(mutexp, infop, NULL);
  157. #endif
  158. if (F_ISSET(mutexp, MUTEX_MPOOL)) {
  159. DB_MPOOL *dbmp;
  160. dbmp = dbenv->mp_handle;
  161. R_LOCK(dbenv, dbmp->reginfo);
  162. __db_shalloc_free(dbmp->reginfo[0].addr, mutexp);
  163. R_UNLOCK(dbenv, dbmp->reginfo);
  164. } else
  165. __db_shalloc_free(infop->addr, mutexp);
  166. R_UNLOCK(dbenv, infop);
  167. #else
  168. COMPQUIET(dbenv, NULL);
  169. COMPQUIET(infop, NULL);
  170. __os_free(dbenv, mutexp);
  171. #endif
  172. }
  173. #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
  174. /*
  175.  * __db_shreg_locks_record --
  176.  * Record an entry in the shared locks area.
  177.  * Region lock must be held in caller.
  178.  */
  179. static int
  180. __db_shreg_locks_record(dbenv, mutexp, infop, rp)
  181. DB_ENV *dbenv;
  182. DB_MUTEX *mutexp;
  183. REGINFO *infop;
  184. REGMAINT *rp;
  185. {
  186. u_int i;
  187. if (!F_ISSET(mutexp, MUTEX_INITED))
  188. return (0);
  189. DB_ASSERT(mutexp->reg_off == INVALID_ROFF);
  190. rp->stat.st_records++;
  191. i = (roff_t *)R_ADDR(infop, rp->regmutex_hint) - &rp->regmutexes[0];
  192. if (rp->regmutexes[i] != INVALID_ROFF) {
  193. /*
  194.  * Our hint failed, search for an open slot.
  195.  */
  196. rp->stat.st_hint_miss++;
  197. for (i = 0; i < rp->reglocks; i++)
  198. if (rp->regmutexes[i] == INVALID_ROFF)
  199. break;
  200. if (i == rp->reglocks) {
  201. rp->stat.st_max_locks++;
  202. __db_err(dbenv,
  203.     "Region mutexes: Exceeded maximum lock slots %lu",
  204.     (u_long)rp->reglocks);
  205. return (ENOMEM);
  206. }
  207. } else
  208. rp->stat.st_hint_hit++;
  209. /*
  210.  * When we get here, i is an empty slot.  Record this
  211.  * mutex, set hint to point to the next slot and we are done.
  212.  */
  213. rp->regmutexes[i] = R_OFFSET(infop, mutexp);
  214. mutexp->reg_off = R_OFFSET(infop, &rp->regmutexes[i]);
  215. rp->regmutex_hint = (i < rp->reglocks - 1) ?
  216.     R_OFFSET(infop, &rp->regmutexes[i+1]) :
  217.     R_OFFSET(infop, &rp->regmutexes[0]);
  218. return (0);
  219. }
  220. /*
  221.  * __db_shreg_locks_clear --
  222.  * Erase an entry in the shared locks area.
  223.  *
  224.  * PUBLIC: void __db_shreg_locks_clear __P((DB_MUTEX *, REGINFO *, REGMAINT *));
  225.  */
  226. void
  227. __db_shreg_locks_clear(mutexp, infop, rp)
  228. DB_MUTEX *mutexp;
  229. REGINFO *infop;
  230. REGMAINT *rp;
  231. {
  232. /*
  233.  * !!!
  234.  * Assumes the caller's region lock is held.
  235.  */
  236. if (!F_ISSET(mutexp, MUTEX_INITED))
  237. return;
  238. /*
  239.  * This function is generally only called on a forcible remove of an
  240.  * environment.  We recorded our index in the mutex, find and clear it.
  241.  */
  242. DB_ASSERT(mutexp->reg_off != INVALID_ROFF);
  243. DB_ASSERT(*(roff_t *)R_ADDR(infop, mutexp->reg_off) == 
  244.     R_OFFSET(infop, mutexp));
  245. *(roff_t *)R_ADDR(infop, mutexp->reg_off) = 0;
  246. if (rp != NULL) {
  247. rp->regmutex_hint = mutexp->reg_off;
  248. rp->stat.st_clears++;
  249. }
  250. mutexp->reg_off = INVALID_ROFF;
  251. __db_mutex_destroy(mutexp);
  252. }
  253. /*
  254.  * __db_shreg_locks_destroy --
  255.  * Destroy all mutexes in a region's range.
  256.  *
  257.  * PUBLIC: void __db_shreg_locks_destroy __P((REGINFO *, REGMAINT *));
  258.  */
  259. void
  260. __db_shreg_locks_destroy(infop, rp)
  261. REGINFO *infop;
  262. REGMAINT *rp;
  263. {
  264. u_int32_t i;
  265. /*
  266.  * Go through the list of all mutexes and destroy them.
  267.  */
  268. for (i = 0; i < rp->reglocks; i++)
  269. if (rp->regmutexes[i] != 0) {
  270. rp->stat.st_destroys++;
  271. __db_mutex_destroy((DB_MUTEX *)R_ADDR(infop,
  272.     rp->regmutexes[i]));
  273. }
  274. }
  275. /*
  276.  * __db_shreg_mutex_init --
  277.  * Initialize a shared memory mutex.
  278.  *
  279.  * PUBLIC: int __db_shreg_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t,
  280.  * PUBLIC:    u_int32_t, REGINFO *, REGMAINT *));
  281.  */
  282. int
  283. __db_shreg_mutex_init(dbenv, mutexp, offset, flags, infop, rp)
  284. DB_ENV *dbenv;
  285. DB_MUTEX *mutexp;
  286. u_int32_t offset;
  287. u_int32_t flags;
  288. REGINFO *infop;
  289. REGMAINT *rp;
  290. {
  291. int ret;
  292. if ((ret = __db_mutex_init_int(dbenv, mutexp, offset, flags)) != 0)
  293. return (ret);
  294. /*
  295.  * Some mutexes cannot be recorded, but we want one interface.
  296.  * So, if we have no REGMAINT, then just return.
  297.  */
  298. if (rp == NULL)
  299. return (ret);
  300. /*
  301.  * !!!
  302.  * Since __db_mutex_init_int is a macro, we may not be
  303.  * using the 'offset' as it is only used for one type
  304.  * of mutex.  We COMPQUIET it here, after the call above.
  305.  */
  306. COMPQUIET(offset, 0);
  307. ret = __db_shreg_locks_record(dbenv, mutexp, infop, rp);
  308. /*
  309.  * If we couldn't record it and we are returning an error,
  310.  * we need to destroy the mutex we just created.
  311.  */
  312. if (ret)
  313. __db_mutex_destroy(mutexp);
  314. return (ret);
  315. }
  316. /*
  317.  * __db_shreg_maintinit --
  318.  * Initialize a region's maintenance information.
  319.  *
  320.  * PUBLIC: void __db_shreg_maintinit __P((REGINFO *, void *addr, size_t));
  321.  */
  322. void
  323. __db_shreg_maintinit(infop, addr, size)
  324. REGINFO *infop;
  325. void *addr;
  326. size_t size;
  327. {
  328. REGMAINT *rp;
  329. u_int32_t i;
  330. rp = (REGMAINT *)addr;
  331. memset(addr, 0, sizeof(REGMAINT));
  332. rp->reglocks = size / sizeof(roff_t);
  333. rp->regmutex_hint = R_OFFSET(infop, &rp->regmutexes[0]);
  334. for (i = 0; i < rp->reglocks; i++)
  335. rp->regmutexes[i] = INVALID_ROFF;
  336. }
  337. static REGMAINT *
  338. __db_mutex_maint(dbenv, infop)
  339. DB_ENV *dbenv;
  340. REGINFO *infop;
  341. {
  342. roff_t moff;
  343. switch (infop->type) {
  344. case REGION_TYPE_LOCK:
  345. moff = ((DB_LOCKREGION *)R_ADDR(infop,
  346.     infop->rp->primary))->maint_off;
  347. break;
  348. case REGION_TYPE_LOG:
  349. moff = ((LOG *)R_ADDR(infop, infop->rp->primary))->maint_off;
  350. break;
  351. case REGION_TYPE_MPOOL:
  352. moff = ((MPOOL *)R_ADDR(infop, infop->rp->primary))->maint_off;
  353. break;
  354. case REGION_TYPE_TXN:
  355. moff = ((DB_TXNREGION *)R_ADDR(infop,
  356.     infop->rp->primary))->maint_off;
  357. break;
  358. default:
  359. __db_err(dbenv,
  360. "Attempting to record mutex in a region not set up to do so");
  361. return (NULL);
  362. }
  363. return ((REGMAINT *)R_ADDR(infop, moff));
  364. }
  365. #endif /* HAVE_MUTEX_SYSTEM_RESOURCES */