librdmacm: fix event reporting when destroying listen
[mirror/winof/.git] / etc / user / comp_channel.cpp
1 /*\r
2  * Copyright (c) 2008, 2009 Intel Corporation.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  */\r
29 \r
30 #include <comp_channel.h>\r
31 #include <process.h>\r
32 \r
33 static void CompManagerQueue(COMP_MANAGER *pMgr, COMP_ENTRY *pEntry);\r
34 static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry);\r
35 \r
36 \r
37 /*\r
38  * Completion manager\r
39  */\r
40 \r
41 static unsigned __stdcall CompThreadPoll(void *Context)\r
42 {\r
43         COMP_MANAGER *mgr = (COMP_MANAGER *) Context;\r
44         COMP_ENTRY *entry;\r
45         OVERLAPPED *overlap;\r
46         DWORD bytes;\r
47         ULONG_PTR key;\r
48 \r
49         while (mgr->Run) {\r
50                 GetQueuedCompletionStatus(mgr->CompQueue, &bytes, &key,\r
51                                                                   &overlap, INFINITE);\r
52                 entry = CONTAINING_RECORD(overlap, COMP_ENTRY, Overlap);\r
53 \r
54                 if (entry->Channel) {\r
55                         CompChannelQueue(entry->Channel, entry);\r
56                 } else {\r
57                         CompManagerQueue(mgr, entry);\r
58                 }\r
59         }\r
60 \r
61         _endthreadex(0);\r
62         return 0;\r
63 }\r
64 \r
65 DWORD CompManagerOpen(COMP_MANAGER *pMgr)\r
66 {\r
67         DWORD ret;\r
68 \r
69         InitializeCriticalSection(&pMgr->Lock);\r
70         pMgr->Busy = 0;\r
71         DListInit(&pMgr->DoneList);\r
72         CompEntryInit(NULL, &pMgr->Entry);\r
73 \r
74         pMgr->CompQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, -1);\r
75         if (pMgr->CompQueue == NULL) {\r
76                 ret = GetLastError();\r
77                 goto err1;\r
78         }\r
79 \r
80         pMgr->Event = CreateEvent(NULL, TRUE, TRUE, NULL);\r
81         if (pMgr->Event == NULL) {\r
82                 ret = GetLastError();\r
83                 goto err2;\r
84         }\r
85 \r
86         pMgr->Run = TRUE;\r
87         pMgr->Thread = (HANDLE) _beginthreadex(NULL, 0, CompThreadPoll, pMgr, 0, NULL);\r
88         if (pMgr->Thread == NULL) {\r
89                 ret = GetLastError();\r
90                 goto err3;\r
91         }\r
92         return 0;\r
93 \r
94 err3:\r
95         CloseHandle(pMgr->Event);\r
96 err2:\r
97         CloseHandle(pMgr->CompQueue);\r
98 err1:\r
99         DeleteCriticalSection(&pMgr->Lock);     \r
100         return ret;\r
101 }\r
102 \r
103 void CompManagerClose(COMP_MANAGER *pMgr)\r
104 {\r
105         pMgr->Run = FALSE;\r
106         CompManagerCancel(pMgr);\r
107         WaitForSingleObject(pMgr->Thread, INFINITE);\r
108         CloseHandle(pMgr->Thread);\r
109 \r
110         CloseHandle(pMgr->CompQueue);\r
111         CloseHandle(pMgr->Event);\r
112         DeleteCriticalSection(&pMgr->Lock);     \r
113 }\r
114 \r
115 DWORD CompManagerMonitor(COMP_MANAGER *pMgr, HANDLE hFile, ULONG_PTR Key)\r
116 {\r
117         HANDLE cq;\r
118 \r
119         cq = CreateIoCompletionPort(hFile, pMgr->CompQueue, Key, 0);\r
120         return (cq == NULL) ? GetLastError() : 0;\r
121 }\r
122 \r
123 static void CompManagerQueue(COMP_MANAGER *pMgr, COMP_ENTRY *pEntry)\r
124 {\r
125         EnterCriticalSection(&pMgr->Lock);\r
126         DListInsertTail(&pEntry->MgrEntry, &pMgr->DoneList);\r
127         SetEvent(pMgr->Event);\r
128         LeaveCriticalSection(&pMgr->Lock);\r
129 }\r
130 \r
131 static void CompManagerRemoveEntry(COMP_MANAGER *pMgr, COMP_ENTRY *pEntry)\r
132 {\r
133         EnterCriticalSection(&pMgr->Lock);\r
134         DListRemove(&pEntry->MgrEntry);\r
135         LeaveCriticalSection(&pMgr->Lock);\r
136 }\r
137 \r
138 DWORD CompManagerPoll(COMP_MANAGER *pMgr, DWORD Milliseconds,\r
139                                           COMP_CHANNEL **ppChannel)\r
140 {\r
141         COMP_ENTRY *entry;\r
142         DWORD ret = 0;\r
143 \r
144         EnterCriticalSection(&pMgr->Lock);\r
145         while (DListEmpty(&pMgr->DoneList)) {\r
146                 ResetEvent(pMgr->Event);\r
147                 LeaveCriticalSection(&pMgr->Lock);\r
148         \r
149                 ret = WaitForSingleObject(pMgr->Event, Milliseconds);\r
150                 if (ret) {\r
151                         return ret;\r
152                 }\r
153 \r
154                 EnterCriticalSection(&pMgr->Lock);\r
155         }\r
156 \r
157         entry = CONTAINING_RECORD(pMgr->DoneList.Next, COMP_ENTRY, MgrEntry);\r
158         *ppChannel = entry->Channel;\r
159         if (entry->Channel == NULL) {\r
160                 DListRemove(&entry->MgrEntry);\r
161                 InterlockedExchange(&entry->Busy, 0);\r
162                 ret = ERROR_CANCELLED;\r
163         }\r
164         LeaveCriticalSection(&pMgr->Lock);\r
165 \r
166         return ret;\r
167 }\r
168 \r
169 void CompManagerCancel(COMP_MANAGER *pMgr)\r
170 {\r
171         if (InterlockedCompareExchange(&pMgr->Entry.Busy, 1, 0) == 0) {\r
172                 PostQueuedCompletionStatus(pMgr->CompQueue, 0, (ULONG_PTR) pMgr,\r
173                                                                    &pMgr->Entry.Overlap);\r
174         }\r
175 }\r
176 \r
177 \r
178 /*\r
179  * Completion channel\r
180  */\r
181 \r
182 DWORD CompChannelInit(COMP_MANAGER *pMgr, COMP_CHANNEL *pChannel, DWORD Milliseconds)\r
183 {\r
184         pChannel->Manager = pMgr;\r
185         pChannel->Head = NULL;\r
186         pChannel->TailPtr = &pChannel->Head;\r
187         pChannel->Milliseconds = Milliseconds;\r
188 \r
189         pChannel->Event = CreateEvent(NULL, TRUE, TRUE, NULL);\r
190         if (pChannel->Event == NULL) {\r
191                 return GetLastError();\r
192         }\r
193 \r
194         InitializeCriticalSection(&pChannel->Lock);\r
195         CompEntryInit(pChannel, &pChannel->Entry);\r
196         return 0;\r
197 }\r
198 \r
199 void CompChannelCleanup(COMP_CHANNEL *pChannel)\r
200 {\r
201         CloseHandle(pChannel->Event);\r
202         DeleteCriticalSection(&pChannel->Lock); \r
203 }\r
204 \r
205 static void CompChannelInsertTail(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
206 {\r
207         *pChannel->TailPtr = pEntry;\r
208         pChannel->TailPtr = &pEntry->Next;\r
209 }\r
210 \r
211 static COMP_ENTRY *CompChannelRemoveHead(COMP_CHANNEL *pChannel)\r
212 {\r
213         COMP_ENTRY *entry;\r
214 \r
215         entry = pChannel->Head;\r
216         pChannel->Head = entry->Next;\r
217         if (pChannel->Head == NULL) {\r
218                 pChannel->TailPtr = &pChannel->Head;\r
219         }\r
220         return entry;\r
221 }\r
222 \r
223 static COMP_ENTRY *CompChannelFindRemove(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
224 {\r
225         COMP_ENTRY **entry_ptr, *entry;\r
226 \r
227         EnterCriticalSection(&pChannel->Lock);\r
228         entry_ptr = &pChannel->Head;\r
229         while (*entry_ptr && *entry_ptr != pEntry) {\r
230                 entry_ptr = &(*entry_ptr)->Next;\r
231         }\r
232 \r
233         entry = *entry_ptr;\r
234         if (entry != NULL) {\r
235                 *entry_ptr = pEntry->Next;\r
236                 if (pChannel->TailPtr == &pEntry->Next) {\r
237                         pChannel->TailPtr = entry_ptr;\r
238                 }\r
239                 CompManagerRemoveEntry(pChannel->Manager, pEntry);\r
240                 InterlockedExchange(&pEntry->Busy, 0);\r
241         }\r
242         LeaveCriticalSection(&pChannel->Lock);\r
243         return entry;\r
244 }\r
245 \r
246 static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
247 {\r
248         pEntry->Next = NULL;\r
249         EnterCriticalSection(&pChannel->Lock);\r
250         CompManagerQueue(pChannel->Manager, pEntry);\r
251         CompChannelInsertTail(pChannel, pEntry);\r
252         SetEvent(pChannel->Event);\r
253         LeaveCriticalSection(&pChannel->Lock);\r
254 }\r
255 \r
256 DWORD CompChannelPoll(COMP_CHANNEL *pChannel, COMP_ENTRY **ppEntry)\r
257 {\r
258         COMP_ENTRY *entry;\r
259         DWORD ret;\r
260 \r
261         EnterCriticalSection(&pChannel->Lock);\r
262         while (pChannel->Head == NULL) {\r
263                 ResetEvent(pChannel->Event);\r
264                 LeaveCriticalSection(&pChannel->Lock);\r
265 \r
266                 ret = WaitForSingleObject(pChannel->Event, pChannel->Milliseconds);\r
267                 if (ret) {\r
268                         return ret;\r
269                 }\r
270 \r
271                 EnterCriticalSection(&pChannel->Lock);\r
272         }\r
273         entry = CompChannelRemoveHead(pChannel);\r
274         CompManagerRemoveEntry(pChannel->Manager, entry);\r
275         LeaveCriticalSection(&pChannel->Lock);\r
276 \r
277         InterlockedExchange(&entry->Busy, 0);\r
278         *ppEntry = entry;\r
279         ret = (entry == &pChannel->Entry) ? ERROR_CANCELLED : 0;\r
280 \r
281         return ret;\r
282 }\r
283 \r
284 void CompChannelCancel(COMP_CHANNEL *pChannel)\r
285 {\r
286         if (InterlockedCompareExchange(&pChannel->Entry.Busy, 1, 0) == 0) {\r
287                 PostQueuedCompletionStatus(pChannel->Manager->CompQueue, 0,\r
288                                                                    (ULONG_PTR) pChannel, &pChannel->Entry.Overlap);\r
289         }\r
290 }\r
291 \r
292 \r
293 /*\r
294  * Completion entry\r
295  */\r
296 \r
297 void CompEntryInit(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
298 {\r
299         RtlZeroMemory(pEntry, sizeof *pEntry);\r
300         pEntry->Channel = pChannel;\r
301 }\r
302 \r
303 DWORD CompEntryPost(COMP_ENTRY *pEntry)\r
304 {\r
305         if (InterlockedCompareExchange(&pEntry->Busy, 1, 0) == 0) {\r
306                 if (!PostQueuedCompletionStatus(pEntry->Channel->Manager->CompQueue,\r
307                                                                                 0, 0, &pEntry->Overlap)) {\r
308                         InterlockedExchange(&pEntry->Busy, 0);\r
309                         return GetLastError();\r
310                 }\r
311         }\r
312         return 0;\r
313 }\r
314 \r
315 COMP_ENTRY *CompEntryCancel(COMP_ENTRY *pEntry)\r
316 {\r
317         COMP_ENTRY *entry = NULL;\r
318 \r
319         while (pEntry->Busy) {\r
320                 Sleep(0);\r
321                 entry = CompChannelFindRemove(pEntry->Channel, pEntry);\r
322         }\r
323         return entry;\r
324 }\r