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.

620 lines
16 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. semphore.c
  5. Abstract:
  6. This module implements the executive semaphore object. Functions are
  7. provided to create, open, release, and query semaphore objects.
  8. Author:
  9. David N. Cutler (davec) 8-May-1989
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "exp.h"
  15. //
  16. // Temporary so boost is patchable
  17. //
  18. ULONG ExpSemaphoreBoost = SEMAPHORE_INCREMENT;
  19. //
  20. // Address of semaphore object type descriptor.
  21. //
  22. POBJECT_TYPE ExSemaphoreObjectType;
  23. //
  24. // Structure that describes the mapping of generic access rights to object
  25. // specific access rights for semaphore objects.
  26. //
  27. #ifdef ALLOC_DATA_PRAGMA
  28. #pragma const_seg("INITCONST")
  29. #endif
  30. const GENERIC_MAPPING ExpSemaphoreMapping = {
  31. STANDARD_RIGHTS_READ |
  32. SEMAPHORE_QUERY_STATE,
  33. STANDARD_RIGHTS_WRITE |
  34. SEMAPHORE_MODIFY_STATE,
  35. STANDARD_RIGHTS_EXECUTE |
  36. SYNCHRONIZE,
  37. SEMAPHORE_ALL_ACCESS
  38. };
  39. #ifdef ALLOC_DATA_PRAGMA
  40. #pragma const_seg()
  41. #endif
  42. #ifdef ALLOC_PRAGMA
  43. #pragma alloc_text(INIT, ExpSemaphoreInitialization)
  44. #pragma alloc_text(PAGE, NtCreateSemaphore)
  45. #pragma alloc_text(PAGE, NtOpenSemaphore)
  46. #pragma alloc_text(PAGE, NtQuerySemaphore)
  47. #pragma alloc_text(PAGE, NtReleaseSemaphore)
  48. #endif
  49. BOOLEAN
  50. ExpSemaphoreInitialization (
  51. )
  52. /*++
  53. Routine Description:
  54. This function creates the semaphore object type descriptor at system
  55. initialization and stores the address of the object type descriptor
  56. in local static storage.
  57. Arguments:
  58. None.
  59. Return Value:
  60. A value of TRUE is returned if the semaphore object type descriptor is
  61. successfully created. Otherwise a value of FALSE is returned.
  62. --*/
  63. {
  64. OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
  65. NTSTATUS Status;
  66. UNICODE_STRING TypeName;
  67. //
  68. // Initialize string descriptor.
  69. //
  70. RtlInitUnicodeString(&TypeName, L"Semaphore");
  71. //
  72. // Create semaphore object type descriptor.
  73. //
  74. RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
  75. ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
  76. ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
  77. ObjectTypeInitializer.GenericMapping = ExpSemaphoreMapping;
  78. ObjectTypeInitializer.PoolType = NonPagedPool;
  79. ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KSEMAPHORE);
  80. ObjectTypeInitializer.ValidAccessMask = SEMAPHORE_ALL_ACCESS;
  81. Status = ObCreateObjectType(&TypeName,
  82. &ObjectTypeInitializer,
  83. (PSECURITY_DESCRIPTOR)NULL,
  84. &ExSemaphoreObjectType);
  85. //
  86. // If the semaphore object type descriptor was successfully created, then
  87. // return a value of TRUE. Otherwise return a value of FALSE.
  88. //
  89. return (BOOLEAN)(NT_SUCCESS(Status));
  90. }
  91. NTSTATUS
  92. NtCreateSemaphore (
  93. IN PHANDLE SemaphoreHandle,
  94. IN ACCESS_MASK DesiredAccess,
  95. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  96. IN LONG InitialCount,
  97. IN LONG MaximumCount
  98. )
  99. /*++
  100. Routine Description:
  101. This function creates a semaphore object, sets its initial count to the
  102. specified value, sets its maximum count to the specified value, and opens
  103. a handle to the object with the specified desired access.
  104. Arguments:
  105. SemaphoreHandle - Supplies a pointer to a variable that will receive the
  106. semaphore object handle.
  107. DesiredAccess - Supplies the desired types of access for the semaphore
  108. object.
  109. ObjectAttributes - Supplies a pointer to an object attributes structure.
  110. InitialCount - Supplies the initial count of the semaphore object.
  111. MaximumCount - Supplies the maximum count of the semaphore object.
  112. Return Value:
  113. NTSTATUS.
  114. --*/
  115. {
  116. HANDLE Handle;
  117. KPROCESSOR_MODE PreviousMode;
  118. PVOID Semaphore;
  119. NTSTATUS Status;
  120. //
  121. // Establish an exception handler, probe the output handle address, and
  122. // attempt to create a semaphore object. If the probe fails, then return
  123. // the exception code as the service status. Otherwise return the status
  124. // value returned by the object insertion routine.
  125. //
  126. // Get previous processor mode and probe output handle address if
  127. // necessary.
  128. //
  129. PreviousMode = KeGetPreviousMode();
  130. if (PreviousMode != KernelMode) {
  131. try {
  132. ProbeForWriteHandle(SemaphoreHandle);
  133. } except(ExSystemExceptionFilter()) {
  134. return GetExceptionCode();
  135. }
  136. }
  137. //
  138. // Check argument validity.
  139. //
  140. if ((MaximumCount <= 0) || (InitialCount < 0) ||
  141. (InitialCount > MaximumCount)) {
  142. return STATUS_INVALID_PARAMETER;
  143. }
  144. //
  145. // Allocate semaphore object.
  146. //
  147. Status = ObCreateObject(PreviousMode,
  148. ExSemaphoreObjectType,
  149. ObjectAttributes,
  150. PreviousMode,
  151. NULL,
  152. sizeof(KSEMAPHORE),
  153. 0,
  154. 0,
  155. (PVOID *)&Semaphore);
  156. //
  157. // If the semaphore object was successfully allocated, then initialize
  158. // the semaphore object and attempt to insert the semaphore object in
  159. // the current process' handle table.
  160. //
  161. if (NT_SUCCESS(Status)) {
  162. KeInitializeSemaphore((PKSEMAPHORE)Semaphore,
  163. InitialCount,
  164. MaximumCount);
  165. Status = ObInsertObject(Semaphore,
  166. NULL,
  167. DesiredAccess,
  168. 0,
  169. (PVOID *)NULL,
  170. &Handle);
  171. //
  172. // If the semaphore object was successfully inserted in the current
  173. // process' handle table, then attempt to write the semaphore handle
  174. // value. If the write attempt fails, then do not report an error.
  175. // When the caller attempts to access the handle value, an access
  176. // violation will occur.
  177. //
  178. if (NT_SUCCESS(Status)) {
  179. if (PreviousMode != KernelMode) {
  180. try {
  181. *SemaphoreHandle = Handle;
  182. } except(ExSystemExceptionFilter()) {
  183. NOTHING;
  184. }
  185. }
  186. else {
  187. *SemaphoreHandle = Handle;
  188. }
  189. }
  190. }
  191. //
  192. // Return service status.
  193. //
  194. return Status;
  195. }
  196. NTSTATUS
  197. NtOpenSemaphore (
  198. OUT PHANDLE SemaphoreHandle,
  199. IN ACCESS_MASK DesiredAccess,
  200. IN POBJECT_ATTRIBUTES ObjectAttributes
  201. )
  202. /*++
  203. Routine Description:
  204. This function opens a handle to a semaphore object with the specified
  205. desired access.
  206. Arguments:
  207. SemaphoreHandle - Supplies a pointer to a variable that will receive the
  208. semaphore object handle.
  209. DesiredAccess - Supplies the desired types of access for the semaphore
  210. object.
  211. ObjectAttributes - Supplies a pointer to an object attributes structure.
  212. Return Value:
  213. NTSTATUS.
  214. --*/
  215. {
  216. HANDLE Handle;
  217. KPROCESSOR_MODE PreviousMode;
  218. NTSTATUS Status;
  219. //
  220. // Establish an exception handler, probe the output handle address, and
  221. // attempt to open a semaphore object. If the probe fails, then return
  222. // the exception code as the service status. Otherwise return the status
  223. // value returned by the object open routine.
  224. //
  225. // Get previous processor mode and probe output handle address if
  226. // necessary.
  227. //
  228. PreviousMode = KeGetPreviousMode();
  229. if (PreviousMode != KernelMode) {
  230. try {
  231. ProbeForWriteHandle(SemaphoreHandle);
  232. } except(ExSystemExceptionFilter()) {
  233. return GetExceptionCode();
  234. }
  235. }
  236. //
  237. // Open handle to the semaphore object with the specified desired access.
  238. //
  239. Status = ObOpenObjectByName(ObjectAttributes,
  240. ExSemaphoreObjectType,
  241. PreviousMode,
  242. NULL,
  243. DesiredAccess,
  244. NULL,
  245. &Handle);
  246. //
  247. // If the open was successful, then attempt to write the semaphore
  248. // object handle value. If the write attempt fails, then do not report
  249. // an error. When the caller attempts to access the handle value, an
  250. // access violation will occur.
  251. //
  252. if (NT_SUCCESS(Status)) {
  253. if (PreviousMode != KernelMode) {
  254. try {
  255. *SemaphoreHandle = Handle;
  256. } except(ExSystemExceptionFilter()) {
  257. NOTHING;
  258. }
  259. }
  260. else {
  261. *SemaphoreHandle = Handle;
  262. }
  263. }
  264. //
  265. // Return service status.
  266. //
  267. return Status;
  268. }
  269. NTSTATUS
  270. NtQuerySemaphore (
  271. IN HANDLE SemaphoreHandle,
  272. IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,
  273. OUT PVOID SemaphoreInformation,
  274. IN ULONG SemaphoreInformationLength,
  275. OUT PULONG ReturnLength OPTIONAL
  276. )
  277. /*++
  278. Routine Description:
  279. This function queries the state of a semaphore object and returns the
  280. requested information in the specified record structure.
  281. Arguments:
  282. SemaphoreHandle - Supplies a handle to a semaphore object.
  283. SemaphoreInformationClass - Supplies the class of information being
  284. requested.
  285. SemaphoreInformation - Supplies a pointer to a record that is to receive
  286. the requested information.
  287. SemaphoreInformationLength - Supplies the length of the record that is
  288. to receive the requested information.
  289. ReturnLength - Supplies an optional pointer to a variable that will
  290. receive the actual length of the information that is returned.
  291. Return Value:
  292. NTSTATUS.
  293. --*/
  294. {
  295. PVOID Semaphore;
  296. LONG Count;
  297. LONG Maximum;
  298. KPROCESSOR_MODE PreviousMode;
  299. NTSTATUS Status;
  300. //
  301. // Establish an exception handler, probe the output arguments, reference
  302. // the semaphore object, and return the specified information. If the probe
  303. // fails, then return the exception code as the service status. Otherwise
  304. // return the status value returned by the reference object by handle
  305. // routine.
  306. //
  307. // Get previous processor mode and probe output arguments if necessary.
  308. //
  309. PreviousMode = KeGetPreviousMode();
  310. if (PreviousMode != KernelMode) {
  311. try {
  312. ProbeForWriteSmallStructure (SemaphoreInformation,
  313. sizeof(SEMAPHORE_BASIC_INFORMATION),
  314. sizeof(ULONG));
  315. if (ARGUMENT_PRESENT(ReturnLength)) {
  316. ProbeForWriteUlong(ReturnLength);
  317. }
  318. } except(ExSystemExceptionFilter()) {
  319. return GetExceptionCode();
  320. }
  321. }
  322. //
  323. // Check argument validity.
  324. //
  325. if (SemaphoreInformationClass != SemaphoreBasicInformation) {
  326. return STATUS_INVALID_INFO_CLASS;
  327. }
  328. if (SemaphoreInformationLength != sizeof(SEMAPHORE_BASIC_INFORMATION)) {
  329. return STATUS_INFO_LENGTH_MISMATCH;
  330. }
  331. //
  332. // Reference semaphore object by handle.
  333. //
  334. Status = ObReferenceObjectByHandle(SemaphoreHandle,
  335. SEMAPHORE_QUERY_STATE,
  336. ExSemaphoreObjectType,
  337. PreviousMode,
  338. &Semaphore,
  339. NULL);
  340. //
  341. // If the reference was successful, then read the current state and
  342. // maximum count of the semaphore object, dereference semaphore object,
  343. // fill in the information structure, and return the length of the
  344. // information structure if specified. If the write of the semaphore
  345. // information or the return length fails, then do not report an error.
  346. // When the caller accesses the information structure or length an
  347. // access violation will occur.
  348. //
  349. if (NT_SUCCESS(Status)) {
  350. Count = KeReadStateSemaphore((PKSEMAPHORE)Semaphore);
  351. Maximum = ((PKSEMAPHORE)Semaphore)->Limit;
  352. ObDereferenceObject(Semaphore);
  353. if (PreviousMode != KernelMode) {
  354. try {
  355. ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->CurrentCount = Count;
  356. ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->MaximumCount = Maximum;
  357. if (ARGUMENT_PRESENT(ReturnLength)) {
  358. *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION);
  359. }
  360. } except(ExSystemExceptionFilter()) {
  361. NOTHING;
  362. }
  363. }
  364. else {
  365. ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->CurrentCount = Count;
  366. ((PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation)->MaximumCount = Maximum;
  367. if (ARGUMENT_PRESENT(ReturnLength)) {
  368. *ReturnLength = sizeof(SEMAPHORE_BASIC_INFORMATION);
  369. }
  370. }
  371. }
  372. //
  373. // Return service status.
  374. //
  375. return Status;
  376. }
  377. NTSTATUS
  378. NtReleaseSemaphore (
  379. IN HANDLE SemaphoreHandle,
  380. IN LONG ReleaseCount,
  381. OUT PLONG PreviousCount OPTIONAL
  382. )
  383. /*++
  384. Routine Description:
  385. This function releases a semaphore object by adding the specified release
  386. count to the current value.
  387. Arguments:
  388. Semaphore - Supplies a handle to a semaphore object.
  389. ReleaseCount - Supplies the release count that is to be added to the
  390. current semaphore count.
  391. PreviousCount - Supplies an optional pointer to a variable that will
  392. receive the previous semaphore count.
  393. Return Value:
  394. NTSTATUS.
  395. --*/
  396. {
  397. LONG Count;
  398. PVOID Semaphore;
  399. KPROCESSOR_MODE PreviousMode;
  400. NTSTATUS Status;
  401. //
  402. // Establish an exception handler, probe the previous count address if
  403. // specified, reference the semaphore object, and release the semaphore
  404. // object. If the probe fails, then return the exception code as the
  405. // service status. Otherwise return the status value returned by the
  406. // reference object by handle routine.
  407. //
  408. // Get previous processor mode and probe previous count address
  409. // if necessary.
  410. //
  411. PreviousMode = KeGetPreviousMode();
  412. if ((ARGUMENT_PRESENT(PreviousCount)) && (PreviousMode != KernelMode)) {
  413. try {
  414. ProbeForWriteLong(PreviousCount);
  415. } except(ExSystemExceptionFilter()) {
  416. return GetExceptionCode();
  417. }
  418. }
  419. //
  420. // Check argument validity.
  421. //
  422. if (ReleaseCount <= 0) {
  423. return STATUS_INVALID_PARAMETER;
  424. }
  425. //
  426. // Reference semaphore object by handle.
  427. //
  428. Status = ObReferenceObjectByHandle(SemaphoreHandle,
  429. SEMAPHORE_MODIFY_STATE,
  430. ExSemaphoreObjectType,
  431. PreviousMode,
  432. &Semaphore,
  433. NULL);
  434. //
  435. // If the reference was successful, then release the semaphore object.
  436. // If an exception occurs because the maximum count of the semaphore
  437. // has been exceeded, then dereference the semaphore object and return
  438. // the exception code as the service status. Otherwise write the previous
  439. // count value if specified. If the write of the previous count fails,
  440. // then do not report an error. When the caller attempts to access the
  441. // previous count value, an access violation will occur.
  442. //
  443. if (NT_SUCCESS(Status)) {
  444. //
  445. // Initialize Count to keep W4 compiler happy.
  446. //
  447. Count = 0;
  448. try {
  449. PERFINFO_DECLARE_OBJECT(Semaphore);
  450. Count = KeReleaseSemaphore((PKSEMAPHORE)Semaphore,
  451. ExpSemaphoreBoost,
  452. ReleaseCount,
  453. FALSE);
  454. } except(ExSystemExceptionFilter()) {
  455. Status = GetExceptionCode();
  456. }
  457. ObDereferenceObject(Semaphore);
  458. if (NT_SUCCESS(Status) && ARGUMENT_PRESENT(PreviousCount)) {
  459. if (PreviousMode != KernelMode) {
  460. try {
  461. *PreviousCount = Count;
  462. } except(ExSystemExceptionFilter()) {
  463. NOTHING;
  464. }
  465. }
  466. else {
  467. *PreviousCount = Count;
  468. }
  469. }
  470. }
  471. //
  472. // Return service status.
  473. //
  474. return Status;
  475. }