1 krisbash 1.1 /*============================================================================
2 * Copyright (C) Microsoft Corporation, All rights reserved.
3 *============================================================================
4 */
5 #ifndef _miapi_childlist_h_
6 #define _miapi_childlist_h_
7 #include <MI.h>
8 #include "SafeHandle.h"
9 #include <pal/lock.h>
10 #include <pal/atomic.h>
11
12 typedef struct _ChildListNode
13 {
14 struct _ChildListNode *left;
15 struct _ChildListNode *right;
16 GenericHandle clientHandle; /* Client handle for object so Cancel can be called on it */
17 }
18 ChildListNode;
19
20 typedef struct _ChildListOutstandingHandles
21 {
22 krisbash 1.1 GenericHandle clientHandle; /* Client handle for object so Cancel can be called on it */
23 GenericHandle *debugHandlePointer; /* Pointer of original for debugging purposes only, do not dereference it as it may be invalid */
24 }
25 ChildListOutstandingHandles;
26
27 typedef struct _ChildList
28 {
29 ChildListNode *headNode;
30 volatile ptrdiff_t childCount;
31 volatile MI_Boolean shutdown;
32 CachedLock lock;
33
34 void (*shutdownCompleteCallback)(void *context);
35 void *shutdownCompleteCallbackContext;
36 }
37 ChildList;
38
39 MI_INLINE MI_Result ChildList_Initialize(_Out_ ChildList *list)
40 {
41 memset(list, 0, sizeof(ChildList));
42 if (CachedLock_Init(&list->lock, CACHEDLOCK_FLAG_SHARED) == 0)
43 krisbash 1.1 {
44 return MI_RESULT_OK;
45 }
46 else
47 {
48 return MI_RESULT_SERVER_LIMITS_EXCEEDED;
49 }
50 }
51 MI_INLINE void ChildList_DeInitialize(_Inout_ ChildList *list)
52 {
53 CachedLock_Destroy(&list->lock);
54 }
55
56 MI_INLINE MI_Result ChildList_AddNode(_Inout_ ChildList *list, _Inout_ ChildListNode *newNode)
57 {
58 MI_Result retValue = MI_RESULT_OK;
59
60 if (!list->shutdown)
61 {
62 CachedLock_AcquireWrite(&list->lock);
63
64 krisbash 1.1 if (!list->shutdown)
65 {
66 Atomic_Inc(&list->childCount);
67
68 /* previous head point left points to new node */
69 if (list->headNode)
70 {
71 list->headNode->left = newNode;
72 }
73 /* new node point to previous head */
74 newNode->left = NULL;
75 newNode->right = list->headNode;
76
77 /* set list head node to new node */
78 list->headNode = newNode;
79 }
80 else
81 {
82 retValue = MI_RESULT_SERVER_IS_SHUTTING_DOWN;
83 }
84
85 krisbash 1.1 CachedLock_ReleaseWrite(&list->lock);
86 }
87 else
88 {
89 retValue = MI_RESULT_SERVER_IS_SHUTTING_DOWN;
90 }
91
92 return retValue;
93 }
94
95 MI_INLINE void ChildList_RemoveNode(_Inout_ ChildList *list, _In_ ChildListNode *removeNode)
96 {
97 int makeShutdownCallbackNow = 0;
98
99 CachedLock_AcquireWrite(&list->lock);
100
101 if (list->headNode == removeNode)
102 {
103 list->headNode = removeNode->right;
104 }
105 if (removeNode->left)
106 krisbash 1.1 {
107 removeNode->left->right = removeNode->right;
108 }
109 if (removeNode->right)
110 {
111 removeNode->right->left = removeNode->left;
112 }
113
114 if ((Atomic_Dec(&list->childCount) == 0) &&
115 list->shutdown &&
116 list->shutdownCompleteCallback)
117 {
118 makeShutdownCallbackNow = 1;
119 }
120
121 CachedLock_ReleaseWrite(&list->lock);
122
123 if (makeShutdownCallbackNow)
124 {
125 list->shutdownCompleteCallback(list->shutdownCompleteCallbackContext);
126 }
127 krisbash 1.1 }
128
129 /* Shutdown returns a list of generic handles that are still in the list. These are not pointers to th handles (except the debug pointer)
130 * so if the handle gets closed these handles will not cause a crashes
131 */
132 MI_INLINE int ChildList_Shutdown(_Inout_ ChildList *list)
133 {
134 int returnVal = 0;
135 CachedLock_AcquireWrite(&list->lock);
136
137 if (list->shutdown == MI_FALSE)
138 {
139 list->shutdown = MI_TRUE;
140 returnVal = 1;
141 }
142
143 CachedLock_ReleaseWrite(&list->lock);
144
145 return returnVal;
146 }
147
148 krisbash 1.1 _Success_(return == 1)
149 MI_INLINE int ChildList_GetCurrentList(_Inout_ ChildList *list, _Out_cap_post_count_(inboundSize, *outboundUsed) ChildListOutstandingHandles *outstandingHandles, ptrdiff_t inboundSize, _Out_ ptrdiff_t *outboundUsed)
150 {
151 int returnVal = 0;
152 CachedLock_AcquireWrite(&list->lock);
153
154 *outboundUsed = 0;
155
156 if (inboundSize >= list->childCount)
157 {
158 ChildListNode *currentNode = list->headNode;
159 (*outboundUsed) = 0;
160 while (currentNode &&
161 ((*outboundUsed) < inboundSize)) //redumbdant check to shut prefast up, it does not know list->childCount is how many items in list
162 {
163 outstandingHandles[*outboundUsed].clientHandle = currentNode->clientHandle;
164 outstandingHandles[*outboundUsed].debugHandlePointer = ¤tNode->clientHandle;
165
166 currentNode = currentNode->right;
167 (*outboundUsed) ++;
168 }
169 krisbash 1.1 if ((*outboundUsed) < inboundSize)
170 {
171 returnVal = 1;
172 }
173 else
174 {
175 //never happen!
176 (*outboundUsed) = 0;
177 }
178 }
179 else
180 {
181 *outboundUsed = list->childCount;
182 }
183
184 CachedLock_ReleaseWrite(&list->lock);
185
186 return returnVal;
187 }
188
189
190 krisbash 1.1 MI_INLINE void ChildList_RegisterShutdownCallback(
191 _Inout_ ChildList *list,
192 _In_ void (*shutdownCompleteCallback)(void *context),
193 _In_ void *shutdownCompleteCallbackContext)
194 {
195 int makeShutdownCallbackNow = 0;
196
197 CachedLock_AcquireWrite(&list->lock);
198
199 if ((list->shutdown == MI_TRUE) &&
200 (list->childCount == 0))
201 {
202 makeShutdownCallbackNow = 1;
203 }
204 else
205 {
206 list->shutdownCompleteCallbackContext = shutdownCompleteCallbackContext;
207 list->shutdownCompleteCallback = shutdownCompleteCallback;
208 }
209
210 CachedLock_ReleaseWrite(&list->lock);
211 krisbash 1.1
212 if (makeShutdownCallbackNow)
213 {
214 shutdownCompleteCallback(shutdownCompleteCallbackContext);
215 }
216
217 }
218 #endif /* _miapi_childlist_h_ */
|