ReactOS 0.4.17-dev-934-g091855f
transaction.c File Reference
#include <ntifs.h>
#include <ndk/rtlfuncs.h>
#include "arbiter.h"
#include <debug.h>
Include dependency graph for transaction.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

static NTSTATUS ArbpBuildAlternative (_In_ PARBITER_INSTANCE Arbiter, _In_ PIO_RESOURCE_DESCRIPTOR Descriptor, _Out_ PARBITER_ALTERNATIVE Alternative)
 Expands one IO_RESOURCE_DESCRIPTOR into an ARBITER_ALTERNATIVE through the arbiter's UnpackRequirement callback and identifies it.
 
static NTSTATUS ArbpBuildAllocationStack (_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList, _In_ ULONG EntryCount)
 Builds the allocation stack for an arbitration list into Arbiter->AllocationStack: one ARBITER_ALLOCATION_STATE per contributing entry, in list order, terminated by a state whose Entry is NULL, followed by the flattened ARBITER_ALTERNATIVE array the states point into.
 
static NTSTATUS ArbpTestAllocation (_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList)
 Test-allocates every entry on an arbitration list into the arbiter's tentative allocation. The shared implementation behind ArbiterLibAttemptAllocation.
 
static NTSTATUS ArbpRetestAllocation (_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList)
 Re-establishes a previously tested solution in the arbiter's tentative allocation without searching again: every entry's SelectedAlternative is re-materialized at the position recorded in its Assignment.
 
NTSTATUS NTAPI ArbiterLibTestAllocation (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_TEST_ALLOCATION_PARAMETERS Parameters)
 The TestAllocation action: tentatively places every entry of the arbitration list, leaving the solution in PossibleAllocation for a later commit or rollback.
 
NTSTATUS NTAPI ArbiterLibRetestAllocation (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_RETEST_ALLOCATION_PARAMETERS Parameters)
 The RetestAllocation action: deterministically re-establishes the placements a previous test chose, without searching.
 
NTSTATUS NTAPI ArbiterLibCommitAllocation (_In_ PARBITER_INSTANCE Arbiter)
 The CommitAllocation action: the tentative PossibleAllocation becomes the committed Allocation, and the old committed list is recycled as the next scratch list.
 
NTSTATUS NTAPI ArbiterLibRollbackAllocation (_In_ PARBITER_INSTANCE Arbiter)
 The RollbackAllocation action: discards the tentative allocation; the committed one is untouched.
 
static NTSTATUS ArbpBootAllocation (_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList)
 Reserves each entry's firmware boot configuration in the committed range list, so devices left where the firmware put them keep their resources. The shared implementation behind ArbiterLibBootAllocation.
 
NTSTATUS NTAPI ArbiterLibBootAllocation (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_BOOT_ALLOCATION_PARAMETERS Parameters)
 The BootAllocation action: records every entry's firmware boot configuration in the committed allocation.
 
static BOOLEAN NTAPI ArbpQueryConflictCallback (_In_ PVOID Context, _In_ PRTL_RANGE Range)
 RtlFindRange conflict callback installed while a conflict query runs: records the range that blocks placement and reports it as a real conflict, so FindSuitableRange fails and the caller can enumerate the owner.
 
static NTSTATUS ArbpQueryConflict (_In_ PARBITER_INSTANCE Arbiter, _In_ PDEVICE_OBJECT PhysicalDeviceObject, _In_ PIO_RESOURCE_DESCRIPTOR ConflictingResource, _Out_ PULONG ConflictCount, _Out_ PARBITER_CONFLICT_INFO *Conflicts)
 Enumerates every committed range that conflicts with a candidate resource for a device. The shared implementation behind ArbiterLibQueryConflict.
 
NTSTATUS NTAPI ArbiterLibQueryConflict (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_QUERY_CONFLICT_PARAMETERS Parameters)
 The QueryConflict action: reports which devices' committed ranges collide with a candidate resource.
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 14 of file transaction.c.

Function Documentation

◆ ArbiterLibBootAllocation()

NTSTATUS NTAPI ArbiterLibBootAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_BOOT_ALLOCATION_PARAMETERS  Parameters 
)

The BootAllocation action: records every entry's firmware boot configuration in the committed allocation.

Parameters
[in]ArbiterThe arbiter instance performing the reservation.
[in,out]ParametersThe action parameters carrying the arbitration list (pre-Vista builds receive the list directly).
Returns
Returns the ArbpBootAllocation status.

Definition at line 684 of file transaction.c.

687{
688 PAGED_CODE();
689 return ArbpBootAllocation(Arbiter, Parameters->ArbitrationList);
690}
#define PAGED_CODE()
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
static NTSTATUS ArbpBootAllocation(_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList)
Reserves each entry's firmware boot configuration in the committed range list, so devices left where ...
Definition: transaction.c:582

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibCommitAllocation()

