summaryrefslogblamecommitdiffstats
path: root/private/ntos/tdi/acd/mem.c
blob: e3c9166c132a765359106194f28e980621566851 (plain) (tree)
































































































































































































































































































                                                                                           
/*++

Copyright(c) 1995 Microsoft Corporation

MODULE NAME
    table.c

ABSTRACT
    Generic hash table manipulation routines.

AUTHOR
    Anthony Discolo (adiscolo) 28-Jul-1995

REVISION HISTORY

--*/

#include <ndis.h>
#include <cxport.h>
#include <tdi.h>
#include <tdikrnl.h>
#include <tdistat.h>
#include <tdiinfo.h>
#include <acd.h>
#include <acdapi.h>

#include "acddefs.h"
#include "mem.h"
#include "debug.h"

//
// The maximum number of allocated
// objects we allocate from outside
// our zones.
//
#define MAX_ALLOCATED_OBJECTS   100

//
// Rounding up macro.
//
#define ROUNDUP(n, b)   (((n) + ((b) - 1)) & ~((b) - 1))

//
// Map an object type to a zone.
//
#define OBJECT_INFO(fObject) \
    (fObject < ACD_OBJECT_MAX) ? &AcdObjectInfoG[fObject] : &AcdObjectInfoG[ACD_OBJECT_MAX]

//
// The spin lock for this module.
//
KSPIN_LOCK AcdMemSpinLockG;

//
// Zone-based object information.  One zone
// per object type.
//
typedef struct _OBJECT_INFORMATION {
    ZONE_HEADER zone;
    ULONG ulSize;           // object size
    ULONG ulTag;            // ExAllocateFromPoolWithTag() tag
    ULONG ulCurrent;        // # currently allocated in zone
    ULONG ulTotal;          // total # zone allocations
} OBJECT_INFORMATION, *POBJECT_INFORMATION;

OBJECT_INFORMATION AcdObjectInfoG[ACD_OBJECT_MAX + 1];

//
// Pool-based object allocation.  This is for
// objects that don't fit into any of the zones,
// or when the zone is full.
//
typedef struct _POOL_INFORMATION {
    ULONG cbMin;            // minimum size
    ULONG cbMax;            // maximum size
    ULONG ulCurrent;        // # current allocations
    ULONG ulTotal;          // total allocations
    ULONG ulFailures;       // total failures
} POOL_INFORMATION, *PPOOL_INFORMATION;

POOL_INFORMATION AcdPoolInfoG;



VOID
InitializeObjectAllocator()
{
    NTSTATUS status;
    PVOID pMem;
    ULONG ulSize;

    KeInitializeSpinLock(&AcdMemSpinLockG);
    //
    // Initialize zone 0 (ACD_OBJECT_CONNECTION).
    //
    AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulTag = 'NdcA';
    AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulSize =
      ROUNDUP(sizeof (ACD_CONNECTION), 8);
    ulSize = PAGE_SIZE;
    pMem = ExAllocatePoolWithTag(
             NonPagedPool, 
             ulSize, 
             AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulTag);
    ASSERT(pMem != NULL);
    status = ExInitializeZone(
               &AcdObjectInfoG[ACD_OBJECT_CONNECTION].zone,
               AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulSize,
               pMem,
               ulSize);
    IF_ACDDBG(ACD_DEBUG_MEMORY) {
        AcdPrint((
          "InitializeObjectAllocator: zone 0 created: blksiz=%d, size=%d (status=%d)\n",
          AcdObjectInfoG[ACD_OBJECT_CONNECTION].ulSize,
          ulSize,
          status));
    }
    //
    // Initialize zone 1 (ACD_OBJECT_COMPLETION).
    //
    AcdObjectInfoG[ACD_OBJECT_MAX].ulTag = 'MdcA';
    //
    // Allow for up to 6 parameters to a completion
    // request (6 used by tcpip.sys).
    //
    AcdObjectInfoG[ACD_OBJECT_MAX].ulSize =
      ROUNDUP(sizeof (ACD_COMPLETION) + (6 * sizeof (PVOID)), 8);
    ulSize = ROUNDUP(6 * AcdObjectInfoG[ACD_OBJECT_MAX].ulSize, PAGE_SIZE), 
    pMem = ExAllocatePoolWithTag(
             NonPagedPool, 
             ulSize,
             AcdObjectInfoG[ACD_OBJECT_MAX].ulTag);
    ASSERT(pMem != NULL);
    status = ExInitializeZone(
               &AcdObjectInfoG[ACD_OBJECT_MAX].zone,
               AcdObjectInfoG[ACD_OBJECT_MAX].ulSize,
               pMem,
               ulSize);
    IF_ACDDBG(ACD_DEBUG_MEMORY) {
        AcdPrint((
          "InitializeObjectAllocator: zone 1 created: blksiz=%d size=%d (status=%d)\n",
          AcdObjectInfoG[ACD_OBJECT_MAX].ulSize,
          ulSize,
          status));
    }
    //
    // Initialize the pool info.
    //
    AcdPoolInfoG.cbMin = 0xffffffff;
    AcdPoolInfoG.cbMax = 0;
    AcdPoolInfoG.ulCurrent = 0;
    AcdPoolInfoG.ulTotal = 0;
    AcdPoolInfoG.ulFailures = 0;
} // InitializeObjectAllocator



