ReactOS 0.4.17-dev-806-gffa4164
handler.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Arbitration Library
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Action dispatch and arbiter startup
5 * COPYRIGHT: Copyright 2026 Justin Miller <justin.miller@reactos.org>
6 */
7
8/* INCLUDES *******************************************************************/
9
10#include <ntifs.h>
11#include <ndk/rtlfuncs.h>
12#include "arbiter.h"
13
14#define NDEBUG
15#include <debug.h>
16
17/* DISPATCH *******************************************************************/
18
27CODE_SEG("PAGE")
28static
29VOID
31 _In_ PARBITER_INSTANCE Arbiter)
32{
33 PAGED_CODE();
34 KeWaitForSingleObject(Arbiter->MutexEvent, Executive, KernelMode, FALSE, NULL);
35}
36
44CODE_SEG("PAGE")
45static
46VOID
48 _In_ PARBITER_INSTANCE Arbiter)
49{
50 PAGED_CODE();
51 KeSetEvent(Arbiter->MutexEvent, IO_NO_INCREMENT, FALSE);
52}
53
69CODE_SEG("PAGE")
72#if (NTDDI_VERSION >= NTDDI_VISTA)
74 _In_ PARBITER_INSTANCE Arbiter,
76{
77 PAGED_CODE();
80 return STATUS_SUCCESS;
81}
82#else
84 _In_ PARBITER_INSTANCE Arbiter,
85 _In_ PLIST_ENTRY ArbitrationList)
86{
87 PAGED_CODE();
89 UNREFERENCED_PARAMETER(ArbitrationList);
90 return STATUS_SUCCESS;
91}
92#endif
93
108CODE_SEG("PAGE")
110NTAPI
111#if (NTDDI_VERSION >= NTDDI_VISTA)
113 _In_ PARBITER_INSTANCE Arbiter,
115{
116 PAGED_CODE();
117 UNREFERENCED_PARAMETER(Arbiter);
119 return STATUS_SUCCESS;
120}
121#else
123 _In_ PARBITER_INSTANCE Arbiter,
126{
127 PAGED_CODE();
128 UNREFERENCED_PARAMETER(Arbiter);
129 UNREFERENCED_PARAMETER(Requirement);
131 return STATUS_SUCCESS;
132}
133#endif
134
161CODE_SEG("PAGE")
163NTAPI
168{
171
172 PAGED_CODE();
173
174 ArbpAcquireLock(Arbiter);
175
176 switch (Action)
177 {
179#if (NTDDI_VERSION >= NTDDI_VISTA)
180 Status = Arbiter->TestAllocation(Arbiter, &Parameters->Parameters.TestAllocation);
181#else
182 Status = Arbiter->TestAllocation(
183 Arbiter,
184 Parameters->Parameters.TestAllocation.ArbitrationList);
185#endif
186 break;
187
189#if (NTDDI_VERSION >= NTDDI_VISTA)
190 Status = Arbiter->RetestAllocation(Arbiter, &Parameters->Parameters.RetestAllocation);
191#else
192 Status = Arbiter->RetestAllocation(
193 Arbiter,
194 Parameters->Parameters.RetestAllocation.ArbitrationList);
195#endif
196 break;
197
199 Status = Arbiter->CommitAllocation(Arbiter);
200 break;
201
203 Status = Arbiter->RollbackAllocation(Arbiter);
204 break;
205
207#if (NTDDI_VERSION >= NTDDI_VISTA)
208 Status = Arbiter->BootAllocation(Arbiter, &Parameters->Parameters.BootAllocation);
209#else
210 Status = Arbiter->BootAllocation(
211 Arbiter,
212 Parameters->Parameters.BootAllocation.ArbitrationList);
213#endif
214 break;
215
217#if (NTDDI_VERSION >= NTDDI_VISTA)
218 Status = Arbiter->QueryConflict(Arbiter, &Parameters->Parameters.QueryConflict);
219#else
220 Status = Arbiter->QueryConflict(
221 Arbiter,
222 Parameters->Parameters.QueryConflict.PhysicalDeviceObject,
223 Parameters->Parameters.QueryConflict.ConflictingResource,
224 Parameters->Parameters.QueryConflict.ConflictCount,
225 Parameters->Parameters.QueryConflict.Conflicts);
226#endif
227 break;
228
230#if (NTDDI_VERSION >= NTDDI_VISTA)
231 Status = Arbiter->QueryArbitrate(Arbiter, &Parameters->Parameters.QueryArbitrate);
232#else
233 Status = Arbiter->QueryArbitrate(
234 Arbiter,
235 Parameters->Parameters.QueryArbitrate.ArbitrationList);
236#endif
237 break;
238
239 /*
240 * Actions the interface defines but this arbiter does not carry
241 * out. AddReserved is one: the instance slot exists and is
242 * defaulted, but nothing routes to it.
243 */
248 break;
249
250 default:
252 break;
253 }
254
255#if (NTDDI_VERSION >= NTDDI_VISTA)
256 /* Track the tested-but-not-yet-committed window for transaction waiters. */
257 if (NT_SUCCESS(Status))
258 {
261 {
262 Arbiter->TransactionInProgress = TRUE;
264 }
267 {
268 Arbiter->TransactionInProgress = FALSE;
270 }
271 }
272#endif
273
274 ArbpReleaseLock(Arbiter);
275 return Status;
276}
277
278/* STARTUP ********************************************************************/
279
311{
315
316CODE_SEG("PAGE")
317static
320 _In_ PARBITER_INSTANCE Arbiter,
323 _Inout_ PRTL_RANGE_LIST RangeList)
324{
325 PARBITER_SEED_WINDOW Windows;
326 ULONG WindowCount = 0;
328 ULONG Index;
329
330 PAGED_CODE();
331
332 RtlFreeRangeList(RangeList);
333 RtlInitializeRangeList(RangeList);
334
335 if ((Arbiter->UnpackResource == NULL) || (ResourceCount == 0))
336 return STATUS_SUCCESS;
337
341 if (Windows == NULL)
343
344 /* Collect the windows of our own resource type, lowest first */
345 for (Index = 0; Index < ResourceCount; ++Index)
346 {
348 ULONG Insert;
349
350 if (Resources[Index].Type != (UCHAR)Arbiter->ResourceType)
351 continue;
352
353 Arbiter->UnpackResource(&Resources[Index], &Start, &Length);
354 if (Length == 0)
355 continue;
356
357 for (Insert = WindowCount; Insert > 0; --Insert)
358 {
359 if (Windows[Insert - 1].Start <= Start)
360 break;
361
362 Windows[Insert] = Windows[Insert - 1];
363 }
364
365 Windows[Insert].Start = Start;
366 Windows[Insert].End = Start + Length - 1;
367 WindowCount++;
368 }
369
370 /*
371 * A bus that reports no window of this kind is not saying it decodes
372 * nothing; it is saying it has nothing to add. Leaving the list empty
373 * leaves every address available, which is how the root arbiters run.
374 */
375 if (WindowCount == 0)
376 {
378 return STATUS_SUCCESS;
379 }
380
381 /*
382 * What goes in the list is what the arbiter may NOT hand out, so the
383 * windows themselves are the gaps in it. Recording the windows instead
384 * would wall off exactly the addresses the bus exists to give away.
385 */
386 Next = 0;
387
388 for (Index = 0; Index < WindowCount; ++Index)
389 {
390 if (Windows[Index].Start > Next)
391 {
392 RtlAddRange(RangeList, Next, Windows[Index].Start - 1, 0,
394 }
395
396 /* Overlapping windows merge, so only ever move the mark forward */
397 if (Windows[Index].End >= Next)
398 Next = Windows[Index].End + 1;
399
400 /* A window running to the top of the space leaves no tail to block */
401 if (Windows[Index].End == ARBITER_MAXIMUM_ADDRESS)
402 {
404 return STATUS_SUCCESS;
405 }
406 }
407
410
412
413 return STATUS_SUCCESS;
414}
415
416#if (NTDDI_VERSION >= NTDDI_VISTA)
437CODE_SEG("PAGE")
439NTAPI
441 _In_ PARBITER_INSTANCE Arbiter,
444 _Inout_ PRTL_RANGE_LIST RangeList)
445{
446 PAGED_CODE();
447 return ArbpSeedRangeList(Arbiter, ResourceCount, Resources, RangeList);
448}
449#endif
450
467CODE_SEG("PAGE")
469NTAPI
471 _In_ PARBITER_INSTANCE Arbiter,
472 _In_ PCM_RESOURCE_LIST StartResources)
473{
475
476 PAGED_CODE();
477
478 if (StartResources == NULL || StartResources->Count == 0)
479 return STATUS_SUCCESS;
480
481 Full = &StartResources->List[0];
482
483#if (NTDDI_VERSION >= NTDDI_VISTA)
484 /* Vista+ routes through the slot, so an arbiter may override the seeding. */
485 return Arbiter->InitializeRangeList(Arbiter,
486 Full->PartialResourceList.Count,
487 Full->PartialResourceList.PartialDescriptors,
488 Arbiter->Allocation);
489#else
490 return ArbpSeedRangeList(Arbiter,
491 Full->PartialResourceList.Count,
492 Full->PartialResourceList.PartialDescriptors,
493 Arbiter->Allocation);
494#endif
495}
496
497/* EXTERNAL RESERVATIONS ******************************************************/
498
525CODE_SEG("PAGE")
526VOID
527NTAPI
529 _In_ PARBITER_INSTANCE Arbiter,
531 _In_ ULONGLONG End,
533 _In_ BOOLEAN Shared)
534{
535 PAGED_CODE();
536
537 ArbpAcquireLock(Arbiter);
538 RtlAddRange(Arbiter->Allocation, Start, End, 0,
540 NULL, Owner);
541 ArbpReleaseLock(Arbiter);
542}
543
558CODE_SEG("PAGE")
559VOID
560NTAPI
562 _In_ PARBITER_INSTANCE Arbiter,
564{
565 PAGED_CODE();
566
567 ArbpAcquireLock(Arbiter);
568 RtlDeleteOwnersRanges(Arbiter->Allocation, Owner);
569 ArbpReleaseLock(Arbiter);
570}
#define PAGED_CODE()
#define CODE_SEG(...)
static _Out_opt_ PULONGLONG Start
Type
Definition: Type.h:7
unsigned char BOOLEAN
Definition: actypes.h:127
#define ARBITER_MAXIMUM_ADDRESS
Definition: arbiter.h:13
#define TAG_ARBITER
Definition: arbiter.h:10
struct _ARBITER_INSTANCE * PARBITER_INSTANCE
Definition: arbiter.h:110
LONG NTSTATUS
Definition: precomp.h:26
_Acquires_exclusive_lock_ Resource _Acquires_shared_lock_ Resource _Inout_ PERESOURCE Resource
Definition: cdprocs.h:843
#define STATUS_NOT_IMPLEMENTED
Definition: d3dkmdt.h:42
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define PagedPool
Definition: env_spec_w32.h:308
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
Status
Definition: gdiplustypes.h:24
static ULONG ResourceCount
Definition: inbv.c:50
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
static UINT WindowCount
Definition: multiwin.c:4
#define KernelMode
Definition: asm.h:38
NTSYSAPI NTSTATUS NTAPI RtlDeleteOwnersRanges(_Inout_ PRTL_RANGE_LIST RangeList, _In_ _Maybenull_ PVOID Owner)
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1629
NTSYSAPI NTSTATUS NTAPI RtlAddRange(_Inout_ PRTL_RANGE_LIST RangeList, _In_ ULONGLONG Start, _In_ ULONGLONG End, _In_ UCHAR Attributes, _In_ ULONG Flags, _In_opt_ PVOID UserData, _In_opt_ PVOID Owner)
NTSYSAPI VOID NTAPI RtlInitializeRangeList(_Out_ PRTL_RANGE_LIST RangeList)
NTSYSAPI VOID NTAPI RtlFreeRangeList(_In_ PRTL_RANGE_LIST RangeList)
#define RTL_RANGE_LIST_ADD_IF_CONFLICT
Definition: rtltypes.h:81
#define RTL_RANGE_LIST_ADD_SHARED
Definition: rtltypes.h:82
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
static BOOL Full
Definition: pageheap.c:12
NTSTATUS NTAPI ArbiterLibInitializeRangeList(_In_ PARBITER_INSTANCE Arbiter, _In_ ULONG ResourceCount, _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Resources, _Inout_ PRTL_RANGE_LIST RangeList)
The InitializeRangeList callback default.
Definition: handler.c:440
static NTSTATUS ArbpSeedRangeList(_In_ PARBITER_INSTANCE Arbiter, _In_ ULONG ResourceCount, _In_ PCM_PARTIAL_RESOURCE_DESCRIPTOR Resources, _Inout_ PRTL_RANGE_LIST RangeList)
Definition: handler.c:319
NTSTATUS NTAPI ArbiterLibAddReserved(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ADD_RESERVED_PARAMETERS Parameters)
The AddReserved action default: nothing to reserve.
Definition: handler.c:112
NTSTATUS NTAPI ArbiterLibQueryArbitrate(_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_QUERY_ARBITRATE_PARAMETERS Parameters)
The QueryArbitrate action default: reports that this arbiter is willing to arbitrate the given list.
Definition: handler.c:73
NTSTATUS NTAPI ArbiterLibStartArbiter(_In_ PARBITER_INSTANCE Arbiter, _In_ PCM_RESOURCE_LIST StartResources)
The StartArbiter action default: seeds the committed allocation with the windows the bus decodes,...
Definition: handler.c:470
NTSTATUS NTAPI ArbiterLibHandler(_In_ PVOID Context, _In_ ARBITER_ACTION Action, _Inout_ PARBITER_PARAMETERS Parameters)
The single ARBITER_ACTION dispatcher every exported ARBITER_INTERFACE points its ArbiterHandler at; C...
Definition: handler.c:164
VOID NTAPI ArbiterLibReleaseResources(_In_ PARBITER_INSTANCE Arbiter, _In_ PVOID Owner)
Releases every committed range owned by Owner.
Definition: handler.c:561
static VOID ArbpReleaseLock(_In_ PARBITER_INSTANCE Arbiter)
Releases the arbiter's per-instance lock.
Definition: handler.c:47
static VOID ArbpAcquireLock(_In_ PARBITER_INSTANCE Arbiter)
Acquires the arbiter's per-instance lock: one arbitration at a time.
Definition: handler.c:30
struct _ARBITER_SEED_WINDOW ARBITER_SEED_WINDOW
Seeds a range list with the resources the bus actually decodes: every descriptor of the arbiter's res...
struct _ARBITER_SEED_WINDOW * PARBITER_SEED_WINDOW
VOID NTAPI ArbiterLibReserveRange(_In_ PARBITER_INSTANCE Arbiter, _In_ ULONGLONG Start, _In_ ULONGLONG End, _In_opt_ PVOID Owner, _In_ BOOLEAN Shared)
Commits a single [Start, End] range into the arbiter as an ordinary allocation owned by Owner.
Definition: handler.c:528
#define STATUS_SUCCESS
Definition: shellext.h:65
STDMETHOD() Next(THIS_ ULONG celt, IAssociationElement *pElement, ULONG *pceltFetched) PURE
_In_ PVOID Context
Definition: storport.h:2269
PARB_RETEST_ALLOCATION RetestAllocation
Definition: arbiter.h:315
BOOLEAN TransactionInProgress
Definition: arbiter.h:333
PARB_QUERY_ARBITRATE QueryArbitrate
Definition: arbiter.h:319
PARB_BOOT_ALLOCATION BootAllocation
Definition: arbiter.h:318
PARB_TEST_ALLOCATION TestAllocation
Definition: arbiter.h:314
PARB_QUERY_CONFLICT QueryConflict
Definition: arbiter.h:320
PKEVENT TransactionEvent
Definition: arbiter.h:335
PARB_COMMIT_ALLOCATION CommitAllocation
Definition: arbiter.h:316
PARB_ROLLBACK_ALLOCATION RollbackAllocation
Definition: arbiter.h:317
Seeds a range list with the resources the bus actually decodes: every descriptor of the arbiter's res...
Definition: handler.c:311
ULONGLONG Start
Definition: handler.c:312
Definition: typedefs.h:120
unsigned char UCHAR
Definition: typedefs.h:53
#define NTAPI
Definition: typedefs.h:36
uint64_t ULONGLONG
Definition: typedefs.h:67
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFCOLLECTION _In_ ULONG Index
_In_ WDFIOTARGET _In_ _Strict_type_match_ WDF_IO_TARGET_SENT_IO_ACTION Action
Definition: wdfiotarget.h:510
#define IO_NO_INCREMENT
Definition: iotypes.h:598
@ ArbiterActionQueryConflict
Definition: iotypes.h:4556
@ ArbiterActionQueryArbitrate
Definition: iotypes.h:4557
@ ArbiterActionBootAllocation
Definition: iotypes.h:4559
@ ArbiterActionWriteReservedResources
Definition: iotypes.h:4555
@ ArbiterActionAddReserved
Definition: iotypes.h:4558
@ ArbiterActionCommitAllocation
Definition: iotypes.h:4552
@ ArbiterActionRollbackAllocation
Definition: iotypes.h:4553
@ ArbiterActionRetestAllocation
Definition: iotypes.h:4551
@ ArbiterActionQueryAllocatedResources
Definition: iotypes.h:4554
@ ArbiterActionTestAllocation
Definition: iotypes.h:4550
enum _ARBITER_ACTION ARBITER_ACTION
@ Executive
Definition: ketypes.h:467