:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 KSPIN_LOCK MmPageOpHashTableLock;
26 PMM_PAGEOP MmPageOpHashTable[PAGEOP_HASH_TABLE_SIZE] = {NULL, } ;
27
28 #define TAG_MM_PAGEOP   TAG('M', 'P', 'O', 'P')
29
30 /* FUNCTIONS *****************************************************************/
31
32 VOID
33 MmReleasePageOp(PMM_PAGEOP PageOp)
34      /*
35       * FUNCTION: Release a reference to a page operation descriptor
36       */
37 {
38   KIRQL oldIrql;
39   PMM_PAGEOP PrevPageOp;
40
41   KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
42   PageOp->ReferenceCount--;
43   if (PageOp->ReferenceCount > 0)
44     {
45       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
46       return;
47     }
48   InterlockedDecrement(&PageOp->MArea->PageOpCount);
49   PrevPageOp = MmPageOpHashTable[PageOp->Hash];
50   if (PrevPageOp == PageOp)
51     {
52       MmPageOpHashTable[PageOp->Hash] = PageOp->Next;
53       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
54       ExFreePool(PageOp);
55       return;
56     }
57   while (PrevPageOp->Next != NULL)
58     {
59       if (PrevPageOp->Next == PageOp)
60         {
61           PrevPageOp->Next = PageOp->Next;
62           KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
63           ExFreePool(PageOp);
64           return;
65         }
66       PrevPageOp = PrevPageOp->Next;
67     }
68   KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
69   KeBugCheck(0);
70 }
71
72 PMM_PAGEOP
73 MmCheckForPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
74                  PMM_SECTION_SEGMENT Segment, ULONG Offset)
75 {
76   ULONG Hash;
77   KIRQL oldIrql;
78   PMM_PAGEOP PageOp;
79   
80   /*
81    * Calcuate the hash value for pageop structure
82    */
83   if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
84     {
85       Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGE_SIZE));
86     }
87   else
88     {
89       Hash = (((ULONG)Pid) | (((ULONG)Address) / PAGE_SIZE));
90     }
91   Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
92
93   KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
94
95   /*
96    * Check for an existing pageop structure
97    */
98   PageOp = MmPageOpHashTable[Hash];
99   while (PageOp != NULL)
100     {
101       if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
102         {
103           if (PageOp->Segment == Segment &&
104               PageOp->Offset == Offset)
105             {
106               break;
107             }
108         }
109       else
110         {
111           if (PageOp->Pid == Pid &&
112               PageOp->Address == Address)
113             {
114               break;
115             }
116         }
117       PageOp = PageOp->Next;
118     }
119   
120   /*
121    * If we found an existing pageop then increment the reference count
122    * and return it.
123    */
124   if (PageOp != NULL)
125     {
126       PageOp->ReferenceCount++;
127       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
128       return(PageOp);
129     }
130   KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
131   return(NULL);
132 }
133
134 PMM_PAGEOP
135 MmGetPageOp(PMEMORY_AREA MArea, ULONG Pid, PVOID Address,
136             PMM_SECTION_SEGMENT Segment, ULONG Offset, ULONG OpType)
137      /*
138       * FUNCTION: Get a page operation descriptor corresponding to
139       * the memory area and either the segment, offset pair or the
140       * pid, address pair.      
141       */
142 {
143   ULONG Hash;
144   KIRQL oldIrql;
145   PMM_PAGEOP PageOp;
146
147   /*
148    * Calcuate the hash value for pageop structure
149    */
150   if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
151     {
152       Hash = (((ULONG)Segment) | (((ULONG)Offset) / PAGE_SIZE));
153     }
154   else
155     {
156       Hash = (((ULONG)Pid) | (((ULONG)Address) / PAGE_SIZE));
157     }
158   Hash = Hash % PAGEOP_HASH_TABLE_SIZE;
159
160   KeAcquireSpinLock(&MmPageOpHashTableLock, &oldIrql);
161
162   /*
163    * Check for an existing pageop structure
164    */
165   PageOp = MmPageOpHashTable[Hash];
166   while (PageOp != NULL)
167     {
168       if (MArea->Type == MEMORY_AREA_SECTION_VIEW)
169         {
170           if (PageOp->Segment == Segment &&
171               PageOp->Offset == Offset)
172             {
173               break;
174             }
175         }
176       else
177         {
178           if (PageOp->Pid == Pid &&
179               PageOp->Address == Address)
180             {
181               break;
182             }
183         }
184       PageOp = PageOp->Next;
185     }
186   
187   /*
188    * If we found an existing pageop then increment the reference count
189    * and return it.
190    */
191   if (PageOp != NULL)
192     {
193       PageOp->ReferenceCount++;
194       KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
195       return(PageOp);
196     }
197
198   /*
199    * Otherwise add a new pageop.
200    */
201   PageOp = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_PAGEOP), 
202                                  TAG_MM_PAGEOP);
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(&MArea->PageOpCount);
230
231   KeReleaseSpinLock(&MmPageOpHashTableLock, oldIrql);
232   return(PageOp);
233 }
234
235
236
237
238
239
240
241