PVOID
AllocateObjectMemory(
    IN ULONG fObject
    )
{
    KIRQL irql;
    POBJECT_INFORMATION pObjectInfo = OBJECT_INFO(fObject);
    PVOID pObject;
    ULONG cbBytes = 0, ulTag;
    static ULONG nAllocations = 0;

    KeAcquireSpinLock(&AcdMemSpinLockG, &irql);
    //
    // If the zone is full, or the object
    // size is greater than the zone object size,
    // then use the pool allocator.
    //
    if (fObject > pObjectInfo->zone.BlockSize) {
        cbBytes = fObject;
        ulTag = 'PdcA';
    }
    else if (ExIsFullZone(&pObjectInfo->zone)) {
        cbBytes = pObjectInfo->ulSize;
        ulTag = pObjectInfo->ulTag;
    }
    if (cbBytes) {
        //
        // Limit memory usage under stress.
        // If we have more than 100 outstanding
        // requests, then we start dropping
        // them.
        //
        if (AcdPoolInfoG.ulCurrent < MAX_ALLOCATED_OBJECTS)
            pObject = ExAllocatePoolWithTag(NonPagedPool, cbBytes, ulTag);
        else {
            pObject = NULL;
            AcdPoolInfoG.ulFailures++;
            goto done;
        }
        if (cbBytes < AcdPoolInfoG.cbMin)
            AcdPoolInfoG.cbMin = cbBytes;
        if (cbBytes > AcdPoolInfoG.cbMax)
            AcdPoolInfoG.cbMax = cbBytes;
        AcdPoolInfoG.ulCurrent++;
        AcdPoolInfoG.ulTotal++;
        IF_ACDDBG(ACD_DEBUG_MEMORY) {
            AcdPrint((
              "AllocateObjectMemory: allocated type %d from pool: pObject=0x%x\n",
              fObject,
              pObject));
        }
    }
    else {
        pObject = ExAllocateFromZone(&pObjectInfo->zone);
        pObjectInfo->ulCurrent++;
        pObjectInfo->ulTotal++;
        IF_ACDDBG(ACD_DEBUG_MEMORY) {
            AcdPrint((
              "AllocateObjectMemory: allocated type %d from zone: pObject=0x%x\n",
              fObject,
              pObject));
        }
    }
#if DBG
    IF_ACDDBG(ACD_DEBUG_MEMORY) {
        INT i;

        if (!(++nAllocations % 10)) {
            for (i = 0; i <= ACD_OBJECT_MAX; i++) {
                AcdPrint((
                  "Zone %d: ulCurrent=%d, ulTotal=%d\n",
                  i,
                  AcdObjectInfoG[i].ulCurrent,
                  AcdObjectInfoG[i].ulTotal));
            }
            AcdPrint((
              "Pool: ulCurrent=%d, ulTotal=%d\n",
              AcdPoolInfoG.ulCurrent,
              AcdPoolInfoG.ulTotal));
        }
    }
#endif
done:
    KeReleaseSpinLock(&AcdMemSpinLockG, irql);

    return pObject;
} // AllocateObjectMemory



VOID
FreeObjectMemory(
    IN PVOID pObject
    )
{
    KIRQL irql;
    INT i;
    POBJECT_INFORMATION pObjectInfo;

    KeAcquireSpinLock(&AcdMemSpinLockG, &irql);
    for (i = 0; i <= ACD_OBJECT_MAX; i++) {
        pObjectInfo = &AcdObjectInfoG[i];

        if (ExIsObjectInFirstZoneSegment(&pObjectInfo->zone, pObject)) {
            ExFreeToZone(&pObjectInfo->zone, pObject);
            pObjectInfo->ulCurrent--;
            IF_ACDDBG(ACD_DEBUG_MEMORY) {
                AcdPrint((
                  "FreeObjectMemory: freed type %d into zone: pObject=0x%x\n",
                  i,
                  pObject));
            }
            goto done;
        }
    }
    ExFreePool(pObject);
    AcdPoolInfoG.ulCurrent--;
    IF_ACDDBG(ACD_DEBUG_MEMORY) {
        AcdPrint((
          "FreeObjectMemory: freed into pool: pObject=0x%x\n",
          pObject));
    }
done:
    KeReleaseSpinLock(&AcdMemSpinLockG, irql);
} // FreeObjectMemory



VOID
FreeObjectAllocator()
{
    // Apparently, we can't do this?
} // FreeObjectAllocator