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.

955 lines
23 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. flocks.c
  5. Abstract:
  6. Implementation of Posix advisory file record locking (via fcntl).
  7. Author:
  8. Matthew Bradburn (mattbr) 11-May-1992
  9. Revision History:
  10. --*/
  11. #include <fcntl.h>
  12. #include "psxsrv.h"
  13. #include "psxmsg.h"
  14. void
  15. InsertFlock(
  16. PIONODE IoNode,
  17. PSYSFLOCK l
  18. );
  19. void
  20. WakeAllFlockers(
  21. PIONODE IoNode
  22. );
  23. int
  24. found_region(
  25. PPSX_PROCESS Proc,
  26. PIONODE IoNode,
  27. int command,
  28. PSYSFLOCK list,
  29. struct flock *new,
  30. off_t *new_off,
  31. ULONG FileLength,
  32. OUT int *error
  33. );
  34. VOID
  35. FlockHandler(
  36. IN PPSX_PROCESS p,
  37. IN PINTCB IntControlBlock,
  38. IN PSX_INTERRUPTREASON InterruptReason,
  39. IN int Signal
  40. );
  41. //
  42. // These macros take care of the notion that if the length is
  43. // 0, it means the lock goes until EOF
  44. //
  45. #define LEN_A(a) ((a)->l_len == 0 ? (off_t)(FileLength - abs_off) : (a)->l_len)
  46. #define LEN_B(b) ((b)->Len == 0 ? (off_t)(FileLength - (b)->Start) : (b)->Len)
  47. #define OVERLAP(a, b) \
  48. ((abs_off >= (b)->Start && \
  49. abs_off < (b)->Start + LEN_B(b)) \
  50. || (abs_off + LEN_A(a) >= (b)->Start && \
  51. abs_off + LEN_A(a) <= (b)->Start + LEN_B(b)) \
  52. || (abs_off <= (b)->Start && \
  53. abs_off + LEN_A(a) >= (b)->Start + LEN_B(b)))
  54. //
  55. // Return values from found_region
  56. //
  57. #define DONE 1
  58. #define CONTINUE 2
  59. #define WAIT 3
  60. #define ERROR 4
  61. //
  62. // DoFlockStuff -- do fcntl commands related to advisory file-record
  63. // locking.
  64. //
  65. // Locking: the caller holds the IoNode locked throughout.
  66. //
  67. // Returns: TRUE if the caller should reply to the api request, FALSE
  68. // if the process has been blocked (F_SETLKW) and no reply
  69. // should be sent.
  70. //
  71. BOOLEAN
  72. DoFlockStuff(
  73. PPSX_PROCESS Proc,
  74. PPSX_API_MSG m,
  75. int command,
  76. IN PFILEDESCRIPTOR Fd,
  77. IN OUT struct flock *new,
  78. OUT int *error)
  79. {
  80. PSYSFLOCK p;
  81. PSYSFLOCK l;
  82. off_t abs_off;
  83. NTSTATUS Status;
  84. IO_STATUS_BLOCK IoStat;
  85. FILE_POSITION_INFORMATION FilePosition;
  86. FILE_STANDARD_INFORMATION FileStandardInfo;
  87. PIONODE IoNode;
  88. int did_find_overlap = 0; // were changes made?
  89. ULONG FileLength;
  90. if (new->l_start < 0) {
  91. *error = EINVAL;
  92. return TRUE;
  93. }
  94. if (new->l_type < F_RDLCK || new->l_type > F_WRLCK) {
  95. *error = EINVAL;
  96. return TRUE;
  97. }
  98. IoNode = Fd->SystemOpenFileDesc->IoNode;
  99. Status = NtQueryInformationFile(
  100. Fd->SystemOpenFileDesc->NtIoHandle, &IoStat,
  101. &FileStandardInfo, sizeof(FileStandardInfo),
  102. FileStandardInformation);
  103. if (!NT_SUCCESS(Status)) {
  104. *error = ENOMEM;
  105. return TRUE;
  106. }
  107. ASSERT(0 == FileStandardInfo.EndOfFile.HighPart);
  108. FileLength = FileStandardInfo.EndOfFile.LowPart;
  109. //
  110. // Convert l_whence and l_start into the absolute position of the
  111. // start of the region described.
  112. //
  113. switch (new->l_whence) {
  114. case SEEK_SET:
  115. abs_off = 0L;
  116. break;
  117. case SEEK_CUR:
  118. Status = NtQueryInformationFile(
  119. Fd->SystemOpenFileDesc->NtIoHandle, &IoStat,
  120. &FilePosition, sizeof(FilePosition),
  121. FilePositionInformation);
  122. ASSERT(NT_SUCCESS(Status));
  123. ASSERT(0 == FilePosition.CurrentByteOffset.HighPart);
  124. abs_off = FilePosition.CurrentByteOffset.LowPart;
  125. break;
  126. case SEEK_END:
  127. abs_off = FileLength;
  128. break;
  129. default:
  130. *error = EINVAL;
  131. return TRUE;
  132. }
  133. abs_off += new->l_start;
  134. //
  135. // If we're actually trying to modify an already-locked region
  136. // or create an additional locked, region, we scan the list of
  137. // locks to see whether we can succeed. If we can, we go through
  138. // the list a second time and perform the action.
  139. //
  140. if ((F_SETLK == command || F_SETLKW == command)
  141. && (F_UNLCK != new->l_type)) {
  142. //
  143. // If the regions overlap, they must either both
  144. // be of type F_RDLCK, or they must have the same
  145. // owner. Otherwise we do not succeed (may block).
  146. //
  147. for (p = (PSYSFLOCK)IoNode->Flocks.Flink;
  148. p != (PSYSFLOCK)&IoNode->Flocks;
  149. p = (PSYSFLOCK)p->Links.Flink) {
  150. if (!OVERLAP(new, p)) {
  151. continue;
  152. }
  153. if ((F_RDLCK == new->l_type && F_RDLCK == p->Type)
  154. || (Proc->Pid == p->Pid)) {
  155. continue;
  156. }
  157. if (F_SETLK == command) {
  158. *error = EAGAIN;
  159. return TRUE;
  160. }
  161. ASSERT(F_SETLKW == command);
  162. //
  163. // BLOCK the process.
  164. //
  165. Status = BlockProcess(Proc, Proc, FlockHandler, m,
  166. &IoNode->Waiters, &IoNode->IoNodeLock);
  167. if (!NT_SUCCESS(Status)) {
  168. m->Error = PsxStatusToErrno(Status);
  169. return TRUE;
  170. }
  171. //
  172. // Successfully blocked -- don't reply to api request.
  173. //
  174. return FALSE;
  175. }
  176. }
  177. //
  178. // Traverse the list of flocks, looking for locks describing
  179. // regions that overlap the given lock. Peform the indicated
  180. // operation on each.
  181. //
  182. p = (PVOID)IoNode->Flocks.Flink;
  183. while (p != (PVOID)&IoNode->Flocks) {
  184. //
  185. // Get the "next" pointer here, so that if found_region
  186. // frees the entry pointed to by p we'll still be able to
  187. // traverse the list.
  188. //
  189. l = (PVOID)p->Links.Flink;
  190. //
  191. // Find out whether the regions overlap or not: does the
  192. // new region start in this region, or does it end in this
  193. // region?
  194. //
  195. if (OVERLAP(new, p)) {
  196. if ((F_SETLK == command || F_SETLKW == command) &&
  197. F_UNLCK == new->l_type) {
  198. //
  199. // The process is only allowed to unlock locks
  200. // that he owns.
  201. //
  202. if (p->Pid != Proc->Pid) {
  203. continue;
  204. }
  205. }
  206. did_find_overlap++;
  207. switch (found_region(Proc, IoNode, command, p,
  208. new, &abs_off, FileLength, error)) {
  209. case DONE:
  210. *error = 0;
  211. return TRUE;
  212. case CONTINUE:
  213. p = l;
  214. continue;
  215. case ERROR:
  216. return TRUE;
  217. default:
  218. ASSERT(0);
  219. }
  220. }
  221. if (p->Start > abs_off) {
  222. break;
  223. }
  224. p = l;
  225. }
  226. //
  227. // we have come to the end of the list, or we have come to a
  228. // place that our region should have been before.
  229. //
  230. if (F_GETLK == command) {
  231. // no such region; the lock type is set to
  232. // UNLOCK.
  233. new->l_type = F_UNLCK;
  234. *error = 0;
  235. return TRUE;
  236. }
  237. if ((F_SETLK == command || F_SETLKW == command) &&
  238. F_UNLCK == new->l_type) {
  239. //
  240. // Return an error only if nothing was found to unlock.
  241. // We do this to allow the user to give a single unlock
  242. // command spanning the entire file, this to unlock all his
  243. // locks. 1003.1-90 isn't really clear on how this stuff
  244. // should work.
  245. //
  246. if (!did_find_overlap) {
  247. *error = EINVAL;
  248. return TRUE;
  249. }
  250. WakeAllFlockers(IoNode);
  251. *error = 0;
  252. return TRUE;
  253. }
  254. // We're setting a lock, and the type is not UNLOCK.
  255. // So insert a new region here.
  256. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  257. if (NULL == l) {
  258. *error = ENOMEM;
  259. return TRUE;
  260. }
  261. l->Start = abs_off;
  262. l->Len = new->l_len;
  263. l->Pid = Proc->Pid;
  264. l->Type = new->l_type;
  265. InsertFlock(IoNode, l);
  266. *error = 0;
  267. return TRUE;
  268. }
  269. //
  270. // found_region -- this gets called when there is a region overlapping the
  271. // one the user is interested in. Actually, the user's request may
  272. // span several regions, in which case this routine will get called
  273. // for each one.
  274. //
  275. int
  276. found_region(
  277. PPSX_PROCESS Proc, // the process making the request
  278. PIONODE IoNode, // our IoNode.
  279. int command, // what to do
  280. PSYSFLOCK list, // region that matches new region
  281. struct flock *new, // new region
  282. IN OUT off_t *new_off, // absolute offset, start of new region
  283. ULONG FileLength, // current length of the file
  284. OUT int *error // returned errno
  285. )
  286. {
  287. off_t abs_off = *new_off;
  288. if (F_GETLK == command) {
  289. //
  290. // If we own the overlapping region, we wouldn't block on
  291. // it. So we must continue searching.
  292. //
  293. if (list->Pid == Proc->Pid) {
  294. return CONTINUE;
  295. }
  296. //
  297. // If both lock types are F_RDLCK, then we have not
  298. // yet found a lock the user would block against; we
  299. // must continue searching.
  300. //
  301. if (new->l_type == F_RDLCK && list->Type == F_RDLCK) {
  302. return CONTINUE;
  303. }
  304. new->l_pid = list->Pid;
  305. new->l_type = list->Type;
  306. new->l_whence = SEEK_SET;
  307. new->l_start = list->Start;
  308. new->l_len = list->Len;
  309. return DONE;
  310. }
  311. if (F_SETLK != command && F_SETLKW != command) {
  312. KdPrint(("PSXSS: found_region: command %d\n", command));
  313. }
  314. ASSERT(F_SETLK == command || F_SETLKW == command);
  315. //
  316. // If this user doesn't own the found region, and they're both
  317. // read locks, we just add a shared lock.
  318. //
  319. if (list->Pid != Proc->Pid &&
  320. F_RDLCK == list->Type && F_RDLCK == new->l_type) {
  321. PSYSFLOCK l;
  322. // set a shared lock.
  323. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  324. if (NULL == l) {
  325. *error = ENOMEM;
  326. return ERROR;
  327. }
  328. l->Start = *new_off;
  329. l->Len = new->l_len;
  330. l->Type = new->l_type;
  331. l->Pid = Proc->Pid;
  332. InsertFlock(IoNode, l);
  333. return DONE;
  334. }
  335. //
  336. // The only way we should get here is if we're unlocking a region
  337. // or if we are changing the type of a region we own. In each case
  338. // we should own the region.
  339. //
  340. ASSERT(list->Pid == Proc->Pid);
  341. if (*new_off == list->Start && LEN_A(new) == LEN_B(list)) {
  342. //
  343. // The found region exactly matches the region in
  344. // the argument.
  345. //
  346. if (F_UNLCK == new->l_type) {
  347. PSYSFLOCK p;
  348. RemoveEntryList(&list->Links);
  349. RtlFreeHeap(PsxHeap, 0, list);
  350. //
  351. // Wake all procs sleeping on this IoNode.
  352. //
  353. WakeAllFlockers(IoNode);
  354. return DONE;
  355. }
  356. list->Type = new->l_type;
  357. return DONE;
  358. }
  359. if (*new_off == list->Start && LEN_A(new) < LEN_B(list)) {
  360. PSYSFLOCK l;
  361. //
  362. // The new region starts at the same place as the found
  363. // region, but does not extend all the way to its end.
  364. //
  365. if (F_UNLCK == new->l_type) {
  366. list->Start += LEN_A(new);
  367. list->Len = LEN_B(list);
  368. list->Len -= LEN_A(new);
  369. //
  370. // We've changed this entry's starting point, so
  371. // we may have changed it's order in the list.
  372. //
  373. RemoveEntryList(&list->Links);
  374. InsertFlock(IoNode, list);
  375. return DONE;
  376. }
  377. //
  378. // Change the type. The region gets split in
  379. // two.
  380. //
  381. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  382. if (NULL == l) {
  383. *error = ENOMEM;
  384. return ERROR;
  385. }
  386. l->Start = *new_off;
  387. l->Len = LEN_A(new);
  388. l->Type = new->l_type;
  389. l->Pid = Proc->Pid;
  390. InsertFlock(IoNode, l);
  391. list->Start += new->l_len;
  392. list->Len = LEN_B(list);
  393. list->Len -= LEN_A(new);
  394. // re-sort
  395. RemoveEntryList(&list->Links);
  396. InsertFlock(IoNode, list);
  397. return DONE;
  398. }
  399. if (*new_off == list->Start && LEN_A(new) > LEN_B(list)) {
  400. //
  401. // The new region starts at the same place as the found
  402. // region, but extends beyond it, perhaps into some number
  403. // of additional regions
  404. //
  405. if (F_UNLCK == new->l_type) {
  406. //
  407. // We are unlocking all of this region and maybe
  408. // some other stuff, too.
  409. //
  410. RemoveEntryList(&list->Links);
  411. RtlFreeHeap(PsxHeap, 0, list);
  412. return CONTINUE;
  413. }
  414. // Just change the type.
  415. list->Type = new->l_type;
  416. new->l_start += list->Len;
  417. *new_off = new->l_start;
  418. new->l_len = LEN_A(new);
  419. new->l_len -= LEN_B(list);
  420. return CONTINUE;
  421. }
  422. if (*new_off > list->Start &&
  423. *new_off + LEN_A(new) == list->Start + LEN_B(list)) {
  424. PSYSFLOCK l;
  425. //
  426. // The new region starts inside the found one and extends
  427. // to its end.
  428. //
  429. if (F_UNLCK == new->l_type) {
  430. ASSERT(list->Pid == Proc->Pid);
  431. // unlocking the last portion of a region
  432. list->Len = *new_off - list->Start;
  433. return DONE;
  434. }
  435. //
  436. // need to split the region.
  437. //
  438. list->Len = *new_off - list->Start;
  439. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  440. if (NULL == l) {
  441. *error = ENOMEM;
  442. return ERROR;
  443. }
  444. l->Start = *new_off;
  445. l->Len = LEN_A(new);
  446. l->Pid = Proc->Pid;
  447. l->Type = new->l_type;
  448. InsertFlock(IoNode, l);
  449. return DONE;
  450. }
  451. if (*new_off > list->Start &&
  452. *new_off + LEN_A(new) < list->Start + LEN_B(list)) {
  453. PSYSFLOCK l;
  454. //
  455. // The new region starts inside the found region and does
  456. // not extend to its end.
  457. //
  458. if (F_UNLCK == new->l_type) {
  459. //
  460. // The list region gets split into two.
  461. // Change the list region to be the left
  462. // side, and add another region for the right side.
  463. //
  464. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  465. if (NULL == l) {
  466. *error = ENOMEM;
  467. return ERROR;
  468. }
  469. l->Start = *new_off + LEN_A(new);
  470. l->Len = (list->Start + LEN_B(list)) -
  471. (*new_off + LEN_A(new));
  472. l->Type = list->Type;
  473. l->Pid = Proc->Pid;
  474. InsertFlock(IoNode, l);
  475. // list->Start stays the same;
  476. list->Len = *new_off - list->Start;
  477. return DONE;
  478. }
  479. //
  480. // changing the type of a sub-region; we end up
  481. // splitting the region into three.
  482. //
  483. // the right region
  484. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  485. if (NULL == l) {
  486. *error = ENOMEM;
  487. return ERROR;
  488. }
  489. l->Start = *new_off + LEN_A(new);
  490. l->Len = (list->Start + LEN_B(list)) - (*new_off + LEN_A(new));
  491. l->Pid = Proc->Pid;
  492. l->Type = list->Type;
  493. InsertFlock(IoNode, l);
  494. // the left region
  495. list->Len = *new_off - list->Start;
  496. // list->Start stays the same
  497. // the center region
  498. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  499. if (NULL == l) {
  500. *error = ENOMEM;
  501. return ERROR;
  502. }
  503. l->Start = *new_off;
  504. l->Len = LEN_A(new);
  505. l->Type = new->l_type;
  506. l->Pid = Proc->Pid;
  507. InsertFlock(IoNode, l);
  508. return DONE;
  509. }
  510. if (*new_off > list->Start &&
  511. *new_off + LEN_A(new) > list->Start + LEN_B(list)) {
  512. PSYSFLOCK l;
  513. //
  514. // The new region starts in the found region and extends
  515. // beyond it.
  516. //
  517. if (F_UNLCK == new->l_type) {
  518. new->l_start = list->Start + LEN_B(list) + 1;
  519. list->Len = *new_off - list->Start;
  520. new->l_whence = SEEK_SET;
  521. new->l_len = LEN_A(new) - (new->l_start - *new_off);
  522. *new_off = new->l_start;
  523. return CONTINUE;
  524. }
  525. //
  526. // changing the lock type of a region starting in this
  527. // region, presumably extending into the next region.
  528. // this involves creating a new region for the change
  529. // and continuing on.
  530. //
  531. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  532. if (NULL == l) {
  533. *error = ENOMEM;
  534. return ERROR;
  535. }
  536. l->Start = *new_off;
  537. l->Whence = SEEK_SET;
  538. l->Len = (list->Start + LEN_B(list)) - *new_off;
  539. l->Pid = Proc->Pid;
  540. l->Type = new->l_type;
  541. InsertFlock(IoNode, l);
  542. new->l_start = list->Start + LEN_B(list);
  543. new->l_whence = SEEK_SET;
  544. new->l_len = LEN_A(new) - (new->l_start - *new_off);
  545. *new_off = new->l_start;
  546. list->Len = l->Start - list->Start;
  547. return CONTINUE;
  548. }
  549. if (*new_off < list->Start &&
  550. *new_off + LEN_A(new) < list->Start + LEN_B(list)) {
  551. off_t new_end = *new_off + (LEN_A(new) - 1);
  552. PSYSFLOCK l;
  553. //
  554. // The new region starts before the list region and ends
  555. // in the midst of it.
  556. //
  557. if (F_UNLCK == new->l_type) {
  558. list->Len = (list->Start + LEN_B(list) - 1) - new_end;
  559. list->Start = new_end + 1;
  560. return DONE;
  561. }
  562. //
  563. // The list region gets split into two.
  564. //
  565. l = RtlAllocateHeap(PsxHeap, 0, sizeof(*l));
  566. if (NULL == l) {
  567. return ERROR;
  568. }
  569. l->Start = *new_off;
  570. l->Len = LEN_A(new);
  571. l->Type = new->l_type;
  572. l->Whence = SEEK_SET;
  573. l->Pid = Proc->Pid;
  574. InsertFlock(IoNode, l);
  575. list->Len = (list->Start + LEN_B(list) - 1) - new_end;
  576. list->Start = new_end + 1;
  577. return DONE;
  578. }
  579. if (*new_off < list->Start &&
  580. *new_off + LEN_A(new) == list->Start + LEN_B(list)) {
  581. //
  582. // The new region starts before the list region and
  583. // ends at the same place.
  584. //
  585. if (F_UNLCK == new->l_type) {
  586. RemoveEntryList(&list->Links);
  587. RtlFreeHeap(PsxHeap, 0, list);
  588. return DONE;
  589. }
  590. list->Start = *new_off;
  591. list->Type = new->l_type;
  592. list->Len = LEN_A(new);
  593. return DONE;
  594. }
  595. if (*new_off < list->Start &&
  596. *new_off + LEN_A(new) > list->Start + LEN_B(list)) {
  597. //
  598. // The new region starts before the list region and
  599. // ends after it.
  600. //
  601. if (F_UNLCK == new->l_type) {
  602. //
  603. // there may be stuff still to unlock when we're
  604. // done.
  605. //
  606. new->l_start = *new_off + LEN_A(new) + 1;
  607. new->l_len = (*new_off + LEN_A(new)) -
  608. (list->Start + LEN_B(list));
  609. new->l_whence = SEEK_SET;
  610. RemoveEntryList(&list->Links);
  611. RtlFreeHeap(PsxHeap, 0, list);
  612. return CONTINUE;
  613. }
  614. //
  615. // The new lock subsumes the one we've found on
  616. // the list.
  617. //
  618. RemoveEntryList(&list->Links);
  619. RtlFreeHeap(PsxHeap, 0, list);
  620. return CONTINUE;
  621. }
  622. ASSERT(0); // shouldn't get here.
  623. return ERROR;
  624. }
  625. void
  626. ReleaseFlocksByPid(
  627. PIONODE IoNode,
  628. pid_t pid
  629. )
  630. {
  631. PSYSFLOCK p;
  632. PINTCB IntCb;
  633. PPSX_PROCESS Waiter;
  634. PLIST_ENTRY next;
  635. //
  636. // Remove all the locks that we hold.
  637. //
  638. for (p = CONTAINING_RECORD(IoNode->Flocks.Flink, SYSFLOCK, Links);
  639. p != (PVOID)&IoNode->Flocks;
  640. /* null */) {
  641. PSYSFLOCK next;
  642. next = CONTAINING_RECORD(p->Links.Flink, SYSFLOCK, Links);
  643. if (pid == p->Pid) {
  644. RemoveEntryList(&p->Links);
  645. RtlFreeHeap(PsxHeap, 0, (PVOID)p);
  646. }
  647. p = next;
  648. }
  649. //
  650. // Wake all procs sleeping on this IoNode; since we've released
  651. // all flocks belonging to the given pid, maybe one of the
  652. // blocked procs can run.
  653. //
  654. WakeAllFlockers(IoNode);
  655. }
  656. #if DBG
  657. void
  658. DumpFlockList(PIONODE IoNode)
  659. {
  660. PSYSFLOCK p;
  661. int i;
  662. KdPrint(("DumpFlockList:\n"));
  663. for (i = 0, p = (PSYSFLOCK)IoNode->Flocks.Flink;
  664. p != (PSYSFLOCK)&IoNode->Flocks;
  665. p = (PSYSFLOCK)p->Links.Flink, ++i) {
  666. KdPrint(("Flock %d:\n", i));
  667. KdPrint(("\t Start %d\n", p->Start));
  668. KdPrint(("\t Length %d\n", p->Len));
  669. KdPrint(("\t Type %d\n", p->Type));
  670. KdPrint(("\t Pid 0x%x\n", p->Pid));
  671. }
  672. }
  673. #endif
  674. //
  675. // InsertFlock -- insert the flock in the list. The list is ordered
  676. // according to the starting offset.
  677. //
  678. //
  679. VOID
  680. InsertFlock(
  681. PIONODE IoNode,
  682. PSYSFLOCK l
  683. )
  684. {
  685. PSYSFLOCK p;
  686. ASSERT(NULL != l);
  687. for (p = CONTAINING_RECORD(IoNode->Flocks.Flink, SYSFLOCK, Links);
  688. p != (PVOID)&IoNode->Flocks;
  689. p = CONTAINING_RECORD(p->Links.Flink, SYSFLOCK, Links)) {
  690. if (p->Start >= l->Start) {
  691. InsertTailList(&p->Links, &l->Links);
  692. return;
  693. }
  694. }
  695. InsertTailList(&IoNode->Flocks, &l->Links);
  696. }
  697. VOID
  698. WakeAllFlockers(
  699. PIONODE IoNode
  700. )
  701. {
  702. PINTCB IntCb;
  703. PPSX_PROCESS Waiter;
  704. PVOID p, prev;
  705. RtlEnterCriticalSection(&BlockLock);
  706. //
  707. // We go through the list of blocked processes and wake them
  708. // all up. Each calls the FlockHandler routine below. This is
  709. // a terrible kludge: we go through the list from end to beginning
  710. // because if any of the processed we've waked are added to the
  711. // list, they get added at the end (BlockProcess() calls Insert-
  712. // TailList()).
  713. //
  714. for (p = (PVOID)IoNode->Waiters.Blink;
  715. p != (PVOID)&IoNode->Waiters;
  716. p = prev) {
  717. ASSERT(NULL != p);
  718. IntCb = CONTAINING_RECORD((PINTCB)p, INTCB, Links);
  719. ASSERT(NULL != IntCb);
  720. Waiter = (PPSX_PROCESS)IntCb->IntContext;
  721. ASSERT(NULL != Waiter);
  722. prev = IntCb->Links.Blink;
  723. UnblockProcess(Waiter, WaitSatisfyInterrupt,
  724. TRUE, 0);
  725. RtlEnterCriticalSection(&BlockLock);
  726. }
  727. RtlLeaveCriticalSection(&BlockLock);
  728. }
  729. VOID
  730. FlockHandler(
  731. IN PPSX_PROCESS p,
  732. IN PINTCB IntControlBlock,
  733. IN PSX_INTERRUPTREASON InterruptReason,
  734. IN int Signal // signal causing wakeup, if any
  735. )
  736. /*++
  737. Routine Description:
  738. This procedure is called when a process releases a lock.
  739. Arguments:
  740. p - Supplies the address of the sleeping process.
  741. IntControlBlock - Supplies the address of the interrupt control
  742. block.
  743. InterruptReason - Why the sleep is being interrupted.
  744. Return value:
  745. None.
  746. --*/
  747. {
  748. PPSX_API_MSG m;
  749. PPSX_FCNTL_MSG args;
  750. RtlLeaveCriticalSection(&BlockLock);
  751. m = IntControlBlock->IntMessage;
  752. if (InterruptReason == SignalInterrupt) {
  753. //
  754. // The sleep is being interrupted by a signal. We return
  755. // EINTR to the Posix process.
  756. //
  757. RtlFreeHeap(PsxHeap, 0, (PVOID)IntControlBlock);
  758. m->Error = EINTR;
  759. m->Signal = Signal;
  760. ApiReply(p, m, NULL);
  761. RtlFreeHeap(PsxHeap, 0, (PVOID)m);
  762. return;
  763. }
  764. args = &m->u.Fcntl;
  765. RtlFreeHeap(PsxHeap, 0, (PVOID)IntControlBlock);
  766. if (PsxFcntl(p, m)) {
  767. ApiReply(p, m, NULL);
  768. }
  769. RtlFreeHeap(PsxHeap, 0, m);
  770. }