spin.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:8k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * spin.c
  4.  *   routines for managing spin locks
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/storage/ipc/spin.c,v 1.18 1999/02/13 23:18:17 momjian Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. /*
  15.  * POSTGRES has two kinds of locks: semaphores (which put the
  16.  * process to sleep) and spinlocks (which are supposed to be
  17.  * short term locks).  Currently both are implemented as SysV
  18.  * semaphores, but presumably this can change if we move to
  19.  * a machine with a test-and-set (TAS) instruction.  Its probably
  20.  * a good idea to think about (and allocate) short term and long
  21.  * term semaphores separately anyway.
  22.  *
  23.  * NOTE: These routines are not supposed to be widely used in Postgres.
  24.  *  They are preserved solely for the purpose of porting Mark Sullivan's
  25.  *  buffer manager to Postgres.
  26.  */
  27. #include <errno.h>
  28. #include "postgres.h"
  29. #include "storage/ipc.h"
  30. #include "storage/s_lock.h"
  31. #include "storage/shmem.h"
  32. #include "storage/spin.h"
  33. #include "storage/proc.h"
  34. #include "utils/trace.h"
  35. #ifndef HAS_TEST_AND_SET
  36. #include <sys/sem.h>
  37. #endif
  38. /* globals used in this file */
  39. IpcSemaphoreId SpinLockId;
  40. #ifdef HAS_TEST_AND_SET
  41. /* real spin lock implementations */
  42. bool
  43. CreateSpinlocks(IPCKey key)
  44. {
  45. /* the spin lock shared memory must have been created by now */
  46. return TRUE;
  47. }
  48. bool
  49. InitSpinLocks(int init, IPCKey key)
  50. {
  51. extern SPINLOCK ShmemLock;
  52. extern SPINLOCK ShmemIndexLock;
  53. extern SPINLOCK BufMgrLock;
  54. extern SPINLOCK LockMgrLock;
  55. extern SPINLOCK ProcStructLock;
  56. extern SPINLOCK SInvalLock;
  57. extern SPINLOCK OidGenLockId;
  58. #ifdef STABLE_MEMORY_STORAGE
  59. extern SPINLOCK MMCacheLock;
  60. #endif
  61. /* These six spinlocks have fixed location is shmem */
  62. ShmemLock = (SPINLOCK) SHMEMLOCKID;
  63. ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
  64. BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
  65. LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
  66. ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
  67. SInvalLock = (SPINLOCK) SINVALLOCKID;
  68. OidGenLockId = (SPINLOCK) OIDGENLOCKID;
  69. #ifdef STABLE_MEMORY_STORAGE
  70. MMCacheLock = (SPINLOCK) MMCACHELOCKID;
  71. #endif
  72. return TRUE;
  73. }
  74. #ifdef LOCKDEBUG
  75. #define PRINT_LOCK(LOCK) 
  76. TPRINTF(TRACE_SPINLOCKS, 
  77. "(locklock = %d, flag = %d, nshlocks = %d, shlock = %d, " 
  78. "exlock =%d)n", LOCK->locklock, 
  79. LOCK->flag, LOCK->nshlocks, LOCK->shlock, 
  80. LOCK->exlock)
  81. #endif
  82. /* from ipc.c */
  83. extern SLock *SLockArray;
  84. void
  85. SpinAcquire(SPINLOCK lockid)
  86. {
  87. SLock    *slckP;
  88. /* This used to be in ipc.c, but move here to reduce function calls */
  89. slckP = &(SLockArray[lockid]);
  90. #ifdef LOCKDEBUG
  91. TPRINTF(TRACE_SPINLOCKS, "SpinAcquire: %d", lockid);
  92. PRINT_LOCK(slckP);
  93. #endif
  94. ex_try_again:
  95. S_LOCK(&(slckP->locklock));
  96. switch (slckP->flag)
  97. {
  98. case NOLOCK:
  99. slckP->flag = EXCLUSIVELOCK;
  100. S_LOCK(&(slckP->exlock));
  101. S_LOCK(&(slckP->shlock));
  102. S_UNLOCK(&(slckP->locklock));
  103. #ifdef LOCKDEBUG
  104. TPRINTF(TRACE_SPINLOCKS, "OUT: ");
  105. PRINT_LOCK(slckP);
  106. #endif
  107. break;
  108. case SHAREDLOCK:
  109. case EXCLUSIVELOCK:
  110. S_UNLOCK(&(slckP->locklock));
  111. S_LOCK(&(slckP->exlock));
  112. S_UNLOCK(&(slckP->exlock));
  113. goto ex_try_again;
  114. }
  115. PROC_INCR_SLOCK(lockid);
  116. #ifdef LOCKDEBUG
  117. TPRINTF(TRACE_SPINLOCKS, "SpinAcquire: got %d", lockid);
  118. #endif
  119. }
  120. void
  121. SpinRelease(SPINLOCK lockid)
  122. {
  123. SLock    *slckP;
  124. /* This used to be in ipc.c, but move here to reduce function calls */
  125. slckP = &(SLockArray[lockid]);
  126. #ifdef USE_ASSERT_CHECKING
  127. /*
  128.  * Check that we are actually holding the lock we are releasing. This
  129.  * can be done only after MyProc has been initialized.
  130.  */
  131. if (MyProc)
  132. Assert(MyProc->sLocks[lockid] > 0);
  133. Assert(slckP->flag != NOLOCK);
  134. #endif
  135. PROC_DECR_SLOCK(lockid);
  136. #ifdef LOCKDEBUG
  137. TPRINTF("SpinRelease: %dn", lockid);
  138. PRINT_LOCK(slckP);
  139. #endif
  140. S_LOCK(&(slckP->locklock));
  141. /* -------------
  142.  * give favor to read processes
  143.  * -------------
  144.  */
  145. slckP->flag = NOLOCK;
  146. if (slckP->nshlocks > 0)
  147. {
  148. while (slckP->nshlocks > 0)
  149. {
  150. S_UNLOCK(&(slckP->shlock));
  151. S_LOCK(&(slckP->comlock));
  152. }
  153. S_UNLOCK(&(slckP->shlock));
  154. }
  155. else
  156. S_UNLOCK(&(slckP->shlock));
  157. S_UNLOCK(&(slckP->exlock));
  158. S_UNLOCK(&(slckP->locklock));
  159. #ifdef LOCKDEBUG
  160. TPRINTF(TRACE_SPINLOCKS, "SpinRelease: released %d", lockid);
  161. PRINT_LOCK(slckP);
  162. #endif
  163. }
  164. #else /* HAS_TEST_AND_SET */
  165. /* Spinlocks are implemented using SysV semaphores */
  166. static bool AttachSpinLocks(IPCKey key);
  167. static bool SpinIsLocked(SPINLOCK lock);
  168. /*
  169.  * SpinAcquire -- try to grab a spinlock
  170.  *
  171.  * FAILS if the semaphore is corrupted.
  172.  */
  173. void
  174. SpinAcquire(SPINLOCK lock)
  175. {
  176. IpcSemaphoreLock(SpinLockId, lock, IpcExclusiveLock);
  177. PROC_INCR_SLOCK(lock);
  178. }
  179. /*
  180.  * SpinRelease -- release a spin lock
  181.  *
  182.  * FAILS if the semaphore is corrupted
  183.  */
  184. void
  185. SpinRelease(SPINLOCK lock)
  186. {
  187. Assert(SpinIsLocked(lock))
  188. PROC_DECR_SLOCK(lock);
  189. IpcSemaphoreUnlock(SpinLockId, lock, IpcExclusiveLock);
  190. }
  191. static bool
  192. SpinIsLocked(SPINLOCK lock)
  193. {
  194. int semval;
  195. semval = IpcSemaphoreGetValue(SpinLockId, lock);
  196. return semval < IpcSemaphoreDefaultStartValue;
  197. }
  198. /*
  199.  * CreateSpinlocks -- Create a sysV semaphore array for
  200.  * the spinlocks
  201.  *
  202.  */
  203. bool
  204. CreateSpinlocks(IPCKey key)
  205. {
  206. int status;
  207. IpcSemaphoreId semid;
  208. semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
  209.    IpcSemaphoreDefaultStartValue, 1, &status);
  210. if (status == IpcSemIdExist)
  211. {
  212. IpcSemaphoreKill(key);
  213. elog(NOTICE, "Destroying old spinlock semaphore");
  214. semid = IpcSemaphoreCreate(key, MAX_SPINS, IPCProtection,
  215.   IpcSemaphoreDefaultStartValue, 1, &status);
  216. }
  217. if (semid >= 0)
  218. {
  219. SpinLockId = semid;
  220. return TRUE;
  221. }
  222. /* cannot create spinlocks */
  223. elog(FATAL, "CreateSpinlocks: cannot create spin locks");
  224. return FALSE;
  225. }
  226. /*
  227.  * Attach to existing spinlock set
  228.  */
  229. static bool
  230. AttachSpinLocks(IPCKey key)
  231. {
  232. IpcSemaphoreId id;
  233. id = semget(key, MAX_SPINS, 0);
  234. if (id < 0)
  235. {
  236. if (errno == EEXIST)
  237. {
  238. /* key is the name of someone else's semaphore */
  239. elog(FATAL, "AttachSpinlocks: SPIN_KEY belongs to someone else");
  240. }
  241. /* cannot create spinlocks */
  242. elog(FATAL, "AttachSpinlocks: cannot create spin locks");
  243. return FALSE;
  244. }
  245. SpinLockId = id;
  246. return TRUE;
  247. }
  248. /*
  249.  * InitSpinLocks -- Spinlock bootstrapping
  250.  *
  251.  * We need several spinlocks for bootstrapping:
  252.  * ShmemIndexLock (for the shmem index table) and
  253.  * ShmemLock (for the shmem allocator), BufMgrLock (for buffer
  254.  * pool exclusive access), LockMgrLock (for the lock table), and
  255.  * ProcStructLock (a spin lock for the shared process structure).
  256.  * If there's a Sony WORM drive attached, we also have a spinlock
  257.  * (SJCacheLock) for it.  Same story for the main memory storage mgr.
  258.  *
  259.  */
  260. bool
  261. InitSpinLocks(int init, IPCKey key)
  262. {
  263. extern SPINLOCK ShmemLock;
  264. extern SPINLOCK ShmemIndexLock;
  265. extern SPINLOCK BufMgrLock;
  266. extern SPINLOCK LockMgrLock;
  267. extern SPINLOCK ProcStructLock;
  268. extern SPINLOCK SInvalLock;
  269. extern SPINLOCK OidGenLockId;
  270. #ifdef STABLE_MEMORY_STORAGE
  271. extern SPINLOCK MMCacheLock;
  272. #endif
  273. if (!init || key != IPC_PRIVATE)
  274. {
  275. /*
  276.  * if bootstrap and key is IPC_PRIVATE, it means that we are
  277.  * running backend by itself.  no need to attach spinlocks
  278.  */
  279. if (!AttachSpinLocks(key))
  280. {
  281. elog(FATAL, "InitSpinLocks: couldnt attach spin locks");
  282. return FALSE;
  283. }
  284. }
  285. /* These five (or six) spinlocks have fixed location is shmem */
  286. ShmemLock = (SPINLOCK) SHMEMLOCKID;
  287. ShmemIndexLock = (SPINLOCK) SHMEMINDEXLOCKID;
  288. BufMgrLock = (SPINLOCK) BUFMGRLOCKID;
  289. LockMgrLock = (SPINLOCK) LOCKMGRLOCKID;
  290. ProcStructLock = (SPINLOCK) PROCSTRUCTLOCKID;
  291. SInvalLock = (SPINLOCK) SINVALLOCKID;
  292. OidGenLockId = (SPINLOCK) OIDGENLOCKID;
  293. #ifdef STABLE_MEMORY_STORAGE
  294. MMCacheLock = (SPINLOCK) MMCACHELOCKID;
  295. #endif
  296. return TRUE;
  297. }
  298. #endif  /* HAS_TEST_AND_SET */