2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
28 #define OVS_DBG_MOD OVS_DBG_EVENT
31 LIST_ENTRY ovsEventQueue;
32 static NDIS_SPIN_LOCK eventQueueLock;
33 UINT32 ovsNumEventQueue;
38 InitializeListHead(&ovsEventQueue);
39 NdisAllocateSpinLock(&eventQueueLock);
40 return STATUS_SUCCESS;
44 OvsCleanupEventQueue()
46 ASSERT(IsListEmpty(&ovsEventQueue));
47 ASSERT(ovsNumEventQueue == 0);
48 NdisFreeSpinLock(&eventQueueLock);
52 OvsAcquireEventQueueLock()
54 NdisAcquireSpinLock(&eventQueueLock);
58 OvsReleaseEventQueueLock()
60 NdisReleaseSpinLock(&eventQueueLock);
64 * --------------------------------------------------------------------------
65 * Cleanup the event queue of the OpenInstance.
66 * --------------------------------------------------------------------------
69 OvsCleanupEvent(POVS_OPEN_INSTANCE instance)
71 POVS_EVENT_QUEUE queue;
73 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
75 POVS_EVENT_QUEUE_ELEM elem;
76 PLIST_ENTRY link, next;
78 OvsAcquireEventQueueLock();
79 RemoveEntryList(&queue->queueLink);
81 if (queue->pendingIrp) {
82 PDRIVER_CANCEL cancelRoutine;
83 irp = queue->pendingIrp;
84 cancelRoutine = IoSetCancelRoutine(irp, NULL);
85 queue->pendingIrp = NULL;
86 if (cancelRoutine == NULL) {
90 instance->eventQueue = NULL;
91 OvsReleaseEventQueueLock();
93 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
96 LIST_FORALL_SAFE(&queue->elemList, link, next) {
97 elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link);
98 OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
100 OvsFreeMemoryWithTag(queue, OVS_EVENT_POOL_TAG);
105 * --------------------------------------------------------------------------
106 * When event is generated, we need to post the event to all
107 * the event queues. If there is pending Irp waiting for event
108 * complete the Irp to wakeup the user thread.
110 * Side effects: User thread may be woken up.
111 * --------------------------------------------------------------------------
114 OvsPostEvent(POVS_EVENT_ENTRY event)
116 POVS_EVENT_QUEUE_ELEM elem;
117 POVS_EVENT_QUEUE queue;
123 InitializeListHead(&list);
125 OVS_LOG_TRACE("Enter: portNo: %#x, status: %#x", event->portNo,
128 OvsAcquireEventQueueLock();
130 LIST_FORALL(&ovsEventQueue, link) {
131 queue = CONTAINING_RECORD(link, OVS_EVENT_QUEUE, queueLink);
132 if ((event->type & queue->mask) == 0) {
135 event->type &= queue->mask;
137 elem = (POVS_EVENT_QUEUE_ELEM)OvsAllocateMemoryWithTag(
138 sizeof(*elem), OVS_EVENT_POOL_TAG);
139 RtlCopyMemory(&elem->event, event, sizeof elem->event);
140 InsertTailList(&queue->elemList, &elem->link);
142 OVS_LOG_INFO("Queue: %p, numElems: %d",
143 queue, queue->numElems);
145 if (queue->pendingIrp != NULL) {
146 PDRIVER_CANCEL cancelRoutine;
147 irp = queue->pendingIrp;
148 queue->pendingIrp = NULL;
149 cancelRoutine = IoSetCancelRoutine(irp, NULL);
151 InsertTailList(&list, &irp->Tail.Overlay.ListEntry);
155 OvsReleaseEventQueueLock();
156 while (!IsListEmpty(&list)) {
157 entry = RemoveHeadList(&list);
158 irp = CONTAINING_RECORD(entry, IRP, Tail.Overlay.ListEntry);
159 OVS_LOG_INFO("Wakeup thread with IRP: %p", irp);
160 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
166 * --------------------------------------------------------------------------
167 * Subscribe for event notification.
170 * STATUS_SUCCESS for valid request and enough resource.
171 * STATUS_NO_RESOURCES for queue allocation failure
172 * STATUS_INVALID_PARAMETER for invalid request
175 * Event queue is created for the current open instance.
176 * --------------------------------------------------------------------------
179 OvsSubscribeEventIoctl(PFILE_OBJECT fileObject,
183 POVS_EVENT_SUBSCRIBE request = (POVS_EVENT_SUBSCRIBE)inputBuffer;
184 NTSTATUS status = STATUS_SUCCESS;
185 POVS_OPEN_INSTANCE instance;
186 POVS_EVENT_QUEUE queue = NULL;
188 OVS_LOG_TRACE("Enter: fileObject: %p, inputLength: %d", fileObject,
191 if (inputLength < sizeof (OVS_EVENT_SUBSCRIBE) ||
192 (request->mask & OVS_EVENT_MASK_ALL) == 0) {
193 OVS_LOG_TRACE("Exit: subscribe failed with invalid request.");
194 return STATUS_INVALID_PARAMETER;
197 OvsAcquireEventQueueLock();
199 instance = OvsGetOpenInstance(fileObject, request->dpNo);
201 if (instance == NULL) {
202 status = STATUS_INVALID_PARAMETER;
203 OVS_LOG_WARN("can not find open instance");
204 goto done_event_subscribe;
208 * XXX for now, we don't allow change mask.
210 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
211 if (request->subscribe && queue) {
212 if (queue->mask != request->mask) {
213 status = STATUS_INVALID_PARAMETER;
214 OVS_LOG_WARN("Can not chnage mask when the queue is subscribed");
216 status = STATUS_SUCCESS;
217 goto done_event_subscribe;
218 } else if (!request->subscribe && queue == NULL) {
219 status = STATUS_SUCCESS;
220 goto done_event_subscribe;
223 if (request->subscribe) {
224 queue = (POVS_EVENT_QUEUE)OvsAllocateMemoryWithTag(
225 sizeof(OVS_EVENT_QUEUE), OVS_EVENT_POOL_TAG);
227 status = STATUS_NO_MEMORY;
228 OVS_LOG_WARN("Fail to allocate event queue");
229 goto done_event_subscribe;
231 InitializeListHead(&queue->elemList);
232 queue->mask = request->mask;
233 queue->pendingIrp = NULL;
235 InsertHeadList(&ovsEventQueue, &queue->queueLink);
237 instance->eventQueue = queue;
238 queue->instance = instance;
240 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
241 RemoveEntryList(&queue->queueLink);
243 instance->eventQueue = NULL;
245 done_event_subscribe:
246 if (!request->subscribe && queue) {
247 POVS_EVENT_QUEUE_ELEM elem;
248 PLIST_ENTRY link, next;
250 if (queue->pendingIrp) {
251 PDRIVER_CANCEL cancelRoutine;
252 irp = queue->pendingIrp;
253 queue->pendingIrp = NULL;
254 cancelRoutine = IoSetCancelRoutine(irp, NULL);
255 if (cancelRoutine == NULL) {
259 OvsReleaseEventQueueLock();
261 OvsCompleteIrpRequest(queue->pendingIrp, 0, STATUS_SUCCESS);
263 LIST_FORALL_SAFE(&queue->elemList, link, next) {
264 elem = CONTAINING_RECORD(link, OVS_EVENT_QUEUE_ELEM, link);
265 OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
267 OvsFreeMemoryWithTag(queue, OVS_EVENT_POOL_TAG);
269 OvsReleaseEventQueueLock();
271 OVS_LOG_TRACE("Exit: subscribe event with status: %#x.", status);
276 * --------------------------------------------------------------------------
277 * Cancel wait IRP for event
279 * Please note, when this routine is called, it is always guaranteed that
282 * Side effects: Pending IRP is completed.
283 * --------------------------------------------------------------------------
286 OvsCancelIrp(PDEVICE_OBJECT deviceObject,
289 PIO_STACK_LOCATION irpSp;
290 PFILE_OBJECT fileObject;
291 POVS_EVENT_QUEUE queue;
292 POVS_OPEN_INSTANCE instance;
294 UNREFERENCED_PARAMETER(deviceObject);
296 IoReleaseCancelSpinLock(irp->CancelIrql);
298 irpSp = IoGetCurrentIrpStackLocation(irp);
299 fileObject = irpSp->FileObject;
301 if (fileObject == NULL) {
304 OvsAcquireEventQueueLock();
305 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
306 if (instance == NULL || instance->eventQueue == NULL) {
307 OvsReleaseEventQueueLock();
310 queue = instance->eventQueue;
311 if (queue->pendingIrp == irp) {
312 queue->pendingIrp = NULL;
314 OvsReleaseEventQueueLock();
316 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
320 * --------------------------------------------------------------------------
324 * STATUS_SUCCESS for valid request
325 * STATUS_DEVICE_BUSY if already in waiting state.
326 * STATUS_INVALID_PARAMETER for invalid request
327 * STATUS_PENDING wait for event
330 * May return pending to IO manager.
331 * --------------------------------------------------------------------------
334 OvsWaitEventIoctl(PIRP irp,
335 PFILE_OBJECT fileObject,
339 NTSTATUS status = STATUS_SUCCESS;
340 POVS_EVENT_POLL poll;
341 POVS_EVENT_QUEUE queue;
342 POVS_OPEN_INSTANCE instance;
343 BOOLEAN cancelled = FALSE;
344 PDRIVER_CANCEL cancelRoutine;
346 OVS_LOG_TRACE("Enter: inputLength: %u", inputLength);
348 if (inputLength < sizeof (OVS_EVENT_POLL)) {
349 OVS_LOG_TRACE("Exit: Invalid input buffer length.");
350 return STATUS_INVALID_PARAMETER;
352 poll = (POVS_EVENT_POLL)inputBuffer;
354 OvsAcquireEventQueueLock();
356 instance = OvsGetOpenInstance(fileObject, poll->dpNo);
357 if (instance == NULL) {
358 OVS_LOG_TRACE("Exit: Can not find open instance, dpNo: %d",
360 return STATUS_INVALID_PARAMETER;
363 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
365 OVS_LOG_TRACE("Exit: Event queue does not exist");
366 status = STATUS_INVALID_PARAMETER;
369 if (queue->pendingIrp) {
370 OVS_LOG_TRACE("Exit: Event queue already in pending state");
371 status = STATUS_DEVICE_BUSY;
375 IoMarkIrpPending(irp);
376 IoSetCancelRoutine(irp, OvsCancelIrp);
378 cancelRoutine = IoSetCancelRoutine(irp, NULL);
383 queue->pendingIrp = irp;
384 status = STATUS_PENDING;
388 OvsReleaseEventQueueLock();
390 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
391 OVS_LOG_INFO("Event IRP cancelled: %p", irp);
393 OVS_LOG_TRACE("Exit: return status: %#x", status);
398 *--------------------------------------------------------------------------
399 * Poll event queued in the event queue.always synchronous.
402 * STATUS_SUCCESS event was dequeued
403 * STATUS_UNSUCCESSFUL the queue is empty.
404 * --------------------------------------------------------------------------
407 OvsRemoveEventEntry(POVS_OPEN_INSTANCE instance,
408 POVS_EVENT_ENTRY entry)
410 NTSTATUS status = STATUS_UNSUCCESSFUL;
411 POVS_EVENT_QUEUE queue;
412 POVS_EVENT_QUEUE_ELEM elem;
414 OvsAcquireEventQueueLock();
416 queue = (POVS_EVENT_QUEUE)instance->eventQueue;
420 goto remove_event_done;
423 if (queue->numElems) {
424 elem = (POVS_EVENT_QUEUE_ELEM)RemoveHeadList(&queue->elemList);
425 *entry = elem->event;
426 OvsFreeMemoryWithTag(elem, OVS_EVENT_POOL_TAG);
428 status = STATUS_SUCCESS;
432 OvsReleaseEventQueueLock();