ULONG Magic;
PXENBUS_CACHE Cache;
LIST_ENTRY ListEntry;
- ULONG Count;
- ULONG Allocated;
+ USHORT MaximumOccupancy;
+ USHORT CurrentOccupancy;
+ ULONG *Mask;
UCHAR Buffer[1];
} XENBUS_CACHE_SLAB, *PXENBUS_CACHE_SLAB;
Next = CONTAINING_RECORD(Cursor, XENBUS_CACHE_SLAB, ListEntry);
- if (Next->Allocated > Slab->Allocated) {
+ if (Next->CurrentOccupancy > Slab->CurrentOccupancy) {
INSERT_BEFORE(Cursor, &Slab->ListEntry);
return;
}
LARGE_INTEGER LowAddress;
LARGE_INTEGER HighAddress;
LARGE_INTEGER Boundary;
+ ULONG Size;
LONG Index;
NTSTATUS status;
Slab->Magic = XENBUS_CACHE_SLAB_MAGIC;
Slab->Cache = Cache;
- Slab->Count = Count;
+ Slab->MaximumOccupancy = (USHORT)Count;
- for (Index = 0; Index < (LONG)Slab->Count; Index++) {
+ Size = P2ROUNDUP(Count, BITS_PER_ULONG);
+ Size /= 8;
+
+ Slab->Mask = __CacheAllocate(Size);
+ if (Slab->Mask == NULL)
+ goto fail3;
+
+ for (Index = 0; Index < (LONG)Slab->MaximumOccupancy; Index++) {
PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
status = __CacheCtor(Cache, Object);
if (!NT_SUCCESS(status))
- goto fail3;
+ goto fail4;
}
CacheInsertSlab(Cache, Slab);
return Slab;
-fail3:
- Error("fail3\n");
+fail4:
+ Error("fail4\n");
while (--Index >= 0) {
PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
__CacheDtor(Cache, Object);
}
+ __CacheFree(Slab->Mask);
+
+fail3:
+ Error("fail3\n");
+
MmFreeContiguousMemory(Slab);
fail2:
{
LONG Index;
- ASSERT3U(Slab->Allocated, ==, 0);
+ ASSERT3U(Slab->CurrentOccupancy, ==, 0);
- ASSERT3U(Cache->Count, >=, Slab->Count);
- Cache->Count -= Slab->Count;
+ ASSERT3U(Cache->Count, >=, Slab->MaximumOccupancy);
+ Cache->Count -= Slab->MaximumOccupancy;
RemoveEntryList(&Slab->ListEntry);
- Index = Slab->Count;
+ Index = Slab->MaximumOccupancy;
while (--Index >= 0) {
PVOID Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
__CacheDtor(Cache, Object);
}
+ __CacheFree(Slab->Mask);
+
MmFreeContiguousMemory(Slab);
}
+static FORCEINLINE ULONG
+__CacheMaskScan(
+ IN ULONG *Mask,
+ IN ULONG Maximum
+ )
+{
+ ULONG Size;
+ ULONG Index;
+
+ Size = P2ROUNDUP(Maximum, BITS_PER_ULONG);
+ Size /= sizeof (ULONG);
+ ASSERT(Size != 0);
+
+ for (Index = 0; Index < Size; Index++) {
+ ULONG Free = ~Mask[Index];
+ ULONG Bit;
+
+ if (!_BitScanForward(&Bit, Free))
+ continue;
+
+ Bit += Index * BITS_PER_ULONG;
+ return Bit;
+ }
+
+ BUG("CACHE SCAN FAILED");
+ return ~0u;
+}
+
+static FORCEINLINE VOID
+__CacheMaskSet(
+ IN ULONG *Mask,
+ IN ULONG Bit
+ )
+{
+ ULONG Index = Bit / BITS_PER_ULONG;
+
+ Mask[Index] |= 1u << (Bit % BITS_PER_ULONG);
+}
+
+static FORCEINLINE BOOLEAN
+__CacheMaskTest(
+ IN ULONG *Mask,
+ IN ULONG Bit
+ )
+{
+ ULONG Index = Bit / BITS_PER_ULONG;
+
+ return (Mask[Index] & (1u << (Bit % BITS_PER_ULONG))) ? TRUE : FALSE;
+}
+
+static FORCEINLINE VOID
+__CacheMaskClear(
+ IN ULONG *Mask,
+ IN ULONG Bit
+ )
+{
+ ULONG Index = Bit / BITS_PER_ULONG;
+
+ Mask[Index] &= ~(1u << (Bit % BITS_PER_ULONG));
+}
+
// Must be called with lock held
static PVOID
CacheGetObjectFromSlab(
)
{
PXENBUS_CACHE Cache;
- ULONG Free;
ULONG Index;
- ULONG Set;
+ PVOID Object;
Cache = Slab->Cache;
- Free = ~Slab->Allocated;
- if (!_BitScanForward(&Index, Free) || Index >= Slab->Count)
+ ASSERT3U(Slab->CurrentOccupancy, <=, Slab->MaximumOccupancy);
+ if (Slab->CurrentOccupancy == Slab->MaximumOccupancy)
return NULL;
- Set = InterlockedBitTestAndSet((LONG *)&Slab->Allocated, Index);
- ASSERT(!Set);
+ Index = __CacheMaskScan(Slab->Mask, Slab->MaximumOccupancy);
+
+ __CacheMaskSet(Slab->Mask, Index);
+ Slab->CurrentOccupancy++;
+
+ Object = (PVOID)&Slab->Buffer[Index * Cache->Size];
+ ASSERT3U(Index, ==, (ULONG)((PUCHAR)Object - &Slab->Buffer[0]) /
+ Cache->Size);
- return (PVOID)&Slab->Buffer[Index * Cache->Size];
+ return Object;
}
// Must be called with lock held
Cache = Slab->Cache;
Index = (ULONG)((PUCHAR)Object - &Slab->Buffer[0]) / Cache->Size;
- BUG_ON(Index >= Slab->Count);
+ BUG_ON(Index >= Slab->MaximumOccupancy);
+
+ ASSERT(Slab->CurrentOccupancy != 0);
+ --Slab->CurrentOccupancy;
- (VOID) InterlockedBitTestAndReset((LONG *)&Slab->Allocated, Index);
+ ASSERT(__CacheMaskTest(Slab->Mask, Index));
+ __CacheMaskClear(Slab->Mask, Index);
}
static PVOID
CachePutObjectToSlab(Slab, Object);
- if (Slab->Allocated == 0) {
+ if (Slab->CurrentOccupancy == 0) {
CacheDestroySlab(Cache, Slab);
} else {
/* Re-insert to keep slab list ordered */