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

Go to the source code of this file.

Macros

#define NDEBUG
 
#define ARBITER_ALLOCATE_DEADLINE   (10ULL * 1000 * 1000) /* 1 second */
 
#define ARBITER_ALLOCATE_HARD_DEADLINE   (10ULL * 1000 * 1000 * 10) /* 10 seconds */
 

Functions

NTSTATUS NTAPI ArbiterLibPreprocessEntry (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Per-entry hook invoked before each placement attempt. The library default does nothing and succeeds.
 
NTSTATUS NTAPI ArbiterLibSortArbitrationList (_Inout_ PLIST_ENTRY ArbitrationList)
 Orders an arbitration list most-constrained first, so fixed requirements are placed before flexible ones can steal their ranges.
 
static VOID ArbpFreeAllocationWorkSpaces (_Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Releases the per-entry workspace a PreprocessEntry override allocated, across the whole allocation stack.
 
static VOID ArbpReportConflictingRanges (_In_ PARBITER_INSTANCE Arbiter, _In_ ULONGLONG Minimum, _In_ ULONGLONG Maximum)
 Says what an arbiter is already holding across a window.
 
NTSTATUS NTAPI ArbiterLibAllocateEntry (_In_ PARBITER_INSTANCE Arbiter, _Inout_ PARBITER_ALLOCATION_STATE ArbState)
 Places the whole stack of entries with backtracking: when an entry cannot be placed, the previous entry's tentative choice is withdrawn and varied, first lower within its window, then via its next window or alternative.
 

Macro Definition Documentation

◆ ARBITER_ALLOCATE_DEADLINE

#define ARBITER_ALLOCATE_DEADLINE   (10ULL * 1000 * 1000) /* 1 second */

Definition at line 18 of file entry.c.

◆ ARBITER_ALLOCATE_HARD_DEADLINE

#define ARBITER_ALLOCATE_HARD_DEADLINE   (10ULL * 1000 * 1000 * 10) /* 10 seconds */

Definition at line 19 of file entry.c.

◆ NDEBUG

#define NDEBUG

Definition at line 14 of file entry.c.

Function Documentation

◆ ArbiterLibAllocateEntry()

NTSTATUS NTAPI ArbiterLibAllocateEntry ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

Places the whole stack of entries with backtracking: when an entry cannot be placed, the previous entry's tentative choice is withdrawn and varied, first lower within its window, then via its next window or alternative.

Parameters
[in]ArbiterThe arbiter instance whose walker callbacks (GetNextAllocationRange, FindSuitableRange, AddAllocation, BacktrackAllocation) drive each placement.
[in,out]ArbStateThe first ARBITER_ALLOCATION_STATE of the allocation stack, one per entry in most-constrained-first order, terminated by a state whose Entry is NULL.
Returns
Returns STATUS_SUCCESS once every entry has a placement (the results are packed into each entry's Assignment and Result), STATUS_UNSUCCESSFUL if even the first entry has no solution, or a PreprocessEntry / PackResource failure status.

Definition at line 223 of file entry.c.

226{
227 PARBITER_ALLOCATION_STATE Current = ArbState;
228 BOOLEAN Backtracking = FALSE;
229 BOOLEAN McfgConflict = FALSE;
230 BOOLEAN DeadlineReported = FALSE;
231 ULONGLONG Deadline;
232 ULONGLONG HardDeadline;
234
235 PAGED_CODE();
236
239
240 while (Current >= ArbState && Current->Entry != NULL)
241 {
243 BOOLEAN RetrySameRange = FALSE;
244
245 /*
246 * A search that cannot terminate must fail rather than wedge the
247 * machine.
248 */
249 if (KeQueryInterruptTime() > HardDeadline)
250 {
251 DPRINT1("Arbiter %ws: abandoning allocation at entry %u, the search "
252 "is not terminating\n",
253 Arbiter->Name ? Arbiter->Name : L"(unnamed)",
254 (ULONG)(Current - ArbState));
255
256 if (ArbState->Entry != NULL)
257 ArbState->Entry->Result = ArbiterResultExternalConflict;
258
260 return STATUS_UNSUCCESSFUL;
261 }
262
263 Status = Arbiter->PreprocessEntry(Arbiter, Current);
264 if (!NT_SUCCESS(Status))
265 {
267 return Status;
268 }
269
270 if (Backtracking)
271 {
272 PARBITER_ALTERNATIVE FailedAlternative = Current->CurrentAlternative;
273
274 /*
275 * The entry after this one could not be placed. Withdraw this
276 * entry's tentative choice and vary it: first lower within the same
277 * window, then via the next window / alternative.
278 */
279 (Current + 1)->CurrentAlternative = NULL;
280 Backtracking = FALSE;
281
282 if (FailedAlternative == NULL || FailedAlternative->Length == 0)
283 goto Backtrack; /* Nothing to vary here */
284
285 Arbiter->BacktrackAllocation(Arbiter, Current);
286
287 /*
288 * Retrying one placement lower walks the window down an alignment
289 * unit at a time, so it has to be bounded, or searching a bridge's
290 * multi-gigabyte window will hang the system.
291 */
292 if (Current->Start > Current->CurrentMinimum &&
293 !(FailedAlternative->Flags & ARBITER_ALTERNATIVE_FLAG_FIXED))
294 {
295 if (KeQueryInterruptTime() <= Deadline)
296 {
297 Current->CurrentMaximum = Current->Start - 1;
298 RetrySameRange = TRUE;
299 }
300 else if (!DeadlineReported)
301 {
302 DeadlineReported = TRUE;
303 DPRINT1("Arbiter %ws: allocation deadline expired, giving up "
304 "range refinement\n",
305 Arbiter->Name ? Arbiter->Name : L"(unnamed)");
306 }
307 }
308 }
309
310 for (;;)
311 {
312 if (!RetrySameRange)
313 {
314 if (!Arbiter->GetNextAllocationRange(Arbiter, Current))
315 break;
316 }
317 RetrySameRange = FALSE;
318
319 if (Arbiter->FindSuitableRange(Arbiter, Current))
320 {
321 Found = TRUE;
322 break;
323 }
324 }
325
326 if (Found)
327 {
328 if (Current->CurrentAlternative->Length != 0)
329 Arbiter->AddAllocation(Arbiter, Current);
330 else
332
333 Current++;
334 continue;
335 }
336
337Backtrack:
339 McfgConflict = TRUE;
340
341 if (Current == ArbState)
342 {
343 /* Even the first entry has no solution. */
344 if (Current->Entry != NULL)
346
347 DPRINT1("Arbiter %ws: nowhere to put 0x%I64x..0x%I64x\n",
348 Arbiter->Name ? Arbiter->Name : L"(unnamed)",
349 Current->CurrentMinimum, Current->CurrentMaximum);
351 Current->CurrentMinimum,
352 Current->CurrentMaximum);
353
355 return McfgConflict ? STATUS_BAD_MCFG_TABLE : STATUS_UNSUCCESSFUL;
356 }
357 Backtracking = TRUE;
358 Current--;
359 }
360
361 /* Complete solution found; report it back to the requesters. */
362 for (Current = ArbState; Current->Entry != NULL; ++Current)
363 {
365
366 if (Current->Entry->Assignment != NULL && Arbiter->PackResource != NULL)
367 {
368 Status = Arbiter->PackResource(Current->CurrentAlternative->Descriptor,
369 Current->Start,
370 Current->Entry->Assignment);
371 if (!NT_SUCCESS(Status))
372 {
374 return Status;
375 }
376 }
377
378 if (Current->Entry->Result != ArbiterResultNullRequest)
380 }
381
383 return STATUS_SUCCESS;
384}
#define PAGED_CODE()
unsigned char BOOLEAN
Definition: actypes.h:127
#define ARBITER_STATE_FLAG_MCFG_CONFLICT
Definition: arbiter.h:62
#define ARBITER_ALTERNATIVE_FLAG_FIXED
Definition: arbiter.h:32
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
return Found
Definition: dirsup.c:1270
#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 L(x)
Definition: resources.c:13
Status
Definition: gdiplustypes.h:24
#define STATUS_BAD_MCFG_TABLE
Definition: ntstatus.h:1360
#define KeQueryInterruptTime()
Definition: ke.h:37
#define ARBITER_ALLOCATE_HARD_DEADLINE
Definition: entry.c:19
#define ARBITER_ALLOCATE_DEADLINE
Definition: entry.c:18
static VOID ArbpReportConflictingRanges(_In_ PARBITER_INSTANCE Arbiter, _In_ ULONGLONG Minimum, _In_ ULONGLONG Maximum)
Says what an arbiter is already holding across a window.
Definition: entry.c:161
static VOID ArbpFreeAllocationWorkSpaces(_Inout_ PARBITER_ALLOCATION_STATE ArbState)
Releases the per-entry workspace a PreprocessEntry override allocated, across the whole allocation st...
Definition: entry.c:121
#define STATUS_SUCCESS
Definition: shellext.h:65
PARBITER_ALTERNATIVE CurrentAlternative
Definition: arbiter.h:88
PARBITER_LIST_ENTRY Entry
Definition: arbiter.h:87
PIO_RESOURCE_DESCRIPTOR Descriptor
Definition: arbiter.h:77
ARBITER_RESULT Result
Definition: iotypes.h:4646
PIO_RESOURCE_DESCRIPTOR SelectedAlternative
Definition: iotypes.h:4645
PCM_PARTIAL_RESOURCE_DESCRIPTOR Assignment
Definition: iotypes.h:4644
uint64_t ULONGLONG
Definition: typedefs.h:67
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
@ ArbiterResultExternalConflict
Definition: iotypes.h:4627
@ ArbiterResultSuccess
Definition: iotypes.h:4626
@ ArbiterResultNullRequest
Definition: iotypes.h:4628

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibPreprocessEntry()

NTSTATUS NTAPI ArbiterLibPreprocessEntry ( _In_ PARBITER_INSTANCE  Arbiter,
_Inout_ PARBITER_ALLOCATION_STATE  ArbState 
)

Per-entry hook invoked before each placement attempt. The library default does nothing and succeeds.

Parameters
[in]ArbiterThe arbiter instance placing the entry.
[in,out]ArbStateThe allocation state of the entry about to be placed.
Returns
Returns STATUS_SUCCESS.

Definition at line 38 of file entry.c.

41{
42 PAGED_CODE();
43
45 UNREFERENCED_PARAMETER(ArbState);
46 return STATUS_SUCCESS;
47}
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329

Referenced by ArbiterLibInitializeInstance().

◆ ArbiterLibSortArbitrationList()

NTSTATUS NTAPI ArbiterLibSortArbitrationList ( _Inout_ PLIST_ENTRY  ArbitrationList)

Orders an arbitration list most-constrained first, so fixed requirements are placed before flexible ones can steal their ranges.

Parameters
[in,out]ArbitrationListThe list of ARBITER_LIST_ENTRY nodes to sort, keyed on the WorkSpace constrainedness score in ascending order. The sort is stable: equally scored entries keep their relative order.
Returns
Returns STATUS_SUCCESS.
Remarks
Without this ordering a wide requirement placed first keeps landing on the one range a later fixed requirement must have, forcing a backtrack for every such collision.

Definition at line 71 of file entry.c.

73{
74 LIST_ENTRY Sorted;
75
76 PAGED_CODE();
77
78 InitializeListHead(&Sorted);
79
80 while (!IsListEmpty(ArbitrationList))
81 {
82 PLIST_ENTRY ListEntry = RemoveHeadList(ArbitrationList);
85
86 for (Position = Sorted.Flink; Position != &Sorted; Position = Position->Flink)
87 {
89 Entry->WorkSpace)
90 {
91 break;
92 }
93 }
94
95 InsertTailList(Position, ListEntry); /* Insert before Position */
96 }
97
98 /* Return the data back to ArbitrationList! */
99 if (!IsListEmpty(&Sorted))
100 {
101 ArbitrationList->Flink = Sorted.Flink;
102 Sorted.Flink->Blink = ArbitrationList;
103 ArbitrationList->Blink = Sorted.Blink;
104 Sorted.Blink->Flink = ArbitrationList;
105 }
106
107 return STATUS_SUCCESS;
108}
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
Entry
Definition: section.c:5216
Definition: iotypes.h:4633
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
static COORD Position
Definition: mouse.c:34
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
_In_ ULONG _In_ ULONG _Out_ PULONG _In_ PVOID WorkSpace
Definition: rtlfuncs.h:2283

Referenced by ArbpTestAllocation().

◆ ArbpFreeAllocationWorkSpaces()

static VOID ArbpFreeAllocationWorkSpaces ( _Inout_ PARBITER_ALLOCATION_STATE  ArbState)
static

Releases the per-entry workspace a PreprocessEntry override allocated, across the whole allocation stack.

Parameters
[in,out]ArbStateThe first state of the allocation stack.

Definition at line 121 of file entry.c.

123{
125
126 PAGED_CODE();
127
128 for (Current = ArbState; Current->Entry != NULL; ++Current)
129 {
130 if (Current->Flags & ARBITER_STATE_FLAG_WORKSPACE)
131 {
133 Current->WorkSpace = 0;
134 Current->Flags &= ~ARBITER_STATE_FLAG_WORKSPACE;
135 }
136 }
137}
#define TAG_ARBITER
Definition: arbiter.h:10
#define ARBITER_STATE_FLAG_WORKSPACE
Definition: arbiter.h:61
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109

Referenced by ArbiterLibAllocateEntry().

◆ ArbpReportConflictingRanges()

static VOID ArbpReportConflictingRanges ( _In_ PARBITER_INSTANCE  Arbiter,
_In_ ULONGLONG  Minimum,
_In_ ULONGLONG  Maximum 
)
static

Says what an arbiter is already holding across a window.

The bare "arbitration failed" a caller reports names the device that could not be placed but not what stopped it, which is the half worth knowing: a fixed requirement can fail either because the window belongs to somebody else or because it was never the arbiter's to give. Both look the same from outside.

Parameters
[in]ArbiterThe arbiter whose bookkeeping to read.
[in]MinimumThe bottom of the window that could not be satisfied.
[in]MaximumThe top of it.

Definition at line 161 of file entry.c.

165{
167 PRTL_RANGE Range;
168 BOOLEAN Overlapped = FALSE;
169
170 PAGED_CODE();
171
172 if (!NT_SUCCESS(RtlGetFirstRange(Arbiter->PossibleAllocation, &Iterator, &Range)))
173 return;
174
175 while (Range != NULL)
176 {
177 if ((Range->Start <= Maximum) && (Range->End >= Minimum))
178 {
179 Overlapped = TRUE;
180 DPRINT1(" 0x%I64x..0x%I64x held by %p, attributes 0x%x%s\n",
181 Range->Start, Range->End, Range->Owner, Range->Attributes,
182 (Range->Flags & RTL_RANGE_SHARED) ? " (shared)" : "");
183 }
184
185 if (!NT_SUCCESS(RtlGetNextRange(&Iterator, &Range, TRUE)))
186 break;
187 }
188
189 if (!Overlapped)
190 {
191 DPRINT1(" nothing holds 0x%I64x..0x%I64x, so it is outside what this "
192 "arbiter was given\n",
193 Minimum, Maximum);
194 }
195}
NTSYSAPI NTSTATUS NTAPI RtlGetNextRange(_Inout_ PRTL_RANGE_LIST_ITERATOR Iterator, _Outptr_ PRTL_RANGE *Range, _In_ BOOLEAN MoveForwards)
NTSYSAPI NTSTATUS NTAPI RtlGetFirstRange(_In_ PRTL_RANGE_LIST RangeList, _Out_ PRTL_RANGE_LIST_ITERATOR Iterator, _Outptr_ PRTL_RANGE *Range)
#define RTL_RANGE_SHARED
Definition: rtltypes.h:92
ULONGLONG End
Definition: rtltypes.h:1497
ULONGLONG Start
Definition: rtltypes.h:1496
UCHAR Attributes
Definition: rtltypes.h:1500
PVOID Owner
Definition: rtltypes.h:1499
UCHAR Flags
Definition: rtltypes.h:1501
_In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR Iterator
Definition: wdfchildlist.h:656

Referenced by ArbiterLibAllocateEntry().