branch update for HEAD-2003050101
[reactos.git] / ntoskrnl / mm / pageop.c
1 /* $Id$
2  *
3  * COPYRIGHT:    See COPYING in the top level directory
4  * PROJECT:      ReactOS kernel
5  * FILE:         ntoskrnl/mm/pageop.c
6  * PROGRAMMER:   David Welch (welch@cwcom.net)
7  * UPDATE HISTORY: 
8  *               27/05/98: Created
9  */
10
11 /* INCLUDES ****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/ps.h>
15 #include <internal/mm.h>
16 #include <internal/pool.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS *******************************************************************/
22
23 #define PAGEOP_HASH_TABLE_SIZE       (32)
24
25 static KSPIN_LOCK MmPageOpHashTableLock;
26 static PMM_PAGEOP MmPageOpHashTable[PAGEOP_HASH_TABLE_SIZE];
27 static NPAGED_LOOKASIDE_LIST MmPageOpLookasideList;
28
29 #define TAG_MM_PAGEOP   TAG('M', 'P', 'O', 'P')
30
31 /* FUNCTIONS *****************************************************************/
32
33 VOID
34 MmReleasePageOp(PMM_PAGEOP PageOp)
35      /*
36       * FUNCTION: Release a reference to a page operation descriptor
37       */
38 {
39   KIRQL oldIrql;
40   PMM_PAGEOP PrevPageOp;
41
42   KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
43   PageOp->ReferenceCount--;
44   if (PageOp->ReferenceCount > 0)
45     {
46       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
47       return;
48     }
49   InterlockedDecrement((LONG *)&PageOp->MArea->PageOpCount);
50   PrevPageOp = MmPageOpHashTable[PageOp->Hash];
51   if (PrevPageOp == PageOp)
52     {
53       MmPageOpHashTable[PageOp->Hash] = PageOp->Next;
54       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
55       ExFreeToNPagedLookasideList(&MmPageOpLookasideList, PageOp);
56       return;
57     }
58   while (PrevPageOp->Next != NULL)
59     {
60       if (PrevPageOp->Next == PageOp)
61         {
62           PrevPageOp->Next = PageOp->Next;
63           KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
64           ExFreeToNPagedLookasideList(&MmPageOpLookasideList, PageOp);
65           return;
66         }
67       PrevPageOp = PrevPageOp->Next;
68     }
69   KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
70   KeBugCheck(0);
71 }
72
73 PMM_PAGEOP
74 MmCheckForPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
75                  PMM_SECTION_SEGMENT Segment, ULONG Offset)
76 {
77   ULONG Hash;
78   KIRQL oldIrql;
79   PMM_PAGEOP PageOp;
80   
81   /*
82    * Calcuate the hash value for pageop structure
83    */
84   if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
85     {
86       Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGE_SIZE));
87     }
88   else
89     {
90       Hash = (((ULONG)Pid) | (((ULONG)Address) / PAGE_SIZE));
91     }
92   Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
93
94   KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
95
96   /*
97    * Check for an existing pageop structure
98    */
99   PageOp = MmPageOpHashTable[Hash];
100   while (PageOp != NULL)
101     {
102       if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
103         {
104           if (PageOp->Segment == Segment &&
105               PageOp->Offset == Offset)
106             {
107               break;
108             }
109         }
110       else
111         {
112           if (PageOp->Pid == Pid &&
113               PageOp->Address == Address)
114             {
115               break;
116             }
117         }
118       PageOp = PageOp->Next;
119     }
120   
121   /*
122    * If we found an existing pageop then increment the reference count
123    * and return it.
124    */
125   if (PageOp != NULL)
126     {
127       PageOp->ReferenceCount++;
128       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
129       return(PageOp);
130     }
131   KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
132   return(NULL);
133 }
134
135 PMM_PAGEOP
136 MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
137             PMM_SECTION_SEGMENT Segment, ULONG Offset, ULONG OpType)
138      /*
139       * FUNCTION: Get a page operation descriptor corresponding to
140       * the memory area and either the segment, offset pair or the
141       * pid, address pair.      
142       */
143 {
144   ULONG Hash;
145   KIRQL oldIrql;
146   PMM_PAGEOP PageOp;
147
148   /*
149    * Calcuate the hash value for pageop structure
150    */
151   if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
152     {
153       Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGE_SIZE));
154     }
155   else
156     {
157       Hash = (((ULONG)Pid) | (((ULONG)Address) / PAGE_SIZE));
158     }
159   Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
160
161   KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
162
163   /*
164    * Check for an existing pageop structure
165    */
166   PageOp = MmPageOpHashTable[Hash];
167   while (PageOp != NULL)
168     {
169       if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
170         {
171           if (PageOp->Segment == Segment &&
172               PageOp->Offset == Offset)
173             {
174               break;
175             }
176         }
177       else
178         {
179           if (PageOp->Pid == Pid &&
180               PageOp->Address == Address)
181             {
182               break;
183             }
184         }
185       PageOp = PageOp->Next;
186     }
187   
188   /*
189    * If we found an existing pageop then increment the reference count
190    * and return it.
191    */
192   if (PageOp != NULL)
193     {
194       PageOp->ReferenceCount++;
195       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
196       return(PageOp);
197     }
198
199   /*
200    * Otherwise add a new pageop.
201    */
202   PageOp = ExAllocateFromNPagedLookasideList(&MmPageOpLookasideList);
203   if (PageOp == NULL)
204     {
205       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
206       return(NULL);
207     }
208   
209   if (MArea->Type != MEMORY_AREA_SECTION_VIEW)
210     {
211       PageOp->Pid = Pid;
212       PageOp->Address = Address;
213     }
214   else
215     {
216       PageOp->Segment = Segment;
217       PageOp->Offset = Offset;
218     }
219   PageOp->ReferenceCount = 1;
220   PageOp->Next = MmPageOpHashTable[Hash];
221   PageOp->Hash = Hash;
222   PageOp->Thread = PsGetCurrentThread();
223   PageOp->Abandoned = FALSE;
224   PageOp->Status = STATUS_PENDING;
225   PageOp->OpType = OpType;
226   PageOp->MArea = MArea;
227   KeInitializeEvent(&PageOp->CompletionEvent, NotificationEvent, FALSE);
228   MmPageOpHashTable[Hash] = PageOp;
229   InterlockedIncrement((LONG *)&MArea->PageOpCount);
230
231   KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
232   return(PageOp);
233 }
234
235 VOID
236 MmInitializePageOp(VOID)
237 {
238   memset(MmPageOpHashTable, 0, sizeof(MmPageOpHashTable));
239   KeInitializeSpinLock(&MmPageOpHashTableLock);
240
241   ExInitializeNPagedLookasideList (&MmPageOpLookasideList,
242                                    NULL,
243                                    NULL,
244                                    0,
245                                    sizeof(MM_PAGEOP),
246                                    TAG_MM_PAGEOP,
247                                    50);
248 }
249
250
251
252
253
254
255