ReactOS 0.4.17-dev-806-gffa4164
entry.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Arbitration Library
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Entry allocation pipeline
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/* Bound the search */
18#define ARBITER_ALLOCATE_DEADLINE (10ULL * 1000 * 1000) /* 1 second */
19#define ARBITER_ALLOCATE_HARD_DEADLINE (10ULL * 1000 * 1000 * 10) /* 10 seconds */
20
35CODE_SEG("PAGE")
39 _In_ PARBITER_INSTANCE Arbiter,
41{
42 PAGED_CODE();
43
45 UNREFERENCED_PARAMETER(ArbState);
46 return STATUS_SUCCESS;
47}
48
68CODE_SEG("PAGE")
72 _Inout_ PLIST_ENTRY ArbitrationList)
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}
109
118CODE_SEG("PAGE")
119static
120VOID
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}
138
158CODE_SEG("PAGE")
159static
160VOID
162 _In_ PARBITER_INSTANCE Arbiter,
163 _In_ ULONGLONG Minimum,
164 _In_ ULONGLONG Maximum)
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}
196
220CODE_SEG("PAGE")
222NTAPI
224 _In_ PARBITER_INSTANCE Arbiter,
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()
#define CODE_SEG(...)
unsigned char BOOLEAN
Definition: actypes.h:127
#define TAG_ARBITER
Definition: arbiter.h:10
#define ARBITER_STATE_FLAG_WORKSPACE
Definition: arbiter.h:61
#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
#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
Status
Definition: gdiplustypes.h:24
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1109
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
#define _Inout_
Definition: no_sal2.h:162
#define _In_
Definition: no_sal2.h:158
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
#define STATUS_BAD_MCFG_TABLE
Definition: ntstatus.h:1360
#define KeQueryInterruptTime()
Definition: ke.h:37
#define ARBITER_ALLOCATE_HARD_DEADLINE
Definition: entry.c:19
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,...
Definition: entry.c:223
#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
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
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.
Definition: entry.c:38
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
Entry
Definition: section.c:5216
#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
Definition: iotypes.h:4633
ARBITER_RESULT Result
Definition: iotypes.h:4646
PIO_RESOURCE_DESCRIPTOR SelectedAlternative
Definition: iotypes.h:4645
PCM_PARTIAL_RESOURCE_DESCRIPTOR Assignment
Definition: iotypes.h:4644
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
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
static COORD Position
Definition: mouse.c:34
#define NTAPI
Definition: typedefs.h:36
uint64_t ULONGLONG
Definition: typedefs.h:67
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR Iterator
Definition: wdfchildlist.h:656
@ ArbiterResultExternalConflict
Definition: iotypes.h:4627
@ ArbiterResultSuccess
Definition: iotypes.h:4626
@ ArbiterResultNullRequest
Definition: iotypes.h:4628
_In_ ULONG _In_ ULONG _Out_ PULONG _In_ PVOID WorkSpace
Definition: rtlfuncs.h:2283