ReactOS 0.4.17-dev-769-g1500a35
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.
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 14 of file transaction.c.

Function Documentation

◆ 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 501 of file transaction.c.

503{
504 PRTL_RANGE_LIST Old = Arbiter->Allocation;
505
506 PAGED_CODE();
507
508 RtlFreeRangeList(Old);
510 Arbiter->Allocation = Arbiter->PossibleAllocation;
511 Arbiter->PossibleAllocation = Old;
512 return STATUS_SUCCESS;
513}
#define PAGED_CODE()
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().

◆ 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 469 of file transaction.c.

472{
473 PAGED_CODE();
474 return ArbpRetestAllocation(Arbiter, Parameters->ArbitrationList);
475}
_In_ HANDLE _In_ CONST PDXGKMDT_OPM_GET_INFO_PARAMETERS Parameters
Definition: dispmprt.h:321
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:323

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 529 of file transaction.c.

531{
532 PAGED_CODE();
533
534 RtlFreeRangeList(Arbiter->PossibleAllocation);
535 RtlInitializeRangeList(Arbiter->PossibleAllocation);
536 return STATUS_SUCCESS;
537}

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 433 of file transaction.c.

436{
437 PAGED_CODE();
438 return ArbpTestAllocation(Arbiter, Parameters->ArbitrationList);
439}
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:220

Referenced by ArbiterLibInitializeInstance().

◆ 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 119 of file transaction.c.

123{
125 PARBITER_ALTERNATIVE Alternative;
126 PLIST_ENTRY ListEntry;
127 ULONG StateCount = EntryCount + 1; /* + NULL terminator */
128 ULONG AlternativeCount = 0;
129 ULONG Size;
130
131 PAGED_CODE();
132
133 for (ListEntry = ArbitrationList->Flink;
134 ListEntry != ArbitrationList;
135 ListEntry = ListEntry->Flink)
136 {
138
139 if (Entry->AlternativeCount == 0)
140 StateCount--; /* an empty entry contributes no state */
141 else
142 AlternativeCount += Entry->AlternativeCount;
143 }
144
145 Size = StateCount * sizeof(ARBITER_ALLOCATION_STATE) +
146 AlternativeCount * sizeof(ARBITER_ALTERNATIVE);
147
148 if (Arbiter->AllocationStackMaxSize < Size)
149 {
151
153 if (NewStack == NULL)
155
156 if (Arbiter->AllocationStack != NULL)
157 ExFreePoolWithTag(Arbiter->AllocationStack, TAG_ARBITER);
158
159 Arbiter->AllocationStack = NewStack;
160 Arbiter->AllocationStackMaxSize = Size;
161 }
162 RtlZeroMemory(Arbiter->AllocationStack, Size);
163
164 State = Arbiter->AllocationStack;
165 Alternative = (PARBITER_ALTERNATIVE)&Arbiter->AllocationStack[StateCount];
166
167 for (ListEntry = ArbitrationList->Flink;
168 ListEntry != ArbitrationList;
169 ListEntry = ListEntry->Flink)
170 {
172 ULONG Index;
173
174 if (Entry->AlternativeCount == 0)
175 continue;
176
177 State->Entry = Entry;
178 State->AlternativeCount = Entry->AlternativeCount;
179 State->Alternatives = Alternative;
180 State->Start = 1; /* Start(1) > End(0): nothing chosen yet */
181
182 for (Index = 0; Index < Entry->AlternativeCount; ++Index)
183 {
184 NTSTATUS Status = ArbpBuildAlternative(Arbiter, &Entry->Alternatives[Index], Alternative);
185 if (!NT_SUCCESS(Status))
186 return Status;
187 Alternative++;
188 }
189 State++;
190 }
191
192 return STATUS_SUCCESS;
193}
struct _ARBITER_ALTERNATIVE * PARBITER_ALTERNATIVE
struct _ARBITER_ALLOCATION_STATE ARBITER_ALLOCATION_STATE
#define TAG_ARBITER
Definition: arbiter.h:10
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define PagedPool
Definition: env_spec_w32.h:308
Status
Definition: gdiplustypes.h:24
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
for(i=0;i< sizeof(testsuite)/sizeof(testsuite[0]);++i) ok(call_test(testsuite[i].func)
Entry
Definition: section.c:5216
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
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)
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
90 return STATUS_SUCCESS;
91}
COMPILER_DEPENDENT_UINT64 UINT64
Definition: actypes.h:131
#define ARBITER_ALTERNATIVE_FLAG_BADRANGE
Definition: arbiter.h:30
#define ARBITER_ALTERNATIVE_FLAG_SHARED
Definition: arbiter.h:29
#define ARBITER_PRIORITY_NULL
Definition: arbiter.h:22
#define ARBITER_ALTERNATIVE_FLAG_FIXED
Definition: arbiter.h:28
union Alignment_ Alignment
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
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

Referenced by ArbpBuildAllocationStack(), and ArbpRetestAllocation().

◆ 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 323 of file transaction.c.

