Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

743 lines
24 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: lock.cxx
  7. //
  8. // Contents: Remote exclusion stuff for docfile
  9. //
  10. // Functions: GetAccess
  11. // ReleaseAccess
  12. // GetOpen
  13. // ReleaseOpen
  14. //
  15. // History: 09-Mar-92 PhilipLa Created.
  16. // 20-Jul-93 DrewB Added dual locking for Mac
  17. // compatibility
  18. //
  19. //--------------------------------------------------------------------------
  20. #include <exphead.cxx>
  21. #pragma hdrstop
  22. #include <header.hxx>
  23. #include <lock.hxx>
  24. // Offset to next lock group from a particular group
  25. #define OLOCKGROUP 1
  26. // The docfile originally locked at 0xffffff00
  27. // It turned out that the Mac can only lock to 0x7fffffff,
  28. // so for compatibility reasons it was decided that the
  29. // docfile would lock at both places. Thus, we have one routine
  30. // that locks with a mask for the offset so that we can
  31. // selectively suppress the high bit
  32. // Since lock indices fit easily within 16 bits, the two
  33. // lock indices are now combined into the existing ULONG
  34. // value to preserve compatibility with other code. This
  35. // implies that lock indices from these routines must be
  36. // handled opaquely since they are no longer simple numbers
  37. // 09/23/1993 - Further change:
  38. // To avoid a Netware 2.2 problem we are offsetting the lock regions
  39. // so that they differ by more than just the high bit. The high
  40. // lock region was moved to 0xffffff80, moving the low region to
  41. // 0x7fffff80. The 0x80 was then taken out of the high mask so that
  42. // the net is no change for high locks and the low locks moved up by 0x80
  43. // Masks for separate lock locations
  44. // moved to lock.hxx
  45. //In a specific open case (Read-only, deny-write), we don't need to
  46. //take locks.
  47. #define P_NOLOCK(df) (!P_WRITE(df) && P_READ(df) && \
  48. P_DENYWRITE(df) && !P_DENYREAD(df))
  49. //+--------------------------------------------------------------
  50. //
  51. // Function: GetAccessWithMask, private
  52. //
  53. // Synopsis: Takes appropriate access locks on an LStream,
  54. // masking the offset with the given mask
  55. //
  56. // Arguments: [plst] - LStream
  57. // [df] - Permissions needed
  58. // [ulMask] - Mask
  59. // [poReturn] - Index of lock taken
  60. //
  61. // Returns: Appropriate status code
  62. //
  63. // Modifies: [poReturn]
  64. //
  65. // History: 08-Apr-92 DrewB Created
  66. //
  67. //---------------------------------------------------------------
  68. SCODE GetAccessWithMask(ILockBytes *plst,
  69. DFLAGS df,
  70. ULONG ulMask,
  71. ULONG *poReturn)
  72. {
  73. SCODE sc;
  74. ULARGE_INTEGER ulOffset, cbLength;
  75. olDebugOut((DEB_ITRACE, "In GetAccessWithMask(%p, %X, %lX, %p)\n",
  76. plst, df, ulMask, poReturn));
  77. olAssert((df & ~(DF_READ | DF_WRITE)) == 0 && P_READ(df) != P_WRITE(df));
  78. *poReturn = NOLOCK;
  79. ULISet32(ulOffset, OACCESS & ulMask);
  80. if (P_READ(df))
  81. {
  82. ULISet32(cbLength, 1);
  83. olHChk(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  84. for (USHORT i = 0; i < CREADLOCKS; i++)
  85. {
  86. ULISetLow(ulOffset, (OREADLOCK+i) & ulMask);
  87. sc = DfGetScode(plst->LockRegion(ulOffset, cbLength,
  88. LOCK_ONLYONCE));
  89. if (SUCCEEDED(sc))
  90. {
  91. *poReturn = i+1;
  92. break;
  93. }
  94. }
  95. ULISetLow(ulOffset, OACCESS & ulMask);
  96. olHVerSucc(sc = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  97. if (i == CREADLOCKS)
  98. olErr(EH_Err, STG_E_TOOMANYOPENFILES);
  99. }
  100. else
  101. {
  102. olAssert((OACCESS + 1 == OREADLOCK) && aMsg("Bad lock dependency"));
  103. ULISet32(cbLength, 1 + CREADLOCKS);
  104. olChk(DfGetScode(plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE)));
  105. *poReturn = 0xFFFF;
  106. }
  107. olDebugOut((DEB_ITRACE, "Out GetAccessWithMask => %lu\n", *poReturn));
  108. olAssert(*poReturn != NOLOCK);
  109. return S_OK;
  110. EH_Err:
  111. return sc;
  112. }
  113. //+--------------------------------------------------------------
  114. //
  115. // Function: ReleaseAccessWithMask, private
  116. //
  117. // Synopsis: Releases an access lock at the given offset
  118. //
  119. // Arguments: [plst] - LStream that is locked
  120. // [df] - Permission to release
  121. // [offset] - Offset of locks taken
  122. // [ulMask] - Mask
  123. //
  124. // History: 08-Apr-92 DrewB Created
  125. //
  126. //---------------------------------------------------------------
  127. void ReleaseAccessWithMask(ILockBytes *plst,
  128. DFLAGS df,
  129. ULONG offset,
  130. ULONG ulMask)
  131. {
  132. ULARGE_INTEGER ulOffset, cbLength;
  133. SCODE scTemp;
  134. olDebugOut((DEB_ITRACE, "In ReleaseAccessWithMask(%p, %lX, %lu, %lX)\n",
  135. plst, df, offset, ulMask));
  136. olAssert((df & ~(DF_READ | DF_WRITE)) == 0 && P_READ(df) != P_WRITE(df));
  137. if (offset == NOLOCK)
  138. return;
  139. if (P_READ(df))
  140. {
  141. ULISet32(ulOffset, (offset+OREADLOCK-1) & ulMask);
  142. ULISet32(cbLength, 1);
  143. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  144. }
  145. else
  146. {
  147. olAssert((OACCESS + 1 == OREADLOCK) && aMsg("Bad lock dependency"));
  148. ULISet32(ulOffset, OACCESS & ulMask);
  149. ULISet32(cbLength, 1 + CREADLOCKS);
  150. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  151. }
  152. olDebugOut((DEB_ITRACE, "Out ReleaseAccessWithMask\n"));
  153. }
  154. //+--------------------------------------------------------------
  155. //
  156. // Function: GetAccess, public
  157. //
  158. // Synopsis: Takes appropriate access locks on an LStream
  159. //
  160. // Arguments: [plst] - LStream
  161. // [df] - Permissions needed
  162. // [poReturn] - Index of lock taken
  163. //
  164. // Returns: Appropriate status code
  165. //
  166. // Modifies: [poReturn]
  167. //
  168. // History: 08-Apr-92 DrewB Created
  169. //
  170. //---------------------------------------------------------------
  171. SCODE GetAccess(ILockBytes *plst,
  172. DFLAGS df,
  173. ULONG *poReturn)
  174. {
  175. SCODE sc;
  176. olDebugOut((DEB_ITRACE, "In GetAccess(%p, %X, %p)\n",
  177. plst, df, poReturn));
  178. // Make sure our lock region hasn't overflowed 32 bits
  179. olAssert(OLOCKREGIONEND > OACCESS);
  180. olChk(GetAccessWithMask(plst, df, 0xFFFFFFFF, poReturn));
  181. olAssert(*poReturn < 0x10000);
  182. olDebugOut((DEB_ITRACE, "Out GetAccess => %lu\n", *poReturn));
  183. return S_OK;
  184. EH_Err:
  185. *poReturn = NOLOCK;
  186. return sc;
  187. }
  188. //+--------------------------------------------------------------
  189. //
  190. // Function: ReleaseAccess, public
  191. //
  192. // Synopsis: Releases access locks
  193. //
  194. // Arguments: [plst] - LStream that is locked
  195. // [df] - Permission to release
  196. // [offset] - Offset of locks taken
  197. //
  198. // History: 08-Apr-92 DrewB Created
  199. //
  200. //---------------------------------------------------------------
  201. void ReleaseAccess(ILockBytes *plst, DFLAGS df, ULONG offset)
  202. {
  203. olDebugOut((DEB_ITRACE, "In ReleaseAccess(%p, %lX, %lu)\n",
  204. plst, df, offset));
  205. ReleaseAccessWithMask(plst, df, offset & 0xffff, 0xFFFFFFFF);
  206. olDebugOut((DEB_ITRACE, "Out ReleaseAccess\n"));
  207. }
  208. //+--------------------------------------------------------------
  209. //
  210. // Function: GetOpenWithMask, private
  211. //
  212. // Synopsis: Gets locks on an LStream during opening, masking the offset
  213. //
  214. // Arguments: [plst] - LStream
  215. // [df] - Permissions to take
  216. // [fCheck] - Whether to check for existing locks or not
  217. // [ulMask] - Mask
  218. // [puReturn] - Index of lock taken
  219. //
  220. // Returns: Appropriate status code
  221. //
  222. // Modifies: [puReturn]
  223. //
  224. // History: 08-Apr-92 DrewB Created
  225. //
  226. //---------------------------------------------------------------
  227. #define WAITUPDATE_INITIAL 100
  228. #define WAITUPDATE_TIMEOUT 10000
  229. SCODE GetOpenWithMask(ILockBytes *plst,
  230. DFLAGS df,
  231. BOOL fCheck,
  232. ULONG ulMask,
  233. ULONG *puReturn)
  234. {
  235. SCODE sc;
  236. ULONG i;
  237. ULARGE_INTEGER ulOffset, cbLength;
  238. #ifdef DIRECTWRITERLOCK
  239. BOOL fDirectWriterMode = P_READWRITE(df) && !P_TRANSACTED(df) &&
  240. !P_DENYREAD(df) && P_DENYWRITE(df);
  241. BOOL fDirectReaderMode = P_READ(df) && !P_WRITE(df) && !P_TRANSACTED(df) &&
  242. !P_DENYREAD(df) && !P_DENYWRITE(df);
  243. #endif
  244. olDebugOut((DEB_ITRACE, "In GetOpenWithMask(%p, %lX, %d, %lX, %p)\n",
  245. plst, df, fCheck, ulMask, puReturn));
  246. *puReturn = NOLOCK;
  247. ULISet32(ulOffset, OUPDATE & ulMask);
  248. ULISet32(cbLength, 1);
  249. //Do a graceful fallback.
  250. DWORD dwWait = WAITUPDATE_INITIAL;
  251. for (;;)
  252. {
  253. sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  254. if (sc != STG_E_LOCKVIOLATION ||
  255. dwWait >= WAITUPDATE_TIMEOUT)
  256. break;
  257. Sleep(dwWait);
  258. dwWait *= (GetTickCount() & 1) ? 1 : 2;
  259. }
  260. olChk(sc);
  261. if (fCheck)
  262. {
  263. ULISetLow(cbLength, COPENLOCKS);
  264. if (P_DENYREAD(df))
  265. {
  266. ULISetLow(ulOffset, OOPENREADLOCK & ulMask);
  267. olHChkTo(EH_UnlockUpdate, plst->LockRegion(ulOffset, cbLength,
  268. LOCK_ONLYONCE));
  269. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  270. }
  271. #ifndef USE_NOSNAPSHOT
  272. if (P_DENYWRITE(df))
  273. #else
  274. if (P_DENYWRITE(df) || P_NOSNAPSHOT(df))
  275. #endif
  276. {
  277. ULISetLow(ulOffset, OOPENWRITELOCK & ulMask);
  278. sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  279. if (SUCCEEDED(sc))
  280. {
  281. olHVerSucc(plst->UnlockRegion(ulOffset,
  282. cbLength,
  283. LOCK_ONLYONCE));
  284. }
  285. #ifdef USE_NOSNAPSHOT
  286. else if (P_NOSNAPSHOT(df))
  287. {
  288. //There is an existing writer. In order for this
  289. //open to succeed, there must also be a lock in the
  290. //no-snapshot region. Otherwise we have a case where
  291. //a normal open proceeded a no-snapshot open attempt,
  292. //and mixing modes is not allowed.
  293. ULISetLow(ulOffset, OOPENNOSNAPSHOTLOCK & ulMask);
  294. sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  295. if (SUCCEEDED(sc))
  296. {
  297. //There was no no-snapshot lock. No mixing modes,
  298. //so fail here.
  299. olHVerSucc(plst->UnlockRegion(ulOffset,
  300. cbLength,
  301. LOCK_ONLYONCE));
  302. olErr(EH_UnlockUpdate, STG_E_LOCKVIOLATION);
  303. }
  304. }
  305. #endif
  306. else
  307. {
  308. olErr(EH_UnlockUpdate, sc);
  309. }
  310. }
  311. if (P_READ(df))
  312. {
  313. ULISetLow(ulOffset, OOPENDENYREADLOCK & ulMask);
  314. olHChkTo(EH_UnlockUpdate, plst->LockRegion(ulOffset, cbLength,
  315. LOCK_ONLYONCE));
  316. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  317. }
  318. if (P_WRITE(df))
  319. {
  320. ULISetLow(ulOffset, OOPENDENYWRITELOCK & ulMask);
  321. #ifndef USE_NOSNAPSHOT
  322. olHChkTo(EH_UnlockUpdate, plst->LockRegion(ulOffset, cbLength,
  323. LOCK_ONLYONCE));
  324. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  325. #else
  326. sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  327. if (P_NOSNAPSHOT(df) && (sc == STG_E_LOCKVIOLATION))
  328. {
  329. //The deny-write lock may be the fake holder we use for
  330. //no-snapshot mode. Check then no-snapshot region - if
  331. //there is a lock there too, then this succeeds, otherwise
  332. //the deny-write lock is real and we must fail the call.
  333. ULISetLow(ulOffset, OOPENNOSNAPSHOTLOCK & ulMask);
  334. sc = plst->LockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  335. if (sc != STG_E_LOCKVIOLATION)
  336. {
  337. if (SUCCEEDED(sc))
  338. {
  339. olHVerSucc(plst->UnlockRegion(ulOffset,
  340. cbLength,
  341. LOCK_ONLYONCE));
  342. olErr(EH_UnlockUpdate, STG_E_LOCKVIOLATION);
  343. }
  344. else
  345. {
  346. olErr(EH_UnlockUpdate, sc);
  347. }
  348. }
  349. }
  350. else
  351. {
  352. olHChkTo(EH_UnlockUpdate, sc);
  353. olHVerSucc(plst->UnlockRegion(ulOffset,
  354. cbLength,
  355. LOCK_ONLYONCE));
  356. }
  357. #endif
  358. }
  359. }
  360. //If we are read-only and deny-write, and we are on our
  361. // ILockBytes, we don't need to lock and can rely on the FS
  362. // to handle the access control.
  363. if (P_NOLOCK(df))
  364. {
  365. //QueryInterface to see if this ILockBytes is ours
  366. IFileLockBytes *pfl;
  367. if (SUCCEEDED(plst->QueryInterface(IID_IFileLockBytes,
  368. (void **) &pfl)))
  369. {
  370. pfl->Release();
  371. ULISetLow(ulOffset, OUPDATE & ulMask);
  372. ULISetLow(cbLength, 1);
  373. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  374. *puReturn = NOLOCK;
  375. return S_OK;
  376. }
  377. }
  378. ULISetLow(cbLength, 1);
  379. for (i = 0; i < COPENLOCKS; i = i + OLOCKGROUP)
  380. {
  381. ULISetLow(ulOffset, (OOPENREADLOCK+i) & ulMask);
  382. olHChkTo(EH_Loop, plst->LockRegion(ulOffset, cbLength,
  383. LOCK_ONLYONCE));
  384. ULISetLow(ulOffset, (OOPENWRITELOCK+i) & ulMask);
  385. olHChkTo(EH_UnlockR, plst->LockRegion(ulOffset, cbLength,
  386. LOCK_ONLYONCE));
  387. ULISetLow(ulOffset, (OOPENDENYREADLOCK+i) & ulMask);
  388. #ifdef DIRECTWRITERLOCK
  389. if (fCheck == TRUE || fDirectWriterMode == FALSE)
  390. #endif
  391. olHChkTo(EH_UnlockW, plst->LockRegion(ulOffset, cbLength,
  392. LOCK_ONLYONCE));
  393. ULISetLow(ulOffset, (OOPENDENYWRITELOCK+i) & ulMask);
  394. #ifdef USE_NOSNAPSHOT
  395. olHChkTo(EH_UnlockDR, plst->LockRegion(ulOffset, cbLength,
  396. LOCK_ONLYONCE));
  397. if (P_NOSNAPSHOT(df))
  398. {
  399. //Note that in the non no-snapshot case we don't need to
  400. //grab this lock, unlike the others where we must grab all
  401. //four to make sure we have a valid slot. This is because
  402. //a no-snapshot open will always have a corresponding
  403. //deny-write lock in the same slot.
  404. ULISetLow(ulOffset, (OOPENNOSNAPSHOTLOCK+i) & ulMask);
  405. if (SUCCEEDED(DfGetScode(plst->LockRegion(ulOffset, cbLength,
  406. LOCK_ONLYONCE))))
  407. {
  408. break;
  409. }
  410. //Unlock the deny-write lock, then all the rest.
  411. ULISetLow(ulOffset, (OOPENDENYWRITELOCK + i));
  412. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  413. }
  414. else
  415. {
  416. //We're not no-snapshot, and we've gotten all our locks
  417. // successfully, so bail.
  418. #ifdef DIRECTWRITERLOCK
  419. if (fDirectReaderMode)
  420. {
  421. ULISetLow(ulOffset, (ODIRECTWRITERLOCK+i) & ulMask);
  422. if(SUCCEEDED(plst->LockRegion(ulOffset,cbLength,LOCK_ONLYONCE)))
  423. break;
  424. }
  425. else
  426. #endif
  427. break;
  428. }
  429. EH_UnlockDR:
  430. #else
  431. if (SUCCEEDED(DfGetScode(plst->LockRegion(ulOffset, cbLength,
  432. LOCK_ONLYONCE))))
  433. #ifdef DIRECTWRITERLOCK
  434. if (fDirectReaderMode)
  435. {
  436. ULISetLow(ulOffset, (ODIRECTWRITERLOCK+i) & ulMask);
  437. if(SUCCEEDED(plst->LockRegion(ulOffset,cbLength,LOCK_ONLYONCE)))
  438. break;
  439. }
  440. else
  441. #endif
  442. break;
  443. #endif //USE_NOSNAPSHOT
  444. ULISetLow(ulOffset, (OOPENDENYREADLOCK+i) & ulMask);
  445. #ifdef DIRECTWRITERLOCK
  446. if (fCheck == TRUE || fDirectWriterMode == FALSE)
  447. #endif
  448. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  449. EH_UnlockW:
  450. ULISetLow(ulOffset, (OOPENWRITELOCK+i) & ulMask);
  451. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  452. EH_UnlockR:
  453. ULISetLow(ulOffset, (OOPENREADLOCK+i) & ulMask);
  454. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  455. EH_Loop:
  456. ;
  457. }
  458. if (i >= COPENLOCKS)
  459. olErr(EH_UnlockUpdate, STG_E_TOOMANYOPENFILES);
  460. if (!P_READ(df))
  461. {
  462. ULISetLow(ulOffset, (OOPENREADLOCK+i) & ulMask);
  463. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  464. }
  465. if (!P_WRITE(df))
  466. {
  467. ULISetLow(ulOffset, (OOPENWRITELOCK+i) & ulMask);
  468. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  469. }
  470. if (!P_DENYREAD(df))
  471. {
  472. ULISetLow(ulOffset, (OOPENDENYREADLOCK+i) & ulMask);
  473. #ifdef DIRECTWRITERLOCK
  474. if (fCheck == TRUE || fDirectWriterMode == FALSE)
  475. #endif
  476. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  477. }
  478. #ifdef USE_NOSNAPSHOT
  479. if (!P_DENYWRITE(df) && !P_NOSNAPSHOT(df))
  480. #else
  481. if (!P_DENYWRITE(df))
  482. #endif
  483. {
  484. ULISetLow(ulOffset, (OOPENDENYWRITELOCK+i) & ulMask);
  485. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  486. }
  487. ULISetLow(ulOffset, OUPDATE & ulMask);
  488. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  489. // 0 <= i < COPENLOCKS, but 0 is the invalid value, so increment
  490. // on the way out
  491. *puReturn = i + 1;
  492. olAssert(*puReturn != NOLOCK);
  493. olDebugOut((DEB_ITRACE, "Out GetOpenWithMask => %lu\n", *puReturn));
  494. return S_OK;
  495. EH_UnlockUpdate:
  496. ULISetLow(ulOffset, OUPDATE & ulMask);
  497. ULISetLow(cbLength, 1);
  498. olHVerSucc(plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE));
  499. EH_Err:
  500. return sc;
  501. }
  502. //+--------------------------------------------------------------
  503. //
  504. // Function: ReleaseOpenWithMask, private
  505. //
  506. // Synopsis: Releases opening locks with offset masking
  507. //
  508. // Arguments: [plst] - LStream
  509. // [df] - Locks taken
  510. // [offset] - Index of locks
  511. // [ulMask] - Mask
  512. //
  513. // Requires: offset != NOLOCK
  514. //
  515. // History: 08-Apr-92 DrewB Created
  516. //
  517. //---------------------------------------------------------------
  518. void ReleaseOpenWithMask(ILockBytes *plst,
  519. DFLAGS df,
  520. ULONG offset,
  521. ULONG ulMask)
  522. {
  523. ULARGE_INTEGER ulOffset, cbLength;
  524. SCODE scTemp;
  525. olDebugOut((DEB_ITRACE, "In ReleaseOpenWithMask(%p, %lX, %lu, %lX)\n",
  526. plst, df, offset, ulMask));
  527. olAssert(offset != NOLOCK);
  528. // we incremented at the end of GetOpen, so we decrement here
  529. // to restore the proper lock index
  530. offset--;
  531. ULISetHigh(ulOffset, 0);
  532. ULISet32(cbLength, 1);
  533. if (P_READ(df))
  534. {
  535. ULISetLow(ulOffset, (OOPENREADLOCK+offset) & ulMask);
  536. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  537. }
  538. if (P_WRITE(df))
  539. {
  540. ULISetLow(ulOffset, (OOPENWRITELOCK+offset) & ulMask);
  541. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  542. }
  543. if (P_DENYREAD(df))
  544. {
  545. ULISetLow(ulOffset, (OOPENDENYREADLOCK+offset) & ulMask);
  546. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  547. }
  548. #ifdef USE_NOSNAPSHOT
  549. if (P_DENYWRITE(df) || P_NOSNAPSHOT(df))
  550. #else
  551. if (P_DENYWRITE(df))
  552. #endif
  553. {
  554. ULISetLow(ulOffset, (OOPENDENYWRITELOCK+offset) & ulMask);
  555. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  556. }
  557. #ifdef USE_NOSNAPSHOT
  558. if (P_NOSNAPSHOT(df))
  559. {
  560. ULISetLow(ulOffset, (OOPENNOSNAPSHOTLOCK+offset) & ulMask);
  561. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  562. }
  563. #endif
  564. #ifdef DIRECTWRITERLOCK
  565. BOOL fDirectReaderMode = P_READ(df) && !P_WRITE(df) && !P_TRANSACTED(df) &&
  566. !P_DENYREAD(df) && !P_DENYWRITE(df);
  567. if (fDirectReaderMode)
  568. {
  569. ULISetLow(ulOffset, (ODIRECTWRITERLOCK+offset) & ulMask);
  570. scTemp = plst->UnlockRegion(ulOffset, cbLength, LOCK_ONLYONCE);
  571. }
  572. #endif
  573. olDebugOut((DEB_ITRACE, "Out ReleaseOpenWithMask\n"));
  574. }
  575. //+--------------------------------------------------------------
  576. //
  577. // Function: GetOpen, public
  578. //
  579. // Synopsis: Gets locks on an LStream during opening
  580. //
  581. // Arguments: [plst] - LStream
  582. // [df] - Permissions to take
  583. // [fCheck] - Whether to check for existing locks or not
  584. // [puReturn] - Index of lock taken
  585. //
  586. // Returns: Appropriate status code
  587. //
  588. // Modifies: [puReturn]
  589. //
  590. // History: 08-Apr-92 DrewB Created
  591. //
  592. //---------------------------------------------------------------
  593. SCODE GetOpen(ILockBytes *plst,
  594. DFLAGS df,
  595. BOOL fCheck,
  596. ULONG *puReturn)
  597. {
  598. SCODE sc;
  599. olDebugOut((DEB_ITRACE, "In GetOpen(%p, %lX, %d, %p)\n",
  600. plst, df, fCheck, puReturn));
  601. // Make sure our lock region hasn't overflowed 32 bits
  602. olAssert(OLOCKREGIONEND > OACCESS);
  603. olChk(GetOpenWithMask(plst, df, fCheck, 0xFFFFFFFF, puReturn));
  604. olAssert(*puReturn < 0x10000);
  605. olDebugOut((DEB_ITRACE, "Out GetOpen => %lu\n", *puReturn));
  606. return S_OK;
  607. EH_Err:
  608. *puReturn = NOLOCK;
  609. return sc;
  610. }
  611. //+--------------------------------------------------------------
  612. //
  613. // Function: ReleaseOpen, public
  614. //
  615. // Synopsis: Releases opening locks
  616. //
  617. // Arguments: [plst] - LStream
  618. // [df] - Locks taken
  619. // [offset] - Index of locks
  620. //
  621. // Requires: offset != NOLOCK
  622. //
  623. // History: 08-Apr-92 DrewB Created
  624. //
  625. //---------------------------------------------------------------
  626. void ReleaseOpen(ILockBytes *plst, DFLAGS df, ULONG offset)
  627. {
  628. olDebugOut((DEB_ITRACE, "In ReleaseOpen(%p, %lX, %lu)\n",
  629. plst, df, offset));
  630. if (offset != NOLOCK)
  631. {
  632. ReleaseOpenWithMask(plst, df, offset & 0xffff, 0xFFFFFFFF);
  633. }
  634. olDebugOut((DEB_ITRACE, "Out ReleaseOpen\n"));
  635. }
  636. //+---------------------------------------------------------------------------
  637. //
  638. // Function: WaitForAccess, public, 32-bit only
  639. //
  640. // Synopsis: Attempts to get access locks, retrying if necessary
  641. // using exponential backoff
  642. //
  643. // Arguments: [plst] - ILockBytes
  644. // [df] - Access desired
  645. // [poReturn] - Lock index return
  646. //
  647. // Returns: Appropriate status code
  648. //
  649. // Modifies: [poReturn]
  650. //
  651. // History: 23-Sep-93 DrewB Created
  652. //
  653. //----------------------------------------------------------------------------
  654. #ifdef WIN32
  655. #define WAITACCESS_INITIAL 100
  656. #define WAITACCESS_TIMEOUT 100000
  657. SCODE WaitForAccess(ILockBytes *plst,
  658. DFLAGS df,
  659. ULONG *poReturn)
  660. {
  661. SCODE sc;
  662. DWORD dwWait;
  663. olDebugOut((DEB_ITRACE, "In WaitForAccess(%p, %X, %p)\n",
  664. plst, df, poReturn));
  665. dwWait = WAITACCESS_INITIAL;
  666. for (;;)
  667. {
  668. sc = GetAccess(plst, df, poReturn);
  669. if (sc != STG_E_LOCKVIOLATION ||
  670. dwWait >= WAITACCESS_TIMEOUT
  671. )
  672. break;
  673. Sleep(dwWait);
  674. dwWait *= (GetTickCount() & 1) ? 1 : 2;
  675. }
  676. olDebugOut((DEB_ITRACE, "Out WaitForAccess => 0x%lX, %lu\n",
  677. sc, poReturn));
  678. return sc;
  679. }
  680. #endif