NTSTATUS NTAPI ArbiterLibCommitAllocation ( _In_ PARBITER_INSTANCE  Arbiter)

The CommitAllocation action: the tentative PossibleAllocation becomes the committed Allocation, and the old committed list is recycled as the next scratch list.

Parameters
[in]ArbiterThe arbiter instance whose transaction is committed.
Returns
Returns STATUS_SUCCESS.

Definition at line 515 of file transaction.c.

517{
518 PRTL_RANGE_LIST Old = Arbiter->Allocation;
519
520 PAGED_CODE();
521
522 RtlFreeRangeList(Old);
524 Arbiter->Allocation = Arbiter->PossibleAllocation;
525 Arbiter->PossibleAllocation = Old;
526 return STATUS_SUCCESS;
527}
NTSYSAPI VOID NTAPI RtlInitializeRangeList(_Out_ PRTL_RANGE_LIST RangeList)
NTSYSAPI VOID NTAPI RtlFreeRangeList(_In_ PRTL_RANGE_LIST RangeList)
#define STATUS_SUCCESS
Definition: shellext.h:65

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibQueryConflict()

NTSTATUS NTAPI ArbiterLibQueryConflict ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_QUERY_CONFLICT_PARAMETERS  Parameters 
)

The QueryConflict action: reports which devices' committed ranges collide with a candidate resource.

Parameters
[in]ArbiterThe arbiter instance performing the query.
[in,out]ParametersThe action parameters carrying the device, the candidate resource and the output slots (pre-Vista builds receive them directly).
Returns
Returns the ArbpQueryConflict status.

Definition at line 937 of file transaction.c.

940{
941 PAGED_CODE();
942 return ArbpQueryConflict(Arbiter,
943 Parameters->PhysicalDeviceObject,
944 Parameters->ConflictingResource,
945 Parameters->ConflictCount,
946 Parameters->Conflicts);
947}
static NTSTATUS ArbpQueryConflict(_In_ PARBITER_INSTANCE Arbiter, _In_ PDEVICE_OBJECT PhysicalDeviceObject, _In_ PIO_RESOURCE_DESCRIPTOR ConflictingResource, _Out_ PULONG ConflictCount, _Out_ PARBITER_CONFLICT_INFO *Conflicts)
Enumerates every committed range that conflicts with a candidate resource for a device....
Definition: transaction.c:770

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibRetestAllocation()

NTSTATUS NTAPI ArbiterLibRetestAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_RETEST_ALLOCATION_PARAMETERS  Parameters 
)

The RetestAllocation action: deterministically re-establishes the placements a previous test chose, without searching.

Parameters
[in]ArbiterThe arbiter instance performing the retest.
[in,out]ParametersThe action parameters carrying the arbitration list (pre-Vista builds receive the list directly).
Returns
Returns the ArbpRetestAllocation status.

Definition at line 483 of file transaction.c.

486{
487 PAGED_CODE();
488 return ArbpRetestAllocation(Arbiter, Parameters->ArbitrationList);
489}
static NTSTATUS ArbpRetestAllocation(_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList)
Re-establishes a previously tested solution in the arbiter's tentative allocation without searching a...
Definition: transaction.c:330

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibRollbackAllocation()

NTSTATUS NTAPI ArbiterLibRollbackAllocation ( _In_ PARBITER_INSTANCE  Arbiter)

The RollbackAllocation action: discards the tentative allocation; the committed one is untouched.

Parameters
[in]ArbiterThe arbiter instance whose transaction is rolled back.
Returns
Returns STATUS_SUCCESS.

Definition at line 543 of file transaction.c.

545{
546 PAGED_CODE();
547
548 RtlFreeRangeList(Arbiter->PossibleAllocation);
549 RtlInitializeRangeList(Arbiter->PossibleAllocation);
550 return STATUS_SUCCESS;
551}

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibTestAllocation()

NTSTATUS NTAPI ArbiterLibTestAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_TEST_ALLOCATION_PARAMETERS  Parameters 
)

The TestAllocation action: tentatively places every entry of the arbitration list, leaving the solution in PossibleAllocation for a later commit or rollback.

Parameters
[in]ArbiterThe arbiter instance performing the test.
[in,out]ParametersThe action parameters carrying the arbitration list (pre-Vista builds receive the list directly).
Returns
Returns the ArbpTestAllocation status.

Definition at line 447 of file transaction.c.

450{
451 PAGED_CODE();
452 return ArbpTestAllocation(Arbiter, Parameters->ArbitrationList);
453}
static NTSTATUS ArbpTestAllocation(_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList)
Test-allocates every entry on an arbitration list into the arbiter's tentative allocation....
Definition: transaction.c:227

Referenced by ArbiterLibInitializeInstance().

◆ ArbpBootAllocation()

