[BUS] prevent disable operation from firing ref count ASSERT(). Clear hca field so...
[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 \r
32 static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry);\r
33 \r
34 DWORD CompManagerOpen(COMP_MANAGER *pMgr)\r
35 {\r
36         pMgr->CompQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, -1);\r
37         if (pMgr->CompQueue == NULL) {\r
38                 return GetLastError();\r
39         }\r
40 \r
41         pMgr->Event = CreateEvent(NULL, TRUE, TRUE, NULL);\r
42         if (pMgr->Event == NULL) {\r
43                 return GetLastError();\r
44         }\r
45 \r
46         pMgr->Lock = 0;\r
47         return 0;\r
48 }\r
49 \r
50 void CompManagerClose(COMP_MANAGER *pMgr)\r
51 {\r
52         CloseHandle(pMgr->CompQueue);\r
53         CloseHandle(pMgr->Event);\r
54 }\r
55 \r
56 DWORD CompManagerMonitor(COMP_MANAGER *pMgr, HANDLE hFile, ULONG_PTR Key)\r
57 {\r
58         HANDLE cq;\r
59 \r
60         cq = CreateIoCompletionPort(hFile, pMgr->CompQueue, Key, 0);\r
61         return (cq == NULL) ? GetLastError() : 0;\r
62 }\r
63 \r
64 DWORD CompManagerPoll(COMP_MANAGER *pMgr, DWORD Milliseconds,\r
65                                           COMP_CHANNEL **ppChannel)\r
66 {\r
67         COMP_ENTRY *entry;\r
68         OVERLAPPED *overlap;\r
69         DWORD bytes, ret;\r
70         ULONG_PTR key;\r
71 \r
72         if (GetQueuedCompletionStatus(pMgr->CompQueue, &bytes, &key, &overlap,\r
73                                                                   Milliseconds)) {\r
74                 entry = CONTAINING_RECORD(overlap, COMP_ENTRY, Overlap);\r
75                 *ppChannel = entry->Channel;\r
76                 CompChannelQueue(entry->Channel, entry);\r
77                 ret = 0;\r
78         } else {\r
79                 ret = GetLastError();\r
80         }\r
81         return ret;\r
82 }\r
83 \r
84 \r
85 void CompChannelInit(COMP_MANAGER *pMgr, COMP_CHANNEL *pChannel, DWORD Milliseconds)\r
86 {\r
87         pChannel->Manager = pMgr;\r
88         pChannel->Head = NULL;\r
89         pChannel->TailPtr = &pChannel->Head;\r
90         InitializeCriticalSection(&pChannel->Lock);\r
91         pChannel->Milliseconds = Milliseconds;\r
92 }\r
93 \r
94 void CompChannelCleanup(COMP_CHANNEL *pChannel)\r
95 {\r
96         DeleteCriticalSection(&pChannel->Lock); \r
97 }\r
98 \r
99 static void CompChannelInsertTail(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
100 {\r
101         *pChannel->TailPtr = pEntry;\r
102         pChannel->TailPtr = &pEntry->Next;\r
103 }\r
104 \r
105 static COMP_ENTRY *CompChannelRemoveHead(COMP_CHANNEL *pChannel)\r
106 {\r
107         COMP_ENTRY *entry;\r
108 \r
109         entry = pChannel->Head;\r
110         pChannel->Head = entry->Next;\r
111         if (pChannel->Head == NULL) {\r
112                 pChannel->TailPtr = &pChannel->Head;\r
113         }\r
114         return entry;\r
115 }\r
116 \r
117 static void CompChannelQueue(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
118 {\r
119         pEntry->Next = NULL;\r
120         EnterCriticalSection(&pChannel->Lock);\r
121         CompChannelInsertTail(pChannel, pEntry);\r
122         LeaveCriticalSection(&pChannel->Lock);\r
123 }\r
124 \r
125 DWORD CompChannelPoll(COMP_CHANNEL *pChannel, COMP_ENTRY **ppEntry)\r
126 {\r
127         COMP_MANAGER *mgr = pChannel->Manager;\r
128         COMP_CHANNEL *chan;\r
129         DWORD ret = 0;\r
130         ULONG locked;\r
131 \r
132         EnterCriticalSection(&pChannel->Lock);\r
133         while (pChannel->Head == NULL) {\r
134                 LeaveCriticalSection(&pChannel->Lock);\r
135 \r
136                 locked = InterlockedCompareExchange(&mgr->Lock, 1, 0);\r
137                 if (locked == 0) {\r
138                         ResetEvent(mgr->Event);\r
139                         ret = CompManagerPoll(mgr, pChannel->Milliseconds, &chan);\r
140                         InterlockedExchange(&mgr->Lock, 0);\r
141                         SetEvent(mgr->Event);\r
142                 } else {\r
143                         ret = WaitForSingleObject(mgr->Event, pChannel->Milliseconds);\r
144                 }\r
145                 if (ret) {\r
146                         goto out;\r
147                 }\r
148 \r
149                 EnterCriticalSection(&pChannel->Lock);\r
150         }\r
151         *ppEntry = CompChannelRemoveHead(pChannel);\r
152         LeaveCriticalSection(&pChannel->Lock);\r
153 \r
154 out:\r
155         return ret;\r
156 }\r
157 \r
158 void CompChannelRemoveEntry(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
159 {\r
160         COMP_CHANNEL *chan;\r
161         COMP_ENTRY **entry_ptr;\r
162         DWORD ret;\r
163 \r
164         do {\r
165                 ret = CompManagerPoll(pChannel->Manager, 0, &chan);\r
166         } while (!ret);\r
167         SetEvent(pChannel->Manager->Event);\r
168 \r
169         EnterCriticalSection(&pChannel->Lock);\r
170         entry_ptr = &pChannel->Head;\r
171         while (*entry_ptr && *entry_ptr != pEntry) {\r
172                 entry_ptr = &(*entry_ptr)->Next;\r
173         }\r
174 \r
175         if (*entry_ptr != NULL) {\r
176                 *entry_ptr = pEntry->Next;\r
177                 if (pChannel->TailPtr == &pEntry->Next) {\r
178                         pChannel->TailPtr = entry_ptr;\r
179                 }\r
180         }\r
181         LeaveCriticalSection(&pChannel->Lock);\r
182 }\r
183 \r
184 void CompEntryInit(COMP_CHANNEL *pChannel, COMP_ENTRY *pEntry)\r
185 {\r
186         pEntry->Channel = pChannel;\r
187 }\r
188 \r
189 DWORD CompEntryPost(COMP_ENTRY *pEntry)\r
190 {\r
191         if (PostQueuedCompletionStatus(pEntry->Channel->Manager->CompQueue, 0, 0,\r
192                                                                    &pEntry->Overlap)) {\r
193                 return 0;\r
194         } else {\r
195                 return GetLastError();\r
196         }\r
197 }\r