1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxCollection.cpp
8 
9 Abstract:
10 
11     This module implements a simple collection class to operate on
12     objects derived from FxObject.
13 
14 Author:
15 
16 
17 
18 Environment:
19 
20     Both kernel and user mode
21 
22 Revision History:
23 
24 --*/
25 
26 #include "fxsupportpch.hpp"
27 
28 FxCollectionInternal::FxCollectionInternal(
29     VOID
30     )
31 {
32     m_Count = 0;
33     InitializeListHead(&m_ListHead);
34 }
35 
36 FxCollectionInternal::~FxCollectionInternal(
37     VOID
38     )
39 {
40     Clear();
41 }
42 
43 VOID
44 FxCollectionInternal::Clear(
45     VOID
46     )
47 {
48     while (!IsListEmpty(&m_ListHead)) {
49         Remove(0);
50     }
51 }
52 
53 ULONG
54 FxCollectionInternal::Count(
55     VOID
56     )
57 {
58     return m_Count;
59 }
60 
61 BOOLEAN
62 FxCollectionInternal::Add(
63     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
64     __in FxObject *Item
65     )
66 {
67     FxCollectionEntry *pNode;
68 
69     pNode = AllocateEntry(FxDriverGlobals);
70 
71     if (pNode != NULL) {
72         InsertTailList(&m_ListHead, &pNode->m_ListEntry);
73 
74         AddEntry(pNode, Item);
75     }
76 
77     return pNode != NULL;
78 }
79 
80 _Must_inspect_result_
81 FxCollectionEntry*
82 FxCollectionInternal::FindEntry(
83     __in ULONG Index
84     )
85 {
86     PLIST_ENTRY ple;
87     ULONG i;
88 
89     if (Index >= m_Count) {
90         return NULL;
91     }
92 
93     for (i = 0, ple = m_ListHead.Flink;
94          ple != &m_ListHead;
95          ple = ple->Flink, i++) {
96         if (i != Index) {
97             continue;
98         }
99 
100         return CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry);
101     }
102 
103     return NULL;
104 }
105 
106 _Must_inspect_result_
107 FxCollectionEntry*
108 FxCollectionInternal::FindEntryByObject(
109     __in FxObject* Object
110     )
111 {
112     PLIST_ENTRY ple;
113 
114     for (ple = m_ListHead.Flink; ple != &m_ListHead; ple = ple->Flink) {
115         FxCollectionEntry* pNode;
116 
117         pNode = CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry);
118         if (pNode->m_Object == Object) {
119             return pNode;
120         }
121     }
122 
123     return NULL;
124 }
125 
126 NTSTATUS
127 FxCollectionInternal::Remove(
128     __in ULONG Index
129     )
130 {
131     FxCollectionEntry *pNode;
132 
133     pNode = FindEntry(Index);
134 
135     if (pNode != NULL) {
136         return RemoveEntry(pNode);
137     }
138     else {
139         return STATUS_NOT_FOUND;
140     }
141 }
142 
143 _Must_inspect_result_
144 NTSTATUS
145 FxCollectionInternal::RemoveItem(
146     __in FxObject* Item
147     )
148 {
149     FxCollectionEntry* pNode;
150 
151     pNode = FindEntryByObject(Item);
152 
153     if (pNode != NULL) {
154         return RemoveEntry(pNode);
155     }
156 
157     return STATUS_NOT_FOUND;
158 }
159 
160 VOID
161 FxCollectionInternal::CleanupEntry(
162     __in FxCollectionEntry* Entry
163     )
164 {
165     RemoveEntryList(&Entry->m_ListEntry);
166     delete Entry;
167 
168     m_Count--;
169 }
170 
171 NTSTATUS
172 FxCollectionInternal::RemoveEntry(
173     __in FxCollectionEntry* Entry
174     )
175 {
176     CleanupEntryObject(Entry->m_Object);
177     CleanupEntry(Entry);
178 
179     return STATUS_SUCCESS;
180 }
181 
182 _Must_inspect_result_
183 FxObject*
184 FxCollectionInternal::GetItem(
185     __in ULONG Index
186     )
187 
188 {
189     FxCollectionEntry* pNode;
190 
191     pNode = FindEntry(Index);
192     if (pNode != NULL) {
193         return pNode->m_Object;
194     }
195     else {
196         return NULL;
197     }
198 }
199 
200 _Must_inspect_result_
201 FxObject*
202 FxCollectionInternal::GetFirstItem(
203     VOID
204     )
205 {
206     if (IsListEmpty(&m_ListHead)) {
207         return NULL;
208     }
209     else {
210         return CONTAINING_RECORD(m_ListHead.Flink,
211                                  FxCollectionEntry,
212                                  m_ListEntry)->m_Object;
213     }
214 }
215 
216 _Must_inspect_result_
217 FxObject*
218 FxCollectionInternal::GetLastItem(
219     VOID
220     )
221 {
222     if (IsListEmpty(&m_ListHead)) {
223         return NULL;
224     }
225     else {
226         return CONTAINING_RECORD(m_ListHead.Blink,
227                                  FxCollectionEntry,
228                                  m_ListEntry)->m_Object;
229     }
230 }
231 
232 FxCollection::FxCollection(
233     __in PFX_DRIVER_GLOBALS FxDriverGlobals
234     ) :
235     FxNonPagedObject(FX_TYPE_COLLECTION, sizeof(FxCollection), FxDriverGlobals)
236 {
237 }
238 
239 FxCollection::FxCollection(
240     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
241     __in WDFTYPE Type,
242     __in USHORT Size
243     ) : FxNonPagedObject(Type, Size, FxDriverGlobals)
244 {
245 }
246 
247 FxCollection::~FxCollection(
248     VOID
249     )
250 {
251     Clear();
252 }
253 
254 VOID
255 FxCollection::StealCollection(
256     __in FxCollection* Collection
257     )
258 {
259     PLIST_ENTRY ple;
260 
261     m_Count = Collection->m_Count;
262     Collection->m_Count = 0;
263 
264     while (!IsListEmpty(&Collection->m_ListHead)) {
265         FxCollectionEntry* pEntry;
266 
267         ple = RemoveHeadList(&Collection->m_ListHead);
268         pEntry = CONTAINING_RECORD(ple, FxCollectionEntry, m_ListEntry);
269 
270         //
271         // When we are tracking reference tags, the tag associated with the
272         // reference matters.  When we added the object to Collection, we used
273         // that pointer as the tag.  We must remove that tag and readd the
274         // reference using the this value as a tag.
275         //
276         // Obviously, order is important here.  Add the reference first so that
277         // we know the relese will make the object go away.
278         //
279         pEntry->m_Object->ADDREF(this);
280         pEntry->m_Object->RELEASE(Collection);
281 
282         InsertTailList(&m_ListHead, ple);
283     }
284 }
285 
286