static NTSTATUS ArbpBootAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ PLIST_ENTRY  ArbitrationList 
)
static

Reserves each entry's firmware boot configuration in the committed range list, so devices left where the firmware put them keep their resources. The shared implementation behind ArbiterLibBootAllocation.

Parameters
[in]ArbiterThe arbiter instance whose committed allocation receives the reservations. The ranges are added through the arbiter's own AddAllocation callback, owned by the device and tagged ARBITER_RANGE_BOOT_ALLOCATED so they read back as available to the owning device's later real allocation.
[in]ArbitrationListThe entries whose boot configurations are to be reserved. Placement is lenient: an entry whose configuration is not one sane, fixed, aligned, exact range is silently skipped, because a malformed firmware config must not block the rest of boot process.
Returns
Returns STATUS_SUCCESS, or the failure status of staging the additions.

Definition at line 582 of file transaction.c.

585{
586 PLIST_ENTRY ListEntry;
588 ARBITER_ALTERNATIVE Alternative;
589 PRTL_RANGE_LIST Old;
591
592 PAGED_CODE();
593
594 /* Stage the additions in PossibleAllocation, then swap them in. */
595 RtlFreeRangeList(Arbiter->PossibleAllocation);
596 RtlInitializeRangeList(Arbiter->PossibleAllocation);
597 Status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
598 if (!NT_SUCCESS(Status))
599 {
600 RtlFreeRangeList(Arbiter->PossibleAllocation);
601 RtlInitializeRangeList(Arbiter->PossibleAllocation);
602 return Status;
603 }
604
605 for (ListEntry = ArbitrationList->Flink;
606 ListEntry != ArbitrationList;
607 ListEntry = ListEntry->Flink)
608 {
610
611 if (Entry->AlternativeCount == 0)
612 continue;
613
614 RtlZeroMemory(&State, sizeof(State));
615 RtlZeroMemory(&Alternative, sizeof(Alternative));
616
617 if (!NT_SUCCESS(ArbpBuildAlternative(Arbiter, &Entry->Alternatives[0], &Alternative)))
618 continue;
619
620 /* Only sane, fixed single-placement configurations are reserved. */
621 if (Alternative.Length == 0 ||
622 Alternative.Alignment == 0 ||
624 !(Alternative.Flags & ARBITER_ALTERNATIVE_FLAG_FIXED) ||
625 (Alternative.Minimum % Alternative.Alignment) != 0)
626 {
627 continue;
628 }
629
630 State.Entry = Entry;
631 State.AlternativeCount = 1;
632 State.Alternatives = &Alternative;
633 State.CurrentAlternative = &Alternative;
635 State.RangeAttributes = ARBITER_RANGE_BOOT_ALLOCATED;
636 State.Start = State.CurrentMinimum = Alternative.Minimum;
637 State.End = State.CurrentMaximum = Alternative.Maximum;
638
639 if (!NT_SUCCESS(Arbiter->PreprocessEntry(Arbiter, &State)))
640 continue;
641
642 Arbiter->AddAllocation(Arbiter, &State);
643
644 /*
645 * The reservation is also written back into the device's
646 * Assignment, or it is left holding an unfilled one.
647 */
648 if (Arbiter->PackResource != NULL && Entry->Assignment != NULL)
649 {
650 (VOID)Arbiter->PackResource(Alternative.Descriptor,
651 State.Start,
652 Entry->Assignment);
653 }
654 }
655
656 Old = Arbiter->Allocation;
657 RtlFreeRangeList(Old);
659 Arbiter->Allocation = Arbiter->PossibleAllocation;
660 Arbiter->PossibleAllocation = Old;
661
662 return STATUS_SUCCESS;
663}
#define VOID
Definition: acefi.h:82
#define ARBITER_ALTERNATIVE_FLAG_BADRANGE
Definition: arbiter.h:33
#define ARBITER_STATE_FLAG_BOOT
Definition: arbiter.h:59
#define ARBITER_ALTERNATIVE_FLAG_FIXED
Definition: arbiter.h:32
#define ARBITER_RANGE_BOOT_ALLOCATED
Definition: arbiter.h:53
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
Status
Definition: gdiplustypes.h:24
NTSYSAPI NTSTATUS NTAPI RtlCopyRangeList(_Out_ PRTL_RANGE_LIST CopyRangeList, _In_ PRTL_RANGE_LIST RangeList)
Entry
Definition: section.c:5216
PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: arbiter.h:77
Definition: iotypes.h:4633
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
static NTSTATUS ArbpBuildAlternative(_In_ PARBITER_INSTANCE Arbiter, _In_ PIO_RESOURCE_DESCRIPTOR Descriptor, _Out_ PARBITER_ALTERNATIVE Alternative)
Expands one IO_RESOURCE_DESCRIPTOR into an ARBITER_ALTERNATIVE through the arbiter's UnpackRequiremen...
Definition: transaction.c:44
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

