PageRenderTime 23ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/PasswordMgr/Community.CsharpSqlite.Phone/Source/btmutex_c.cs

#
C# | 379 lines | 217 code | 31 blank | 131 comment | 65 complexity | 5edbbbba39997a1f1c456b208ad2bdc4 MD5 | raw file
Possible License(s): LGPL-2.0
  1. using System.Diagnostics;
  2. namespace Community.CsharpSqlite
  3. {
  4. public partial class Sqlite3
  5. {
  6. /*
  7. ** 2007 August 27
  8. **
  9. ** The author disclaims copyright to this source code. In place of
  10. ** a legal notice, here is a blessing:
  11. **
  12. ** May you do good and not evil.
  13. ** May you find forgiveness for yourself and forgive others.
  14. ** May you share freely, never taking more than you give.
  15. **
  16. *************************************************************************
  17. **
  18. ** This file contains code used to implement mutexes on Btree objects.
  19. ** This code really belongs in btree.c. But btree.c is getting too
  20. ** big and we want to break it down some. This packaged seemed like
  21. ** a good breakout.
  22. *************************************************************************
  23. ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart
  24. ** C#-SQLite is an independent reimplementation of the SQLite software library
  25. **
  26. ** SQLITE_SOURCE_ID: 2009-12-07 16:39:13 1ed88e9d01e9eda5cbc622e7614277f29bcc551c
  27. **
  28. ** $Header: Community.CsharpSqlite/src/btmutex_c.cs,v bcbd36f24b23 2010/02/18 17:35:24 Noah $
  29. *************************************************************************
  30. */
  31. //#include "btreeInt.h"
  32. #if !SQLITE_OMIT_SHARED_CACHE
  33. #if SQLITE_THREADSAFE
  34. /*
  35. ** Obtain the BtShared mutex associated with B-Tree handle p. Also,
  36. ** set BtShared.db to the database handle associated with p and the
  37. ** p->locked boolean to true.
  38. */
  39. static void lockBtreeMutex(Btree *p){
  40. assert( p->locked==0 );
  41. assert( sqlite3_mutex_notheld(p->pBt->mutex) );
  42. assert( sqlite3_mutex_held(p->db->mutex) );
  43. sqlite3_mutex_enter(p->pBt->mutex);
  44. p->pBt->db = p->db;
  45. p->locked = 1;
  46. }
  47. /*
  48. ** Release the BtShared mutex associated with B-Tree handle p and
  49. ** clear the p->locked boolean.
  50. */
  51. static void unlockBtreeMutex(Btree *p){
  52. assert( p->locked==1 );
  53. assert( sqlite3_mutex_held(p->pBt->mutex) );
  54. assert( sqlite3_mutex_held(p->db->mutex) );
  55. assert( p->db==p->pBt->db );
  56. sqlite3_mutex_leave(p->pBt->mutex);
  57. p->locked = 0;
  58. }
  59. /*
  60. ** Enter a mutex on the given BTree object.
  61. **
  62. ** If the object is not sharable, then no mutex is ever required
  63. ** and this routine is a no-op. The underlying mutex is non-recursive.
  64. ** But we keep a reference count in Btree.wantToLock so the behavior
  65. ** of this interface is recursive.
  66. **
  67. ** To avoid deadlocks, multiple Btrees are locked in the same order
  68. ** by all database connections. The p->pNext is a list of other
  69. ** Btrees belonging to the same database connection as the p Btree
  70. ** which need to be locked after p. If we cannot get a lock on
  71. ** p, then first unlock all of the others on p->pNext, then wait
  72. ** for the lock to become available on p, then relock all of the
  73. ** subsequent Btrees that desire a lock.
  74. */
  75. void sqlite3BtreeEnter(Btree *p){
  76. Btree *pLater;
  77. /* Some basic sanity checking on the Btree. The list of Btrees
  78. ** connected by pNext and pPrev should be in sorted order by
  79. ** Btree.pBt value. All elements of the list should belong to
  80. ** the same connection. Only shared Btrees are on the list. */
  81. assert( p->pNext==0 || p->pNext->pBt>p->pBt );
  82. assert( p->pPrev==0 || p->pPrev->pBt<p->pBt );
  83. assert( p->pNext==0 || p->pNext->db==p->db );
  84. assert( p->pPrev==0 || p->pPrev->db==p->db );
  85. assert( p->sharable || (p->pNext==0 && p->pPrev==0) );
  86. /* Check for locking consistency */
  87. assert( !p->locked || p->wantToLock>0 );
  88. assert( p->sharable || p->wantToLock==0 );
  89. /* We should already hold a lock on the database connection */
  90. assert( sqlite3_mutex_held(p->db->mutex) );
  91. /* Unless the database is sharable and unlocked, then BtShared.db
  92. ** should already be set correctly. */
  93. assert( (p->locked==0 && p->sharable) || p->pBt->db==p->db );
  94. if( !p->sharable ) return;
  95. p->wantToLock++;
  96. if( p->locked ) return;
  97. /* In most cases, we should be able to acquire the lock we
  98. ** want without having to go throught the ascending lock
  99. ** procedure that follows. Just be sure not to block.
  100. */
  101. if( sqlite3_mutex_try(p->pBt->mutex)==SQLITE_OK ){
  102. p->pBt->db = p->db;
  103. p->locked = 1;
  104. return;
  105. }
  106. /* To avoid deadlock, first release all locks with a larger
  107. ** BtShared address. Then acquire our lock. Then reacquire
  108. ** the other BtShared locks that we used to hold in ascending
  109. ** order.
  110. */
  111. for(pLater=p->pNext; pLater; pLater=pLater->pNext){
  112. assert( pLater->sharable );
  113. assert( pLater->pNext==0 || pLater->pNext->pBt>pLater->pBt );
  114. assert( !pLater->locked || pLater->wantToLock>0 );
  115. if( pLater->locked ){
  116. unlockBtreeMutex(pLater);
  117. }
  118. }
  119. lockBtreeMutex(p);
  120. for(pLater=p->pNext; pLater; pLater=pLater->pNext){
  121. if( pLater->wantToLock ){
  122. lockBtreeMutex(pLater);
  123. }
  124. }
  125. }
  126. /*
  127. ** Exit the recursive mutex on a Btree.
  128. */
  129. void sqlite3BtreeLeave(Btree *p){
  130. if( p->sharable ){
  131. assert( p->wantToLock>0 );
  132. p->wantToLock--;
  133. if( p->wantToLock==0 ){
  134. unlockBtreeMutex(p);
  135. }
  136. }
  137. }
  138. #if !NDEBUG
  139. /*
  140. ** Return true if the BtShared mutex is held on the btree, or if the
  141. ** B-Tree is not marked as sharable.
  142. **
  143. ** This routine is used only from within assert() statements.
  144. */
  145. int sqlite3BtreeHoldsMutex(Btree *p){
  146. assert( p->sharable==0 || p->locked==0 || p->wantToLock>0 );
  147. assert( p->sharable==0 || p->locked==0 || p->db==p->pBt->db );
  148. assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->pBt->mutex) );
  149. assert( p->sharable==0 || p->locked==0 || sqlite3_mutex_held(p->db->mutex) );
  150. return (p->sharable==0 || p->locked);
  151. }
  152. #endif
  153. #if !SQLITE_OMIT_INCRBLOB
  154. /*
  155. ** Enter and leave a mutex on a Btree given a cursor owned by that
  156. ** Btree. These entry points are used by incremental I/O and can be
  157. ** omitted if that module is not used.
  158. */
  159. void sqlite3BtreeEnterCursor(BtCursor *pCur){
  160. sqlite3BtreeEnter(pCur->pBtree);
  161. }
  162. void sqlite3BtreeLeaveCursor(BtCursor *pCur){
  163. sqlite3BtreeLeave(pCur->pBtree);
  164. }
  165. #endif //* SQLITE_OMIT_INCRBLOB */
  166. /*
  167. ** Enter the mutex on every Btree associated with a database
  168. ** connection. This is needed (for example) prior to parsing
  169. ** a statement since we will be comparing table and column names
  170. ** against all schemas and we do not want those schemas being
  171. ** reset out from under us.
  172. **
  173. ** There is a corresponding leave-all procedures.
  174. **
  175. ** Enter the mutexes in accending order by BtShared pointer address
  176. ** to avoid the possibility of deadlock when two threads with
  177. ** two or more btrees in common both try to lock all their btrees
  178. ** at the same instant.
  179. */
  180. void sqlite3BtreeEnterAll(sqlite3 *db){
  181. int i;
  182. Btree *p, *pLater;
  183. assert( sqlite3_mutex_held(db->mutex) );
  184. for(i=0; i<db->nDb; i++){
  185. p = db->aDb[i].pBt;
  186. assert( !p || (p->locked==0 && p->sharable) || p->pBt->db==p->db );
  187. if( p && p->sharable ){
  188. p->wantToLock++;
  189. if( !p->locked ){
  190. assert( p->wantToLock==1 );
  191. while( p->pPrev ) p = p->pPrev;
  192. /* Reason for ALWAYS: There must be at least on unlocked Btree in
  193. ** the chain. Otherwise the !p->locked test above would have failed */
  194. while( p->locked && ALWAYS(p->pNext) ) p = p->pNext;
  195. for(pLater = p->pNext; pLater; pLater=pLater->pNext){
  196. if( pLater->locked ){
  197. unlockBtreeMutex(pLater);
  198. }
  199. }
  200. while( p ){
  201. lockBtreeMutex(p);
  202. p = p->pNext;
  203. }
  204. }
  205. }
  206. }
  207. }
  208. void sqlite3BtreeLeaveAll(sqlite3 *db){
  209. int i;
  210. Btree *p;
  211. assert( sqlite3_mutex_held(db->mutex) );
  212. for(i=0; i<db->nDb; i++){
  213. p = db->aDb[i].pBt;
  214. if( p && p->sharable ){
  215. assert( p->wantToLock>0 );
  216. p->wantToLock--;
  217. if( p->wantToLock==0 ){
  218. unlockBtreeMutex(p);
  219. }
  220. }
  221. }
  222. }
  223. #if !NDEBUG
  224. /*
  225. ** Return true if the current thread holds the database connection
  226. ** mutex and all required BtShared mutexes.
  227. **
  228. ** This routine is used inside assert() statements only.
  229. */
  230. int sqlite3BtreeHoldsAllMutexes(sqlite3 *db){
  231. int i;
  232. if( !sqlite3_mutex_held(db->mutex) ){
  233. return 0;
  234. }
  235. for(i=0; i<db->nDb; i++){
  236. Btree *p;
  237. p = db->aDb[i].pBt;
  238. if( p && p->sharable &&
  239. (p->wantToLock==0 || !sqlite3_mutex_held(p->pBt->mutex)) ){
  240. return 0;
  241. }
  242. }
  243. return 1;
  244. }
  245. #endif //* NDEBUG */
  246. /*
  247. ** Add a new Btree pointer to a BtreeMutexArray.
  248. ** if the pointer can possibly be shared with
  249. ** another database connection.
  250. **
  251. ** The pointers are kept in sorted order by pBtree->pBt. That
  252. ** way when we go to enter all the mutexes, we can enter them
  253. ** in order without every having to backup and retry and without
  254. ** worrying about deadlock.
  255. **
  256. ** The number of shared btrees will always be small (usually 0 or 1)
  257. ** so an insertion sort is an adequate algorithm here.
  258. */
  259. void sqlite3BtreeMutexArrayInsert(BtreeMutexArray *pArray, Btree *pBtree){
  260. int i, j;
  261. BtShared *pBt;
  262. if( pBtree==0 || pBtree->sharable==0 ) return;
  263. #if !NDEBUG
  264. {
  265. for(i=0; i<pArray->nMutex; i++){
  266. assert( pArray->aBtree[i]!=pBtree );
  267. }
  268. }
  269. #endif
  270. assert( pArray->nMutex>=0 );
  271. assert( pArray->nMutex<ArraySize(pArray->aBtree)-1 );
  272. pBt = pBtree->pBt;
  273. for(i=0; i<pArray->nMutex; i++){
  274. assert( pArray->aBtree[i]!=pBtree );
  275. if( pArray->aBtree[i]->pBt>pBt ){
  276. for(j=pArray->nMutex; j>i; j--){
  277. pArray->aBtree[j] = pArray->aBtree[j-1];
  278. }
  279. pArray->aBtree[i] = pBtree;
  280. pArray->nMutex++;
  281. return;
  282. }
  283. }
  284. pArray->aBtree[pArray->nMutex++] = pBtree;
  285. }
  286. /*
  287. ** Enter the mutex of every btree in the array. This routine is
  288. ** called at the beginning of sqlite3VdbeExec(). The mutexes are
  289. ** exited at the end of the same function.
  290. */
  291. void sqlite3BtreeMutexArrayEnter(BtreeMutexArray *pArray){
  292. int i;
  293. for(i=0; i<pArray->nMutex; i++){
  294. Btree *p = pArray->aBtree[i];
  295. /* Some basic sanity checking */
  296. assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
  297. assert( !p->locked || p->wantToLock>0 );
  298. /* We should already hold a lock on the database connection */
  299. assert( sqlite3_mutex_held(p->db->mutex) );
  300. /* The Btree is sharable because only sharable Btrees are entered
  301. ** into the array in the first place. */
  302. assert( p->sharable );
  303. p->wantToLock++;
  304. if( !p->locked ){
  305. lockBtreeMutex(p);
  306. }
  307. }
  308. }
  309. /*
  310. ** Leave the mutex of every btree in the group.
  311. */
  312. void sqlite3BtreeMutexArrayLeave(BtreeMutexArray *pArray){
  313. int i;
  314. for(i=0; i<pArray->nMutex; i++){
  315. Btree *p = pArray->aBtree[i];
  316. /* Some basic sanity checking */
  317. assert( i==0 || pArray->aBtree[i-1]->pBt<p->pBt );
  318. assert( p->locked);
  319. assert( p->wantToLock>0 );
  320. /* We should already hold a lock on the database connection */
  321. assert( sqlite3_mutex_held(p->db->mutex) );
  322. p->wantToLock--;
  323. if( p->wantToLock==0){
  324. unlockBtreeMutex(p);
  325. }
  326. }
  327. }
  328. #else
  329. static void sqlite3BtreeEnter( Btree p )
  330. {
  331. p.pBt.db = p.db;
  332. }
  333. static void sqlite3BtreeEnterAll( sqlite3 db )
  334. {
  335. int i;
  336. for ( i = 0 ; i < db.nDb ; i++ )
  337. {
  338. Btree p = db.aDb[i].pBt;
  339. if ( p != null )
  340. {
  341. p.pBt.db = p.db;
  342. }
  343. }
  344. }
  345. #endif //* if SQLITE_THREADSAFE */
  346. #endif //* ifndef SQLITE_OMIT_SHARED_CACHE */
  347. }
  348. }