reactos/reactos/ntoskrnl/mm/slab.c
Casper Hornstrup 1e847489e4 2002-10-01 Casper S. Hornstrup <chorns@users.sourceforge.net>
* drivers/dd/floppy/floppy.c: Changed PAGESIZE to PAGE_SIZE.
	* drivers/fs/cdfs/fcb.c: Ditto.
	* drivers/fs/cdfs/fsctl.c: Ditto.
	* drivers/fs/cdfs/rw.c: Ditto.
	* drivers/fs/ext2/dir.c: Ditto.
	* drivers/fs/ext2/inode.c: Ditto.
	* drivers/fs/ext2/rw.c: Ditto.
	* drivers/fs/ext2/super.c: Ditto.
	* drivers/fs/minix/blockdev.c: Ditto.
	* drivers/fs/minix/cache.c: Ditto.
	* drivers/fs/minix/inode.c: Ditto.
	* drivers/fs/minix/rw.c: Ditto.
	* drivers/fs/ntfs/fcb.c: Ditto.
	* drivers/fs/ntfs/ntfs.h: Ditto.
	* drivers/fs/vfat/create.c: Ditto.
	* drivers/fs/vfat/direntry.c: Ditto.
	* drivers/fs/vfat/dirwr.c: Ditto.
	* drivers/fs/vfat/fat.c: Ditto.
	* drivers/fs/vfat/fcb.c: Ditto.
	* drivers/fs/vfat/fsctl.c: Ditto.
	* drivers/fs/vfat/rw.c: Ditto.
	* drivers/storage/class2/class2.c: Ditto.
	* drivers/storage/scsiport/scsiport.c: Ditto.
	* hal/halx86/adapter.c: Ditto.
	* hal/halx86/mp.c: Ditto.
	* include/ddk/mmfuncs.h: Ditto.
	* include/ddk/mmtypes.h: Ditto.
	* include/ddk/i386/pagesize.h: Ditto.
	* include/ntdll/pagesize.h: Ditto.
	* lib/kernel32/process/create.c: Ditto.
	* lib/kernel32/thread/thread.c: Ditto.
	* lib/ntdll/ldr/utils.c: Ditto.
	* lib/ntdll/rtl/env.c: Ditto.
	* lib/ntdll/rtl/heap.c: Ditto.
	* lib/ntdll/rtl/ppb.c: Ditto.
	* lib/ntdll/rtl/process.c: Ditto.
	* lib/ntdll/rtl/thread.c: Ditto.
	* ntoskrnl/cc/copy.c: Ditto.
	* ntoskrnl/cc/view.c: Ditto.
	* ntoskrnl/ex/sysinfo.c: Ditto.
	* ntoskrnl/include/internal/i386/mm.h: Ditto.
	* ntoskrnl/io/mdl.c: Ditto.
	* ntoskrnl/ke/kthread.c: Ditto.
	* ntoskrnl/ke/i386/kernel.c: Ditto.
	* ntoskrnl/ldr/init.c: Ditto.
	* ntoskrnl/ldr/loader.c: Ditto.
	* ntoskrnl/mm/anonmem.c: Ditto.
	* ntoskrnl/mm/cont.c: Ditto.
	* ntoskrnl/mm/freelist.c: Ditto.
	* ntoskrnl/mm/iospace.c: Ditto.
	* ntoskrnl/mm/kmap.c: Ditto.
	* ntoskrnl/mm/marea.c: Ditto.
	* ntoskrnl/mm/mdl.c: Ditto.
	* ntoskrnl/mm/mminit.c: Ditto.
	* ntoskrnl/mm/ncache.c: Ditto.
	* ntoskrnl/mm/npool.c: Ditto.
	* ntoskrnl/mm/pagefile.c: Ditto.
	* ntoskrnl/mm/pageop.c: Ditto.
	* ntoskrnl/mm/section.c: Ditto.
	* ntoskrnl/mm/slab.c: Ditto.
	* ntoskrnl/mm/i386/page.c: Ditto.
	* ntoskrnl/ob/handle.c: Ditto.
	* ntoskrnl/ps/create.c: Ditto.
	* ntoskrnl/ps/process.c: Ditto.
	* ntoskrnl/ps/w32call.c: Ditto.
	* subsys/win32k/include/object.h: Ditto.

svn path=/trunk/; revision=3594
2002-10-01 19:27:25 +00:00

323 lines
8.2 KiB
C