Referenced by ArbiterLibBootAllocation().

◆ ArbpBuildAllocationStack()

static NTSTATUS ArbpBuildAllocationStack ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ PLIST_ENTRY  ArbitrationList,
_In_ ULONG  EntryCount 
)
static

Builds the allocation stack for an arbitration list into Arbiter->AllocationStack: one ARBITER_ALLOCATION_STATE per contributing entry, in list order, terminated by a state whose Entry is NULL, followed by the flattened ARBITER_ALTERNATIVE array the states point into.

Parameters
[in]ArbiterThe arbiter instance whose AllocationStack buffer is (re)used, growing it when the list needs more room.
[in]ArbitrationListThe (sorted) list of ARBITER_LIST_ENTRY nodes to flatten. Entries without alternatives contribute no state.
[in]EntryCountThe number of entries on the list.
Returns
Returns STATUS_SUCCESS, STATUS_INSUFFICIENT_RESOURCES if the stack cannot grow, or an ArbpBuildAlternative failure status.

Definition at line 126 of file transaction.c.

130{
132 PARBITER_ALTERNATIVE Alternative;
133 PLIST_ENTRY ListEntry;
134 ULONG StateCount = EntryCount + 1; /* + NULL terminator */
135 ULONG AlternativeCount = 0;
136 ULONG Size;
137
138 PAGED_CODE();
139
140 for (ListEntry = ArbitrationList->Flink;
141 ListEntry != ArbitrationList;
142 ListEntry = ListEntry->Flink)
143 {
145
146 if (Entry->AlternativeCount == 0)
147 StateCount--; /* an empty entry contributes no state */
148 else
149 AlternativeCount += Entry->AlternativeCount;
150 }
151
152 Size = StateCount * sizeof(ARBITER_ALLOCATION_STATE) +
153 AlternativeCount * sizeof(ARBITER_ALTERNATIVE);
154
155 if (Arbiter->AllocationStackMaxSize < Size)
156 {
158
160 if (NewStack == NULL)
162
163 if (Arbiter->AllocationStack != NULL)
164 ExFreePoolWithTag(Arbiter->AllocationStack, TAG_ARBITER);
165
166 Arbiter->AllocationStack = NewStack;
167 Arbiter->AllocationStackMaxSize = Size;
168 }
169 RtlZeroMemory(Arbiter->AllocationStack, Size);
170
171 State = Arbiter->AllocationStack;
172 Alternative = (PARBITER_ALTERNATIVE)&Arbiter->AllocationStack[StateCount];
173
174 for (ListEntry = ArbitrationList->Flink;
175 ListEntry != ArbitrationList;
176 ListEntry = ListEntry->Flink)
177 {
179 ULONG Index;
180
181 if (Entry->AlternativeCount == 0)
182 continue;
183
184 State->Entry = Entry;
185 State->AlternativeCount = Entry->AlternativeCount;
186 State->Alternatives = Alternative;
187 State->Start = 1; /* Start(1) > End(0): nothing chosen yet */
188
189 for (Index = 0; Index < Entry->AlternativeCount; ++Index)
190 {
191 NTSTATUS Status = ArbpBuildAlternative(Arbiter, &Entry->Alternatives[Index], Alternative);
192 if (!NT_SUCCESS(Status))
193 return Status;
194 Alternative++;
195 }
196 State++;
197 }
198
199 return STATUS_SUCCESS;
200}
struct _ARBITER_ALTERNATIVE * PARBITER_ALTERNATIVE
struct _ARBITER_ALLOCATION_STATE ARBITER_ALLOCATION_STATE
#define TAG_ARBITER
Definition: arbiter.h:10
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
for(i=0;i< sizeof(testsuite)/sizeof(testsuite[0]);++i) ok(call_test(testsuite[i].func)
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539

Referenced by ArbpTestAllocation().

◆ ArbpBuildAlternative()

static NTSTATUS ArbpBuildAlternative ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ PIO_RESOURCE_DESCRIPTOR  Descriptor,
_Out_ PARBITER_ALTERNATIVE  Alternative 
)
static

Expands one IO_RESOURCE_DESCRIPTOR into an ARBITER_ALTERNATIVE through the arbiter's UnpackRequirement callback and identifies it.

Parameters
[in]ArbiterThe arbiter instance whose UnpackRequirement decodes the descriptor.
[in]DescriptorThe requirement descriptor to expand.
[out]AlternativeReceives the decoded window, length, alignment and the derived FIXED / SHARED / INVALID flags. The minimum is rounded up to the requested alignment first, so a misaligned window base does not later affect the range search.
Returns
Returns STATUS_SUCCESS, or the UnpackRequirement failure status.

Definition at line 44 of file transaction.c.

