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 }

Generated on Sat May 15 19:41:37 2004 for test by doxygen 1.3.7