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.

1874 lines
51 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. channel.c
  5. Abstract:
  6. This module implements the executive channel object. Channel obects
  7. provide a very high speed local interprocess communication mechanism.
  8. Author:
  9. David N. Cutler (davec) 26-Mar-1995
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. //
  16. // Define local function prototypes.
  17. //
  18. VOID
  19. KiAllocateReceiveBufferChannel (
  20. VOID
  21. );
  22. VOID
  23. KiCloseChannel (
  24. IN PEPROCESS Process,
  25. IN PVOID Object,
  26. IN ACCESS_MASK GrantedAccess,
  27. IN ULONG ProcessHandleCount,
  28. IN ULONG SystemHandleCount
  29. );
  30. VOID
  31. KiDeleteChannel (
  32. IN PVOID Object
  33. );
  34. NTSTATUS
  35. KiListenChannel (
  36. IN PRECHANNEL ServerChannel,
  37. IN KPROCESSOR_MODE WaitMode,
  38. OUT PCHANNEL_MESSAGE *Message
  39. );
  40. PKTHREAD
  41. KiRendezvousWithThread (
  42. IN PRECHANNEL WaitChannel,
  43. IN ULONG WaitMode
  44. );
  45. //
  46. // Address of event object type descriptor.
  47. //
  48. POBJECT_TYPE KeChannelType;
  49. //
  50. // Structure that describes the mapping of generic access rights to object
  51. // specific access rights for event objects.
  52. //
  53. #ifdef ALLOC_DATA_PRAGMA
  54. #pragma const_seg("INITCONST")
  55. #endif
  56. const GENERIC_MAPPING KiChannelMapping = {
  57. STANDARD_RIGHTS_READ |
  58. CHANNEL_READ_MESSAGE,
  59. STANDARD_RIGHTS_WRITE |
  60. CHANNEL_WRITE_MESSAGE,
  61. STANDARD_RIGHTS_EXECUTE |
  62. SYNCHRONIZE,
  63. CHANNEL_ALL_ACCESS
  64. };
  65. #ifdef ALLOC_DATA_PRAGMA
  66. #pragma const_seg()
  67. #endif
  68. //
  69. // Define function sections.
  70. //
  71. #ifdef ALLOC_PRAGMA
  72. #pragma alloc_text(PAGE, KiAllocateReceiveBufferChannel)
  73. #pragma alloc_text(INIT, KiChannelInitialization)
  74. #pragma alloc_text(PAGE, KiDeleteChannel)
  75. #pragma alloc_text(PAGE, KiRundownChannel)
  76. #pragma alloc_text(PAGE, NtCreateChannel)
  77. #pragma alloc_text(PAGE, NtListenChannel)
  78. #pragma alloc_text(PAGE, NtOpenChannel)
  79. #pragma alloc_text(PAGE, NtSetContextChannel)
  80. #endif
  81. NTSTATUS
  82. NtCreateChannel (
  83. OUT PHANDLE ChannelHandle,
  84. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
  85. )
  86. /*++
  87. Routine Description:
  88. This function creates a server listen channel object and opens a handle
  89. to the object with the specified desired access.
  90. Arguments:
  91. ChannelHandle - Supplies a pointer to a variable that will receive the
  92. channel object handle.
  93. ObjectAttributes - Supplies a pointer to an object attributes structure.
  94. Return Value:
  95. If the channel object is created, then a success status is returned.
  96. Otherwise, a failure status is returned.
  97. --*/
  98. {
  99. #if 0
  100. PVOID ChannelObject;
  101. KPROCESSOR_MODE PreviousMode;
  102. PRECHANNEL ServerChannel;
  103. HANDLE ServerHandle;
  104. NTSTATUS Status;
  105. //
  106. // Establish an exception handler, probe and zero the output handle
  107. // address, and attempt to create a channel object. If the probe fails
  108. // or access to the object attributes fails, then return the exception
  109. // code as the service status.
  110. //
  111. PreviousMode = KeGetPreviousMode();
  112. try {
  113. //
  114. // Get previous processor mode and probe output handle address if
  115. // necessary.
  116. //
  117. if (PreviousMode != KernelMode) {
  118. ProbeAndZeroHandle(ChannelHandle);
  119. }
  120. //
  121. // Allocate channel object.
  122. //
  123. Status = ObCreateObject(PreviousMode,
  124. KeChannelType,
  125. ObjectAttributes,
  126. PreviousMode,
  127. NULL,
  128. sizeof(ECHANNEL),
  129. 0,
  130. 0,
  131. &ChannelObject);
  132. } except(ExSystemExceptionFilter()) {
  133. return GetExceptionCode();
  134. }
  135. //
  136. // If the channel object was successfully created, then initialize the
  137. // channel object and insert the channel object in the process handle
  138. // table.
  139. //
  140. if (NT_SUCCESS(Status)) {
  141. ServerChannel = (PRECHANNEL)ChannelObject;
  142. ServerChannel->Type = LISTEN_CHANNEL;
  143. ServerChannel->State = ServerIdle;
  144. ServerChannel->OwnerProcess = &PsGetCurrentProcess()->Pcb;
  145. ServerChannel->ClientThread = NULL;
  146. ServerChannel->ServerThread = NULL;
  147. ServerChannel->ServerContext = NULL;
  148. ServerChannel->ServerChannel = NULL;
  149. KeInitializeEvent(&ServerChannel->ReceiveEvent,
  150. SynchronizationEvent,
  151. FALSE);
  152. KeInitializeEvent(&ServerChannel->ClearToSendEvent,
  153. SynchronizationEvent,
  154. FALSE);
  155. Status = ObInsertObject(ServerChannel,
  156. NULL,
  157. CHANNEL_ALL_ACCESS,
  158. 0,
  159. NULL,
  160. &ServerHandle);
  161. //
  162. // If the channel object was successfully inserted in the process
  163. // handle table, then attempt to write the channel object handle
  164. // value. If the write attempt fails, then do not report an error.
  165. // When the caller attempts to access the handle value, an access
  166. // violation will occur.
  167. //
  168. if (NT_SUCCESS(Status)) {
  169. try {
  170. *ChannelHandle = ServerHandle;
  171. } except(ExSystemExceptionFilter()) {
  172. }
  173. }
  174. }
  175. //
  176. // Return service status.
  177. //
  178. return Status;
  179. #else
  180. return STATUS_NOT_IMPLEMENTED;
  181. #endif
  182. }
  183. NTSTATUS
  184. NtListenChannel (
  185. IN HANDLE ChannelHandle,
  186. OUT PCHANNEL_MESSAGE *Message
  187. )
  188. /*++
  189. Routine Description:
  190. This function listens for a client message.
  191. N.B. This function can only be executed from a server thread.
  192. Arguments:
  193. ChannelHandle - Supplies a handle to a listen channel on which the
  194. server thread listens.
  195. Message - Supplies a pointer to a variable that receives a pointer
  196. to the client message header.
  197. Return Value:
  198. If the function is successfully completed, then a success status is
  199. returned. Otherwise, a failure status is returned.
  200. --*/
  201. {
  202. #if 0
  203. KPROCESSOR_MODE PreviousMode;
  204. PRECHANNEL ServerChannel;
  205. PRKTHREAD ServerThread;
  206. NTSTATUS Status;
  207. //
  208. // Establish an exception handler, probe the output message address,
  209. // and allocate a receive buffer if necessary. If the probe fails or
  210. // the receive buffer allocation is not successful, then return the
  211. // exception code as the service status.
  212. //
  213. ServerThread = KeGetCurrentThread();
  214. try {
  215. //
  216. // Get previous processor mode and probe output message address.
  217. //
  218. PreviousMode = KeGetPreviousMode();
  219. if (PreviousMode != KernelMode) {
  220. ProbeAndNullPointer(Message);
  221. }
  222. //
  223. // If the current thread does not have an associated receive buffer,
  224. // then attempt to allocate one now. If the allocation fails, then
  225. // an exception is raised.
  226. //
  227. if (ServerThread->Section == NULL) {
  228. KiAllocateReceiveBufferChannel();
  229. }
  230. } except(ExSystemExceptionFilter()) {
  231. return GetExceptionCode();
  232. }
  233. //
  234. // Reference channel object by handle.
  235. //
  236. Status = ObReferenceObjectByHandle(ChannelHandle,
  237. CHANNEL_ALL_ACCESS,
  238. KeChannelType,
  239. PreviousMode,
  240. &ServerChannel,
  241. NULL);
  242. //
  243. // If the reference was successful and the channel is a listen channel,
  244. // then wait for a client message to arrive.
  245. //
  246. if (NT_SUCCESS(Status)) {
  247. if (ServerChannel->ServerChannel != NULL) {
  248. Status = STATUS_INVALID_PARAMETER; // **** fix ****
  249. } else {
  250. Status = KiListenChannel(ServerChannel, PreviousMode, Message);
  251. }
  252. ObDereferenceObject(ServerChannel);
  253. }
  254. //
  255. // Return service status.
  256. //
  257. return Status;
  258. #else
  259. return STATUS_NOT_IMPLEMENTED;
  260. #endif
  261. }
  262. NTSTATUS
  263. NtOpenChannel (
  264. OUT PHANDLE ChannelHandle,
  265. IN POBJECT_ATTRIBUTES ObjectAttributes
  266. )
  267. /*++
  268. Routine Description:
  269. This function opens a handle to a server channel by creating a message
  270. channel that is connected to the specified server channel.
  271. Arguments:
  272. ChannelHandle - Supplies a pointer to a variable that will receive the
  273. channel object handle.
  274. ObjectAttributes - Supplies a pointer to an object attributes structure.
  275. Return Value:
  276. If the channel object is opened, then a success status is returned.
  277. Otherwise, a failure status is returned.
  278. --*/
  279. {
  280. #if 0
  281. PRECHANNEL ClientChannel;
  282. HANDLE ClientHandle;
  283. PKTHREAD ClientThread;
  284. KPROCESSOR_MODE PreviousMode;
  285. PRECHANNEL ServerChannel;
  286. PVOID ServerObject;
  287. NTSTATUS Status;
  288. //
  289. // Establish an exception handler, probe and zero the output handle
  290. // address, and attempt to open the server channel object. If the
  291. // probe fails, then return the exception code as the service status.
  292. //
  293. try {
  294. //
  295. // Get previous processor mode and probe output handle address
  296. // if necessary.
  297. //
  298. PreviousMode = KeGetPreviousMode();
  299. if (PreviousMode != KernelMode) {
  300. ProbeAndZeroHandle(ChannelHandle);
  301. }
  302. //
  303. // Reference the server channel object with the specified desired
  304. // access.
  305. //
  306. Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
  307. ObjectAttributes->Attributes,
  308. NULL,
  309. CHANNEL_ALL_ACCESS,
  310. KeChannelType,
  311. PreviousMode,
  312. NULL,
  313. (PVOID *)&ServerObject);
  314. } except(ExSystemExceptionFilter()) {
  315. return GetExceptionCode();
  316. }
  317. //
  318. // If the reference was successful, then attempt to create a client
  319. // channel object.
  320. //
  321. if (NT_SUCCESS(Status)) {
  322. //
  323. // If the owner process of the server channel is the same as
  324. // the current process, then a server thread is attempting to
  325. // open a client handle. This is not allowed since it would
  326. // not be possible to distinguish the server from the cient.
  327. //
  328. ClientThread = KeGetCurrentThread();
  329. ServerChannel = (PECHANNEL)ServerObject;
  330. if (ServerChannel->OwnerProcess == ClientThread->ApcState.Process) {
  331. Status = STATUS_INVALID_PARAMETER; // **** fix ***
  332. } else {
  333. Status = ObCreateObject(PreviousMode,
  334. KeChannelType,
  335. NULL,
  336. PreviousMode,
  337. NULL,
  338. sizeof(ECHANNEL),
  339. 0,
  340. 0,
  341. (PVOID *)&ClientChannel);
  342. //
  343. // If the channel object was successfully created, then
  344. // initialize the channel object and attempt to insert the
  345. // channel object in the server process channel table.
  346. //
  347. if (NT_SUCCESS(Status)) {
  348. ClientChannel->Type = MESSAGE_CHANNEL;
  349. ClientChannel->State = ClientIdle;
  350. ClientChannel->OwnerProcess = &PsGetCurrentProcess()->Pcb;
  351. ClientChannel->ClientThread = NULL;
  352. ClientChannel->ServerThread = NULL;
  353. ClientChannel->ServerContext = NULL;
  354. ClientChannel->ServerChannel = ServerChannel;
  355. KeInitializeEvent(&ClientChannel->ReceiveEvent,
  356. SynchronizationEvent,
  357. FALSE);
  358. KeInitializeEvent(&ClientChannel->ClearToSendEvent,
  359. SynchronizationEvent,
  360. FALSE);
  361. //
  362. // Create a handle to the message channel object.
  363. //
  364. Status = ObInsertObject(ClientChannel,
  365. NULL,
  366. CHANNEL_ALL_ACCESS,
  367. 0,
  368. NULL,
  369. &ClientHandle);
  370. //
  371. // If the channel object was successfully inserted in the
  372. // client process handle table, then attempt to write the
  373. // client channel object handle value. If the write attempt
  374. // fails, then do not report an error. When the caller
  375. // attempts to access the handle value, an access violation
  376. // will occur.
  377. //
  378. if (NT_SUCCESS(Status)) {
  379. try {
  380. *ChannelHandle = ClientHandle;
  381. } except(ExSystemExceptionFilter()) {
  382. }
  383. }
  384. return Status;
  385. }
  386. }
  387. ObDereferenceObject(ServerChannel);
  388. }
  389. //
  390. // Return service status.
  391. //
  392. return Status;
  393. #else
  394. return STATUS_NOT_IMPLEMENTED;
  395. #endif
  396. }
  397. NTSTATUS
  398. NtReplyWaitSendChannel (
  399. IN PVOID Text,
  400. IN ULONG Length,
  401. OUT PCHANNEL_MESSAGE *Message
  402. )
  403. /*++
  404. Routine Description:
  405. This function sends a reply message to a client and waits for a send.
  406. N.B. This function can only be executed from a server thread that
  407. has an assoicated message channel.
  408. Arguments:
  409. Text - Supplies a pointer to the message text.
  410. Length - Supplies the length of the message text.
  411. Message - Supplies a pointer to a variable that receives the send
  412. message header.
  413. Return Value:
  414. If the function is successfully completed, then a succes status is
  415. returned. Otherwise, a failure status is returned.
  416. --*/
  417. {
  418. #if 0
  419. PKTHREAD ClientThread;
  420. PCHANNEL_MESSAGE ClientView;
  421. PRECHANNEL MessageChannel;
  422. KPROCESSOR_MODE PreviousMode;
  423. PECHANNEL ServerChannel;
  424. PKTHREAD ServerThread;
  425. NTSTATUS Status;
  426. //
  427. // Establish an exception handler, probe the output message address,
  428. // probe the message text, and allocate a receive buffer if necessary.
  429. // If either of the probes fail or the receive buffer allocation is
  430. // not successful, then return the exception code as the service
  431. // status.
  432. //
  433. ServerThread = KeGetCurrentThread();
  434. try {
  435. //
  436. // Get previous processor mode and probe output message address and
  437. // the message text if necessary.
  438. //
  439. PreviousMode = KeGetPreviousMode();
  440. if (PreviousMode != KernelMode) {
  441. ProbeForRead(Text, Length, sizeof(CHAR));
  442. ProbeAndNullPointer(Message);
  443. }
  444. //
  445. // If the current thread does not have an associated receive buffer,
  446. // then attempt to allocate one now. If the allocation fails, then
  447. // an exception is raised.
  448. //
  449. if (ServerThread->Section == NULL) {
  450. KiAllocateReceiveBufferChannel();
  451. }
  452. } except(ExSystemExceptionFilter()) {
  453. return GetExceptionCode();
  454. }
  455. //
  456. // If the message length is greater than the host page size minus
  457. // the message header length, then return an error.
  458. //
  459. if (Length >= (PAGE_SIZE - sizeof(CHANNEL_MESSAGE))) {
  460. return STATUS_BUFFER_OVERFLOW;
  461. }
  462. //
  463. // If the server thread has an associated message channel, the channel
  464. // is in server receive message state, and the channel server thread
  465. // matches the current thread.
  466. //
  467. // This implies that:
  468. //
  469. // 1. The channel is a message channel.
  470. //
  471. // 2. The channel is being accessed by the server thread.
  472. //
  473. // 3. The channel is associated with a listen channel.
  474. //
  475. // 4. There is currently a server channel owner.
  476. //
  477. // 5. There is currently a client channel owner.
  478. //
  479. KiLockDispatcherDatabase(&ServerThread->WaitIrql);
  480. MessageChannel = ServerThread->Channel;
  481. if ((MessageChannel == NULL) ||
  482. (MessageChannel->State != ServerReceiveMessage) ||
  483. (MessageChannel->ServerThread != ServerThread)) {
  484. //
  485. // A message is not associated with the current thread,
  486. // the message channel is in the wrong state, or the
  487. // current thread is not the owner of the channel.
  488. //
  489. KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
  490. Status = STATUS_INVALID_PARAMETER; // **** fix ****
  491. } else {
  492. //
  493. // Rendezvous with the client thread so a transfer of the
  494. // reply text to the client thread can occur.
  495. //
  496. ClientThread = KiRendezvousWithThread(MessageChannel, PreviousMode);
  497. //
  498. // Control is returned when:
  499. //
  500. // 1. The server thread is being terminated (USER_APC).
  501. //
  502. // 2. A rendezvous with a client thread has occured.
  503. //
  504. // N.B. If the status value is less than zero, then it
  505. // is the address of the client thread.
  506. //
  507. if ((LONG)ClientThread < 0) {
  508. //
  509. // The client thread is returned as the rendezvous status
  510. // with the thread in the transition state. Get the address
  511. // of the client thread system view, establish an exception
  512. // handler, and transfer the message text from the server's
  513. // buffer to the client's receive buffer. If an exception
  514. // occurs during the copy, then return the exception code
  515. // as the service status.
  516. //
  517. ClientView = ClientThread->SystemView;
  518. Status = STATUS_SUCCESS;
  519. if (Length != 0) {
  520. try {
  521. RtlCopyMemory(ClientView + 1, Text, Length);
  522. } except (ExSystemExceptionFilter()) {
  523. Status = GetExceptionCode();
  524. }
  525. }
  526. //
  527. // Set the channel message parameters.
  528. //
  529. ClientView->Text = (PVOID)(ClientThread->ThreadView + 1);
  530. ClientView->Length = Length;
  531. ClientView->Context = NULL;
  532. ClientView->Base = Text;
  533. ClientView->Close = FALSE;
  534. //
  535. // Raise IRQL to dispatch level, lock the dispatcher
  536. // database, and check if the message was successfully
  537. // transfered to the client's receive buffer. If the
  538. // message was successfully transfered to the client's
  539. // receive buffer. then reset the channel state, fill
  540. // in the message parameters, ready the client thread,
  541. // and listen for the next message. Otherwise, set the
  542. // client wait status and ready the client thread for
  543. // execution.
  544. //
  545. KiLockDispatcherDatabase(&ServerThread->WaitIrql);
  546. if (NT_SUCCESS(Status)) {
  547. MessageChannel->State = ClientIdle;
  548. MessageChannel->ClientThread = NULL;
  549. MessageChannel->ServerThread = NULL;
  550. ClientThread->WaitStatus = STATUS_SUCCESS;
  551. //
  552. // Reference the server channel and dereference the
  553. // message channel.
  554. //
  555. ServerChannel = MessageChannel->ServerChannel;
  556. ObReferenceObject(ServerChannel);
  557. ObDereferenceObject(MessageChannel);
  558. //
  559. // If there are no clients waiting to send to the server,
  560. // then switch directly to the client thread. Otherwise,
  561. // ready the client thread, then listen for the next
  562. // message.
  563. //
  564. if (IsListEmpty(&ServerChannel->ClearToSendEvent.Header.WaitListHead) == FALSE) {
  565. KiReadyThread(ClientThread);
  566. KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
  567. Status = KiListenChannel(ServerChannel,
  568. PreviousMode,
  569. Message);
  570. } else {
  571. Status = KiSwitchToThread(ClientThread,
  572. WrRendezvous,
  573. PreviousMode,
  574. &ServerChannel->ReceiveEvent);
  575. //
  576. // If a client message was successfully received, then
  577. // attempt to write the address of the send message
  578. // address. If the write attempt fails, then do not
  579. // report an error. When the caller attempts to access
  580. // the message address, an access violation will occur.
  581. //
  582. if (NT_SUCCESS(Status)) {
  583. try {
  584. *Message = ServerThread->ThreadView;
  585. } except(ExSystemExceptionFilter()) {
  586. }
  587. }
  588. }
  589. ObDereferenceObject(ServerChannel);
  590. } else {
  591. //
  592. // The reply message was not successfully transfered
  593. // to the client receive buffer because of an access
  594. // violation encountered durring the access to the
  595. // server buffer.
  596. //
  597. ClientThread->WaitStatus = STATUS_KERNEL_APC;
  598. KiReadyThread(ClientThread);
  599. KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
  600. }
  601. } else {
  602. //
  603. // The server thread is terminating and the channel
  604. // structures will be cleaned up by the termiantion
  605. // code.
  606. //
  607. Status = (NTSTATUS)ClientThread;
  608. }
  609. }
  610. //
  611. // Return service status.
  612. //
  613. return Status;
  614. #else
  615. return STATUS_NOT_IMPLEMENTED;
  616. #endif
  617. }
  618. NTSTATUS
  619. NtSendWaitReplyChannel (
  620. IN HANDLE ChannelHandle,
  621. IN PVOID Text,
  622. IN ULONG Length,
  623. OUT PCHANNEL_MESSAGE *Message
  624. )
  625. /*++
  626. Routine Description:
  627. This function sends a message to a server and waits for a reply.
  628. N.B. This function can only be executed from a client thread.
  629. Arguments:
  630. ChannelHandle - Supplies a handle to a message channel over which the
  631. specified message text is sent.
  632. Text - Supplies a pointer to the message text.
  633. Length - Supplies the length of the message text.
  634. Message - Supplies a pointer to a variable that receives a pointer
  635. to the reply message header.
  636. Return Value:
  637. If the function is successfully completed, then a success status is
  638. returned. Otherwise, a failure status is returned.
  639. --*/
  640. {
  641. #if 0
  642. PKTHREAD ClientThread;
  643. PRECHANNEL MessageChannel;
  644. KPROCESSOR_MODE PreviousMode;
  645. PRECHANNEL ServerChannel;
  646. PKTHREAD ServerThread;
  647. PCHANNEL_MESSAGE ServerView;
  648. NTSTATUS Status;
  649. //
  650. // Establish an exception handler, probe the output message address,
  651. // probe the message text, and allocate a receive buffer if necessary.
  652. // If either of the probes fail or the receive buffer allocation is
  653. // not successful, then return the exception code as the service
  654. // status.
  655. //
  656. ClientThread = KeGetCurrentThread();
  657. try {
  658. //
  659. // Get previous processor mode and probe output message address
  660. // and the message text.
  661. //
  662. PreviousMode = KeGetPreviousMode();
  663. if (PreviousMode != KernelMode) {
  664. ProbeForRead(Text, Length, sizeof(UCHAR));
  665. ProbeAndNullPointer(Message);
  666. }
  667. //
  668. // If the current thread does not have an associated receive buffer,
  669. // then attempt to allocate one now. If the allocation fails, then
  670. // an exception is raised.
  671. //
  672. if (ClientThread->Section == NULL) {
  673. KiAllocateReceiveBufferChannel();
  674. }
  675. } except(ExSystemExceptionFilter()) {
  676. return GetExceptionCode();
  677. }
  678. //
  679. // If the message length is greater than the host page size minus
  680. // the message header length, then return an error.
  681. //
  682. if (Length >= (PAGE_SIZE - sizeof(CHANNEL_MESSAGE))) {
  683. return STATUS_BUFFER_OVERFLOW;
  684. }
  685. //
  686. // Reference channel object by handle.
  687. //
  688. Status = ObReferenceObjectByHandle(ChannelHandle,
  689. CHANNEL_ALL_ACCESS,
  690. KeChannelType,
  691. PreviousMode,
  692. (PVOID *)&MessageChannel,
  693. NULL);
  694. //
  695. // If the reference was successful, then check if the channel is in
  696. // the client idle state.
  697. //
  698. // This implies that:
  699. //
  700. // 1. The channel is a message channel.
  701. //
  702. // 2. The channel is being accessed by a client thread.
  703. //
  704. // 3. The channel is connected to a listen channel.
  705. //
  706. // 4. There is currently no client thread channel owner.
  707. //
  708. // 5. There is currently no server thread channel owner.
  709. //
  710. if (NT_SUCCESS(Status)) {
  711. KiLockDispatcherDatabase(&ClientThread->WaitIrql);
  712. if (MessageChannel->State != ClientIdle) {
  713. //
  714. // The message channel is in the wrong state.
  715. //
  716. KiUnlockDispatcherDatabase(ClientThread->WaitIrql);
  717. Status = STATUS_INVALID_PARAMETER; // **** fix ****
  718. } else {
  719. //
  720. // Set the channel state, set the client owner thread, and
  721. // rendezvous with a server thread.
  722. //
  723. MessageChannel->State = ClientSendWaitReply;
  724. MessageChannel->ClientThread = ClientThread;
  725. ClientThread->Channel = MessageChannel;
  726. ServerChannel = MessageChannel->ServerChannel;
  727. ServerThread = KiRendezvousWithThread(ServerChannel, PreviousMode);
  728. //
  729. // Control is returned when:
  730. //
  731. // 1. The client thread is being terminated (USER_APC).
  732. //
  733. // 2. A rendezvous with a server thread has occured.
  734. //
  735. // N.B. If the status value is less than zero, then it
  736. // is the address of the server thread.
  737. //
  738. if ((LONG)ServerThread < 0) {
  739. //
  740. // The server thread is returned as the rendezvous status
  741. // with the thread in the transition state. Get the address
  742. // of the server thread system view, establish an exception
  743. // handler, and transfer the message text from the client's
  744. // buffer to the server's receive buffer. If an exception
  745. // occurs during the copy, then return the exception code
  746. // as the service status.
  747. //
  748. ServerView = ServerThread->SystemView;
  749. if (Length != 0) {
  750. try {
  751. RtlCopyMemory(ServerView + 1, Text, Length);
  752. } except (ExSystemExceptionFilter()) {
  753. Status = GetExceptionCode();
  754. }
  755. }
  756. //
  757. // Set the channel message parameters.
  758. //
  759. ServerView->Text = (PVOID)(ServerThread->ThreadView + 1);
  760. ServerView->Length = Length;
  761. ServerView->Context = MessageChannel->ServerContext;
  762. ServerView->Base = Text;
  763. ServerView->Close = FALSE;
  764. //
  765. // Raise IRQL to dispatch level, lock the dispatcher
  766. // database and check if the message was successfully
  767. // transfered to the server's receive buffer. If the
  768. // message was successfully transfered, then set the
  769. // channel state, set the server thread address, set
  770. // the address of the message channel in the server
  771. // thread, increment the message channel reference
  772. // count, fill in the message parameters, and switch
  773. // directly to the server thread. Otherwise, set the
  774. // channel state, and reready the server thread for
  775. // execution.
  776. //
  777. KiLockDispatcherDatabase(&ClientThread->WaitIrql);
  778. if (NT_SUCCESS(Status)) {
  779. MessageChannel->State = ServerReceiveMessage;
  780. MessageChannel->ServerThread = ServerThread;
  781. ObReferenceObject(MessageChannel);
  782. ServerThread->Channel = MessageChannel;
  783. Status = KiSwitchToThread(ServerThread,
  784. WrRendezvous,
  785. PreviousMode,
  786. &MessageChannel->ReceiveEvent);
  787. //
  788. // If the send and subsequent reply from the server
  789. // thread is successful, then attempt to write the
  790. // address of the reply message address. If the write
  791. // attempt fails, then do not report an error. When
  792. // the caller attempts to access the message address,
  793. // an access violation will occur.
  794. //
  795. if (NT_SUCCESS(Status)) {
  796. try {
  797. *Message = ClientThread->ThreadView;
  798. } except(ExSystemExceptionFilter()) {
  799. }
  800. }
  801. } else {
  802. //
  803. // The send message was not successfully transfered
  804. // to the server receive buffer because of an access
  805. // violation encountered durring the access to the
  806. // client buffer.
  807. //
  808. MessageChannel->State = ClientIdle;
  809. MessageChannel->ClientThread = NULL;
  810. ClientThread->Channel = NULL;
  811. ServerThread->WaitStatus = STATUS_KERNEL_APC;
  812. KiReadyThread(ServerThread);
  813. KiUnlockDispatcherDatabase(ClientThread->WaitIrql);
  814. }
  815. } else {
  816. //
  817. // The client thread is terminating and the channel
  818. // structures will be cleaned up by the termination
  819. // code.
  820. //
  821. Status = (NTSTATUS)ServerThread;
  822. }
  823. }
  824. ObDereferenceObject(MessageChannel);
  825. }
  826. //
  827. // Return service status.
  828. //
  829. return Status;
  830. #else
  831. return STATUS_NOT_IMPLEMENTED;
  832. #endif
  833. }
  834. NTSTATUS
  835. NtSetContextChannel (
  836. IN PVOID Context
  837. )
  838. /*++
  839. Routine Description:
  840. This function stores a context value for the current associated
  841. message channel.
  842. N.B. This function can only be executed from a server thread that
  843. has an associated message channel.
  844. Arguments:
  845. Context - Supplies a context value that is to be stored in the
  846. associated message channel.
  847. Return Value:
  848. If the channel information is set, then a success status is returned.
  849. Otherwise, a failure status is returned.
  850. --*/
  851. {
  852. #if 0
  853. PRECHANNEL MessageChannel;
  854. PKTHREAD CurrentThread;
  855. NTSTATUS Status;
  856. //
  857. // If the thread has an assoicated channel and the server thread for
  858. // the channel is the current thread, then store the channel context.
  859. //
  860. CurrentThread = KeGetCurrentThread();
  861. MessageChannel = CurrentThread->Channel;
  862. if ((MessageChannel == NULL) ||
  863. (CurrentThread != MessageChannel->ServerThread)) {
  864. Status = STATUS_INVALID_PARAMETER; // ****** FIX *****
  865. } else {
  866. MessageChannel->ServerContext = Context;
  867. Status = STATUS_SUCCESS;
  868. }
  869. //
  870. // Return service status.
  871. //
  872. return Status;
  873. #else
  874. return STATUS_NOT_IMPLEMENTED;
  875. #endif
  876. }
  877. #if 0
  878. VOID
  879. KiAllocateReceiveBufferChannel (
  880. VOID
  881. )
  882. /*++
  883. Routine Description:
  884. This function creates an unnamed section with a single page, maps
  885. a view of the section into the current process and into the system
  886. address space, and associates the view with the current thread.
  887. Arguments:
  888. None.
  889. Return Value:
  890. If a channel receive buffer is not allocated, then raise an exception.
  891. --*/
  892. {
  893. LARGE_INTEGER MaximumSize;
  894. PEPROCESS Process;
  895. NTSTATUS Status;
  896. PKTHREAD Thread;
  897. LARGE_INTEGER ViewOffset;
  898. ULONG ViewSize;
  899. //
  900. // Create an unnamed section object.
  901. //
  902. Thread = KeGetCurrentThread();
  903. ASSERT(Thread->Section == NULL);
  904. MaximumSize.QuadPart = PAGE_SIZE;
  905. Status = MmCreateSection(&Thread->Section,
  906. 0,
  907. NULL,
  908. &MaximumSize,
  909. PAGE_READWRITE,
  910. SEC_COMMIT,
  911. NULL,
  912. NULL);
  913. if (NT_SUCCESS(Status)) {
  914. //
  915. // Map a view of the section into the current process.
  916. //
  917. Process = PsGetCurrentProcess();
  918. ViewOffset.QuadPart = 0;
  919. ViewSize = PAGE_SIZE;
  920. Status = MmMapViewOfSection(Thread->Section,
  921. Process,
  922. &Thread->ThreadView,
  923. 0,
  924. ViewSize,
  925. &ViewOffset,
  926. &ViewSize,
  927. ViewUnmap,
  928. 0,
  929. PAGE_READWRITE);
  930. if (NT_SUCCESS(Status)) {
  931. //
  932. // Map a view of the section into the system address
  933. // space.
  934. //
  935. Status = MmMapViewInSystemSpace(Thread->Section,
  936. &Thread->SystemView,
  937. &ViewSize);
  938. if (NT_SUCCESS(Status)) {
  939. return;
  940. }
  941. MmUnmapViewOfSection(Process, Thread->ThreadView);
  942. }
  943. ObDereferenceObject(Thread->Section);
  944. }
  945. //
  946. // The allocation of a receive buffer was not successful. Raise an
  947. // exception that will be caught by the caller.
  948. //
  949. ExRaiseStatus(Status);
  950. return;
  951. }
  952. BOOLEAN
  953. KiChannelInitialization (
  954. VOID
  955. )
  956. /*++
  957. Routine Description:
  958. This function creates the channel object type descriptor at system
  959. initialization and stores the address of the object type descriptor
  960. in global storage.
  961. Arguments:
  962. None.
  963. Return Value:
  964. A value of TRUE is returned if the channel object type descriptor is
  965. successfully initialized. Otherwise a value of FALSE is returned.
  966. --*/
  967. {
  968. OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
  969. NTSTATUS Status;
  970. UNICODE_STRING TypeName;
  971. //
  972. // Initialize string descriptor.
  973. //
  974. RtlInitUnicodeString(&TypeName, L"Channel");
  975. //
  976. // Create channel object type descriptor.
  977. //
  978. RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
  979. ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
  980. ObjectTypeInitializer.GenericMapping = KiChannelMapping;
  981. ObjectTypeInitializer.PoolType = NonPagedPool;
  982. ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(ECHANNEL);
  983. ObjectTypeInitializer.ValidAccessMask = CHANNEL_ALL_ACCESS;
  984. ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_INHERIT | OBJ_PERMANENT;
  985. ObjectTypeInitializer.CloseProcedure = KiCloseChannel;
  986. ObjectTypeInitializer.DeleteProcedure = KiDeleteChannel;
  987. Status = ObCreateObjectType(&TypeName,
  988. &ObjectTypeInitializer,
  989. NULL,
  990. &KeChannelType);
  991. //
  992. // If the channel object type descriptor was successfully created, then
  993. // return a value of TRUE. Otherwise return a value of FALSE.
  994. //
  995. return (BOOLEAN)(NT_SUCCESS(Status));
  996. }
  997. VOID
  998. KiCloseChannel (
  999. IN PEPROCESS Process,
  1000. IN PVOID Object,
  1001. IN ACCESS_MASK GrantedAccess,
  1002. IN ULONG ProcessHandleCount,
  1003. IN ULONG SystemHandleCount
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This function is called when a handle to a channel is closed. If the
  1008. hanlde is the last handle in the process to the channel object and
  1009. the channel object is a message channel, then send a message to the
  1010. server indicating that the client handle is being closed.
  1011. Arguments:
  1012. Object - Supplies a pointer to an executive channel.
  1013. Return Value:
  1014. None.
  1015. --*/
  1016. {
  1017. PECHANNEL MessageChannel = (PECHANNEL)Object;
  1018. //
  1019. // If the object is a message channel and hte last handle is being
  1020. // closed, then send a message to the server indicating that the
  1021. // channel is being closed.
  1022. //
  1023. if ((MessageChannel->ServerChannel != NULL) &&
  1024. (ProcessHandleCount == 1)) {
  1025. }
  1026. return;
  1027. }
  1028. VOID
  1029. KiDeleteChannel (
  1030. IN PVOID Object
  1031. )
  1032. /*++
  1033. Routine Description:
  1034. This function is the delete routine for channel objects. Its function
  1035. is to ...
  1036. Arguments:
  1037. Object - Supplies a pointer to an executive channel.
  1038. Return Value:
  1039. None.
  1040. --*/
  1041. {
  1042. PRECHANNEL ChannelObject = (PECHANNEL)Object;
  1043. //
  1044. // If the channel is a message channel, then dereference the connnected
  1045. // server channel.
  1046. //
  1047. if (ChannelObject->ServerChannel != NULL) {
  1048. ObDereferenceObject(ChannelObject->ServerChannel);
  1049. }
  1050. return;
  1051. }
  1052. VOID
  1053. KiRundownChannel (
  1054. VOID
  1055. )
  1056. /*++
  1057. Routine Description:
  1058. This function runs down associated channel object and receive buffers
  1059. when the a thread is terminated.
  1060. Arguments:
  1061. None.
  1062. Return Value:
  1063. None.
  1064. --*/
  1065. {
  1066. PKTHREAD Thread;
  1067. //
  1068. // If the current thread has an associated receive buffer, then unmap
  1069. // the receive buffer and dereference the underlying section.
  1070. //
  1071. Thread = KeGetCurrentThread();
  1072. if (Thread->Section != NULL) {
  1073. MmUnmapViewOfSection(PsGetCurrentProcess(), Thread->ThreadView);
  1074. MmUnmapViewInSystemSpace(Thread->SystemView);
  1075. ObDereferenceObject(Thread->Section);
  1076. Thread->Section = NULL;
  1077. }
  1078. //
  1079. // If the current thread has an associated channel, then ...
  1080. //
  1081. return;
  1082. }
  1083. NTSTATUS
  1084. KiListenChannel (
  1085. IN PRECHANNEL ServerChannel,
  1086. IN KPROCESSOR_MODE WaitMode,
  1087. OUT PCHANNEL_MESSAGE *Message
  1088. )
  1089. /*++
  1090. Routine Description:
  1091. This function listens for a client message to arrive.
  1092. N.B. This function can only be executed from a server thread.
  1093. Arguments:
  1094. ServerChannel - Supplies a pointer to a litent channel on which the
  1095. server thread listens.
  1096. WaitMode - Supplies the processor wait mode.
  1097. Message - Supplies a pointer to a variable that receives a pointer
  1098. to the client message header.
  1099. Return Value:
  1100. If the function is successfully completed, then a success status is
  1101. returned. Otherwise, a failure status is returned.
  1102. --*/
  1103. {
  1104. PKEVENT ClearToSendEvent;
  1105. PKTHREAD ClientThread;
  1106. PKQUEUE Queue;
  1107. PKTHREAD ServerThread;
  1108. PKWAIT_BLOCK WaitBlock;
  1109. PLIST_ENTRY WaitEntry;
  1110. NTSTATUS WaitStatus;
  1111. //
  1112. // Raise IRQL to dispatch level and lock the dispatcher database.
  1113. //
  1114. ServerThread = KeGetCurrentThread();
  1115. KiLockDispatcherDatabase(&ServerThread->WaitIrql);
  1116. //
  1117. // Start of wait loop.
  1118. //
  1119. // Note this loop is repeated if a kernel APC is delivered in the
  1120. // middle of the wait or a kernel APC is pending on the first attempt
  1121. // through the loop.
  1122. //
  1123. do {
  1124. //
  1125. // Check if there is a thread waiting on the clear to send event.
  1126. //
  1127. ClearToSendEvent = &ServerChannel->ClearToSendEvent;
  1128. WaitEntry = ClearToSendEvent->Header.WaitListHead.Flink;
  1129. if (WaitEntry != &ClearToSendEvent->Header.WaitListHead) {
  1130. WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
  1131. ClientThread = WaitBlock->Thread;
  1132. //
  1133. // Remove the wait block from the wait list of the receive event,
  1134. // and remove the client thread from the wait list.
  1135. //
  1136. RemoveEntryList(&WaitBlock->WaitListEntry);
  1137. RemoveEntryList(&ClientThread->WaitListEntry);
  1138. //
  1139. // If the client thread is processing a queue entry, then increment the
  1140. // count of currently active threads.
  1141. //
  1142. Queue = ClientThread->Queue;
  1143. if (Queue != NULL) {
  1144. Queue->CurrentCount += 1;
  1145. }
  1146. //
  1147. // Set the wait completion status to kernel APC so the client
  1148. // will attempt another rendezvous and ready the client thread
  1149. // for execution.
  1150. //
  1151. ClientThread->WaitStatus = STATUS_KERNEL_APC;
  1152. KiReadyThread(ClientThread);
  1153. }
  1154. //
  1155. // Test to determine if a kernel APC is pending.
  1156. //
  1157. // If a kernel APC is pending and the previous IRQL was less than
  1158. // APC_LEVEL, then a kernel APC was queued by another processor
  1159. // just after IRQL was raised to DISPATCH_LEVEL, but before the
  1160. // dispatcher database was locked.
  1161. //
  1162. // N.B. that this can only happen in a multiprocessor system.
  1163. //
  1164. if (ServerThread->ApcState.KernelApcPending &&
  1165. (ServerThread->WaitIrql < APC_LEVEL)) {
  1166. //
  1167. // Unlock the dispatcher database and lower IRQL to its
  1168. // previous value. An APC interrupt will immediately occur
  1169. // which will result in the delivery of the kernel APC if
  1170. // possible.
  1171. //
  1172. KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
  1173. } else {
  1174. //
  1175. // Test if a user APC is pending.
  1176. //
  1177. if ((WaitMode != KernelMode) &&
  1178. (ServerThread->ApcState.UserApcPending)) {
  1179. WaitStatus = STATUS_USER_APC;
  1180. break;
  1181. }
  1182. //
  1183. // Construct a wait block for the clear to send event object.
  1184. //
  1185. WaitBlock = &ServerThread->WaitBlock[0];
  1186. ServerThread->WaitBlockList = WaitBlock;
  1187. ServerThread->WaitStatus = (NTSTATUS)0;
  1188. WaitBlock->Object = (PVOID)&ServerChannel->ReceiveEvent;
  1189. WaitBlock->NextWaitBlock = WaitBlock;
  1190. WaitBlock->WaitKey = (CSHORT)STATUS_SUCCESS;
  1191. WaitBlock->WaitType = WaitAny;
  1192. InsertTailList(&ServerChannel->ReceiveEvent.Header.WaitListHead,
  1193. &WaitBlock->WaitListEntry);
  1194. //
  1195. // If the current thread is processing a queue entry, then
  1196. // attempt to activate another thread that is blocked on the
  1197. // queue object.
  1198. //
  1199. Queue = ServerThread->Queue;
  1200. if (Queue != NULL) {
  1201. KiActivateWaiterQueue(Queue);
  1202. }
  1203. //
  1204. // Set the thread wait parameters, set the thread dispatcher
  1205. // state to Waiting, and insert the thread in the wait list.
  1206. //
  1207. ServerThread->Alertable = FALSE;
  1208. ServerThread->WaitMode = WaitMode;
  1209. ServerThread->WaitReason = WrRendezvous;
  1210. ServerThread->WaitTime = KiQueryLowTickCount();
  1211. ServerThread->State = Waiting;
  1212. KiInsertWaitList(WaitMode, ServerThread);
  1213. //
  1214. // Switch context to selected thread.
  1215. //
  1216. // Control is returned at the original IRQL.
  1217. //
  1218. ASSERT(KeIsExecutingDpc() == FALSE);
  1219. ASSERT(ServerThread->WaitIrql <= DISPATCH_LEVEL);
  1220. WaitStatus = KiSwapThread();
  1221. //
  1222. // If the thread was not awakened to deliver a kernel mode APC,
  1223. // then return wait status.
  1224. //
  1225. if (WaitStatus != STATUS_KERNEL_APC) {
  1226. //
  1227. // If a client message was successfully received, then
  1228. // attempt to write the address of the send message
  1229. // address. If the write attempt fails, then do not
  1230. // report an error. When the caller attempts to access
  1231. // the message address, an access violation will occur.
  1232. //
  1233. if (NT_SUCCESS(WaitStatus)) {
  1234. try {
  1235. *Message = ServerThread->ThreadView;
  1236. } except(ExSystemExceptionFilter()) {
  1237. }
  1238. }
  1239. return WaitStatus;
  1240. }
  1241. }
  1242. //
  1243. // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
  1244. //
  1245. KiLockDispatcherDatabase(&ServerThread->WaitIrql);
  1246. } while (TRUE);
  1247. //
  1248. // Unlock the dispatcher database and return the target thread.
  1249. //
  1250. KiUnlockDispatcherDatabase(ServerThread->WaitIrql);
  1251. return WaitStatus;
  1252. }
  1253. PKTHREAD
  1254. KiRendezvousWithThread (
  1255. IN PRECHANNEL WaitChannel,
  1256. IN ULONG WaitMode
  1257. )
  1258. /*++
  1259. Routine Description:
  1260. This function performs a rendezvous with a thread waiting on the
  1261. channel receive event.
  1262. N.B. This routine is called with the dispatcher database locked.
  1263. N.B. The wait IRQL is assumed to be set for the current thread.
  1264. N.B. Control is returned from this function with the dispatcher
  1265. database unlocked.
  1266. Arguments:
  1267. WaitChannel - Supplies a pointer to a channel whose receive event
  1268. is the target of the rendezvous operation.
  1269. WaitMode - Supplies the processor wait mode.
  1270. Return Value:
  1271. If a thread rendezvous is successfully performed, then the address
  1272. of the thread object is returned as the completion status. Otherwise,
  1273. if the wait completes because of a timeout or because the thread is
  1274. being terminated, then the appropriate status is returned.
  1275. --*/
  1276. {
  1277. PKTHREAD CurrentThread;
  1278. PKQUEUE Queue;
  1279. PKTHREAD TargetThread;
  1280. PKWAIT_BLOCK WaitBlock;
  1281. PLIST_ENTRY WaitEntry;
  1282. NTSTATUS WaitStatus;
  1283. //
  1284. // Start of wait loop.
  1285. //
  1286. // Note this loop is repeated if a kernel APC is delivered in the
  1287. // middle of the wait or a kernel APC is pending on the first attempt
  1288. // through the loop.
  1289. //
  1290. // If the rendezvous event wait list is not empty, then remove the first
  1291. // entry from the list, compute the address of the respective thread,
  1292. // cancel the thread timer if appropraite, and return the thread address.
  1293. // Otherwise, wait for a thread to rendezvous with.
  1294. //
  1295. CurrentThread = KeGetCurrentThread();
  1296. do {
  1297. //
  1298. // Check if there is a thread waiting on the rendezvous event.
  1299. //
  1300. WaitEntry = WaitChannel->ReceiveEvent.Header.WaitListHead.Flink;
  1301. if (WaitEntry != &WaitChannel->ReceiveEvent.Header.WaitListHead) {
  1302. WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry);
  1303. TargetThread = WaitBlock->Thread;
  1304. //
  1305. // Remove the wait block from the wait list of the receive event,
  1306. // and remove the target thread from the wait list.
  1307. //
  1308. RemoveEntryList(&WaitBlock->WaitListEntry);
  1309. RemoveEntryList(&TargetThread->WaitListEntry);
  1310. //
  1311. // If the target thread is processing a queue entry, then increment the
  1312. // count of currently active threads.
  1313. //
  1314. Queue = TargetThread->Queue;
  1315. if (Queue != NULL) {
  1316. Queue->CurrentCount += 1;
  1317. }
  1318. //
  1319. // Set the thread state to transistion.
  1320. //
  1321. TargetThread->State = Transition;
  1322. break;
  1323. } else {
  1324. //
  1325. // Test to determine if a kernel APC is pending.
  1326. //
  1327. // If a kernel APC is pending and the previous IRQL was less than
  1328. // APC_LEVEL, then a kernel APC was queued by another processor
  1329. // just after IRQL was raised to DISPATCH_LEVEL, but before the
  1330. // dispatcher database was locked.
  1331. //
  1332. // N.B. that this can only happen in a multiprocessor system.
  1333. //
  1334. if (CurrentThread->ApcState.KernelApcPending &&
  1335. (CurrentThread->WaitIrql < APC_LEVEL)) {
  1336. //
  1337. // Unlock the dispatcher database and lower IRQL to its
  1338. // previous value. An APC interrupt will immediately occur
  1339. // which will result in the delivery of the kernel APC if
  1340. // possible.
  1341. //
  1342. KiUnlockDispatcherDatabase(CurrentThread->WaitIrql);
  1343. } else {
  1344. //
  1345. // Test if a user APC is pending.
  1346. //
  1347. if ((WaitMode != KernelMode) &&
  1348. (CurrentThread->ApcState.UserApcPending)) {
  1349. TargetThread = (PKTHREAD)STATUS_USER_APC;
  1350. break;
  1351. }
  1352. //
  1353. // Construct a wait block for the clear to send event object.
  1354. //
  1355. WaitBlock = &CurrentThread->WaitBlock[0];
  1356. CurrentThread->WaitBlockList = WaitBlock;
  1357. CurrentThread->WaitStatus = (NTSTATUS)0;
  1358. WaitBlock->Object = (PVOID)&WaitChannel->ClearToSendEvent;
  1359. WaitBlock->NextWaitBlock = WaitBlock;
  1360. WaitBlock->WaitKey = (CSHORT)STATUS_SUCCESS;
  1361. WaitBlock->WaitType = WaitAny;
  1362. InsertTailList(&WaitChannel->ClearToSendEvent.Header.WaitListHead,
  1363. &WaitBlock->WaitListEntry);
  1364. //
  1365. // If the current thread is processing a queue entry, then
  1366. // attempt to activate another thread that is blocked on the
  1367. // queue object.
  1368. //
  1369. Queue = CurrentThread->Queue;
  1370. if (Queue != NULL) {
  1371. KiActivateWaiterQueue(Queue);
  1372. }
  1373. //
  1374. // Set the thread wait parameters, set the thread dispatcher
  1375. // state to Waiting, and insert the thread in the wait list.
  1376. //
  1377. CurrentThread->Alertable = FALSE;
  1378. CurrentThread->WaitMode = (KPROCESSOR_MODE)WaitMode;
  1379. CurrentThread->WaitReason = WrRendezvous;
  1380. CurrentThread->WaitTime = KiQueryLowTickCount();
  1381. CurrentThread->State = Waiting;
  1382. KiInsertWaitList(WaitMode, CurrentThread);
  1383. //
  1384. // Switch context to selected thread.
  1385. //
  1386. // Control is returned at the original IRQL.
  1387. //
  1388. ASSERT(KeIsExecutingDpc() == FALSE);
  1389. ASSERT(CurrentThread->WaitIrql <= DISPATCH_LEVEL);
  1390. WaitStatus = KiSwapThread();
  1391. //
  1392. // If the thread was not awakened to deliver a kernel mode APC,
  1393. // then return wait status.
  1394. //
  1395. if (WaitStatus != STATUS_KERNEL_APC) {
  1396. return (PKTHREAD)WaitStatus;
  1397. }
  1398. }
  1399. //
  1400. // Raise IRQL to DISPATCH_LEVEL and lock the dispatcher database.
  1401. //
  1402. KiLockDispatcherDatabase(&CurrentThread->WaitIrql);
  1403. }
  1404. } while (TRUE);
  1405. //
  1406. // Unlock the dispatcher database and return the target thread.
  1407. //
  1408. KiUnlockDispatcherDatabase(CurrentThread->WaitIrql);
  1409. return TargetThread;
  1410. }
  1411. #endif