48{
51
52 PAGED_CODE();
53
54 /*
55 * UnpackRequirement always writes 64-bit Length/Alignment; ARBITER_ALTERNATIVE
56 * narrows them to 32 bits pre-Vista, so decode through 64-bit temporaries and
57 * assign, just to keep both versions in source.
58 */
59 Alternative->Descriptor = Descriptor;
60 Status = Arbiter->UnpackRequirement(Descriptor,
61 &Alternative->Minimum,
62 &Alternative->Maximum,
63 &Length,
64 &Alignment);
65 if (!NT_SUCCESS(Status))
66 return Status;
67
68#if (NTDDI_VERSION >= NTDDI_VISTA) || defined(__REACTOS__)
69 Alternative->Length = Length;
70 Alternative->Alignment = Alignment;
71#else
72 Alternative->Length = (UINT32)Length;
73 Alternative->Alignment = (UINT32)Alignment;
74#endif
75
76 if (Alignment != 0 && (Alternative->Minimum % Alignment) != 0)
77 Alternative->Minimum += Alignment - (Alternative->Minimum % Alignment);
78
79 Alternative->Flags = 0;
80 Alternative->Priority = ARBITER_PRIORITY_NULL;
81
82 if (Descriptor->ShareDisposition == CmResourceShareShared)
83 Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_SHARED;
84
85 if (Alternative->Maximum < Alternative->Minimum)
86 Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_BADRANGE;
87 else if ((Alternative->Maximum - Alternative->Minimum + 1) == Alternative->Length)
88 Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_FIXED;
89
93 {
94 Alternative->Flags |= ARBITER_ALTERNATIVE_FLAG_INACCESSIBLE_OK;
95 }
96
97 return STATUS_SUCCESS;
98}
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
#define ARBITER_ALTERNATIVE_FLAG_SHARED
Definition: arbiter.h:31
#define ARBITER_PRIORITY_NULL
Definition: arbiter.h:25
#define ARBITER_ALTERNATIVE_FLAG_INACCESSIBLE_OK
Definition: arbiter.h:34
union Alignment_ Alignment
if(dx< 0)
Definition: linetemp.h:194
#define CM_RESOURCE_MEMORY_COMPAT_FOR_INACCESSIBLE_RANGE
Definition: cmtypes.h:131
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define CmResourceTypeMemory
Definition: restypes.h:106
uint32_t UINT32
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFIORESLIST _In_ PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: wdfresource.h:342
@ CmResourceShareShared
Definition: cmtypes.h:243
#define CmResourceTypeMemoryLarge
Definition: cmtypes.h:231

Referenced by ArbpBootAllocation(), ArbpBuildAllocationStack(), ArbpQueryConflict(), and ArbpRetestAllocation().

◆ ArbpQueryConflict()

static NTSTATUS ArbpQueryConflict ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ PDEVICE_OBJECT  PhysicalDeviceObject,
_In_ PIO_RESOURCE_DESCRIPTOR  ConflictingResource,
_Out_ PULONG  ConflictCount,
_Out_ PARBITER_CONFLICT_INFO *  Conflicts 
)
static

Enumerates every committed range that conflicts with a candidate resource for a device. The shared implementation behind ArbiterLibQueryConflict.

Parameters
[in]ArbiterThe arbiter instance whose committed allocation is examined (through a scratch copy; the committed list is untouched).
[in]PhysicalDeviceObjectThe device the resource is being probed for. Its own ranges are never reported as conflicts.
[in]ConflictingResourceThe candidate requirement descriptor to probe.
[out]ConflictCountReceives the number of conflicts found.
[out]ConflictsReceives the ARBITER_CONFLICT_INFO array (pool tag TAG_ARBITER); the caller frees it.
Returns
Returns STATUS_SUCCESS with the conflict array filled in, or a copy/decode/allocation failure status.
Remarks
FindSuitableRange is asked to place the resource in the scratch copy; each failure names one conflicting owner through the recording callback, which is then removed so the next round finds the next one. Going through FindSuitableRange keeps the share and boot semantics identical to assignment time.

Definition at line 770 of file transaction.c.

