No functional change. Just largely mechanical textual substitution.
Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
<ClCompile Include="..\..\src\xenbus\thread.c" />
<ClCompile Include="..\..\src\xenbus\range_set.c" />
<ClCompile Include="..\..\src\xenbus\balloon.c" />
- <ClCompile Include="..\..\src\xenbus\pool.c" />
+ <ClCompile Include="..\..\src\xenbus\cache.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\src\xenbus\xenbus.rc" />
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <util.h>
+
+#include "cache.h"
+#include "dbg_print.h"
+#include "assert.h"
+
+extern ULONG
+NTAPI
+RtlRandomEx (
+ __inout PULONG Seed
+ );
+
+#define CACHE_TAG 'HCAC'
+
+typedef struct _OBJECT_HEADER {
+ ULONG Magic;
+
+#define OBJECT_HEADER_MAGIC 0x02121996
+
+ LIST_ENTRY ListEntry;
+} OBJECT_HEADER, *POBJECT_HEADER;
+
+#define MAXIMUM_SLOTS 6
+
+typedef struct _CACHE_MAGAZINE {
+ PVOID Slot[MAXIMUM_SLOTS];
+} CACHE_MAGAZINE, *PCACHE_MAGAZINE;
+
+typedef struct _CACHE_FIST {
+ LONG Defer;
+ ULONG Probability;
+ ULONG Seed;
+} CACHE_FIST, *PCACHE_FIST;
+
+#define MAXNAMELEN 128
+
+struct _XENBUS_CACHE {
+ CHAR Name[MAXNAMELEN];
+ ULONG Size;
+ ULONG Reservation;
+ NTSTATUS (*Ctor)(PVOID, PVOID);
+ VOID (*Dtor)(PVOID, PVOID);
+ VOID (*AcquireLock)(PVOID);
+ VOID (*ReleaseLock)(PVOID);
+ PVOID Argument;
+ KTIMER Timer;
+ KDPC Dpc;
+ LIST_ENTRY GetList;
+ PLIST_ENTRY PutList;
+ CACHE_MAGAZINE Magazine[MAXIMUM_PROCESSORS];
+ LONG Allocated;
+ LONG MaximumAllocated;
+ LONG Population;
+ LONG MinimumPopulation;
+ CACHE_FIST FIST;
+};
+
+static FORCEINLINE PVOID
+__CacheAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocateNonPagedPoolWithTag(Length, CACHE_TAG);
+}
+
+static FORCEINLINE VOID
+__CacheFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, CACHE_TAG);
+}
+
+static FORCEINLINE VOID
+__CacheFill(
+ IN PXENBUS_CACHE Cache,
+ IN PLIST_ENTRY List
+ )
+{
+ // Not really a doubly-linked list; it's actually a singly-linked
+ // list via the Flink field.
+ while (List != NULL) {
+ PLIST_ENTRY Next;
+ POBJECT_HEADER Header;
+
+ Next = List->Flink;
+ List->Flink = NULL;
+ ASSERT3P(List->Blink, ==, NULL);
+
+ Header = CONTAINING_RECORD(List, OBJECT_HEADER, ListEntry);
+ ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+ InsertTailList(&Cache->GetList, &Header->ListEntry);
+
+ List = Next;
+ }
+}
+
+static FORCEINLINE VOID
+__CacheSwizzle(
+ IN PXENBUS_CACHE Cache
+ )
+{
+ PLIST_ENTRY List;
+
+ List = InterlockedExchangePointer(&Cache->PutList, NULL);
+
+ __CacheFill(Cache, List);
+}
+
+static FORCEINLINE NTSTATUS
+__CacheCreateObject(
+ IN PXENBUS_CACHE Cache,
+ OUT POBJECT_HEADER *Header
+ )
+{
+ PVOID Object;
+ NTSTATUS status;
+
+ (*Header) = __CacheAllocate(sizeof (OBJECT_HEADER) + Cache->Size);
+
+ status = STATUS_NO_MEMORY;
+ if (*Header == NULL)
+ goto fail1;
+
+ (*Header)->Magic = OBJECT_HEADER_MAGIC;
+
+ Object = (*Header) + 1;
+
+ status = Cache->Ctor(Cache->Argument, Object);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+ (*Header)->Magic = 0;
+
+ ASSERT(IsZeroMemory(*Header, sizeof (OBJECT_HEADER)));
+ __CacheFree(*Header);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static FORCEINLINE PVOID
+__CacheGetShared(
+ IN PXENBUS_CACHE Cache,
+ IN BOOLEAN Locked
+ )
+{
+ LONG Population;
+ POBJECT_HEADER Header;
+ PVOID Object;
+ LONG Allocated;
+ NTSTATUS status;
+
+ Population = InterlockedDecrement(&Cache->Population);
+
+ if (Population >= 0) {
+ PLIST_ENTRY ListEntry;
+
+ if (!Locked)
+ Cache->AcquireLock(Cache->Argument);
+
+ if (Population < Cache->MinimumPopulation)
+ Cache->MinimumPopulation = Population;
+
+ if (IsListEmpty(&Cache->GetList))
+ __CacheSwizzle(Cache);
+
+ ListEntry = RemoveHeadList(&Cache->GetList);
+ ASSERT(ListEntry != &Cache->GetList);
+
+ if (!Locked)
+ Cache->ReleaseLock(Cache->Argument);
+
+ RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+ Header = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, ListEntry);
+ ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+ goto done;
+ }
+
+ (VOID) InterlockedIncrement(&Cache->Population);
+
+ status = __CacheCreateObject(Cache, &Header);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Allocated = InterlockedIncrement(&Cache->Allocated);
+
+ if (Allocated > Cache->MaximumAllocated) {
+ if (!Locked)
+ Cache->AcquireLock(Cache->Argument);
+
+ if (Allocated > Cache->MaximumAllocated)
+ Cache->MaximumAllocated = Allocated;
+
+ if (!Locked)
+ Cache->ReleaseLock(Cache->Argument);
+ }
+
+done:
+ Object = Header + 1;
+
+ return Object;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return NULL;
+}
+
+static FORCEINLINE VOID
+__CachePutShared(
+ IN PXENBUS_CACHE Cache,
+ IN PVOID Object,
+ IN BOOLEAN Locked
+ )
+{
+ POBJECT_HEADER Header;
+ PLIST_ENTRY Old;
+ PLIST_ENTRY New;
+
+ ASSERT(Object != NULL);
+
+ Header = Object;
+ --Header;
+ ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+ ASSERT(IsZeroMemory(&Header->ListEntry, sizeof (LIST_ENTRY)));
+
+ if (!Locked) {
+ New = &Header->ListEntry;
+
+ do {
+ Old = Cache->PutList;
+ New->Flink = Old;
+ } while (InterlockedCompareExchangePointer(&Cache->PutList, New, Old) != Old);
+ } else {
+ InsertTailList(&Cache->GetList, &Header->ListEntry);
+ }
+
+ KeMemoryBarrier();
+
+ (VOID) InterlockedIncrement(&Cache->Population);
+}
+
+static FORCEINLINE PVOID
+__CacheGetMagazine(
+ IN PXENBUS_CACHE Cache,
+ IN ULONG Cpu
+ )
+{
+ PCACHE_MAGAZINE Magazine;
+ ULONG Index;
+
+ Magazine = &Cache->Magazine[Cpu];
+
+ for (Index = 0; Index < MAXIMUM_SLOTS; Index++) {
+ PVOID Object;
+
+ if (Magazine->Slot[Index] != NULL) {
+ Object = Magazine->Slot[Index];
+ Magazine->Slot[Index] = NULL;
+
+ return Object;
+ }
+ }
+
+ return NULL;
+}
+
+static FORCEINLINE BOOLEAN
+__CachePutMagazine(
+ IN PXENBUS_CACHE Cache,
+ IN ULONG Cpu,
+ IN PVOID Object
+ )
+{
+ PCACHE_MAGAZINE Magazine;
+ ULONG Index;
+
+ Magazine = &Cache->Magazine[Cpu];
+
+ for (Index = 0; Index < MAXIMUM_SLOTS; Index++) {
+ if (Magazine->Slot[Index] == NULL) {
+ Magazine->Slot[Index] = Object;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+PVOID
+CacheGet(
+ IN PXENBUS_CACHE Cache,
+ IN BOOLEAN Locked
+ )
+{
+ KIRQL Irql;
+ ULONG Cpu;
+ PVOID Object;
+
+ if (Cache->FIST.Probability != 0) {
+ LONG Defer;
+
+ Defer = InterlockedDecrement(&Cache->FIST.Defer);
+
+ if (Defer <= 0) {
+ ULONG Random = RtlRandomEx(&Cache->FIST.Seed);
+ ULONG Threshold = (MAXLONG / 100) * Cache->FIST.Probability;
+
+ if (Random < Threshold)
+ return NULL;
+ }
+ }
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+ Cpu = KeGetCurrentProcessorNumber();
+
+ Object = __CacheGetMagazine(Cache, Cpu);
+ if (Object == NULL)
+ Object = __CacheGetShared(Cache, Locked);
+
+ KeLowerIrql(Irql);
+
+ return Object;
+}
+
+VOID
+CachePut(
+ IN PXENBUS_CACHE Cache,
+ IN PVOID Object,
+ IN BOOLEAN Locked
+ )
+{
+ KIRQL Irql;
+ ULONG Cpu;
+
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+ Cpu = KeGetCurrentProcessorNumber();
+
+ if (!__CachePutMagazine(Cache, Cpu, Object))
+ __CachePutShared(Cache, Object, Locked);
+
+ KeLowerIrql(Irql);
+}
+
+VOID
+CacheGetStatistics(
+ IN PXENBUS_CACHE Cache,
+ OUT PXENBUS_CACHE_STATISTICS Statistics
+ )
+{
+ Statistics->Allocated = Cache->Allocated;
+ Statistics->MaximumAllocated = Cache->MaximumAllocated;
+ Statistics->Population = Cache->Population;
+ Statistics->MinimumPopulation = Cache->MinimumPopulation;
+}
+
+static FORCEINLINE
+__CacheFlushMagazines(
+ IN PXENBUS_CACHE Cache
+ )
+{
+ ULONG Cpu;
+
+ for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
+ PVOID Object;
+
+ while ((Object = __CacheGetMagazine(Cache, Cpu)) != NULL)
+ __CachePutShared(Cache, Object, TRUE);
+ }
+}
+
+static FORCEINLINE VOID
+__CacheTrimShared(
+ IN PXENBUS_CACHE Cache,
+ IN OUT PLIST_ENTRY List
+ )
+{
+ LONG Population;
+ LONG Excess;
+
+ Population = Cache->Population;
+
+ KeMemoryBarrier();
+
+ Excess = __max((LONG)Cache->MinimumPopulation - (LONG)Cache->Reservation, 0);
+
+ while (Excess != 0) {
+ PLIST_ENTRY ListEntry;
+
+ Population = InterlockedDecrement(&Cache->Population);
+ if (Population < 0) {
+ Population = InterlockedIncrement(&Cache->Population);
+ break;
+ }
+
+ if (IsListEmpty(&Cache->GetList))
+ __CacheSwizzle(Cache);
+
+ ListEntry = RemoveHeadList(&Cache->GetList);
+ ASSERT(ListEntry != &Cache->GetList);
+
+ InsertTailList(List, ListEntry);
+
+ InterlockedDecrement(&Cache->Allocated);
+ --Excess;
+ }
+
+ Cache->MinimumPopulation = Population;
+}
+
+static FORCEINLINE VOID
+__CacheDestroyObject(
+ IN PXENBUS_CACHE Cache,
+ IN POBJECT_HEADER Header
+ )
+{
+ PVOID Object;
+
+ Object = Header + 1;
+
+ Cache->Dtor(Cache->Argument, Object);
+
+ Header->Magic = 0;
+
+ ASSERT(IsZeroMemory(Header, sizeof (OBJECT_HEADER)));
+ __CacheFree(Header);
+}
+
+static FORCEINLINE VOID
+__CacheEmpty(
+ IN PXENBUS_CACHE Cache,
+ IN OUT PLIST_ENTRY List
+ )
+{
+ while (!IsListEmpty(List)) {
+ PLIST_ENTRY ListEntry;
+ POBJECT_HEADER Header;
+
+ ListEntry = RemoveHeadList(List);
+ RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+ Header = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, ListEntry);
+ ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
+
+ __CacheDestroyObject(Cache, Header);
+ }
+}
+
+#define TIME_US(_us) ((_us) * 10)
+#define TIME_MS(_ms) (TIME_US((_ms) * 1000))
+#define TIME_RELATIVE(_t) (-(_t))
+
+#define CACHE_PERIOD 1000
+
+KDEFERRED_ROUTINE CacheDpc;
+
+VOID
+CacheDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID Argument1,
+ IN PVOID Argument2
+ )
+{
+ PXENBUS_CACHE Cache = Context;
+ LIST_ENTRY List;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Argument1);
+ UNREFERENCED_PARAMETER(Argument2);
+
+ ASSERT(Cache != NULL);
+
+ InitializeListHead(&List);
+
+ Cache->AcquireLock(Cache->Argument);
+ __CacheTrimShared(Cache, &List);
+ Cache->ReleaseLock(Cache->Argument);
+
+ __CacheEmpty(Cache, &List);
+ ASSERT(IsListEmpty(&List));
+}
+
+static FORCEINLINE VOID
+__CacheSetupFIST(
+ IN PXENBUS_CACHE Cache,
+ IN PXENBUS_STORE_INTERFACE StoreInterface
+ )
+{
+ CHAR Node[sizeof ("fist/cache/") + MAXNAMELEN];
+ PCHAR Buffer;
+ LARGE_INTEGER Now;
+ NTSTATUS status;
+
+ status = RtlStringCbPrintfA(Node,
+ sizeof (Node),
+ "fist/cache/%s",
+ Cache->Name);
+ ASSERT(NT_SUCCESS(status));
+
+ status = STORE(Read,
+ StoreInterface,
+ NULL,
+ Node,
+ "defer",
+ &Buffer);
+ if (!NT_SUCCESS(status)) {
+ Cache->FIST.Defer = 0;
+ } else {
+ Cache->FIST.Defer = (ULONG)strtol(Buffer, NULL, 0);
+
+ STORE(Free,
+ StoreInterface,
+ Buffer);
+ }
+
+ status = STORE(Read,
+ StoreInterface,
+ NULL,
+ Node,
+ "probability",
+ &Buffer);
+ if (!NT_SUCCESS(status)) {
+ Cache->FIST.Probability = 0;
+ } else {
+ Cache->FIST.Probability = (ULONG)strtol(Buffer, NULL, 0);
+
+ STORE(Free,
+ StoreInterface,
+ Buffer);
+ }
+
+ if (Cache->FIST.Probability > 100)
+ Cache->FIST.Probability = 100;
+
+ if (Cache->FIST.Probability != 0)
+ Info("%s: Defer = %d Probability = %d\n",
+ Cache->Name,
+ Cache->FIST.Defer,
+ Cache->FIST.Probability);
+
+ KeQuerySystemTime(&Now);
+ Cache->FIST.Seed = Now.LowPart;
+}
+
+NTSTATUS
+CacheInitialize(
+ IN PXENBUS_STORE_INTERFACE StoreInterface,
+ IN const CHAR *Name,
+ IN ULONG Size,
+ IN ULONG Reservation,
+ IN NTSTATUS (*Ctor)(PVOID, PVOID),
+ IN VOID (*Dtor)(PVOID, PVOID),
+ IN VOID (*AcquireLock)(PVOID),
+ IN VOID (*ReleaseLock)(PVOID),
+ IN PVOID Argument,
+ OUT PXENBUS_CACHE *Cache
+ )
+{
+ LARGE_INTEGER Timeout;
+ LIST_ENTRY List;
+ NTSTATUS status;
+
+ *Cache = __CacheAllocate(sizeof (XENBUS_CACHE));
+
+ status = STATUS_NO_MEMORY;
+ if (*Cache == NULL)
+ goto fail1;
+
+ status = RtlStringCbPrintfA((*Cache)->Name,
+ sizeof ((*Cache)->Name),
+ "%s",
+ Name);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ (*Cache)->Size = Size;
+ (*Cache)->Ctor = Ctor;
+ (*Cache)->Dtor = Dtor;
+ (*Cache)->AcquireLock = AcquireLock;
+ (*Cache)->ReleaseLock = ReleaseLock;
+ (*Cache)->Argument = Argument;
+
+ __CacheSetupFIST(*Cache, StoreInterface);
+
+ InitializeListHead(&(*Cache)->GetList);
+
+ while (Reservation != 0) {
+ POBJECT_HEADER Header;
+
+ status = __CacheCreateObject(*Cache, &Header);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ (VOID) InterlockedIncrement(&(*Cache)->Allocated);
+
+ InsertTailList(&(*Cache)->GetList, &Header->ListEntry);
+ (VOID) InterlockedIncrement(&(*Cache)->Population);
+
+ --Reservation;
+ }
+ (*Cache)->MaximumAllocated = (*Cache)->Allocated;
+ (*Cache)->Reservation = (*Cache)->Population;
+
+ KeInitializeDpc(&(*Cache)->Dpc,
+ CacheDpc,
+ (*Cache));
+
+ Timeout.QuadPart = TIME_RELATIVE(TIME_MS(CACHE_PERIOD));
+
+ KeInitializeTimer(&(*Cache)->Timer);
+ KeSetTimerEx(&(*Cache)->Timer,
+ Timeout,
+ CACHE_PERIOD,
+ &(*Cache)->Dpc);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ InitializeListHead(&List);
+
+ (*Cache)->MinimumPopulation = (*Cache)->Population;
+ __CacheTrimShared(*Cache, &List);
+ __CacheEmpty(*Cache, &List);
+
+ ASSERT3U((*Cache)->Population, ==, 0);
+ ASSERT3U((*Cache)->Allocated, ==, 0);
+
+ RtlZeroMemory(&(*Cache)->GetList, sizeof (LIST_ENTRY));
+
+ RtlZeroMemory(&(*Cache)->FIST, sizeof (CACHE_FIST));
+
+ (*Cache)->Argument = NULL;
+ (*Cache)->ReleaseLock = NULL;
+ (*Cache)->AcquireLock = NULL;
+ (*Cache)->Dtor = NULL;
+ (*Cache)->Ctor = NULL;
+ (*Cache)->Size = 0;
+
+fail2:
+ Error("fail2\n");
+
+ RtlZeroMemory((*Cache)->Name, sizeof ((*Cache)->Name));
+
+ ASSERT(IsZeroMemory(*Cache, sizeof (XENBUS_CACHE)));
+ __CacheFree(*Cache);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+CacheTeardown(
+ IN PXENBUS_CACHE Cache
+ )
+{
+ LIST_ENTRY List;
+
+ KeCancelTimer(&Cache->Timer);
+ KeFlushQueuedDpcs();
+
+ RtlZeroMemory(&Cache->Timer, sizeof (KTIMER));
+ RtlZeroMemory(&Cache->Dpc, sizeof (KDPC));
+
+ Cache->Reservation = 0;
+ Cache->MaximumAllocated = 0;
+
+ InitializeListHead(&List);
+
+ __CacheFlushMagazines(Cache);
+
+ Cache->MinimumPopulation = Cache->Population;
+ __CacheTrimShared(Cache, &List);
+ __CacheEmpty(Cache, &List);
+
+ ASSERT3U(Cache->Population, ==, 0);
+ ASSERT3U(Cache->Allocated, ==, 0);
+
+ RtlZeroMemory(&Cache->GetList, sizeof (LIST_ENTRY));
+
+ RtlZeroMemory(&Cache->FIST, sizeof (CACHE_FIST));
+
+ Cache->Argument = NULL;
+ Cache->ReleaseLock = NULL;
+ Cache->AcquireLock = NULL;
+ Cache->Dtor = NULL;
+ Cache->Ctor = NULL;
+ Cache->Size = 0;
+
+ RtlZeroMemory(Cache->Name, sizeof (Cache->Name));
+
+ ASSERT(IsZeroMemory(Cache, sizeof (XENBUS_CACHE)));
+ __CacheFree(Cache);
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENBUS_CACHE_H
+#define _XENBUS_CACHE_H
+
+#include <ntddk.h>
+#include <store_interface.h>
+
+typedef struct _XENBUS_CACHE XENBUS_CACHE, *PXENBUS_CACHE;
+
+extern NTSTATUS
+CacheInitialize(
+ IN PXENBUS_STORE_INTERFACE StoreInterface,
+ IN const CHAR *Name,
+ IN ULONG Size,
+ IN ULONG Reservation,
+ IN NTSTATUS (*Ctor)(PVOID, PVOID),
+ IN VOID (*Dtor)(PVOID, PVOID),
+ IN VOID (*AcquireLock)(PVOID),
+ IN VOID (*ReleaseLock)(PVOID),
+ IN PVOID Argument,
+ OUT PXENBUS_CACHE *Cache
+ );
+
+extern VOID
+CacheTeardown(
+ IN PXENBUS_CACHE Cache
+ );
+
+extern PVOID
+CacheGet(
+ IN PXENBUS_CACHE Cache,
+ IN BOOLEAN Locked
+ );
+
+extern VOID
+CachePut(
+ IN PXENBUS_CACHE Cache,
+ IN PVOID Object,
+ IN BOOLEAN Locked
+ );
+
+typedef struct _XENBUS_CACHE_STATISTICS {
+ ULONG Allocated;
+ ULONG MaximumAllocated;
+ ULONG Population;
+ ULONG MinimumPopulation;
+} XENBUS_CACHE_STATISTICS, *PXENBUS_CACHE_STATISTICS;
+
+extern VOID
+CacheGetStatistics(
+ IN PXENBUS_CACHE Cache,
+ OUT PXENBUS_CACHE_STATISTICS Statistics
+ );
+
+#endif // _XENBUS_CACHE_H
#include "gnttab.h"
#include "fdo.h"
#include "range_set.h"
-#include "pool.h"
+#include "cache.h"
#include "dbg_print.h"
#include "assert.h"
PXENBUS_RANGE_SET RangeSet;
ULONG Seed;
LONG GetFailed;
- PXENBUS_POOL DescriptorPool;
+ PXENBUS_CACHE DescriptorCache;
PXENBUS_STORE_INTERFACE StoreInterface;
PXENBUS_SUSPEND_INTERFACE SuspendInterface;
PXENBUS_SUSPEND_CALLBACK SuspendCallbackEarly;
if (!NT_SUCCESS(status))
goto fail1;
- status = PoolInitialize(Context->StoreInterface,
+ status = CacheInitialize(Context->StoreInterface,
"gnttab",
sizeof (XENBUS_GNTTAB_DESCRIPTOR),
GNTTAB_RESERVATION,
GnttabAcquireLock,
GnttabReleaseLock,
Context,
- &Context->DescriptorPool);
+ &Context->DescriptorCache);
if (!NT_SUCCESS(status))
goto fail2;
{
LONGLONG Entry;
- PoolTeardown(Context->DescriptorPool);
- Context->DescriptorPool = NULL;
+ CacheTeardown(Context->DescriptorCache);
+ Context->DescriptorCache = NULL;
for (Entry = GNTTAB_RESERVED_ENTRY_COUNT;
Entry < (LONGLONG)(Context->FrameCount * GNTTAB_ENTRY_PER_FRAME);
{
PXENBUS_GNTTAB_DESCRIPTOR Descriptor;
- Descriptor = PoolGet(Context->DescriptorPool, FALSE);
+ Descriptor = CacheGet(Context->DescriptorCache, FALSE);
if (Descriptor == NULL)
(VOID) InterlockedIncrement(&Context->GetFailed);
{
ASSERT3U(Descriptor->Magic, ==, GNTTAB_DESCRIPTOR_MAGIC);
- PoolPut(Context->DescriptorPool, Descriptor, FALSE);
+ CachePut(Context->DescriptorCache, Descriptor, FALSE);
}
static FORCEINLINE NTSTATUS
)
{
PXENBUS_GNTTAB_CONTEXT Context = Argument;
- XENBUS_POOL_STATISTICS Statistics;
+ XENBUS_CACHE_STATISTICS Statistics;
UNREFERENCED_PARAMETER(Crashing);
"FrameCount = %u\n",
Context->FrameCount);
- PoolGetStatistics(Context->DescriptorPool,
- &Statistics);
+ CacheGetStatistics(Context->DescriptorCache,
+ &Statistics);
DEBUG(Printf,
Context->DebugInterface,
Context->DebugCallback,
- "DESCRIPTOR POOL: Allocated = %u (Maximum = %u)\n",
+ "DESCRIPTOR CACHE: Allocated = %u (Maximum = %u)\n",
Statistics.Allocated,
Statistics.MaximumAllocated);
DEBUG(Printf,
Context->DebugInterface,
Context->DebugCallback,
- "DESCRIPTOR POOL: Population = %u (Minimum = %u)\n",
+ "DESCRIPTOR CACHE: Population = %u (Minimum = %u)\n",
Statistics.Population,
Statistics.MinimumPopulation);
+++ /dev/null
-/* Copyright (c) Citrix Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms,
- * with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * * Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the
- * following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the
- * following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <ntddk.h>
-#include <ntstrsafe.h>
-#include <stdlib.h>
-#include <util.h>
-
-#include "pool.h"
-#include "dbg_print.h"
-#include "assert.h"
-
-extern ULONG
-NTAPI
-RtlRandomEx (
- __inout PULONG Seed
- );
-
-#define POOL_POOL 'OBJE'
-
-typedef struct _OBJECT_HEADER {
- ULONG Magic;
-
-#define OBJECT_HEADER_MAGIC 0x02121996
-
- LIST_ENTRY ListEntry;
-} OBJECT_HEADER, *POBJECT_HEADER;
-
-#define MAXIMUM_SLOTS 6
-
-typedef struct _POOL_MAGAZINE {
- PVOID Slot[MAXIMUM_SLOTS];
-} POOL_MAGAZINE, *PPOOL_MAGAZINE;
-
-typedef struct _POOL_FIST {
- LONG Defer;
- ULONG Probability;
- ULONG Seed;
-} POOL_FIST, *PPOOL_FIST;
-
-#define MAXNAMELEN 128
-
-struct _XENBUS_POOL {
- CHAR Name[MAXNAMELEN];
- ULONG Size;
- ULONG Reservation;
- NTSTATUS (*Ctor)(PVOID, PVOID);
- VOID (*Dtor)(PVOID, PVOID);
- VOID (*AcquireLock)(PVOID);
- VOID (*ReleaseLock)(PVOID);
- PVOID Argument;
- KTIMER Timer;
- KDPC Dpc;
- LIST_ENTRY GetList;
- PLIST_ENTRY PutList;
- POOL_MAGAZINE Magazine[MAXIMUM_PROCESSORS];
- LONG Allocated;
- LONG MaximumAllocated;
- LONG Population;
- LONG MinimumPopulation;
- POOL_FIST FIST;
-};
-
-static FORCEINLINE PVOID
-__PoolAllocate(
- IN ULONG Length
- )
-{
- return __AllocateNonPagedPoolWithTag(Length, POOL_POOL);
-}
-
-static FORCEINLINE VOID
-__PoolFree(
- IN PVOID Buffer
- )
-{
- __FreePoolWithTag(Buffer, POOL_POOL);
-}
-
-static FORCEINLINE VOID
-__PoolFill(
- IN PXENBUS_POOL Pool,
- IN PLIST_ENTRY List
- )
-{
- // Not really a doubly-linked list; it's actually a singly-linked
- // list via the Flink field.
- while (List != NULL) {
- PLIST_ENTRY Next;
- POBJECT_HEADER Header;
-
- Next = List->Flink;
- List->Flink = NULL;
- ASSERT3P(List->Blink, ==, NULL);
-
- Header = CONTAINING_RECORD(List, OBJECT_HEADER, ListEntry);
- ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
-
- InsertTailList(&Pool->GetList, &Header->ListEntry);
-
- List = Next;
- }
-}
-
-static FORCEINLINE VOID
-__PoolSwizzle(
- IN PXENBUS_POOL Pool
- )
-{
- PLIST_ENTRY List;
-
- List = InterlockedExchangePointer(&Pool->PutList, NULL);
-
- __PoolFill(Pool, List);
-}
-
-static FORCEINLINE NTSTATUS
-__PoolCreateObject(
- IN PXENBUS_POOL Pool,
- OUT POBJECT_HEADER *Header
- )
-{
- PVOID Object;
- NTSTATUS status;
-
- (*Header) = __PoolAllocate(sizeof (OBJECT_HEADER) + Pool->Size);
-
- status = STATUS_NO_MEMORY;
- if (*Header == NULL)
- goto fail1;
-
- (*Header)->Magic = OBJECT_HEADER_MAGIC;
-
- Object = (*Header) + 1;
-
- status = Pool->Ctor(Pool->Argument, Object);
- if (!NT_SUCCESS(status))
- goto fail2;
-
- return STATUS_SUCCESS;
-
-fail2:
- Error("fail2\n");
-
- (*Header)->Magic = 0;
-
- ASSERT(IsZeroMemory(*Header, sizeof (OBJECT_HEADER)));
- __PoolFree(*Header);
-
-fail1:
- Error("fail1 (%08x)\n", status);
-
- return status;
-}
-
-static FORCEINLINE PVOID
-__PoolGetShared(
- IN PXENBUS_POOL Pool,
- IN BOOLEAN Locked
- )
-{
- LONG Population;
- POBJECT_HEADER Header;
- PVOID Object;
- LONG Allocated;
- NTSTATUS status;
-
- Population = InterlockedDecrement(&Pool->Population);
-
- if (Population >= 0) {
- PLIST_ENTRY ListEntry;
-
- if (!Locked)
- Pool->AcquireLock(Pool->Argument);
-
- if (Population < Pool->MinimumPopulation)
- Pool->MinimumPopulation = Population;
-
- if (IsListEmpty(&Pool->GetList))
- __PoolSwizzle(Pool);
-
- ListEntry = RemoveHeadList(&Pool->GetList);
- ASSERT(ListEntry != &Pool->GetList);
-
- if (!Locked)
- Pool->ReleaseLock(Pool->Argument);
-
- RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
-
- Header = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, ListEntry);
- ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
-
- goto done;
- }
-
- (VOID) InterlockedIncrement(&Pool->Population);
-
- status = __PoolCreateObject(Pool, &Header);
- if (!NT_SUCCESS(status))
- goto fail1;
-
- Allocated = InterlockedIncrement(&Pool->Allocated);
-
- if (Allocated > Pool->MaximumAllocated) {
- if (!Locked)
- Pool->AcquireLock(Pool->Argument);
-
- if (Allocated > Pool->MaximumAllocated)
- Pool->MaximumAllocated = Allocated;
-
- if (!Locked)
- Pool->ReleaseLock(Pool->Argument);
- }
-
-done:
- Object = Header + 1;
-
- return Object;
-
-fail1:
- Error("fail1 (%08x)\n", status);
-
- return NULL;
-}
-
-static FORCEINLINE VOID
-__PoolPutShared(
- IN PXENBUS_POOL Pool,
- IN PVOID Object,
- IN BOOLEAN Locked
- )
-{
- POBJECT_HEADER Header;
- PLIST_ENTRY Old;
- PLIST_ENTRY New;
-
- ASSERT(Object != NULL);
-
- Header = Object;
- --Header;
- ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
-
- ASSERT(IsZeroMemory(&Header->ListEntry, sizeof (LIST_ENTRY)));
-
- if (!Locked) {
- New = &Header->ListEntry;
-
- do {
- Old = Pool->PutList;
- New->Flink = Old;
- } while (InterlockedCompareExchangePointer(&Pool->PutList, New, Old) != Old);
- } else {
- InsertTailList(&Pool->GetList, &Header->ListEntry);
- }
-
- KeMemoryBarrier();
-
- (VOID) InterlockedIncrement(&Pool->Population);
-}
-
-static FORCEINLINE PVOID
-__PoolGetMagazine(
- IN PXENBUS_POOL Pool,
- IN ULONG Cpu
- )
-{
- PPOOL_MAGAZINE Magazine;
- ULONG Index;
-
- Magazine = &Pool->Magazine[Cpu];
-
- for (Index = 0; Index < MAXIMUM_SLOTS; Index++) {
- PVOID Object;
-
- if (Magazine->Slot[Index] != NULL) {
- Object = Magazine->Slot[Index];
- Magazine->Slot[Index] = NULL;
-
- return Object;
- }
- }
-
- return NULL;
-}
-
-static FORCEINLINE BOOLEAN
-__PoolPutMagazine(
- IN PXENBUS_POOL Pool,
- IN ULONG Cpu,
- IN PVOID Object
- )
-{
- PPOOL_MAGAZINE Magazine;
- ULONG Index;
-
- Magazine = &Pool->Magazine[Cpu];
-
- for (Index = 0; Index < MAXIMUM_SLOTS; Index++) {
- if (Magazine->Slot[Index] == NULL) {
- Magazine->Slot[Index] = Object;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-PVOID
-PoolGet(
- IN PXENBUS_POOL Pool,
- IN BOOLEAN Locked
- )
-{
- KIRQL Irql;
- ULONG Cpu;
- PVOID Object;
-
- if (Pool->FIST.Probability != 0) {
- LONG Defer;
-
- Defer = InterlockedDecrement(&Pool->FIST.Defer);
-
- if (Defer <= 0) {
- ULONG Random = RtlRandomEx(&Pool->FIST.Seed);
- ULONG Threshold = (MAXLONG / 100) * Pool->FIST.Probability;
-
- if (Random < Threshold)
- return NULL;
- }
- }
-
- KeRaiseIrql(DISPATCH_LEVEL, &Irql);
- Cpu = KeGetCurrentProcessorNumber();
-
- Object = __PoolGetMagazine(Pool, Cpu);
- if (Object == NULL)
- Object = __PoolGetShared(Pool, Locked);
-
- KeLowerIrql(Irql);
-
- return Object;
-}
-
-VOID
-PoolPut(
- IN PXENBUS_POOL Pool,
- IN PVOID Object,
- IN BOOLEAN Locked
- )
-{
- KIRQL Irql;
- ULONG Cpu;
-
- KeRaiseIrql(DISPATCH_LEVEL, &Irql);
- Cpu = KeGetCurrentProcessorNumber();
-
- if (!__PoolPutMagazine(Pool, Cpu, Object))
- __PoolPutShared(Pool, Object, Locked);
-
- KeLowerIrql(Irql);
-}
-
-VOID
-PoolGetStatistics(
- IN PXENBUS_POOL Pool,
- OUT PXENBUS_POOL_STATISTICS Statistics
- )
-{
- Statistics->Allocated = Pool->Allocated;
- Statistics->MaximumAllocated = Pool->MaximumAllocated;
- Statistics->Population = Pool->Population;
- Statistics->MinimumPopulation = Pool->MinimumPopulation;
-}
-
-static FORCEINLINE
-__PoolFlushMagazines(
- IN PXENBUS_POOL Pool
- )
-{
- ULONG Cpu;
-
- for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
- PVOID Object;
-
- while ((Object = __PoolGetMagazine(Pool, Cpu)) != NULL)
- __PoolPutShared(Pool, Object, TRUE);
- }
-}
-
-static FORCEINLINE VOID
-__PoolTrimShared(
- IN PXENBUS_POOL Pool,
- IN OUT PLIST_ENTRY List
- )
-{
- LONG Population;
- LONG Excess;
-
- Population = Pool->Population;
-
- KeMemoryBarrier();
-
- Excess = __max((LONG)Pool->MinimumPopulation - (LONG)Pool->Reservation, 0);
-
- while (Excess != 0) {
- PLIST_ENTRY ListEntry;
-
- Population = InterlockedDecrement(&Pool->Population);
- if (Population < 0) {
- Population = InterlockedIncrement(&Pool->Population);
- break;
- }
-
- if (IsListEmpty(&Pool->GetList))
- __PoolSwizzle(Pool);
-
- ListEntry = RemoveHeadList(&Pool->GetList);
- ASSERT(ListEntry != &Pool->GetList);
-
- InsertTailList(List, ListEntry);
-
- InterlockedDecrement(&Pool->Allocated);
- --Excess;
- }
-
- Pool->MinimumPopulation = Population;
-}
-
-static FORCEINLINE VOID
-__PoolDestroyObject(
- IN PXENBUS_POOL Pool,
- IN POBJECT_HEADER Header
- )
-{
- PVOID Object;
-
- Object = Header + 1;
-
- Pool->Dtor(Pool->Argument, Object);
-
- Header->Magic = 0;
-
- ASSERT(IsZeroMemory(Header, sizeof (OBJECT_HEADER)));
- __PoolFree(Header);
-}
-
-static FORCEINLINE VOID
-__PoolEmpty(
- IN PXENBUS_POOL Pool,
- IN OUT PLIST_ENTRY List
- )
-{
- while (!IsListEmpty(List)) {
- PLIST_ENTRY ListEntry;
- POBJECT_HEADER Header;
-
- ListEntry = RemoveHeadList(List);
- RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
-
- Header = CONTAINING_RECORD(ListEntry, OBJECT_HEADER, ListEntry);
- ASSERT3U(Header->Magic, ==, OBJECT_HEADER_MAGIC);
-
- __PoolDestroyObject(Pool, Header);
- }
-}
-
-#define TIME_US(_us) ((_us) * 10)
-#define TIME_MS(_ms) (TIME_US((_ms) * 1000))
-#define TIME_RELATIVE(_t) (-(_t))
-
-#define POOL_PERIOD 1000
-
-KDEFERRED_ROUTINE PoolDpc;
-
-VOID
-PoolDpc(
- IN PKDPC Dpc,
- IN PVOID Context,
- IN PVOID Argument1,
- IN PVOID Argument2
- )
-{
- PXENBUS_POOL Pool = Context;
- LIST_ENTRY List;
-
- UNREFERENCED_PARAMETER(Dpc);
- UNREFERENCED_PARAMETER(Argument1);
- UNREFERENCED_PARAMETER(Argument2);
-
- ASSERT(Pool != NULL);
-
- InitializeListHead(&List);
-
- Pool->AcquireLock(Pool->Argument);
- __PoolTrimShared(Pool, &List);
- Pool->ReleaseLock(Pool->Argument);
-
- __PoolEmpty(Pool, &List);
- ASSERT(IsListEmpty(&List));
-}
-
-static FORCEINLINE VOID
-__PoolSetupFIST(
- IN PXENBUS_POOL Pool,
- IN PXENBUS_STORE_INTERFACE StoreInterface
- )
-{
- CHAR Node[sizeof ("fist/pool/") + MAXNAMELEN];
- PCHAR Buffer;
- LARGE_INTEGER Now;
- NTSTATUS status;
-
- status = RtlStringCbPrintfA(Node,
- sizeof (Node),
- "fist/pool/%s",
- Pool->Name);
- ASSERT(NT_SUCCESS(status));
-
- status = STORE(Read,
- StoreInterface,
- NULL,
- Node,
- "defer",
- &Buffer);
- if (!NT_SUCCESS(status)) {
- Pool->FIST.Defer = 0;
- } else {
- Pool->FIST.Defer = (ULONG)strtol(Buffer, NULL, 0);
-
- STORE(Free,
- StoreInterface,
- Buffer);
- }
-
- status = STORE(Read,
- StoreInterface,
- NULL,
- Node,
- "probability",
- &Buffer);
- if (!NT_SUCCESS(status)) {
- Pool->FIST.Probability = 0;
- } else {
- Pool->FIST.Probability = (ULONG)strtol(Buffer, NULL, 0);
-
- STORE(Free,
- StoreInterface,
- Buffer);
- }
-
- if (Pool->FIST.Probability > 100)
- Pool->FIST.Probability = 100;
-
- if (Pool->FIST.Probability != 0)
- Info("%s: Defer = %d Probability = %d\n",
- Pool->Name,
- Pool->FIST.Defer,
- Pool->FIST.Probability);
-
- KeQuerySystemTime(&Now);
- Pool->FIST.Seed = Now.LowPart;
-}
-
-NTSTATUS
-PoolInitialize(
- IN PXENBUS_STORE_INTERFACE StoreInterface,
- IN const CHAR *Name,
- IN ULONG Size,
- IN ULONG Reservation,
- IN NTSTATUS (*Ctor)(PVOID, PVOID),
- IN VOID (*Dtor)(PVOID, PVOID),
- IN VOID (*AcquireLock)(PVOID),
- IN VOID (*ReleaseLock)(PVOID),
- IN PVOID Argument,
- OUT PXENBUS_POOL *Pool
- )
-{
- LARGE_INTEGER Timeout;
- LIST_ENTRY List;
- NTSTATUS status;
-
- *Pool = __PoolAllocate(sizeof (XENBUS_POOL));
-
- status = STATUS_NO_MEMORY;
- if (*Pool == NULL)
- goto fail1;
-
- status = RtlStringCbPrintfA((*Pool)->Name,
- sizeof ((*Pool)->Name),
- "%s",
- Name);
- if (!NT_SUCCESS(status))
- goto fail2;
-
- (*Pool)->Size = Size;
- (*Pool)->Ctor = Ctor;
- (*Pool)->Dtor = Dtor;
- (*Pool)->AcquireLock = AcquireLock;
- (*Pool)->ReleaseLock = ReleaseLock;
- (*Pool)->Argument = Argument;
-
- __PoolSetupFIST(*Pool, StoreInterface);
-
- InitializeListHead(&(*Pool)->GetList);
-
- while (Reservation != 0) {
- POBJECT_HEADER Header;
-
- status = __PoolCreateObject(*Pool, &Header);
- if (!NT_SUCCESS(status))
- goto fail3;
-
- (VOID) InterlockedIncrement(&(*Pool)->Allocated);
-
- InsertTailList(&(*Pool)->GetList, &Header->ListEntry);
- (VOID) InterlockedIncrement(&(*Pool)->Population);
-
- --Reservation;
- }
- (*Pool)->MaximumAllocated = (*Pool)->Allocated;
- (*Pool)->Reservation = (*Pool)->Population;
-
- KeInitializeDpc(&(*Pool)->Dpc,
- PoolDpc,
- (*Pool));
-
- Timeout.QuadPart = TIME_RELATIVE(TIME_MS(POOL_PERIOD));
-
- KeInitializeTimer(&(*Pool)->Timer);
- KeSetTimerEx(&(*Pool)->Timer,
- Timeout,
- POOL_PERIOD,
- &(*Pool)->Dpc);
-
- return STATUS_SUCCESS;
-
-fail3:
- Error("fail3\n");
-
- InitializeListHead(&List);
-
- (*Pool)->MinimumPopulation = (*Pool)->Population;
- __PoolTrimShared(*Pool, &List);
- __PoolEmpty(*Pool, &List);
-
- ASSERT3U((*Pool)->Population, ==, 0);
- ASSERT3U((*Pool)->Allocated, ==, 0);
-
- RtlZeroMemory(&(*Pool)->GetList, sizeof (LIST_ENTRY));
-
- RtlZeroMemory(&(*Pool)->FIST, sizeof (POOL_FIST));
-
- (*Pool)->Argument = NULL;
- (*Pool)->ReleaseLock = NULL;
- (*Pool)->AcquireLock = NULL;
- (*Pool)->Dtor = NULL;
- (*Pool)->Ctor = NULL;
- (*Pool)->Size = 0;
-
-fail2:
- Error("fail2\n");
-
- RtlZeroMemory((*Pool)->Name, sizeof ((*Pool)->Name));
-
- ASSERT(IsZeroMemory(*Pool, sizeof (XENBUS_POOL)));
- __PoolFree(*Pool);
-
-fail1:
- Error("fail1 (%08x)\n", status);
-
- return status;
-}
-
-VOID
-PoolTeardown(
- IN PXENBUS_POOL Pool
- )
-{
- LIST_ENTRY List;
-
- KeCancelTimer(&Pool->Timer);
- KeFlushQueuedDpcs();
-
- RtlZeroMemory(&Pool->Timer, sizeof (KTIMER));
- RtlZeroMemory(&Pool->Dpc, sizeof (KDPC));
-
- Pool->Reservation = 0;
- Pool->MaximumAllocated = 0;
-
- InitializeListHead(&List);
-
- __PoolFlushMagazines(Pool);
-
- Pool->MinimumPopulation = Pool->Population;
- __PoolTrimShared(Pool, &List);
- __PoolEmpty(Pool, &List);
-
- ASSERT3U(Pool->Population, ==, 0);
- ASSERT3U(Pool->Allocated, ==, 0);
-
- RtlZeroMemory(&Pool->GetList, sizeof (LIST_ENTRY));
-
- RtlZeroMemory(&Pool->FIST, sizeof (POOL_FIST));
-
- Pool->Argument = NULL;
- Pool->ReleaseLock = NULL;
- Pool->AcquireLock = NULL;
- Pool->Dtor = NULL;
- Pool->Ctor = NULL;
- Pool->Size = 0;
-
- RtlZeroMemory(Pool->Name, sizeof (Pool->Name));
-
- ASSERT(IsZeroMemory(Pool, sizeof (XENBUS_POOL)));
- __PoolFree(Pool);
-}
+++ /dev/null
-/* Copyright (c) Citrix Systems Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms,
- * with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * * Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the
- * following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the
- * following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _XENBUS_POOL_H
-#define _XENBUS_POOL_H
-
-#include <ntddk.h>
-#include <store_interface.h>
-
-typedef struct _XENBUS_POOL XENBUS_POOL, *PXENBUS_POOL;
-
-extern NTSTATUS
-PoolInitialize(
- IN PXENBUS_STORE_INTERFACE StoreInterface,
- IN const CHAR *Name,
- IN ULONG Size,
- IN ULONG Reservation,
- IN NTSTATUS (*Ctor)(PVOID, PVOID),
- IN VOID (*Dtor)(PVOID, PVOID),
- IN VOID (*AcquireLock)(PVOID),
- IN VOID (*ReleaseLock)(PVOID),
- IN PVOID Argument,
- OUT PXENBUS_POOL *Pool
- );
-
-extern VOID
-PoolTeardown(
- IN PXENBUS_POOL Pool
- );
-
-extern PVOID
-PoolGet(
- IN PXENBUS_POOL Pool,
- IN BOOLEAN Locked
- );
-
-extern VOID
-PoolPut(
- IN PXENBUS_POOL Pool,
- IN PVOID Object,
- IN BOOLEAN Locked
- );
-
-typedef struct _XENBUS_POOL_STATISTICS {
- ULONG Allocated;
- ULONG MaximumAllocated;
- ULONG Population;
- ULONG MinimumPopulation;
-} XENBUS_POOL_STATISTICS, *PXENBUS_POOL_STATISTICS;
-
-extern VOID
-PoolGetStatistics(
- IN PXENBUS_POOL Pool,
- OUT PXENBUS_POOL_STATISTICS Statistics
- );
-
-#endif // _XENBUS_POOL_H