test: region.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# region.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1995  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     region.c
    00008
    00009 Abstract:
    00010
    00011     This module implements a simple region buffer manager that is MP safe.
    00012
    00013 Author:
    00014
    00015     David N. Cutler (davec) 25-Novy-1995
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "exp.h"
    00022
    00023 VOID
    00024 ExInitializeRegion(
    00025     IN PREGION_HEADER Region,
    00026     IN ULONG BlockSize,
    00027     IN PVOID Segment,
    00028     IN ULONG SegmentSize
    00029     )
    00030
    00031 /*++
    00032
    00033 Routine Description:
    00034
    00035     This function initializes a region header.
    00036
    00037 Arguments:
    00038
    00039     Region - Supplies the address of a region header to initialize.
    00040
    00041     BlockSize - Supplies the block size of the allocatable units within
    00042         the region. The size must be larger that the size of the initial
    00043         segment, and must be 64-bit aligned.
    00044
    00045     Segment - Supplies the address of a segment of storage.
    00046
    00047     SegmentSize - Supplies the size in bytes of the segment.
    00048
    00049 Return Value:
    00050
    00051     None.
    00052
    00053 --*/
    00054
    00055 {
    00056
    00057     SINGLE_LIST_ENTRY FirstEntry;
    00058     PSINGLE_LIST_ENTRY LastEntry;
    00059     PSINGLE_LIST_ENTRY NextEntry;
    00060     ULONG TotalSize;
    00061
    00062     //
    00063     // If the host system is a small system and the segment size is greater
    00064     // than two pages, then bugcheck.
    00065     //
    00066
    00067     if ((MmQuerySystemSize() == MmSmallSystem) && (SegmentSize > (2 * PAGE_SIZE))) {
    00068         KeBugCheckEx(NO_PAGES_AVAILABLE, 0x123, SegmentSize, 0, 0);
    00069     }
    00070
    00071     //
    00072     // If the segment address is not quadword aligned, or the block size is
    00073     // greater than the segment size minus size of the segment header, then
    00074     // the region is not valid - bugcheck.
    00075     //
    00076
    00077     if ((((ULONG)Segment & 7) != 0) ||
    00078         ((BlockSize & 7) != 0) ||
    00079         (BlockSize > (SegmentSize - sizeof(REGION_SEGMENT_HEADER)))) {
    00080         KeBugCheckEx(INVALID_REGION_OR_SEGMENT, (ULONG)Segment, SegmentSize, BlockSize, 0);
    00081     }
    00082
    00083     //
    00084     // Initialize the region header.
    00085     //
    00086
    00087     ExInitializeSListHead(&Region->ListHead);
    00088     Region->FirstSegment = (PREGION_SEGMENT_HEADER)Segment;
    00089     Region->BlockSize = BlockSize;
    00090     TotalSize = ((SegmentSize - sizeof(REGION_SEGMENT_HEADER)) / BlockSize) * BlockSize;
    00091     Region->TotalSize = TotalSize;
    00092
    00093     //
    00094     // Initialize the segment free list.
    00095     //
    00096
    00097     FirstEntry.Next = NULL;
    00098     NextEntry = (PSINGLE_LIST_ENTRY)((PCHAR)Segment + sizeof(REGION_SEGMENT_HEADER));
    00099     LastEntry = (PSINGLE_LIST_ENTRY)((PCHAR)NextEntry + TotalSize);
    00100     do {
    00101        NextEntry->Next = FirstEntry.Next;
    00102        FirstEntry.Next = NextEntry;
    00103        NextEntry = (PSINGLE_LIST_ENTRY)((PCHAR)NextEntry + BlockSize);
    00104     } while (NextEntry != LastEntry);
    00105     Region->ListHead.Next.Next = FirstEntry.Next;
    00106     return;
    00107 }
    00108
    00109 VOID
    00110 ExInterlockedExtendRegion(
    00111     IN PREGION_HEADER Region,
    00112     IN PVOID Segment,
    00113     IN ULONG SegmentSize,
    00114     IN PKSPIN_LOCK Lock
    00115     )
    00116
    00117 /*++
    00118
    00119 Routine Description:
    00120
    00121     This function extends a region by adding another segment's worth of
    00122     blocks to the region.
    00123
    00124 Arguments:
    00125
    00126     Region - Supplies the address of a region header.
    00127
    00128     Segment - Supplies the address of a segment of storage.
    00129
    00130     SegmentSize - Supplies the size in bytes of Segment.
    00131
    00132     Lock - Supplies the address of a spinlock.
    00133
    00134 Return Value:
    00135
    00136     None.
    00137
    00138 --*/
    00139
    00140 {
    00141
    00142     ULONG BlockSize;
    00143     SINGLE_LIST_ENTRY FirstEntry;
    00144     KIRQL OldIrql;
    00145     PSINGLE_LIST_ENTRY LastEntry;
    00146     PSINGLE_LIST_ENTRY NextEntry;
    00147     ULONG TotalSize;
    00148
    00149     //
    00150     // If the segment address is not quadword aligned, or the block size is
    00151     // greater than the segment size minus size of the segment header, then
    00152     // the region is not valid.
    00153     //
    00154
    00155     BlockSize = Region->BlockSize;
    00156     if ((((ULONG)Segment & 7) != 0) ||
    00157         ((BlockSize & 7) != 0) ||
    00158         (BlockSize > (SegmentSize - sizeof(REGION_SEGMENT_HEADER)))) {
    00159         KeBugCheckEx(INVALID_REGION_OR_SEGMENT, (ULONG)Segment, SegmentSize, BlockSize, 0);
    00160     }
    00161
    00162     //
    00163     // Initialize the segment free list.
    00164     //
    00165
    00166     TotalSize = ((SegmentSize - sizeof(REGION_SEGMENT_HEADER)) / BlockSize) * BlockSize;
    00167     FirstEntry.Next = NULL;
    00168     NextEntry = (PSINGLE_LIST_ENTRY)((PCHAR)Segment + sizeof(REGION_SEGMENT_HEADER));
    00169     LastEntry = (PSINGLE_LIST_ENTRY)((PCHAR)NextEntry + TotalSize);
    00170     do {
    00171        NextEntry->Next = FirstEntry.Next;
    00172        FirstEntry.Next = NextEntry;
    00173        NextEntry = (PSINGLE_LIST_ENTRY)((PCHAR)NextEntry + BlockSize);
    00174     } while (NextEntry != LastEntry);
    00175
    00176     //
    00177     // Acquire the specified spinlock, insert the next segment in the segment
    00178     // list, update the total segment size, and carefully merge the new segment
    00179     // list with the current list.
    00180     //
    00181     // N.B. The merging of the free list is done very carefully such that
    00182     //      manipulation of the free list can occur without using spinlocks.
    00183     //
    00184
    00185     ExAcquireSpinLock(Lock, &OldIrql);
    00186     ((PREGION_SEGMENT_HEADER)Segment)->NextSegment = Region->FirstSegment;
    00187     Region->FirstSegment = (PREGION_SEGMENT_HEADER)Segment;
    00188     Region->TotalSize += TotalSize;
    00189     NextEntry = (PSINGLE_LIST_ENTRY)((PCHAR)Segment + sizeof(REGION_SEGMENT_HEADER));
    00190     LastEntry = (PSINGLE_LIST_ENTRY)((PCHAR)LastEntry - Region->BlockSize);
    00191     do {
    00192
    00193         //
    00194         // The next entry in the region list head is a volatile entry and,
    00195         // therefore, is read each time through the loop.
    00196         //
    00197
    00198         FirstEntry.Next = Region->ListHead.Next.Next;
    00199
    00200         //
    00201         // The last entry in the new segment list, i.e., the one with a link
    00202         // of NULL, is merged with the current list by storing the captured
    00203         // region next link in the free entry. A compare and exchange is then
    00204         // done using the merged link address as the comparand and the head
    00205         // of the new free list as the exchange value. This is safe since it
    00206         // does not matter if the next link of the first region entry changes.
    00207         //
    00208
    00209         NextEntry->Next = FirstEntry.Next;
    00210     } while (InterlockedCompareExchange((PVOID)&Region->ListHead.Next,
    00211                                         LastEntry,
    00212                                         FirstEntry.Next) != FirstEntry.Next);
    00213
    00214     ExReleaseSpinLock(Lock, OldIrql);
    00215     return;
    00216 }