776{
777 PRTL_CONFLICT_RANGE_CALLBACK SavedCallback = Arbiter->ConflictCallback;
778 PVOID SavedContext = Arbiter->ConflictCallbackContext;
779 PRTL_RANGE ConflictingRange = NULL;
782 ARBITER_ALTERNATIVE Alternative;
784 ULONG Count = 0;
785 ULONG Capacity = 10;
788
789 PAGED_CODE();
790
791 *ConflictCount = 0;
792 *Conflicts = NULL;
793
794 RtlZeroMemory(&State, sizeof(State));
795
796 Arbiter->ConflictCallback = ArbpQueryConflictCallback;
797 Arbiter->ConflictCallbackContext = &ConflictingRange;
798
799 RtlFreeRangeList(Arbiter->PossibleAllocation);
800 RtlInitializeRangeList(Arbiter->PossibleAllocation);
801 Status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
802 if (!NT_SUCCESS(Status))
803 goto Cleanup;
804
805 Status = ArbpBuildAlternative(Arbiter, ConflictingResource, &Alternative);
806 if (!NT_SUCCESS(Status))
807 goto Cleanup;
808
809 RtlZeroMemory(&Entry, sizeof(Entry));
810 State.Start = State.CurrentMinimum = Alternative.Minimum;
811 State.End = State.CurrentMaximum = Alternative.Maximum;
812 State.CurrentAlternative = State.Alternatives = &Alternative;
813 State.AlternativeCount = 1;
814 State.Entry = &Entry;
815 Entry.RequestSource = ArbiterRequestPnpEnumerated;
816 Entry.PhysicalDeviceObject = PhysicalDeviceObject;
819 sizeof(Entry.InterfaceType),
820 &Entry.InterfaceType,
821 &ResultLength)))
822 {
823 Entry.InterfaceType = Isa;
824 }
826 sizeof(Entry.BusNumber), &Entry.BusNumber, &ResultLength)))
827 {
828 Entry.BusNumber = 0;
829 }
830
831 List = ExAllocatePoolWithTag(PagedPool, Capacity * sizeof(*List), TAG_ARBITER);
832 if (List == NULL)
833 {
835 goto Cleanup;
836 }
837
838 Status = Arbiter->PreprocessEntry(Arbiter, &State);
839 if (!NT_SUCCESS(Status))
840 {
842 goto Cleanup;
843 }
844
845 /* The requester's own ranges are not conflicts. */
846 RtlDeleteOwnersRanges(Arbiter->PossibleAllocation, PhysicalDeviceObject);
847
848 for (;;)
849 {
850 ConflictingRange = NULL;
851 State.CurrentMinimum = State.Start;
852 State.CurrentMaximum = State.End;
853
854 if (Arbiter->FindSuitableRange(Arbiter, &State))
855 break; /* placeable now: no more conflicts */
856
857 if (Count == Capacity)
858 {
861 (Capacity + 5) * sizeof(*Grown),
863 if (Grown == NULL)
864 {
867 goto Cleanup;
868 }
871 List = Grown;
872 Capacity += 5;
873 }
874
875 if (ConflictingRange == NULL)
876 {
877 /* Blocked, but no specific owner: report one whole-range conflict. */
879 List[Count].Start = 0;
881 ++Count;
882 break;
883 }
884
885 List[Count].OwningObject = (PDEVICE_OBJECT)ConflictingRange->Owner;
886 List[Count].Start = ConflictingRange->Start;
887 List[Count].End = ConflictingRange->End;
888 ++Count;
889
890 /* Remove that owner and look for the next conflict. */
891 Status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation, ConflictingRange->Owner);
892 if (!NT_SUCCESS(Status))
893 {
895 goto Cleanup;
896 }
897 }
898
899 *Conflicts = List;
900 *ConflictCount = Count;
902
903Cleanup:
905 {
907 State.WorkSpace = 0;
908 State.Flags &= ~ARBITER_STATE_FLAG_WORKSPACE;
909 }
910 RtlFreeRangeList(Arbiter->PossibleAllocation);
911 RtlInitializeRangeList(Arbiter->PossibleAllocation);
912 Arbiter->ConflictCallback = SavedCallback;
913 Arbiter->ConflictCallbackContext = SavedContext;
914 return Status;
915}
#define ARBITER_MAXIMUM_ADDRESS
Definition: arbiter.h:13
#define ARBITER_STATE_FLAG_WORKSPACE
Definition: arbiter.h:61
PDEVICE_OBJECT PhysicalDeviceObject
Definition: btrfs_drv.h:1157
static const WCHAR Cleanup[]
Definition: register.c:80
struct _DEVICE_OBJECT * PDEVICE_OBJECT
NTSYSAPI NTSTATUS NTAPI RtlDeleteOwnersRanges(_Inout_ PRTL_RANGE_LIST RangeList, _In_ _Maybenull_ PVOID Owner)
BOOLEAN(NTAPI * PRTL_CONFLICT_RANGE_CALLBACK)(PVOID Context, struct _RTL_RANGE *Range)
Definition: rtltypes.h:708
int Count
Definition: noreturn.cpp:7
NTSTATUS NTAPI IoGetDeviceProperty(IN PDEVICE_OBJECT DeviceObject, IN DEVICE_REGISTRY_PROPERTY DeviceProperty, IN ULONG BufferLength, OUT PVOID PropertyBuffer, OUT PULONG ResultLength)
Definition: pnpmgr.c:1382
@ Isa
Definition: restypes.h:123
PDEVICE_OBJECT OwningObject
Definition: iotypes.h:4563
ULONGLONG End
Definition: rtltypes.h:1517
ULONGLONG Start
Definition: rtltypes.h:1516
PVOID Owner
Definition: rtltypes.h:1519
static BOOLEAN NTAPI ArbpQueryConflictCallback(_In_ PVOID Context, _In_ PRTL_RANGE Range)
RtlFindRange conflict callback installed while a conflict query runs: records the range that blocks p...
Definition: transaction.c:723
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3782
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
@ ArbiterRequestPnpEnumerated
Definition: iotypes.h:4621
@ DevicePropertyBusNumber
Definition: iotypes.h:1209
@ DevicePropertyLegacyBusType
Definition: iotypes.h:1208