326{
328 ARBITER_ALTERNATIVE Alternative;
329 PLIST_ENTRY ListEntry;
331
332 PAGED_CODE();
333
334 RtlZeroMemory(&State, sizeof(State));
335 RtlZeroMemory(&Alternative, sizeof(Alternative));
336 State.Alternatives = &Alternative;
337 State.CurrentAlternative = &Alternative;
338 State.AlternativeCount = 1;
339
340 /*
341 * Rebuild the tentative allocation from the committed one
342 * minus everything the listed devices already own.
343 */
344 RtlFreeRangeList(Arbiter->PossibleAllocation);
345 RtlInitializeRangeList(Arbiter->PossibleAllocation);
346 Status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
347 if (!NT_SUCCESS(Status))
348 goto Failure;
349
350 for (ListEntry = ArbitrationList->Flink;
351 ListEntry != ArbitrationList;
352 ListEntry = ListEntry->Flink)
353 {
355
356 Status = RtlDeleteOwnersRanges(Arbiter->PossibleAllocation,
357 Entry->PhysicalDeviceObject);
358 if (!NT_SUCCESS(Status))
359 goto Failure;
360 }
361
362 for (ListEntry = ArbitrationList->Flink;
363 ListEntry != ArbitrationList;
364 ListEntry = ListEntry->Flink)
365 {
368
369 if (Entry->Result == ArbiterResultNullRequest)
370 continue;
371
372 /* A retest without a preceding successful test is a caller bug. */
373 if (Entry->SelectedAlternative == NULL || Entry->Assignment == NULL)
374 {
376 goto Failure;
377 }
378
379 Status = ArbpBuildAlternative(Arbiter, Entry->SelectedAlternative, &Alternative);
380 if (!NT_SUCCESS(Status))
381 goto Failure;
382
383 State.Entry = Entry;
384 State.WorkSpace = 0;
385
386 Status = Arbiter->UnpackResource(Entry->Assignment, &State.Start, &Length);
387 if (!NT_SUCCESS(Status))
388 goto Failure;
389 State.End = State.Start + Length - 1;
390
391 Status = Arbiter->PreprocessEntry(Arbiter, &State);
392 if (!NT_SUCCESS(Status))
393 goto Failure;
394
395 if (Length != 0)
396 Arbiter->AddAllocation(Arbiter, &State);
397
399 {
401 State.Flags &= ~ARBITER_STATE_FLAG_WORKSPACE;
402 }
403 }
404
405 return STATUS_SUCCESS;
406
407Failure:
408 RtlFreeRangeList(Arbiter->PossibleAllocation);
409 RtlInitializeRangeList(Arbiter->PossibleAllocation);
410 return Status;
411}
#define ARBITER_STATE_FLAG_WORKSPACE
Definition: arbiter.h:52
NTSYSAPI NTSTATUS NTAPI RtlDeleteOwnersRanges(_Inout_ PRTL_RANGE_LIST RangeList, _In_ _Maybenull_ PVOID Owner)
NTSYSAPI NTSTATUS NTAPI RtlCopyRangeList(_Out_ PRTL_RANGE_LIST CopyRangeList, _In_ PRTL_RANGE_LIST RangeList)
#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 220 of file transaction.c.

223{
224 PLIST_ENTRY ListEntry;
225 PVOID PreviousOwner = NULL;
226 ULONG EntryCount = 0;
228
229 PAGED_CODE();
230
231 /* Start the tentative allocation as a copy of the committed one. */
232 RtlFreeRangeList(Arbiter->PossibleAllocation);
233 RtlInitializeRangeList(Arbiter->PossibleAllocation);
234 Status = RtlCopyRangeList(Arbiter->PossibleAllocation, Arbiter->Allocation);
235 if (!NT_SUCCESS(Status))
236 goto Failure;
237
238 for (ListEntry = ArbitrationList->Flink;
239 ListEntry != ArbitrationList;
240 ListEntry = ListEntry->Flink)
241 {
243 ULONG Index;
244
245 EntryCount++;
246
247 /*
248 * Everything a device on the arbitration list already owns is up for
249 * reassignment - remove it from the working list so the device does not
250 * conflict with itself (its boot config in particular).
251 */
252 if (Entry->PhysicalDeviceObject != PreviousOwner)
253 {
254 PreviousOwner = Entry->PhysicalDeviceObject;
255 RtlDeleteOwnersRanges(Arbiter->PossibleAllocation, Entry->PhysicalDeviceObject);
256 }
257
258 /* Score each entry: the sum of its alternatives' constrainedness. */
259 Entry->WorkSpace = 0;
260 if (Arbiter->ScoreRequirement != NULL)
261 {
262 for (Index = 0; Index < Entry->AlternativeCount; ++Index)
263 {
264 INT32 Score = Arbiter->ScoreRequirement(&Entry->Alternatives[Index]);
265 if (Score < 0)
266 {
268 goto Failure;
269 }
270 Entry->WorkSpace += Score;
271 }
272 }
273 }
274
275 ArbiterLibSortArbitrationList(ArbitrationList);
276
277 Status = ArbpBuildAllocationStack(Arbiter, ArbitrationList, EntryCount);
278 if (!NT_SUCCESS(Status))
279 goto Failure;
280
281 Status = Arbiter->AllocateEntry(Arbiter, Arbiter->AllocationStack);
282 if (!NT_SUCCESS(Status))
283 goto Failure;
284
285 return STATUS_SUCCESS;
286
287Failure:
288 RtlFreeRangeList(Arbiter->PossibleAllocation);
289 RtlInitializeRangeList(Arbiter->PossibleAllocation);
290 return Status;
291}
NTSTATUS NTAPI ArbiterLibSortArbitrationList(_Inout_ PLIST_ENTRY ArbitrationList)
Definition: arbiter.c:139
#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:119
int32_t INT32
Definition: typedefs.h:58

Referenced by ArbiterLibTestAllocation().