/*
* ReactOS kernel
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: slab.c,v 1.8 2002/10/01 19:27:24 chorns Exp $
*
* COPYRIGHT: See COPYING in the top directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/slab.c
* PURPOSE: Slab allocator.
* PROGRAMMER: David Welch (welch@cwcom.net)
* UPDATE HISTORY:
* Created 27/12/01
*/
/* INCLUDES *****************************************************************/
#include <ddk/ntddk.h>
#include <internal/mm.h>
#define NDEBUG
#include <internal/debug.h>
/* TYPES ********************************************************************/
typedef VOID (*SLAB_CACHE_CONSTRUCTOR)(VOID*, ULONG);
typedef VOID (*SLAB_CACHE_DESTRUCTOR)(VOID*, ULONG);
struct _SLAB_CACHE_PAGE;
typedef struct _SLAB_CACHE
{
SLAB_CACHE_CONSTRUCTOR Constructor;
SLAB_CACHE_DESTRUCTOR Destructor;
ULONG BaseSize;
ULONG ObjectSize;
ULONG ObjectsPerPage;
LIST_ENTRY PageListHead;
struct _SLAB_CACHE_PAGE* FirstFreePage;
KSPIN_LOCK SlabLock;
} SLAB_CACHE, *PSLAB_CACHE;
typedef struct _SLAB_CACHE_BUFCTL
{
struct _SLAB_CACHE_BUFCTL* NextFree;
} SLAB_CACHE_BUFCTL, *PSLAB_CACHE_BUFCTL;
typedef struct _SLAB_CACHE_PAGE
{
LIST_ENTRY PageListEntry;
PSLAB_CACHE_BUFCTL FirstFreeBuffer;
ULONG ReferenceCount;
} SLAB_CACHE_PAGE, *PSLAB_CACHE_PAGE;
/* GLOBALS ******************************************************************/
/* FUNCTIONS ****************************************************************/
PSLAB_CACHE
ExCreateSlabCache(PUNICODE_STRING Name, ULONG Size, ULONG Align,
SLAB_CACHE_CONSTRUCTOR Constructor,
SLAB_CACHE_DESTRUCTOR Destructor)
{
PSLAB_CACHE Slab;
ULONG ObjectSize;
ULONG AlignSize;
Slab = ExAllocatePool(NonPagedPool, sizeof(SLAB_CACHE));
if (Slab == NULL)
{
return(NULL);
}
Slab->Constructor = Constructor;
Slab->Destructor = Destructor;
Slab->BaseSize = Size;
ObjectSize = Size + sizeof(SLAB_CACHE_BUFCTL);
AlignSize = Align - (ObjectSize % Align);
Slab->ObjectSize = ObjectSize + AlignSize;
Slab->ObjectsPerPage =
(PAGE_SIZE - sizeof(SLAB_CACHE_PAGE)) / Slab->ObjectSize;
InitializeListHead(&Slab->PageListHead);
KeInitializeSpinLock(&Slab->SlabLock);
return(Slab);
}
PSLAB_CACHE_PAGE
ExGrowSlabCache(PSLAB_CACHE Slab)
{
PSLAB_CACHE_PAGE SlabPage;
PHYSICAL_ADDRESS PhysicalPage;
PVOID Page;
NTSTATUS Status;
ULONG i;
PSLAB_CACHE_BUFCTL BufCtl;
PVOID Object;
Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &PhysicalPage);
if (!NT_SUCCESS(Status))
{
return(NULL);
}
Page = ExAllocatePageWithPhysPage(PhysicalPage);
if (Page == NULL)
{
MmReleasePageMemoryConsumer(MC_NPPOOL, PhysicalPage);
return(NULL);
}
SlabPage = (PSLAB_CACHE_PAGE)(Page + PAGE_SIZE - sizeof(SLAB_CACHE_PAGE));
SlabPage->ReferenceCount = 0;
SlabPage->FirstFreeBuffer = (PSLAB_CACHE_BUFCTL)Page;
for (i = 0; i < Slab->ObjectsPerPage; i++)
{
BufCtl = (PSLAB_CACHE_BUFCTL)(Page + (i * Slab->ObjectSize));
Object = (PVOID)(BufCtl + 1);
if (Slab->Constructor != NULL)
{
Slab->Constructor(Object, Slab->BaseSize);
}
if (i == (Slab->ObjectsPerPage - 1))
{
BufCtl->NextFree =
(PSLAB_CACHE_BUFCTL)(Page + ((i + 1) * Slab->ObjectSize));
}
else
{
BufCtl->NextFree = NULL;
}
}
return(SlabPage);
}
PVOID
ExAllocateSlabCache(PSLAB_CACHE Slab, BOOLEAN MayWait)
{
KIRQL oldIrql;
PSLAB_CACHE_PAGE Page;
PVOID Object;
BOOLEAN NewPage;
KeAcquireSpinLock(&Slab->SlabLock, &oldIrql);
/*
* Check if there is a page with free objects
* present, if so allocate from it, if
* not grow the slab.
*/
if (Slab->FirstFreePage == NULL)
{
KeReleaseSpinLock(&Slab->SlabLock, oldIrql);
Page = ExGrowSlabCache(Slab);
NewPage = TRUE;
KeAcquireSpinLock(&Slab->SlabLock, &oldIrql);
}
else
{
Page = Slab->FirstFreePage;
NewPage = FALSE;
}
/*
* We shouldn't have got a page without free buffers.
*/
if (Page->FirstFreeBuffer == NULL)
{
DPRINT1("First free page had no free buffers.\n");
KeBugCheck(0);
}
/*
* Allocate the first free object from the page.
*/
Object = (PVOID)Page->FirstFreeBuffer + sizeof(SLAB_CACHE_BUFCTL);
Page->FirstFreeBuffer = Page->FirstFreeBuffer->NextFree;
Page->ReferenceCount++;
/*
* If we just allocated all the objects from this page
* and it was the first free page then adjust the
* first free page pointer and move the page to the head
* of the list.
*/
if (Page->ReferenceCount == Slab->ObjectsPerPage && !NewPage)
{
if (Page->PageListEntry.Flink == &Slab->PageListHead)
{
Slab->FirstFreePage = NULL;
}
else
{
PSLAB_CACHE_PAGE NextPage;
NextPage = CONTAINING_RECORD(Page->PageListEntry.Flink,
SLAB_CACHE_PAGE,
PageListEntry);
Slab->FirstFreePage = NextPage;
}
RemoveEntryList(&Page->PageListEntry);
InsertHeadList(&Slab->PageListHead, &Page->PageListEntry);
}
/*
* Otherwise if we created a new page then add it to the end of
* the page list.
*/
else if (NewPage)
{
InsertTailList(&Slab->PageListHead, &Page->PageListEntry);
if (Slab->FirstFreePage == NULL)
{
Slab->FirstFreePage = Page;
}
}
KeReleaseSpinLock(&Slab->SlabLock, oldIrql);
return(Object);
}
VOID
ExFreeFromPageSlabCache(PSLAB_CACHE Slab,
PSLAB_CACHE_PAGE Page,
PVOID Object)
{
PSLAB_CACHE_BUFCTL BufCtl;
BufCtl = (PSLAB_CACHE_BUFCTL)(Object - sizeof(SLAB_CACHE_BUFCTL));
BufCtl->NextFree = Page->FirstFreeBuffer;
Page->FirstFreeBuffer = BufCtl;
Page->ReferenceCount--;
}
VOID
ExFreeSlabCache(PSLAB_CACHE Slab, PVOID Object)
{
KIRQL oldIrql;
PLIST_ENTRY current_entry;
PSLAB_CACHE_PAGE current;
KeAcquireSpinLock(&Slab->SlabLock, &oldIrql);
current_entry = Slab->PageListHead.Flink;
while (current_entry != &Slab->PageListHead)
{
PVOID Base;
current = CONTAINING_RECORD(current_entry,
SLAB_CACHE_PAGE,
PageListEntry);
Base = (PVOID)current + sizeof(SLAB_CACHE_PAGE) - PAGE_SIZE;
if (Base >= Object &&
(Base + PAGE_SIZE - sizeof(SLAB_CACHE_PAGE)) >=
(Object + Slab->ObjectSize))
{
ExFreeFromPageSlabCache(Slab, current, Object);
/*
* If the page just become free then rearrange things.
*/
if (current->ReferenceCount == 0)
{
RemoveEntryList(&current->PageListEntry);
InsertTailList(&Slab->PageListHead, &current->PageListEntry);
if (Slab->FirstFreePage == NULL)
{
Slab->FirstFreePage = current;
}
}
KeReleaseSpinLock(&Slab->SlabLock, oldIrql);
return;
}
}
DPRINT1("Tried to free object not in cache.\n");
KeBugCheck(0);
}
VOID
ExDestroySlabCache(PSLAB_CACHE Slab)
{
PLIST_ENTRY current_entry;
PSLAB_CACHE_PAGE current;
ULONG i;
PVOID Object;
current_entry = Slab->PageListHead.Flink;
while (current_entry != &Slab->PageListHead)
{
PVOID Base;
PHYSICAL_ADDRESS PhysicalPage;
current = CONTAINING_RECORD(current_entry,
SLAB_CACHE_PAGE,
PageListEntry);
Base = (PVOID)current + sizeof(SLAB_CACHE_PAGE) - PAGE_SIZE;
if (Slab->Destructor != NULL)
{
for (i = 0; i < Slab->ObjectsPerPage; i++)
{
Object = Base + (i * Slab->ObjectSize) +
sizeof(SLAB_CACHE_BUFCTL);
Slab->Destructor(Object, Slab->BaseSize);
}
}
PhysicalPage = MmGetPhysicalAddressForProcess(NULL, Base);
ExUnmapPage(Base);
MmReleasePageMemoryConsumer(MC_NPPOOL, PhysicalPage);
}
ExFreePool(Slab);
}