Referenced by ArbiterLibQueryConflict().

◆ ArbpQueryConflictCallback()

static BOOLEAN NTAPI ArbpQueryConflictCallback ( _In_ PVOID  Context,
_In_ PRTL_RANGE  Range 
)
static

RtlFindRange conflict callback installed while a conflict query runs: records the range that blocks placement and reports it as a real conflict, so FindSuitableRange fails and the caller can enumerate the owner.

Parameters
[in]ContextReceives the conflicting range (a PRTL_RANGE pointer slot).
[in]RangeThe range RtlFindRange collided with.
Returns
Returns FALSE: the conflict stands.

Definition at line 723 of file transaction.c.

726{
727 PAGED_CODE();
728 *(PRTL_RANGE *)Context = Range;
729 return FALSE;
730}
#define FALSE
Definition: types.h:117
_In_ PVOID Context
Definition: storport.h:2269

Referenced by ArbpQueryConflict().

◆ ArbpRetestAllocation()

static NTSTATUS ArbpRetestAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ PLIST_ENTRY  ArbitrationList 
)
static

Re-establishes a previously tested solution in the arbiter's tentative allocation without searching again: every entry's SelectedAlternative is re-materialized at the position recorded in its Assignment.

Parameters
[in]ArbiterThe arbiter instance whose PossibleAllocation is rebuilt from the committed allocation.
[in]ArbitrationListThe list of entries from an earlier successful test: each must carry the SelectedAlternative and Assignment that test produced, except entries whose Result is ArbiterResultNullRequest, which are skipped.
Returns
Returns STATUS_SUCCESS with the solution re-recorded, STATUS_INVALID_PARAMETER for an entry that was never tested, or the failure status of the copy, decode or preprocess step. On failure the tentative allocation is discarded.
Remarks
after every arbiter's Test has succeeded, each is re-driven through Retest so the exact chosen placements are laid down for the Commit that follows.

Definition at line 330 of file transaction.c.

333{
335 ARBITER_ALTERNATIVE Alternative;
336 PLIST_ENTRY ListEntry;
338
339 PAGED_CODE();
340
341 RtlZeroMemory(&State, sizeof(State));
342 RtlZeroMemory(&Alternative, sizeof(Alternative));
343 State.Alternatives = &Alternative;
344 State.CurrentAlternative = &Alternative;
345 State.AlternativeCount = 1;
346
347 /*
348 * Rebuild the tentative allocation from the committed one
349 * minus everything the listed devices already own.
350 */
351 RtlFreeRangeList(Arbiter->PossibleAllocation);
352 RtlInitializeRangeList(Arbiter->PossibleAllocation);
353 Status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
354 if (!NT_SUCCESS(Status))
355 goto Failure;
356
357 for (ListEntry = ArbitrationList->Flink;
358 ListEntry != ArbitrationList;
359 ListEntry = ListEntry->Flink)
360 {
362
363 Status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
364 Entry->PhysicalDeviceObject);
365 if (!NT_SUCCESS(Status))
366 goto Failure;
367 }
368
369 for (ListEntry = ArbitrationList->Flink;
370 ListEntry != ArbitrationList;
371 ListEntry = ListEntry->Flink)
372 {
375
376 if (Entry->Result == ArbiterResultNullRequest)
377 continue;
378
379 /* A retest without a preceding successful test is a caller bug. */
380 if (Entry->SelectedAlternative == NULL || Entry->Assignment == NULL)
381 {
383 goto Failure;
384 }
385
386 Status = ArbpBuildAlternative(Arbiter, Entry->SelectedAlternative, &Alternative);
387 if (!NT_SUCCESS(Status))
388 goto Failure;
389
390 State.Entry = Entry;
391 State.WorkSpace = 0;
392
393 Status = Arbiter->UnpackResource(Entry->Assignment, &State.Start, &Length);
394 if (!NT_SUCCESS(Status))
395 goto Failure;
396 State.End = State.Start + Length - 1;
397
398 Status = Arbiter->PreprocessEntry(Arbiter, &State);
399 if (!NT_SUCCESS(Status))
400 goto Failure;
401
402 if (Length != 0)
403 Arbiter->AddAllocation(Arbiter, &State);
404
406 {
408 State.WorkSpace = 0;
409 State.Flags &= ~ARBITER_STATE_FLAG_WORKSPACE;
410 }
411 }
412
413 return STATUS_SUCCESS;
414
415Failure:
417 {
419 State.WorkSpace = 0;
420 State.Flags &= ~ARBITER_STATE_FLAG_WORKSPACE;
421 }
422 RtlFreeRangeList(Arbiter->PossibleAllocation);
423 RtlInitializeRangeList(Arbiter->PossibleAllocation);
424 return Status;
425}
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
@ ArbiterResultNullRequest
Definition: iotypes.h:4628

