[NTOS:EX]
[reactos.git] / reactos / ntoskrnl / ex / zone.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/zone.c
5 * PURPOSE: Implements zone buffers
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * David Welch (welch@mcmail.com)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* FUNCTIONS ***************************************************************/
17
18 /*
19 * @implemented
20 */
21 NTSTATUS
22 NTAPI
23 ExExtendZone(PZONE_HEADER Zone,
24 PVOID Segment,
25 ULONG SegmentSize)
26 {
27 ULONG_PTR Entry;
28 ULONG i;
29
30 /*
31 * BlockSize and Segment must be 8-byte aligned.
32 * Blocksize cannot exceed Segment Size.
33 */
34 if (((ULONG_PTR)Segment & 7) ||
35 (SegmentSize & 7) ||
36 (Zone->BlockSize > SegmentSize))
37 {
38 DPRINT1("Invalid ExExtendZone Alignment and/or Size\n");
39 return STATUS_INVALID_PARAMETER;
40 }
41
42 /* Link the Zone and Segment */
43 PushEntryList(&Zone->SegmentList,
44 &((PZONE_SEGMENT_HEADER)Segment)->SegmentList);
45
46 /* Get to the first entry */
47 Entry = (ULONG_PTR)Segment + sizeof(ZONE_SEGMENT_HEADER);
48
49 /* Loop through the segments */
50 for (i = sizeof(ZONE_SEGMENT_HEADER);
51 i <= SegmentSize - Zone->BlockSize;
52 i+= Zone->BlockSize)
53 {
54 /* Link the Free and Segment Lists */
55 PushEntryList(&Zone->FreeList, (PSINGLE_LIST_ENTRY)Entry);
56
57 /* Go to the next entry */
58 Entry += Zone->BlockSize;
59 }
60
61 /* Update Segment Size */
62 Zone->TotalSegmentSize += i;
63
64 /* Return Success */
65 return STATUS_SUCCESS;
66 }
67
68 /*
69 * @implemented
70 */
71 NTSTATUS
72 NTAPI
73 ExInterlockedExtendZone(PZONE_HEADER Zone,
74 PVOID Segment,
75 ULONG SegmentSize,
76 PKSPIN_LOCK Lock)
77 {
78 NTSTATUS Status;
79 KIRQL OldIrql;
80
81 /* Get the lock */
82 KeAcquireSpinLock(Lock, &OldIrql);
83
84 /* Extend the Zone */
85 Status = ExExtendZone(Zone, Segment, SegmentSize);
86
87 /* Release lock and return status */
88 KeReleaseSpinLock(Lock, OldIrql);
89 return Status;
90 }
91
92 /*
93 * FUNCTION: Initializes a zone header
94 * ARGUMENTS:
95 * Zone = zone header to be initialized
96 * BlockSize = Size (in bytes) of the allocation size of the zone
97 * InitialSegment = Initial segment of storage allocated by the
98 * caller
99 * InitialSegmentSize = Initial size of the segment
100 *
101 * @implemented
102 */
103 NTSTATUS
104 NTAPI
105 ExInitializeZone(PZONE_HEADER Zone,
106 ULONG BlockSize,
107 PVOID InitialSegment,
108 ULONG InitialSegmentSize)
109 {
110 ULONG i;
111 ULONG_PTR Entry;
112
113 /*
114 * BlockSize and Segment must be 8-byte aligned.
115 * Blocksize cannot exceed Segment Size.
116 */
117 if (((ULONG_PTR)InitialSegment & 7) ||
118 (InitialSegmentSize & 7) ||
119 (BlockSize > InitialSegmentSize))
120 {
121 DPRINT1("Invalid ExInitializeZone Alignment and/or Size\n");
122 return STATUS_INVALID_PARAMETER;
123 }
124
125 /* Set the Zone Header */
126 Zone->BlockSize = BlockSize;
127
128 /* Link empty list */
129 Zone->FreeList.Next = NULL;
130 Zone->SegmentList.Next = NULL;
131 PushEntryList(&Zone->SegmentList,
132 &((PZONE_SEGMENT_HEADER)InitialSegment)->SegmentList);
133 ((PZONE_SEGMENT_HEADER)InitialSegment)->Reserved = NULL;
134
135 /* Get first entry */
136 Entry = (ULONG_PTR)InitialSegment + sizeof(ZONE_SEGMENT_HEADER);
137
138 /* Loop through the segments */
139 for (i = sizeof(ZONE_SEGMENT_HEADER);
140 i <= InitialSegmentSize - BlockSize;
141 i+= BlockSize)
142 {
143 /* Link the Free and Segment Lists */
144 PushEntryList(&Zone->FreeList, (PSINGLE_LIST_ENTRY)Entry);
145
146 /* Go to the next entry */
147 Entry += Zone->BlockSize;
148 }
149
150 /* Set Segment Size */
151 Zone->TotalSegmentSize = i;
152
153 /* Return success */
154 return STATUS_SUCCESS;
155 }
156
157 /* EOF */