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.

1983 lines
52 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. synch.c
  5. Abstract:
  6. This module implements all Win32 syncronization
  7. objects.
  8. Author:
  9. Mark Lucovsky (markl) 19-Sep-1990
  10. Revision History:
  11. --*/
  12. #include "basedll.h"
  13. //
  14. // Critical Section Services
  15. //
  16. VOID
  17. InitializeCriticalSection(
  18. LPCRITICAL_SECTION lpCriticalSection
  19. )
  20. /*++
  21. Routine Description:
  22. A critical section object is initialized using
  23. Win32InitializeCriticalSection.
  24. Once a critical section object has been initialized threads within a
  25. single process may enter and exit critical sections using the
  26. critical section object. A critical section object may not me moved
  27. or copied. The application must also not modify the insides of the
  28. object, but must treat it as logically opaque.
  29. description-of-function.
  30. Arguments:
  31. lpCriticalSection - Supplies the address of a critical section object
  32. to be initialized. It is the callers resposibility to allocate
  33. the storage used by a critical section object.
  34. Return Value:
  35. None.
  36. --*/
  37. {
  38. NTSTATUS Status;
  39. Status = RtlInitializeCriticalSection(lpCriticalSection);
  40. if ( !NT_SUCCESS(Status) ){
  41. RtlRaiseStatus(Status);
  42. }
  43. }
  44. BOOL
  45. InitializeCriticalSectionAndSpinCount(
  46. LPCRITICAL_SECTION lpCriticalSection,
  47. DWORD dwSpinCount
  48. )
  49. /*++
  50. Routine Description:
  51. A critical section object is initialized using
  52. Win32InitializeCriticalSection.
  53. Once a critical section object has been initialized threads within a
  54. single process may enter and exit critical sections using the
  55. critical section object. A critical section object may not me moved
  56. or copied. The application must also not modify the insides of the
  57. object, but must treat it as logically opaque.
  58. description-of-function.
  59. Arguments:
  60. lpCriticalSection - Supplies the address of a critical section object
  61. to be initialized. It is the callers resposibility to allocate
  62. the storage used by a critical section object.
  63. Return Value:
  64. None.
  65. --*/
  66. {
  67. NTSTATUS Status;
  68. BOOL rv;
  69. rv = TRUE;
  70. Status = RtlInitializeCriticalSectionAndSpinCount(lpCriticalSection,dwSpinCount);
  71. if ( !NT_SUCCESS(Status) ){
  72. BaseSetLastNTError(Status);
  73. rv = FALSE;
  74. }
  75. return rv;
  76. }
  77. //
  78. // Event Services
  79. //
  80. HANDLE
  81. APIENTRY
  82. CreateEventA(
  83. LPSECURITY_ATTRIBUTES lpEventAttributes,
  84. BOOL bManualReset,
  85. BOOL bInitialState,
  86. LPCSTR lpName
  87. )
  88. /*++
  89. Routine Description:
  90. ANSI thunk to CreateEventW
  91. --*/
  92. {
  93. PUNICODE_STRING Unicode;
  94. ANSI_STRING AnsiString;
  95. NTSTATUS Status;
  96. LPCWSTR NameBuffer;
  97. NameBuffer = NULL;
  98. if ( ARGUMENT_PRESENT(lpName) ) {
  99. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  100. RtlInitAnsiString(&AnsiString,lpName);
  101. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  102. if ( !NT_SUCCESS(Status) ) {
  103. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  104. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  105. }
  106. else {
  107. BaseSetLastNTError(Status);
  108. }
  109. return NULL;
  110. }
  111. NameBuffer = (LPCWSTR)Unicode->Buffer;
  112. }
  113. return CreateEventW(
  114. lpEventAttributes,
  115. bManualReset,
  116. bInitialState,
  117. NameBuffer
  118. );
  119. }
  120. HANDLE
  121. APIENTRY
  122. CreateEventW(
  123. LPSECURITY_ATTRIBUTES lpEventAttributes,
  124. BOOL bManualReset,
  125. BOOL bInitialState,
  126. LPCWSTR lpName
  127. )
  128. /*++
  129. Routine Description:
  130. An event object is created and a handle opened for access to the
  131. object with the CreateEvent function.
  132. The CreateEvent function creates an event object with the specified
  133. initial state. If an event is in the Signaled state (TRUE), a wait
  134. operation on the event does not block. If the event is in the Not-
  135. Signaled state (FALSE), a wait operation on the event blocks until
  136. the specified event attains a state of Signaled, or the timeout
  137. value is exceeded.
  138. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the following
  139. object type specific access flags are valid for event objects:
  140. - EVENT_MODIFY_STATE - Modify state access (set and reset) to
  141. the event is desired.
  142. - SYNCHRONIZE - Synchronization access (wait) to the event is
  143. desired.
  144. - EVENT_ALL_ACCESS - This set of access flags specifies all of
  145. the possible access flags for an event object.
  146. Arguments:
  147. lpEventAttributes - An optional parameter that may be used to
  148. specify the attributes of the new event. If the parameter is
  149. not specified, then the event is created without a security
  150. descriptor, and the resulting handle is not inherited on process
  151. creation.
  152. bManualReset - Supplies a flag which if TRUE specifies that the
  153. event must be manually reset. If the value is FALSE, then after
  154. releasing a single waiter, the system automaticaly resets the
  155. event.
  156. bInitialState - The initial state of the event object, one of TRUE
  157. or FALSE. If the InitialState is specified as TRUE, the event's
  158. current state value is set to one, otherwise it is set to zero.
  159. lpName - Optional unicode name of event
  160. Return Value:
  161. NON-NULL - Returns a handle to the new event. The handle has full
  162. access to the new event and may be used in any API that requires
  163. a handle to an event object.
  164. FALSE/NULL - The operation failed. Extended error status is available
  165. using GetLastError.
  166. --*/
  167. {
  168. NTSTATUS Status;
  169. OBJECT_ATTRIBUTES Obja;
  170. POBJECT_ATTRIBUTES pObja;
  171. HANDLE Handle;
  172. UNICODE_STRING ObjectName;
  173. PWCHAR pstrNewObjName = NULL;
  174. if ( ARGUMENT_PRESENT(lpName) ) {
  175. if (gpTermsrvFormatObjectName &&
  176. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  177. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  178. } else {
  179. RtlInitUnicodeString(&ObjectName,lpName);
  180. }
  181. pObja = BaseFormatObjectAttributes(&Obja,lpEventAttributes,&ObjectName);
  182. }
  183. else {
  184. pObja = BaseFormatObjectAttributes(&Obja,lpEventAttributes,NULL);
  185. }
  186. Status = NtCreateEvent(
  187. &Handle,
  188. EVENT_ALL_ACCESS,
  189. pObja,
  190. bManualReset ? NotificationEvent : SynchronizationEvent,
  191. (BOOLEAN)bInitialState
  192. );
  193. if (pstrNewObjName) {
  194. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  195. }
  196. if ( NT_SUCCESS(Status) ) {
  197. if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
  198. SetLastError(ERROR_ALREADY_EXISTS);
  199. }
  200. else {
  201. SetLastError(0);
  202. }
  203. return Handle;
  204. }
  205. else {
  206. BaseSetLastNTError(Status);
  207. return NULL;
  208. }
  209. }
  210. HANDLE
  211. APIENTRY
  212. OpenEventA(
  213. DWORD dwDesiredAccess,
  214. BOOL bInheritHandle,
  215. LPCSTR lpName
  216. )
  217. /*++
  218. Routine Description:
  219. ANSI thunk to OpenNamedEventW
  220. --*/
  221. {
  222. PUNICODE_STRING Unicode;
  223. ANSI_STRING AnsiString;
  224. NTSTATUS Status;
  225. if ( ARGUMENT_PRESENT(lpName) ) {
  226. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  227. RtlInitAnsiString(&AnsiString,lpName);
  228. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  229. if ( !NT_SUCCESS(Status) ) {
  230. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  231. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  232. }
  233. else {
  234. BaseSetLastNTError(Status);
  235. }
  236. return NULL;
  237. }
  238. }
  239. else {
  240. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  241. return NULL;
  242. }
  243. return OpenEventW(
  244. dwDesiredAccess,
  245. bInheritHandle,
  246. (LPCWSTR)Unicode->Buffer
  247. );
  248. }
  249. HANDLE
  250. APIENTRY
  251. OpenEventW(
  252. DWORD dwDesiredAccess,
  253. BOOL bInheritHandle,
  254. LPCWSTR lpName
  255. )
  256. {
  257. OBJECT_ATTRIBUTES Obja;
  258. UNICODE_STRING ObjectName;
  259. NTSTATUS Status;
  260. HANDLE Object;
  261. PWCHAR pstrNewObjName = NULL;
  262. if ( !lpName ) {
  263. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  264. return NULL;
  265. }
  266. if (gpTermsrvFormatObjectName &&
  267. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  268. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  269. } else {
  270. RtlInitUnicodeString(&ObjectName,lpName);
  271. }
  272. InitializeObjectAttributes(
  273. &Obja,
  274. &ObjectName,
  275. (bInheritHandle ? OBJ_INHERIT : 0),
  276. BaseGetNamedObjectDirectory(),
  277. NULL
  278. );
  279. Status = NtOpenEvent(
  280. &Object,
  281. dwDesiredAccess,
  282. &Obja
  283. );
  284. if (pstrNewObjName) {
  285. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  286. }
  287. if ( !NT_SUCCESS(Status) ) {
  288. BaseSetLastNTError(Status);
  289. return NULL;
  290. }
  291. return Object;
  292. }
  293. BOOL
  294. SetEvent(
  295. HANDLE hEvent
  296. )
  297. /*++
  298. Routine Description:
  299. An event can be set to the signaled state (TRUE) with the SetEvent
  300. function.
  301. Setting the event causes the event to attain a state of Signaled,
  302. which releases all currently waiting threads (for manual reset
  303. events), or a single waiting thread (for automatic reset events).
  304. Arguments:
  305. hEvent - Supplies an open handle to an event object. The
  306. handle must have EVENT_MODIFY_STATE access to the event.
  307. Return Value:
  308. TRUE - The operation was successful
  309. FALSE/NULL - The operation failed. Extended error status is available
  310. using GetLastError.
  311. --*/
  312. {
  313. NTSTATUS Status;
  314. Status = NtSetEvent(hEvent,NULL);
  315. if ( NT_SUCCESS(Status) ) {
  316. return TRUE;
  317. }
  318. else {
  319. BaseSetLastNTError(Status);
  320. return FALSE;
  321. }
  322. }
  323. BOOL
  324. ResetEvent(
  325. HANDLE hEvent
  326. )
  327. /*++
  328. Routine Description:
  329. The state of an event is set to the Not-Signaled state (FALSE) using
  330. the ClearEvent function.
  331. Once the event attains a state of Not-Signaled, any threads which
  332. wait on the event block, awaiting the event to become Signaled. The
  333. reset event service sets the event count to zero for the state of
  334. the event.
  335. Arguments:
  336. hEvent - Supplies an open handle to an event object. The
  337. handle must have EVENT_MODIFY_STATE access to the event.
  338. Return Value:
  339. TRUE - The operation was successful
  340. FALSE/NULL - The operation failed. Extended error status is available
  341. using GetLastError.
  342. --*/
  343. {
  344. NTSTATUS Status;
  345. Status = NtClearEvent(hEvent);
  346. if ( NT_SUCCESS(Status) ) {
  347. return TRUE;
  348. }
  349. else {
  350. BaseSetLastNTError(Status);
  351. return FALSE;
  352. }
  353. }
  354. BOOL
  355. PulseEvent(
  356. HANDLE hEvent
  357. )
  358. /*++
  359. Routine Description:
  360. An event can be set to the Signaled state and reset to the Not-
  361. Signaled state atomically with the PulseEvent function.
  362. Pulsing the event causes the event to attain a state of Signaled,
  363. release appropriate threads, and then reset the event. When no
  364. waiters are currently waiting on the event, pulsing an event causes
  365. the event to release no threads and end up in the Not-Signaled
  366. state. With waiters waiting on an event, pulsing an event has a
  367. different effect for manual reset events that it does for automatic
  368. reset events. For manual reset events, pulsing releases all waiters
  369. and then leaves the event in the Not-Signaled state. For automatic
  370. reset events, pulsing the event releases a single waiter and then
  371. leaves the event in the Not-Signaled state.
  372. Arguments:
  373. hEvent - Supplies an open handle to an event object. The
  374. handle must have EVENT_MODIFY_STATE access to the event.
  375. Return Value:
  376. TRUE - The operation was successful
  377. FALSE/NULL - The operation failed. Extended error status is available
  378. using GetLastError.
  379. --*/
  380. {
  381. NTSTATUS Status;
  382. Status = NtPulseEvent(hEvent,NULL);
  383. if ( NT_SUCCESS(Status) ) {
  384. return TRUE;
  385. }
  386. else {
  387. BaseSetLastNTError(Status);
  388. return FALSE;
  389. }
  390. }
  391. //
  392. // Semaphore Services
  393. //
  394. HANDLE
  395. APIENTRY
  396. CreateSemaphoreA(
  397. LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  398. LONG lInitialCount,
  399. LONG lMaximumCount,
  400. LPCSTR lpName
  401. )
  402. /*++
  403. Routine Description:
  404. ANSI thunk to CreateSemaphoreW
  405. --*/
  406. {
  407. PUNICODE_STRING Unicode;
  408. ANSI_STRING AnsiString;
  409. NTSTATUS Status;
  410. LPCWSTR NameBuffer;
  411. NameBuffer = NULL;
  412. if ( ARGUMENT_PRESENT(lpName) ) {
  413. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  414. RtlInitAnsiString(&AnsiString,lpName);
  415. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  416. if ( !NT_SUCCESS(Status) ) {
  417. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  418. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  419. }
  420. else {
  421. BaseSetLastNTError(Status);
  422. }
  423. return NULL;
  424. }
  425. NameBuffer = (LPCWSTR)Unicode->Buffer;
  426. }
  427. return CreateSemaphoreW(
  428. lpSemaphoreAttributes,
  429. lInitialCount,
  430. lMaximumCount,
  431. NameBuffer
  432. );
  433. }
  434. HANDLE
  435. APIENTRY
  436. CreateSemaphoreW(
  437. LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
  438. LONG lInitialCount,
  439. LONG lMaximumCount,
  440. LPCWSTR lpName
  441. )
  442. /*++
  443. Routine Description:
  444. A semaphore object is created and a handle opened for access to the
  445. object with the CreateSemaphore function.
  446. The CreateSemaphore function causes a semaphore object to be created
  447. which contains the specified initial and maximum counts.
  448. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the
  449. following object type specific access flags are valid for semaphore
  450. objects:
  451. - SEMAPHORE_MODIFY_STATE - Modify state access (release) to the
  452. semaphore is desired.
  453. - SYNCHRONIZE - Synchronization access (wait) to the semaphore
  454. is desired.
  455. - SEMAPHORE_ALL_ACCESS - This set of access flags specifies all
  456. of the possible access flags for a semaphore object.
  457. Arguments:
  458. lpSemaphoreAttributes - An optional parameter that may be used to
  459. specify the attributes of the new semaphore. If the parameter
  460. is not specified, then the semaphore is created without a
  461. security descriptor, , and the resulting handle is not inherited
  462. on process creation.
  463. lInitialCount - The initial count for the semaphore, this value
  464. must be positive and less than or equal to the maximum count.
  465. lMaximumCount - The maximum count for the semaphore, this value
  466. must be greater than zero..
  467. lpName - Supplies an optional unicode name for the object.
  468. Return Value:
  469. NON-NULL - Returns a handle to the new semaphore. The handle has
  470. full access to the new semaphore and may be used in any API that
  471. requires a handle to a semaphore object.
  472. FALSE/NULL - The operation failed. Extended error status is available
  473. using GetLastError.
  474. --*/
  475. {
  476. NTSTATUS Status;
  477. OBJECT_ATTRIBUTES Obja;
  478. POBJECT_ATTRIBUTES pObja;
  479. HANDLE Handle;
  480. UNICODE_STRING ObjectName;
  481. PWCHAR pstrNewObjName = NULL;
  482. if ( ARGUMENT_PRESENT(lpName) ) {
  483. if (gpTermsrvFormatObjectName &&
  484. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  485. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  486. } else {
  487. RtlInitUnicodeString(&ObjectName,lpName);
  488. }
  489. pObja = BaseFormatObjectAttributes(&Obja,lpSemaphoreAttributes,&ObjectName);
  490. }
  491. else {
  492. pObja = BaseFormatObjectAttributes(&Obja,lpSemaphoreAttributes,NULL);
  493. }
  494. Status = NtCreateSemaphore(
  495. &Handle,
  496. SEMAPHORE_ALL_ACCESS,
  497. pObja,
  498. lInitialCount,
  499. lMaximumCount
  500. );
  501. if (pstrNewObjName) {
  502. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  503. }
  504. if ( NT_SUCCESS(Status) ) {
  505. if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
  506. SetLastError(ERROR_ALREADY_EXISTS);
  507. }
  508. else {
  509. SetLastError(0);
  510. }
  511. return Handle;
  512. }
  513. else {
  514. BaseSetLastNTError(Status);
  515. return NULL;
  516. }
  517. }
  518. HANDLE
  519. APIENTRY
  520. OpenSemaphoreA(
  521. DWORD dwDesiredAccess,
  522. BOOL bInheritHandle,
  523. LPCSTR lpName
  524. )
  525. /*++
  526. Routine Description:
  527. ANSI thunk to OpenSemaphoreW
  528. --*/
  529. {
  530. PUNICODE_STRING Unicode;
  531. ANSI_STRING AnsiString;
  532. NTSTATUS Status;
  533. if ( ARGUMENT_PRESENT(lpName) ) {
  534. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  535. RtlInitAnsiString(&AnsiString,lpName);
  536. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  537. if ( !NT_SUCCESS(Status) ) {
  538. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  539. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  540. }
  541. else {
  542. BaseSetLastNTError(Status);
  543. }
  544. return NULL;
  545. }
  546. }
  547. else {
  548. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  549. return NULL;
  550. }
  551. return OpenSemaphoreW(
  552. dwDesiredAccess,
  553. bInheritHandle,
  554. (LPCWSTR)Unicode->Buffer
  555. );
  556. }
  557. HANDLE
  558. APIENTRY
  559. OpenSemaphoreW(
  560. DWORD dwDesiredAccess,
  561. BOOL bInheritHandle,
  562. LPCWSTR lpName
  563. )
  564. {
  565. OBJECT_ATTRIBUTES Obja;
  566. UNICODE_STRING ObjectName;
  567. NTSTATUS Status;
  568. HANDLE Object;
  569. PWCHAR pstrNewObjName = NULL;
  570. if ( !lpName ) {
  571. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  572. return NULL;
  573. }
  574. if (gpTermsrvFormatObjectName &&
  575. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  576. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  577. } else {
  578. RtlInitUnicodeString(&ObjectName,lpName);
  579. }
  580. InitializeObjectAttributes(
  581. &Obja,
  582. &ObjectName,
  583. (bInheritHandle ? OBJ_INHERIT : 0),
  584. BaseGetNamedObjectDirectory(),
  585. NULL
  586. );
  587. Status = NtOpenSemaphore(
  588. &Object,
  589. dwDesiredAccess,
  590. &Obja
  591. );
  592. if (pstrNewObjName) {
  593. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  594. }
  595. if ( !NT_SUCCESS(Status) ) {
  596. BaseSetLastNTError(Status);
  597. return NULL;
  598. }
  599. return Object;
  600. }
  601. BOOL
  602. ReleaseSemaphore(
  603. HANDLE hSemaphore,
  604. LONG lReleaseCount,
  605. LPLONG lpPreviousCount
  606. )
  607. /*++
  608. Routine Description:
  609. A semaphore object can be released with the ReleaseSemaphore
  610. function.
  611. When the semaphore is released, the current count of the semaphore
  612. is incremented by the ReleaseCount. Any threads that are waiting
  613. for the semaphore are examined to see if the current semaphore value
  614. is sufficient to satisfy their wait.
  615. If the value specified by ReleaseCount would cause the maximum count
  616. for the semaphore to be exceeded, then the count for the semaphore
  617. is not affected and an error status is returned.
  618. Arguments:
  619. hSemaphore - Supplies an open handle to a semaphore object. The
  620. handle must have SEMAPHORE_MODIFY_STATE access to the semaphore.
  621. lReleaseCount - The release count for the semaphore. The count
  622. must be greater than zero and less than the maximum value
  623. specified for the semaphore.
  624. lpPreviousCount - An optional pointer to a variable that receives
  625. the previous count for the semaphore.
  626. Return Value:
  627. TRUE - The operation was successful
  628. FALSE/NULL - The operation failed. Extended error status is available
  629. using GetLastError.
  630. --*/
  631. {
  632. NTSTATUS Status;
  633. Status = NtReleaseSemaphore(hSemaphore,lReleaseCount,lpPreviousCount);
  634. if ( NT_SUCCESS(Status) ) {
  635. return TRUE;
  636. }
  637. else {
  638. BaseSetLastNTError(Status);
  639. return FALSE;
  640. }
  641. }
  642. //
  643. // Mutex Services
  644. //
  645. HANDLE
  646. APIENTRY
  647. CreateMutexA(
  648. LPSECURITY_ATTRIBUTES lpMutexAttributes,
  649. BOOL bInitialOwner,
  650. LPCSTR lpName
  651. )
  652. /*++
  653. Routine Description:
  654. ANSI thunk to CreateMutexW
  655. --*/
  656. {
  657. PUNICODE_STRING Unicode;
  658. ANSI_STRING AnsiString;
  659. NTSTATUS Status;
  660. LPCWSTR NameBuffer;
  661. NameBuffer = NULL;
  662. if ( ARGUMENT_PRESENT(lpName) ) {
  663. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  664. RtlInitAnsiString(&AnsiString,lpName);
  665. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  666. if ( !NT_SUCCESS(Status) ) {
  667. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  668. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  669. }
  670. else {
  671. BaseSetLastNTError(Status);
  672. }
  673. return NULL;
  674. }
  675. NameBuffer = (LPCWSTR)Unicode->Buffer;
  676. }
  677. return CreateMutexW(
  678. lpMutexAttributes,
  679. bInitialOwner,
  680. NameBuffer
  681. );
  682. }
  683. HANDLE
  684. APIENTRY
  685. CreateMutexW(
  686. LPSECURITY_ATTRIBUTES lpMutexAttributes,
  687. BOOL bInitialOwner,
  688. LPCWSTR lpName
  689. )
  690. /*++
  691. Routine Description:
  692. A mutex object can be created and a handle opened for access to the
  693. object with the CreateMutex function.
  694. A new mutex object is created and a handle opened to the object with
  695. ownership as determined by the InitialOwner parameter. The status
  696. of the newly created mutex object is set to not abandoned.
  697. In addition to the STANDARD_RIGHTS_REQUIRED access flags, the
  698. following object type specific access flags are valid for mutex
  699. objects:
  700. - MUTEX_MODIFY_STATE - Modify access to the mutex is desired.
  701. This allows a process to release a mutex.
  702. - SYNCHRONIZE - Synchronization access (wait or release) to the
  703. mutex object is desired.
  704. - MUTEX_ALL_ACCESS - All possible types of access to the mutex
  705. object are desired.
  706. Arguments:
  707. lpMutexAttributes - An optional parameter that may be used to specify
  708. the attributes of the new mutex. If the parameter is not
  709. specified, then the mutex is created without a security
  710. descriptor, and the resulting handle is not inherited on process
  711. creation.
  712. bInitialOwner - A boolean value that determines whether the creator
  713. of the object desires immediate ownership of the mutex object.
  714. lpName - Supplies an optional unicode name for the mutex.
  715. Return Value:
  716. NON-NULL - Returns a handle to the new mutex. The handle has full
  717. access to the new mutex and may be used in any API that
  718. requires a handle to a mutex object.
  719. FALSE/NULL - The operation failed. Extended error status is available
  720. using GetLastError.
  721. --*/
  722. {
  723. NTSTATUS Status;
  724. OBJECT_ATTRIBUTES Obja;
  725. POBJECT_ATTRIBUTES pObja;
  726. HANDLE Handle;
  727. UNICODE_STRING ObjectName;
  728. PWCHAR pstrNewObjName = NULL;
  729. if ( ARGUMENT_PRESENT(lpName) ) {
  730. if (gpTermsrvFormatObjectName &&
  731. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  732. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  733. } else {
  734. RtlInitUnicodeString(&ObjectName,lpName);
  735. }
  736. pObja = BaseFormatObjectAttributes(&Obja,lpMutexAttributes,&ObjectName);
  737. }
  738. else {
  739. pObja = BaseFormatObjectAttributes(&Obja,lpMutexAttributes,NULL);
  740. }
  741. Status = NtCreateMutant(
  742. &Handle,
  743. MUTANT_ALL_ACCESS,
  744. pObja,
  745. (BOOLEAN)bInitialOwner
  746. );
  747. if (pstrNewObjName) {
  748. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  749. }
  750. if ( NT_SUCCESS(Status) ) {
  751. if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
  752. SetLastError(ERROR_ALREADY_EXISTS);
  753. }
  754. else {
  755. SetLastError(0);
  756. }
  757. return Handle;
  758. }
  759. else {
  760. BaseSetLastNTError(Status);
  761. return NULL;
  762. }
  763. }
  764. HANDLE
  765. APIENTRY
  766. OpenMutexA(
  767. DWORD dwDesiredAccess,
  768. BOOL bInheritHandle,
  769. LPCSTR lpName
  770. )
  771. /*++
  772. Routine Description:
  773. ANSI thunk to OpenMutexW
  774. --*/
  775. {
  776. PUNICODE_STRING Unicode;
  777. ANSI_STRING AnsiString;
  778. NTSTATUS Status;
  779. if ( ARGUMENT_PRESENT(lpName) ) {
  780. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  781. RtlInitAnsiString(&AnsiString,lpName);
  782. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  783. if ( !NT_SUCCESS(Status) ) {
  784. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  785. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  786. }
  787. else {
  788. BaseSetLastNTError(Status);
  789. }
  790. return NULL;
  791. }
  792. }
  793. else {
  794. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  795. return NULL;
  796. }
  797. return OpenMutexW(
  798. dwDesiredAccess,
  799. bInheritHandle,
  800. (LPCWSTR)Unicode->Buffer
  801. );
  802. }
  803. HANDLE
  804. APIENTRY
  805. OpenMutexW(
  806. DWORD dwDesiredAccess,
  807. BOOL bInheritHandle,
  808. LPCWSTR lpName
  809. )
  810. {
  811. OBJECT_ATTRIBUTES Obja;
  812. UNICODE_STRING ObjectName;
  813. NTSTATUS Status;
  814. HANDLE Object;
  815. PWCHAR pstrNewObjName = NULL;
  816. if ( !lpName ) {
  817. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  818. return NULL;
  819. }
  820. if (gpTermsrvFormatObjectName &&
  821. (pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {
  822. RtlInitUnicodeString(&ObjectName,pstrNewObjName);
  823. } else {
  824. RtlInitUnicodeString(&ObjectName,lpName);
  825. }
  826. InitializeObjectAttributes(
  827. &Obja,
  828. &ObjectName,
  829. (bInheritHandle ? OBJ_INHERIT : 0),
  830. BaseGetNamedObjectDirectory(),
  831. NULL
  832. );
  833. Status = NtOpenMutant(
  834. &Object,
  835. dwDesiredAccess,
  836. &Obja
  837. );
  838. if (pstrNewObjName) {
  839. RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
  840. }
  841. if ( !NT_SUCCESS(Status) ) {
  842. BaseSetLastNTError(Status);
  843. return NULL;
  844. }
  845. return Object;
  846. }
  847. BOOL
  848. ReleaseMutex(
  849. HANDLE hMutex
  850. )
  851. /*++
  852. Routine Description:
  853. Ownership of a mutex object can be released with the ReleaseMutex
  854. function.
  855. A mutex object can only be released by a thread that currently owns
  856. the mutex object. When the mutex is released, the current count of
  857. the mutex object is incremented by one. If the resultant count is
  858. one, then the mutex object is no longer owned. Any threads that are
  859. waiting for the mutex object are examined to see if their wait can
  860. be satisfied.
  861. Arguments:
  862. hMutex - An open handle to a mutex object. The handle must
  863. have MUTEX_MODIFY_STATE access to the mutex.
  864. Return Value:
  865. TRUE - The operation was successful
  866. FALSE/NULL - The operation failed. Extended error status is available
  867. using GetLastError.
  868. --*/
  869. {
  870. NTSTATUS Status;
  871. Status = NtReleaseMutant(hMutex,NULL);
  872. if ( NT_SUCCESS(Status) ) {
  873. return TRUE;
  874. }
  875. else {
  876. BaseSetLastNTError(Status);
  877. return FALSE;
  878. }
  879. }
  880. //
  881. // Wait Services
  882. //
  883. DWORD
  884. WaitForSingleObject(
  885. HANDLE hHandle,
  886. DWORD dwMilliseconds
  887. )
  888. /*++
  889. Routine Description:
  890. A wait operation on a waitable object is accomplished with the
  891. WaitForSingleObject function.
  892. Waiting on an object checks the current state of the object. If the
  893. current state of the object allows continued execution, any
  894. adjustments to the object state are made (for example, decrementing
  895. the semaphore count for a semaphore object) and the thread continues
  896. execution. If the current state of the object does not allow
  897. continued execution, the thread is placed into the wait state
  898. pending the change of the object's state or time-out.
  899. Arguments:
  900. hHandle - An open handle to a waitable object. The handle must have
  901. SYNCHRONIZE access to the object.
  902. dwMilliseconds - A time-out value that specifies the relative time,
  903. in milliseconds, over which the wait is to be completed. A
  904. timeout value of 0 specified that the wait is to timeout
  905. immediately. This allows an application to test an object to
  906. determine if it is in the signaled state. A timeout value of -1
  907. specifies an infinite timeout period.
  908. Return Value:
  909. WAIT_TIME_OUT - Indicates that the wait was terminated due to the
  910. TimeOut conditions.
  911. 0 - indicates the specified object attained a Signaled
  912. state thus completing the wait.
  913. WAIT_ABANDONED - indicates the specified object attained a Signaled
  914. state but was abandoned.
  915. --*/
  916. {
  917. return WaitForSingleObjectEx(hHandle,dwMilliseconds,FALSE);
  918. }
  919. DWORD
  920. APIENTRY
  921. WaitForSingleObjectEx(
  922. HANDLE hHandle,
  923. DWORD dwMilliseconds,
  924. BOOL bAlertable
  925. )
  926. /*++
  927. Routine Description:
  928. A wait operation on a waitable object is accomplished with the
  929. WaitForSingleObjectEx function.
  930. Waiting on an object checks the current state of the object. If the
  931. current state of the object allows continued execution, any
  932. adjustments to the object state are made (for example, decrementing
  933. the semaphore count for a semaphore object) and the thread continues
  934. execution. If the current state of the object does not allow
  935. continued execution, the thread is placed into the wait state
  936. pending the change of the object's state or time-out.
  937. If the bAlertable parameter is FALSE, the only way the wait
  938. terminates is because the specified timeout period expires, or
  939. because the specified object entered the signaled state. If the
  940. bAlertable parameter is TRUE, then the wait can return due to any
  941. one of the above wait termination conditions, or because an I/O
  942. completion callback terminated the wait early (return value of
  943. WAIT_IO_COMPLETION).
  944. Arguments:
  945. hHandle - An open handle to a waitable object. The handle must have
  946. SYNCHRONIZE access to the object.
  947. dwMilliseconds - A time-out value that specifies the relative time,
  948. in milliseconds, over which the wait is to be completed. A
  949. timeout value of 0 specified that the wait is to timeout
  950. immediately. This allows an application to test an object to
  951. determine if it is in the signaled state. A timeout value of
  952. 0xffffffff specifies an infinite timeout period.
  953. bAlertable - Supplies a flag that controls whether or not the
  954. wait may terminate early due to an I/O completion callback.
  955. A value of TRUE allows this API to complete early due to an I/O
  956. completion callback. A value of FALSE will not allow I/O
  957. completion callbacks to terminate this call early.
  958. Return Value:
  959. WAIT_TIME_OUT - Indicates that the wait was terminated due to the
  960. TimeOut conditions.
  961. 0 - indicates the specified object attained a Signaled
  962. state thus completing the wait.
  963. 0xffffffff - The wait terminated due to an error. GetLastError may be
  964. used to get additional error information.
  965. WAIT_ABANDONED - indicates the specified object attained a Signaled
  966. state but was abandoned.
  967. WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
  968. completion callbacks.
  969. --*/
  970. {
  971. NTSTATUS Status;
  972. LARGE_INTEGER TimeOut;
  973. PLARGE_INTEGER pTimeOut;
  974. PPEB Peb;
  975. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  976. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  977. __try {
  978. Peb = NtCurrentPeb();
  979. switch( HandleToUlong(hHandle) ) {
  980. case STD_INPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardInput;
  981. break;
  982. case STD_OUTPUT_HANDLE: hHandle = Peb->ProcessParameters->StandardOutput;
  983. break;
  984. case STD_ERROR_HANDLE: hHandle = Peb->ProcessParameters->StandardError;
  985. break;
  986. }
  987. if (CONSOLE_HANDLE(hHandle) && VerifyConsoleIoHandle(hHandle)) {
  988. hHandle = GetConsoleInputWaitHandle();
  989. }
  990. pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
  991. rewait:
  992. Status = NtWaitForSingleObject(hHandle,(BOOLEAN)bAlertable,pTimeOut);
  993. if ( !NT_SUCCESS(Status) ) {
  994. BaseSetLastNTError(Status);
  995. Status = (NTSTATUS)0xffffffff;
  996. }
  997. else {
  998. if ( bAlertable && Status == STATUS_ALERTED ) {
  999. goto rewait;
  1000. }
  1001. }
  1002. } __finally {
  1003. RtlDeactivateActivationContextUnsafeFast(&Frame);
  1004. }
  1005. return (DWORD)Status;
  1006. }
  1007. DWORD
  1008. WINAPI
  1009. SignalObjectAndWait(
  1010. HANDLE hObjectToSignal,
  1011. HANDLE hObjectToWaitOn,
  1012. DWORD dwMilliseconds,
  1013. BOOL bAlertable
  1014. )
  1015. {
  1016. NTSTATUS Status;
  1017. LARGE_INTEGER TimeOut;
  1018. PLARGE_INTEGER pTimeOut;
  1019. PPEB Peb;
  1020. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  1021. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  1022. __try {
  1023. Peb = NtCurrentPeb();
  1024. switch( HandleToUlong(hObjectToWaitOn) ) {
  1025. case STD_INPUT_HANDLE: hObjectToWaitOn = Peb->ProcessParameters->StandardInput;
  1026. break;
  1027. case STD_OUTPUT_HANDLE: hObjectToWaitOn = Peb->ProcessParameters->StandardOutput;
  1028. break;
  1029. case STD_ERROR_HANDLE: hObjectToWaitOn = Peb->ProcessParameters->StandardError;
  1030. break;
  1031. }
  1032. if (CONSOLE_HANDLE(hObjectToWaitOn) && VerifyConsoleIoHandle(hObjectToWaitOn)) {
  1033. hObjectToWaitOn = GetConsoleInputWaitHandle();
  1034. }
  1035. pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
  1036. rewait:
  1037. Status = NtSignalAndWaitForSingleObject(
  1038. hObjectToSignal,
  1039. hObjectToWaitOn,
  1040. (BOOLEAN)bAlertable,
  1041. pTimeOut
  1042. );
  1043. if ( !NT_SUCCESS(Status) ) {
  1044. BaseSetLastNTError(Status);
  1045. Status = (NTSTATUS)0xffffffff;
  1046. }
  1047. else {
  1048. if ( bAlertable && Status == STATUS_ALERTED ) {
  1049. goto rewait;
  1050. }
  1051. }
  1052. } __finally {
  1053. RtlDeactivateActivationContextUnsafeFast(&Frame);
  1054. }
  1055. return (DWORD)Status;
  1056. }
  1057. DWORD
  1058. WaitForMultipleObjects(
  1059. DWORD nCount,
  1060. CONST HANDLE *lpHandles,
  1061. BOOL bWaitAll,
  1062. DWORD dwMilliseconds
  1063. )
  1064. /*++
  1065. Routine Description:
  1066. A wait operation on multiple waitable objects (up to
  1067. MAXIMUM_WAIT_OBJECTS) is accomplished with the WaitForMultipleObjects
  1068. function.
  1069. Arguments:
  1070. nCount - A count of the number of objects that are to be waited on.
  1071. lpHandles - An array of object handles. Each handle must have
  1072. SYNCHRONIZE access to the associated object.
  1073. bWaitAll - A flag that supplies the wait type. A value of TRUE
  1074. indicates a "wait all". A value of false indicates a "wait
  1075. any".
  1076. dwMilliseconds - A time-out value that specifies the relative time,
  1077. in milliseconds, over which the wait is to be completed. A
  1078. timeout value of 0 specified that the wait is to timeout
  1079. immediately. This allows an application to test an object to
  1080. determine if it is in the signaled state. A timeout value of -1
  1081. specifies an infinite timeout period.
  1082. Return Value:
  1083. WAIT_TIME_OUT - indicates that the wait was terminated due to the
  1084. TimeOut conditions.
  1085. 0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
  1086. object, the object number which satisfied the wait. In the case
  1087. of wait for all objects, the value only indicates that the wait
  1088. was completed successfully.
  1089. WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
  1090. indicates, in the case of wait for any object, the object number
  1091. which satisfied the event, and that the object which satisfied
  1092. the event was abandoned. In the case of wait for all objects,
  1093. the value indicates that the wait was completed successfully and
  1094. at least one of the objects was abandoned.
  1095. --*/
  1096. {
  1097. return WaitForMultipleObjectsEx(nCount,lpHandles,bWaitAll,dwMilliseconds,FALSE);
  1098. }
  1099. DWORD
  1100. APIENTRY
  1101. WaitForMultipleObjectsEx(
  1102. DWORD nCount,
  1103. CONST HANDLE *lpHandles,
  1104. BOOL bWaitAll,
  1105. DWORD dwMilliseconds,
  1106. BOOL bAlertable
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. A wait operation on multiple waitable objects (up to
  1111. MAXIMUM_WAIT_OBJECTS) is accomplished with the
  1112. WaitForMultipleObjects function.
  1113. This API can be used to wait on any of the specified objects to
  1114. enter the signaled state, or all of the objects to enter the
  1115. signaled state.
  1116. If the bAlertable parameter is FALSE, the only way the wait
  1117. terminates is because the specified timeout period expires, or
  1118. because the specified objects entered the signaled state. If the
  1119. bAlertable parameter is TRUE, then the wait can return due to any one of
  1120. the above wait termination conditions, or because an I/O completion
  1121. callback terminated the wait early (return value of
  1122. WAIT_IO_COMPLETION).
  1123. Arguments:
  1124. nCount - A count of the number of objects that are to be waited on.
  1125. lpHandles - An array of object handles. Each handle must have
  1126. SYNCHRONIZE access to the associated object.
  1127. bWaitAll - A flag that supplies the wait type. A value of TRUE
  1128. indicates a "wait all". A value of false indicates a "wait
  1129. any".
  1130. dwMilliseconds - A time-out value that specifies the relative time,
  1131. in milliseconds, over which the wait is to be completed. A
  1132. timeout value of 0 specified that the wait is to timeout
  1133. immediately. This allows an application to test an object to
  1134. determine if it is in the signaled state. A timeout value of
  1135. 0xffffffff specifies an infinite timeout period.
  1136. bAlertable - Supplies a flag that controls whether or not the
  1137. wait may terminate early due to an I/O completion callback.
  1138. A value of TRUE allows this API to complete early due to an I/O
  1139. completion callback. A value of FALSE will not allow I/O
  1140. completion callbacks to terminate this call early.
  1141. Return Value:
  1142. WAIT_TIME_OUT - indicates that the wait was terminated due to the
  1143. TimeOut conditions.
  1144. 0 to MAXIMUM_WAIT_OBJECTS-1, indicates, in the case of wait for any
  1145. object, the object number which satisfied the wait. In the case
  1146. of wait for all objects, the value only indicates that the wait
  1147. was completed successfully.
  1148. 0xffffffff - The wait terminated due to an error. GetLastError may be
  1149. used to get additional error information.
  1150. WAIT_ABANDONED_0 to (WAIT_ABANDONED_0)+(MAXIMUM_WAIT_OBJECTS - 1),
  1151. indicates, in the case of wait for any object, the object number
  1152. which satisfied the event, and that the object which satisfied
  1153. the event was abandoned. In the case of wait for all objects,
  1154. the value indicates that the wait was completed successfully and
  1155. at least one of the objects was abandoned.
  1156. WAIT_IO_COMPLETION - The wait terminated due to one or more I/O
  1157. completion callbacks.
  1158. --*/
  1159. {
  1160. NTSTATUS Status;
  1161. LARGE_INTEGER TimeOut;
  1162. PLARGE_INTEGER pTimeOut;
  1163. DWORD i;
  1164. LPHANDLE HandleArray;
  1165. HANDLE Handles[ 8 ];
  1166. PPEB Peb;
  1167. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  1168. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  1169. __try {
  1170. if (nCount > 8) {
  1171. HandleArray = (LPHANDLE) RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), nCount*sizeof(HANDLE));
  1172. if (HandleArray == NULL) {
  1173. BaseSetLastNTError(STATUS_NO_MEMORY);
  1174. return 0xffffffff;
  1175. }
  1176. } else {
  1177. HandleArray = Handles;
  1178. }
  1179. RtlCopyMemory(HandleArray,(LPVOID)lpHandles,nCount*sizeof(HANDLE));
  1180. Peb = NtCurrentPeb();
  1181. for (i=0;i<nCount;i++) {
  1182. switch( HandleToUlong(HandleArray[i]) ) {
  1183. case STD_INPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardInput;
  1184. break;
  1185. case STD_OUTPUT_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardOutput;
  1186. break;
  1187. case STD_ERROR_HANDLE: HandleArray[i] = Peb->ProcessParameters->StandardError;
  1188. break;
  1189. }
  1190. if (CONSOLE_HANDLE(HandleArray[i]) && VerifyConsoleIoHandle(HandleArray[i])) {
  1191. HandleArray[i] = GetConsoleInputWaitHandle();
  1192. }
  1193. }
  1194. pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
  1195. rewait:
  1196. Status = NtWaitForMultipleObjects(
  1197. (CHAR)nCount,
  1198. HandleArray,
  1199. bWaitAll ? WaitAll : WaitAny,
  1200. (BOOLEAN)bAlertable,
  1201. pTimeOut
  1202. );
  1203. if ( !NT_SUCCESS(Status) ) {
  1204. BaseSetLastNTError(Status);
  1205. Status = (NTSTATUS)0xffffffff;
  1206. }
  1207. else {
  1208. if ( bAlertable && Status == STATUS_ALERTED ) {
  1209. goto rewait;
  1210. }
  1211. }
  1212. if (HandleArray != Handles) {
  1213. RtlFreeHeap(RtlProcessHeap(), 0, HandleArray);
  1214. }
  1215. } __finally {
  1216. RtlDeactivateActivationContextUnsafeFast(&Frame);
  1217. }
  1218. return (DWORD)Status;
  1219. }
  1220. VOID
  1221. Sleep(
  1222. DWORD dwMilliseconds
  1223. )
  1224. /*++
  1225. Routine Description:
  1226. The execution of the current thread can be delayed for a specified
  1227. interval of time with the Sleep function.
  1228. The Sleep function causes the current thread to enter a
  1229. waiting state until the specified interval of time has passed.
  1230. Arguments:
  1231. dwMilliseconds - A time-out value that specifies the relative time,
  1232. in milliseconds, over which the wait is to be completed. A
  1233. timeout value of 0 specified that the wait is to timeout
  1234. immediately. This allows an application to test an object to
  1235. determine if it is in the signaled state. A timeout value of -1
  1236. specifies an infinite timeout period.
  1237. Return Value:
  1238. None.
  1239. --*/
  1240. {
  1241. SleepEx(dwMilliseconds,FALSE);
  1242. }
  1243. DWORD
  1244. APIENTRY
  1245. SleepEx(
  1246. DWORD dwMilliseconds,
  1247. BOOL bAlertable
  1248. )
  1249. /*++
  1250. Routine Description:
  1251. The execution of the current thread can be delayed for a specified
  1252. interval of time with the SleepEx function.
  1253. The SleepEx function causes the current thread to enter a waiting
  1254. state until the specified interval of time has passed.
  1255. If the bAlertable parameter is FALSE, the only way the SleepEx
  1256. returns is when the specified time interval has passed. If the
  1257. bAlertable parameter is TRUE, then the SleepEx can return due to the
  1258. expiration of the time interval (return value of 0), or because an
  1259. I/O completion callback terminated the SleepEx early (return value
  1260. of WAIT_IO_COMPLETION).
  1261. Arguments:
  1262. dwMilliseconds - A time-out value that specifies the relative time,
  1263. in milliseconds, over which the wait is to be completed. A
  1264. timeout value of 0 specified that the wait is to timeout
  1265. immediately. A timeout value of -1 specifies an infinite
  1266. timeout period.
  1267. bAlertable - Supplies a flag that controls whether or not the
  1268. SleepEx may terminate early due to an I/O completion callback.
  1269. A value of TRUE allows this API to complete early due to an I/O
  1270. completion callback. A value of FALSE will not allow I/O
  1271. completion callbacks to terminate this call early.
  1272. Return Value:
  1273. 0 - The SleepEx terminated due to expiration of the time interval.
  1274. WAIT_IO_COMPLETION - The SleepEx terminated due to one or more I/O
  1275. completion callbacks.
  1276. --*/
  1277. {
  1278. LARGE_INTEGER TimeOut;
  1279. PLARGE_INTEGER pTimeOut;
  1280. NTSTATUS Status;
  1281. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME Frame = { sizeof(Frame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  1282. RtlActivateActivationContextUnsafeFast(&Frame, NULL); // make the process default activation context active so that APCs are delivered under it
  1283. __try {
  1284. pTimeOut = BaseFormatTimeOut(&TimeOut,dwMilliseconds);
  1285. if (pTimeOut == NULL) {
  1286. //
  1287. // If Sleep( -1 ) then delay for the longest possible integer
  1288. // relative to now.
  1289. //
  1290. TimeOut.LowPart = 0x0;
  1291. TimeOut.HighPart = 0x80000000;
  1292. pTimeOut = &TimeOut;
  1293. }
  1294. rewait:
  1295. Status = NtDelayExecution(
  1296. (BOOLEAN)bAlertable,
  1297. pTimeOut
  1298. );
  1299. if ( bAlertable && Status == STATUS_ALERTED ) {
  1300. goto rewait;
  1301. }
  1302. } __finally {
  1303. RtlDeactivateActivationContextUnsafeFast(&Frame);
  1304. }
  1305. return Status == STATUS_USER_APC ? WAIT_IO_COMPLETION : 0;
  1306. }
  1307. HANDLE
  1308. WINAPI
  1309. CreateWaitableTimerA(
  1310. LPSECURITY_ATTRIBUTES lpTimerAttributes,
  1311. BOOL bManualReset,
  1312. LPCSTR lpTimerName
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. ANSI thunk to CreateWaitableTimerW
  1317. --*/
  1318. {
  1319. PUNICODE_STRING Unicode;
  1320. ANSI_STRING AnsiString;
  1321. NTSTATUS Status;
  1322. LPCWSTR NameBuffer;
  1323. NameBuffer = NULL;
  1324. if ( ARGUMENT_PRESENT(lpTimerName) ) {
  1325. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  1326. RtlInitAnsiString(&AnsiString,lpTimerName);
  1327. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  1328. if ( !NT_SUCCESS(Status) ) {
  1329. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1330. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1331. }
  1332. else {
  1333. BaseSetLastNTError(Status);
  1334. }
  1335. return NULL;
  1336. }
  1337. NameBuffer = (LPCWSTR)Unicode->Buffer;
  1338. }
  1339. return CreateWaitableTimerW(
  1340. lpTimerAttributes,
  1341. bManualReset,
  1342. NameBuffer
  1343. );
  1344. }
  1345. HANDLE
  1346. WINAPI
  1347. CreateWaitableTimerW(
  1348. LPSECURITY_ATTRIBUTES lpTimerAttributes,
  1349. BOOL bManualReset,
  1350. LPCWSTR lpTimerName
  1351. )
  1352. {
  1353. NTSTATUS Status;
  1354. OBJECT_ATTRIBUTES Obja;
  1355. POBJECT_ATTRIBUTES pObja;
  1356. HANDLE Handle;
  1357. UNICODE_STRING ObjectName;
  1358. if ( ARGUMENT_PRESENT(lpTimerName) ) {
  1359. RtlInitUnicodeString(&ObjectName,lpTimerName);
  1360. pObja = BaseFormatObjectAttributes(&Obja,lpTimerAttributes,&ObjectName);
  1361. }
  1362. else {
  1363. pObja = BaseFormatObjectAttributes(&Obja,lpTimerAttributes,NULL);
  1364. }
  1365. Status = NtCreateTimer(
  1366. &Handle,
  1367. TIMER_ALL_ACCESS,
  1368. pObja,
  1369. bManualReset ? NotificationTimer : SynchronizationTimer
  1370. );
  1371. if ( NT_SUCCESS(Status) ) {
  1372. if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
  1373. SetLastError(ERROR_ALREADY_EXISTS);
  1374. }
  1375. else {
  1376. SetLastError(0);
  1377. }
  1378. return Handle;
  1379. }
  1380. else {
  1381. BaseSetLastNTError(Status);
  1382. return NULL;
  1383. }
  1384. }
  1385. HANDLE
  1386. WINAPI
  1387. OpenWaitableTimerA(
  1388. DWORD dwDesiredAccess,
  1389. BOOL bInheritHandle,
  1390. LPCSTR lpTimerName
  1391. )
  1392. {
  1393. PUNICODE_STRING Unicode;
  1394. ANSI_STRING AnsiString;
  1395. NTSTATUS Status;
  1396. if ( ARGUMENT_PRESENT(lpTimerName) ) {
  1397. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  1398. RtlInitAnsiString(&AnsiString,lpTimerName);
  1399. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  1400. if ( !NT_SUCCESS(Status) ) {
  1401. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1402. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  1403. }
  1404. else {
  1405. BaseSetLastNTError(Status);
  1406. }
  1407. return NULL;
  1408. }
  1409. }
  1410. else {
  1411. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1412. return NULL;
  1413. }
  1414. return OpenWaitableTimerW(
  1415. dwDesiredAccess,
  1416. bInheritHandle,
  1417. (LPCWSTR)Unicode->Buffer
  1418. );
  1419. }
  1420. HANDLE
  1421. WINAPI
  1422. OpenWaitableTimerW(
  1423. DWORD dwDesiredAccess,
  1424. BOOL bInheritHandle,
  1425. LPCWSTR lpTimerName
  1426. )
  1427. {
  1428. OBJECT_ATTRIBUTES Obja;
  1429. UNICODE_STRING ObjectName;
  1430. NTSTATUS Status;
  1431. HANDLE Object;
  1432. if ( !lpTimerName ) {
  1433. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1434. return NULL;
  1435. }
  1436. RtlInitUnicodeString(&ObjectName,lpTimerName);
  1437. InitializeObjectAttributes(
  1438. &Obja,
  1439. &ObjectName,
  1440. (bInheritHandle ? OBJ_INHERIT : 0),
  1441. BaseGetNamedObjectDirectory(),
  1442. NULL
  1443. );
  1444. Status = NtOpenTimer(
  1445. &Object,
  1446. dwDesiredAccess,
  1447. &Obja
  1448. );
  1449. if ( !NT_SUCCESS(Status) ) {
  1450. BaseSetLastNTError(Status);
  1451. return NULL;
  1452. }
  1453. return Object;
  1454. }
  1455. static
  1456. VOID
  1457. CALLBACK
  1458. BasepTimerAPCProc(
  1459. PVOID pvContext,
  1460. ULONG TimerLowValue,
  1461. LONG TimerHighValue
  1462. )
  1463. {
  1464. PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK ActivationBlock = (PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK) pvContext;
  1465. const PVOID CallbackContext = ActivationBlock->CallbackContext;
  1466. const PTIMERAPCROUTINE TimerAPCRoutine = (PTIMERAPCROUTINE) ActivationBlock->CallbackFunction;
  1467. RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME ActivationFrame = { sizeof(ActivationFrame), RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER };
  1468. const PACTIVATION_CONTEXT ActivationContext = ActivationBlock->ActivationContext;
  1469. if ((ActivationBlock->Flags & BASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK) == 0) {
  1470. BasepFreeActivationContextActivationBlock(ActivationBlock);
  1471. }
  1472. RtlActivateActivationContextUnsafeFast(&ActivationFrame, ActivationContext);
  1473. __try {
  1474. (*TimerAPCRoutine)(CallbackContext, TimerLowValue, TimerHighValue);
  1475. } __finally {
  1476. RtlDeactivateActivationContextUnsafeFast(&ActivationFrame);
  1477. }
  1478. }
  1479. BOOL
  1480. WINAPI
  1481. SetWaitableTimer(
  1482. HANDLE hTimer,
  1483. const LARGE_INTEGER *lpDueTime,
  1484. LONG lPeriod,
  1485. PTIMERAPCROUTINE pfnCompletionRoutine,
  1486. LPVOID lpArgToCompletionRoutine,
  1487. BOOL fResume
  1488. )
  1489. {
  1490. NTSTATUS Status;
  1491. PBASE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK ActivationBlock = NULL;
  1492. PTIMER_APC_ROUTINE TimerApcRoutine = (PTIMER_APC_ROUTINE) pfnCompletionRoutine;
  1493. PVOID TimerApcContext = lpArgToCompletionRoutine;
  1494. // If there's an APC routine to call and we have a non-default activation
  1495. // context active for this thread, we need to allocate a little chunk of heap
  1496. // to pass to the APC callback.
  1497. if (pfnCompletionRoutine != NULL) {
  1498. DWORD dwActivationBlockAllocationFlags = BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_ALLOCATE_IF_PROCESS_DEFAULT;
  1499. // If it's a periodic timer, don't free the block until the timer is cancelled.
  1500. if (lPeriod > 0)
  1501. dwActivationBlockAllocationFlags |= BASEP_ALLOCATE_ACTIVATION_CONTEXT_ACTIVATION_BLOCK_FLAG_DO_NOT_FREE_AFTER_CALLBACK;
  1502. Status = BasepAllocateActivationContextActivationBlock(dwActivationBlockAllocationFlags, pfnCompletionRoutine, lpArgToCompletionRoutine, &ActivationBlock);
  1503. if (!NT_SUCCESS(Status)) {
  1504. BaseSetLastNTError(Status);
  1505. return FALSE;
  1506. }
  1507. if (ActivationBlock != NULL) {
  1508. TimerApcRoutine = &BasepTimerAPCProc;
  1509. TimerApcContext = ActivationBlock;
  1510. }
  1511. }
  1512. Status = NtSetTimer(
  1513. hTimer,
  1514. (PLARGE_INTEGER) lpDueTime,
  1515. TimerApcRoutine, // will be NULL if pfnCompletionRoutine was null
  1516. TimerApcContext,
  1517. (BOOLEAN) fResume,
  1518. lPeriod,
  1519. NULL
  1520. );
  1521. if ( !NT_SUCCESS(Status) ) {
  1522. if (ActivationBlock != NULL)
  1523. BasepFreeActivationContextActivationBlock(ActivationBlock);
  1524. BaseSetLastNTError(Status);
  1525. return FALSE;
  1526. } else {
  1527. if ( Status == STATUS_TIMER_RESUME_IGNORED ) {
  1528. SetLastError(ERROR_NOT_SUPPORTED);
  1529. } else {
  1530. SetLastError(ERROR_SUCCESS);
  1531. }
  1532. return TRUE;
  1533. }
  1534. }
  1535. BOOL
  1536. WINAPI
  1537. CancelWaitableTimer(
  1538. HANDLE hTimer
  1539. )
  1540. {
  1541. NTSTATUS Status;
  1542. Status = NtCancelTimer(hTimer, NULL);
  1543. if ( !NT_SUCCESS(Status) ) {
  1544. BaseSetLastNTError(Status);
  1545. return FALSE;
  1546. }
  1547. else {
  1548. return TRUE;
  1549. }
  1550. }