Referenced by ArbiterLibRetestAllocation().

◆ ArbpTestAllocation()

static NTSTATUS ArbpTestAllocation ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ PLIST_ENTRY  ArbitrationList 
)
static

Test-allocates every entry on an arbitration list into the arbiter's tentative allocation. The shared implementation behind ArbiterLibAttemptAllocation.

Parameters
[in]ArbiterThe arbiter instance whose PossibleAllocation receives the tentative solution.
[in]ArbitrationListThe list of ARBITER_LIST_ENTRY nodes to place. Everything a listed device already owns is removed from the working list first, so a device does not conflict with itself (its boot configuration in particular).
Returns
Returns STATUS_SUCCESS with the solution recorded in PossibleAllocation, STATUS_DEVICE_CONFIGURATION_ERROR for a malformed requirement, or the failure status of the stack build or the solver. On failure the tentative allocation is discarded.

Definition at line 227 of file transaction.c.

230{
231 PLIST_ENTRY ListEntry;
232 PVOID PreviousOwner = NULL;
233 ULONG EntryCount = 0;
235
236 PAGED_CODE();
237
238 /* Start the tentative allocation as a copy of the committed one. */
239 RtlFreeRangeList(Arbiter->PossibleAllocation);
240 RtlInitializeRangeList(Arbiter->PossibleAllocation);
241 Status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
242 if (!NT_SUCCESS(Status))
243 goto Failure;
244
245 for (ListEntry = ArbitrationList->Flink;
246 ListEntry != ArbitrationList;
247 ListEntry = ListEntry->Flink)
248 {
250 ULONG Index;
251
252 EntryCount++;
253
254 /*
255 * Everything a device on the arbitration list already owns is up for
256 * reassignment - remove it from the working list so the device does not
257 * conflict with itself (its boot config in particular).
258 */
259 if (Entry->PhysicalDeviceObject != PreviousOwner)
260 {
261 PreviousOwner = Entry->PhysicalDeviceObject;
262 RtlDeleteOwnersRanges(Arbiter->PossibleAllocation, Entry->PhysicalDeviceObject);
263 }
264
265 /* Score each entry: the sum of its alternatives' constrainedness. */
266 Entry->WorkSpace = 0;
267 if (Arbiter->ScoreRequirement != NULL)
268 {
269 for (Index = 0; Index < Entry->AlternativeCount; ++Index)
270 {
271 INT32 Score = Arbiter->ScoreRequirement(&Entry->Alternatives[Index]);
272 if (Score < 0)
273 {
275 goto Failure;
276 }
277 Entry->WorkSpace += Score;
278 }
279 }
280 }
281
282 ArbiterLibSortArbitrationList(ArbitrationList);
283
284 Status = ArbpBuildAllocationStack(Arbiter, ArbitrationList, EntryCount);
285 if (!NT_SUCCESS(Status))
286 goto Failure;
287
288 Status = Arbiter->AllocateEntry(Arbiter, Arbiter->AllocationStack);
289 if (!NT_SUCCESS(Status))
290 goto Failure;
291
292 return STATUS_SUCCESS;
293
294Failure:
295 RtlFreeRangeList(Arbiter->PossibleAllocation);
296 RtlInitializeRangeList(Arbiter->PossibleAllocation);
297 return Status;
298}
NTSTATUS NTAPI ArbiterLibSortArbitrationList(_Inout_ PLIST_ENTRY ArbitrationList)
Orders an arbitration list most-constrained first, so fixed requirements are placed before flexible o...
Definition: entry.c:71
#define STATUS_DEVICE_CONFIGURATION_ERROR
Definition: ntstatus.h:713
static NTSTATUS ArbpBuildAllocationStack(_In_ PARBITER_INSTANCE Arbiter, _In_ PLIST_ENTRY ArbitrationList, _In_ ULONG EntryCount)
Builds the allocation stack for an arbitration list into Arbiter->AllocationStack: one ARBITER_ALLOCA...
Definition: transaction.c:126
int32_t INT32
Definition: typedefs.h:58

Referenced by ArbiterLibTestAllocation().