#include "vmciQueuePair.h"
#include "vmciRoute.h"
+
/*
* VMCIQPair
*
uint32 flags;
VMCIPrivilegeFlags privFlags;
Bool guestEndpoint;
+ uint32 blocked;
+ VMCIEvent event;
};
static int VMCIQPairMapQueueHeaders(VMCIQueue *produceQ, VMCIQueue *consumeQ);
+static int VMCIQPairGetQueueHeaders(const VMCIQPair *qpair,
+ VMCIQueueHeader **produceQHeader,
+ VMCIQueueHeader **consumeQHeader);
+static int VMCIQPairWakeupCB(void *clientData);
+static int VMCIQPairReleaseMutexCB(void *clientData);
+static Bool VMCIQPairWaitForReadyQueue(VMCIQPair *qpair);
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPair_Lock --
+ *
+ * Helper routine that will lock the QPair before subsequent operations.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May block.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQPairLock(const VMCIQPair *qpair) // IN
+{
+#if !defined VMX86_VMX
+ VMCI_AcquireQueueMutex(qpair->produceQ);
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPair_Unlock --
+ *
+ * Helper routine that will unlock the QPair after various operations.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static INLINE void
+VMCIQPairUnlock(const VMCIQPair *qpair) // IN
+{
+#if !defined VMX86_VMX
+ VMCI_ReleaseQueueMutex(qpair->produceQ);
+#endif
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPairGetQueueHeaders --
+ *
+ * Helper routine that will retrieve the produce and consume
+ * headers of a given queue pair. If the guest memory of the
+ * queue pair is currently not available, the saved queue headers
+ * will be returned, if these are available.
+ *
+ * Results:
+ * VMCI_SUCCESS if either current or saved queue headers are found.
+ * Appropriate error code otherwise.
+ *
+ * Side effects:
+ * May block.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VMCIQPairGetQueueHeaders(const VMCIQPair *qpair, // IN
+ VMCIQueueHeader **produceQHeader, // OUT
+ VMCIQueueHeader **consumeQHeader) // OUT
+{
+ int result;
+
+ result = VMCIQPairMapQueueHeaders(qpair->produceQ, qpair->consumeQ);
+ if (result == VMCI_SUCCESS) {
+ *produceQHeader = qpair->produceQ->qHeader;
+ *consumeQHeader = qpair->consumeQ->qHeader;
+ } else if (qpair->produceQ->savedHeader && qpair->consumeQ->savedHeader) {
+ ASSERT(!qpair->guestEndpoint);
+ *produceQHeader = qpair->produceQ->savedHeader;
+ *consumeQHeader = qpair->consumeQ->savedHeader;
+ result = VMCI_SUCCESS;
+ }
+
+ return result;
+}
-#define VMCI_QPAIR_NO_QUEUE(_qp) (VMCIQPairMapQueueHeaders(_qp->produceQ, \
- _qp->consumeQ) != VMCI_SUCCESS)
/*
*-----------------------------------------------------------------------------
* VMCI_SUCCESS if queues were validated, appropriate error code otherwise.
*
* Side effects:
- * Windows blocking call.
+ * May attempt to map in guest memory.
*
*-----------------------------------------------------------------------------
*/
if (NULL == produceQ->qHeader || NULL == consumeQ->qHeader) {
result = VMCIHost_MapQueueHeaders(produceQ, consumeQ);
if (result < VMCI_SUCCESS) {
- return result;
+ if (produceQ->savedHeader && consumeQ->savedHeader) {
+ return VMCI_ERROR_QUEUEPAIR_NOT_READY;
+ } else {
+ return VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+ }
}
}
}
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPairWakeupCB --
+ *
+ * Callback from VMCI queue pair broker indicating that a queue
+ * pair that was previously not ready, now either is ready or
+ * gone forever.
+ *
+ * Results:
+ * VMCI_SUCCESS always.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VMCIQPairWakeupCB(void *clientData)
+{
+ VMCIQPair *qpair = (VMCIQPair *)clientData;
+ ASSERT(qpair);
+
+ VMCIQPairLock(qpair);
+ while (qpair->blocked > 0) {
+ qpair->blocked--;
+ VMCI_SignalEvent(&qpair->event);
+ }
+ VMCIQPairUnlock(qpair);
+
+ return VMCI_SUCCESS;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPairReleaseMutexCB --
+ *
+ * Callback from VMCI_WaitOnEvent releasing the queue pair mutex
+ * protecting the queue pair header state.
+ *
+ * Results:
+ * 0 always.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+VMCIQPairReleaseMutexCB(void *clientData)
+{
+ VMCIQPair *qpair = (VMCIQPair *)clientData;
+ ASSERT(qpair);
+ VMCIQPairUnlock(qpair);
+ return 0;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * VMCIQPairWaitForReadyQueue --
+ *
+ * Makes the calling thread wait for the queue pair to become
+ * ready for host side access.
+ *
+ * Results:
+ * TRUE when thread is woken up after queue pair state change.
+ * FALSE otherwise.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static Bool
+VMCIQPairWaitForReadyQueue(VMCIQPair *qpair)
+{
+ if (UNLIKELY(qpair->guestEndpoint)) {
+ ASSERT(FALSE);
+ return FALSE;
+ }
+ if (qpair->flags & VMCI_QPFLAG_NONBLOCK) {
+ return FALSE;
+ }
+ qpair->blocked++;
+ VMCI_WaitOnEvent(&qpair->event, VMCIQPairReleaseMutexCB, qpair);
+ VMCIQPairLock(qpair);
+ return TRUE;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
VMCIHandle src = VMCI_INVALID_HANDLE;
VMCIHandle dst = VMCI_MAKE_HANDLE(peer, VMCI_INVALID_ID);
VMCIRoute route;
+ VMCIEventReleaseCB wakeupCB;
+ void *clientData;
/*
* Restrict the size of a queuepair. The device already enforces a limit
myQPair->peer = peer;
myQPair->flags = flags;
myQPair->privFlags = privFlags;
-
retval = VMCI_Route(&src, &dst, FALSE, &route);
if (retval < VMCI_SUCCESS) {
if (VMCI_GuestPersonalityActive()) {
}
}
+ wakeupCB = clientData = NULL;
if (VMCI_ROUTE_AS_HOST == route) {
myQPair->guestEndpoint = FALSE;
+ if (!(flags & VMCI_QPFLAG_LOCAL)) {
+ myQPair->blocked = 0;
+ VMCI_CreateEvent(&myQPair->event);
+ wakeupCB = VMCIQPairWakeupCB;
+ clientData = (void *)myQPair;
+ }
} else {
myQPair->guestEndpoint = TRUE;
}
myQPair->peer,
myQPair->flags,
myQPair->privFlags,
- myQPair->guestEndpoint);
+ myQPair->guestEndpoint,
+ wakeupCB,
+ clientData);
if (retval < VMCI_SUCCESS) {
+ if (VMCI_ROUTE_AS_HOST == route && !(flags & VMCI_QPFLAG_LOCAL)) {
+ VMCI_DestroyEvent(&myQPair->event);
+ }
VMCI_FreeKernelMem(myQPair, sizeof *myQPair);
return retval;
}
* there isn't much the caller can do, and we don't want to leak.
*/
+ if (!(oldQPair->guestEndpoint || (oldQPair->flags & VMCI_QPFLAG_LOCAL))) {
+ VMCI_DestroyEvent(&oldQPair->event);
+ }
memset(oldQPair, 0, sizeof *oldQPair);
oldQPair->handle = VMCI_INVALID_HANDLE;
oldQPair->peer = VMCI_INVALID_ID;
}
-/*
- * "Windows blocking call."
- *
- * Note that on the Windows platform, kernel module clients may
- * block when calling into any these rouintes. The reason is
- * that a mutex has to be acquired in order to view/modify the
- * VMCIQueue structure fields: pointers, handle, and buffer data.
- * However, other platforms don't require the acquisition of a
- * mutex and thus don't block.
- */
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPair_Lock --
- *
- * Helper routine that will lock the QPair before subsequent operations.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Windows blocking call.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIQPairLock(const VMCIQPair *qpair) // IN
-{
-#if !defined VMX86_VMX
- VMCI_AcquireQueueMutex(qpair->produceQ);
-#endif
-}
-
-
-/*
- *-----------------------------------------------------------------------------
- *
- * VMCIQPair_Unlock --
- *
- * Helper routine that will unlock the QPair after various operations.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *-----------------------------------------------------------------------------
- */
-
-static INLINE void
-VMCIQPairUnlock(const VMCIQPair *qpair) // IN
-{
-#if !defined VMX86_VMX
- VMCI_ReleaseQueueMutex(qpair->produceQ);
-#endif
-}
-
-
/*
*-----------------------------------------------------------------------------
*
uint64 *producerTail, // OUT
uint64 *consumerHead) // OUT
{
+ VMCIQueueHeader *produceQHeader;
+ VMCIQueueHeader *consumeQHeader;
int result;
if (!qpair) {
}
VMCIQPairLock(qpair);
-
- if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
- result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
- } else {
- VMCIQueueHeader_GetPointers(qpair->produceQ->qHeader,
- qpair->consumeQ->qHeader,
- producerTail,
- consumerHead);
- result = VMCI_SUCCESS;
+ result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
+ if (result == VMCI_SUCCESS) {
+ VMCIQueueHeader_GetPointers(produceQHeader, consumeQHeader,
+ producerTail, consumerHead);
}
-
VMCIQPairUnlock(qpair);
if (result == VMCI_SUCCESS &&
uint64 *consumerTail, // OUT
uint64 *producerHead) // OUT
{
+ VMCIQueueHeader *produceQHeader;
+ VMCIQueueHeader *consumeQHeader;
int result;
if (!qpair) {
}
VMCIQPairLock(qpair);
-
- if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
- result = VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
- } else {
- VMCIQueueHeader_GetPointers(qpair->consumeQ->qHeader,
- qpair->produceQ->qHeader,
- consumerTail,
- producerHead);
- result = VMCI_SUCCESS;
+ result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
+ if (result == VMCI_SUCCESS) {
+ VMCIQueueHeader_GetPointers(consumeQHeader, produceQHeader,
+ consumerTail, producerHead);
}
-
VMCIQPairUnlock(qpair);
if (result == VMCI_SUCCESS &&
int64
VMCIQPair_ProduceFreeSpace(const VMCIQPair *qpair) // IN
{
+ VMCIQueueHeader *produceQHeader;
+ VMCIQueueHeader *consumeQHeader;
int64 result;
if (!qpair) {
}
VMCIQPairLock(qpair);
-
- if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
- result = 0;
- } else {
- result = VMCIQueueHeader_FreeSpace(qpair->produceQ->qHeader,
- qpair->consumeQ->qHeader,
+ result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
+ if (result == VMCI_SUCCESS) {
+ result = VMCIQueueHeader_FreeSpace(produceQHeader, consumeQHeader,
qpair->produceQSize);
+ } else {
+ result = 0;
}
-
VMCIQPairUnlock(qpair);
return result;
int64
VMCIQPair_ConsumeFreeSpace(const VMCIQPair *qpair) // IN
{
+ VMCIQueueHeader *produceQHeader;
+ VMCIQueueHeader *consumeQHeader;
int64 result;
if (!qpair) {
}
VMCIQPairLock(qpair);
-
- if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
- result = 0;
- } else {
- result = VMCIQueueHeader_FreeSpace(qpair->consumeQ->qHeader,
- qpair->produceQ->qHeader,
+ result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
+ if (result == VMCI_SUCCESS) {
+ result = VMCIQueueHeader_FreeSpace(consumeQHeader, produceQHeader,
qpair->consumeQSize);
+ } else {
+ result = 0;
}
-
VMCIQPairUnlock(qpair);
return result;
int64
VMCIQPair_ProduceBufReady(const VMCIQPair *qpair) // IN
{
+ VMCIQueueHeader *produceQHeader;
+ VMCIQueueHeader *consumeQHeader;
int64 result;
if (!qpair) {
}
VMCIQPairLock(qpair);
-
- if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
- result = 0;
- } else {
- result = VMCIQueueHeader_BufReady(qpair->produceQ->qHeader,
- qpair->consumeQ->qHeader,
+ result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
+ if (result == VMCI_SUCCESS) {
+ result = VMCIQueueHeader_BufReady(produceQHeader, consumeQHeader,
qpair->produceQSize);
+ } else {
+ result = 0;
}
-
VMCIQPairUnlock(qpair);
return result;
int64
VMCIQPair_ConsumeBufReady(const VMCIQPair *qpair) // IN
{
+ VMCIQueueHeader *produceQHeader;
+ VMCIQueueHeader *consumeQHeader;
int64 result;
if (!qpair) {
}
VMCIQPairLock(qpair);
-
- if (UNLIKELY(VMCI_QPAIR_NO_QUEUE(qpair))) {
- result = 0;
- } else {
- result = VMCIQueueHeader_BufReady(qpair->consumeQ->qHeader,
- qpair->produceQ->qHeader,
+ result = VMCIQPairGetQueueHeaders(qpair, &produceQHeader, &consumeQHeader);
+ if (result == VMCI_SUCCESS) {
+ result = VMCIQueueHeader_BufReady(consumeQHeader, produceQHeader,
qpair->consumeQSize);
+ } else {
+ result = 0;
}
-
VMCIQPairUnlock(qpair);
return result;
return (ssize_t) bufSize;
}
- if (UNLIKELY(VMCIQPairMapQueueHeaders(produceQ, consumeQ) != VMCI_SUCCESS)) {
- return VMCI_ERROR_QUEUEPAIR_NOTATTACHED;
+ result = VMCIQPairMapQueueHeaders(produceQ, consumeQ);
+ if (UNLIKELY(result != VMCI_SUCCESS)) {
+ return result;
}
#endif
ssize_t result;
#if !defined VMX86_VMX
- if (UNLIKELY(VMCIQPairMapQueueHeaders(produceQ, consumeQ) != VMCI_SUCCESS)) {
- return VMCI_ERROR_QUEUEPAIR_NODATA;
+ result = VMCIQPairMapQueueHeaders(produceQ, consumeQ);
+ if (UNLIKELY(result != VMCI_SUCCESS)) {
+ return result;
}
#endif
VMCIQPairLock(qpair);
- result = EnqueueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->produceQSize,
- buf, bufSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyToQueueLocal:
- VMCIMemcpyToQueue);
+ do {
+ result = EnqueueLocked(qpair->produceQ,
+ qpair->consumeQ,
+ qpair->produceQSize,
+ buf, bufSize, bufType,
+ qpair->flags & VMCI_QPFLAG_LOCAL?
+ VMCIMemcpyToQueueLocal:
+ VMCIMemcpyToQueue);
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
+ if (!VMCIQPairWaitForReadyQueue(qpair)) {
+ result = VMCI_ERROR_WOULD_BLOCK;
+ }
+ }
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
VMCIQPairUnlock(qpair);
VMCIQPairLock(qpair);
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- buf, bufSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyFromQueueLocal:
- VMCIMemcpyFromQueue,
- TRUE);
+ do {
+ result = DequeueLocked(qpair->produceQ,
+ qpair->consumeQ,
+ qpair->consumeQSize,
+ buf, bufSize, bufType,
+ qpair->flags & VMCI_QPFLAG_LOCAL?
+ VMCIMemcpyFromQueueLocal:
+ VMCIMemcpyFromQueue,
+ TRUE);
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
+ if (!VMCIQPairWaitForReadyQueue(qpair)) {
+ result = VMCI_ERROR_WOULD_BLOCK;
+ }
+ }
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
VMCIQPairUnlock(qpair);
VMCIQPairLock(qpair);
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- buf, bufSize, bufType,
- qpair->flags & VMCI_QPFLAG_LOCAL?
- VMCIMemcpyFromQueueLocal:
- VMCIMemcpyFromQueue,
- FALSE);
+ do {
+ result = DequeueLocked(qpair->produceQ,
+ qpair->consumeQ,
+ qpair->consumeQSize,
+ buf, bufSize, bufType,
+ qpair->flags & VMCI_QPFLAG_LOCAL?
+ VMCIMemcpyFromQueueLocal:
+ VMCIMemcpyFromQueue,
+ FALSE);
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
+ if (!VMCIQPairWaitForReadyQueue(qpair)) {
+ result = VMCI_ERROR_WOULD_BLOCK;
+ }
+ }
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
VMCIQPairUnlock(qpair);
VMCIQPairLock(qpair);
- result = EnqueueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->produceQSize,
- iov, iovSize, bufType,
- VMCIMemcpyToQueueV);
+ do {
+ result = EnqueueLocked(qpair->produceQ,
+ qpair->consumeQ,
+ qpair->produceQSize,
+ iov, iovSize, bufType,
+ VMCIMemcpyToQueueV);
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
+ if (!VMCIQPairWaitForReadyQueue(qpair)) {
+ result = VMCI_ERROR_WOULD_BLOCK;
+ }
+ }
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
VMCIQPairUnlock(qpair);
return VMCI_ERROR_INVALID_ARGS;
}
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- iov, iovSize, bufType,
- VMCIMemcpyFromQueueV,
- TRUE);
+ do {
+ result = DequeueLocked(qpair->produceQ,
+ qpair->consumeQ,
+ qpair->consumeQSize,
+ iov, iovSize, bufType,
+ VMCIMemcpyFromQueueV,
+ TRUE);
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
+ if (!VMCIQPairWaitForReadyQueue(qpair)) {
+ result = VMCI_ERROR_WOULD_BLOCK;
+ }
+ }
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
VMCIQPairUnlock(qpair);
VMCIQPairLock(qpair);
- result = DequeueLocked(qpair->produceQ,
- qpair->consumeQ,
- qpair->consumeQSize,
- iov, iovSize, bufType,
- VMCIMemcpyFromQueueV,
- FALSE);
+ do {
+ result = DequeueLocked(qpair->produceQ,
+ qpair->consumeQ,
+ qpair->consumeQSize,
+ iov, iovSize, bufType,
+ VMCIMemcpyFromQueueV,
+ FALSE);
+ if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY) {
+ if (!VMCIQPairWaitForReadyQueue(qpair)) {
+ result = VMCI_ERROR_WOULD_BLOCK;
+ }
+ }
+ } while (result == VMCI_ERROR_QUEUEPAIR_NOT_READY);
VMCIQPairUnlock(qpair);
Bool vmciPageFiles; // Created by VMX using VMCI page files
VMCIQueue *produceQ;
VMCIQueue *consumeQ;
+ VMCIQueueHeader savedProduceQ;
+ VMCIQueueHeader savedConsumeQ;
+ VMCIEventReleaseCB wakeupCB;
+ void *clientData;
void *localMem; // Kernel memory for local queue pair
} QPBrokerEntry;
uint64 consumeSize,
QueuePairPageStore *pageStore,
VMCIContext *context,
+ VMCIEventReleaseCB wakeupCB,
+ void *clientData,
QPBrokerEntry **ent,
Bool *swap);
static int VMCIQPBrokerAttach(QPBrokerEntry *entry,
uint64 consumeSize,
QueuePairPageStore *pageStore,
VMCIContext *context,
+ VMCIEventReleaseCB wakeupCB,
+ void *clientData,
QPBrokerEntry **ent);
static int VMCIQPBrokerCreate(VMCIHandle handle,
VMCIId peer,
uint64 consumeSize,
QueuePairPageStore *pageStore,
VMCIContext *context,
+ VMCIEventReleaseCB wakeupCB,
+ void *clientData,
QPBrokerEntry **ent);
static int VMCIQueuePairAllocHostWork(VMCIHandle *handle, VMCIQueue **produceQ,
uint64 produceSize, VMCIQueue **consumeQ,
uint64 consumeSize,
VMCIId peer, uint32 flags,
- VMCIPrivilegeFlags privFlags);
+ VMCIPrivilegeFlags privFlags,
+ VMCIEventReleaseCB wakeupCB,
+ void *clientData);
static int VMCIQueuePairDetachHostWork(VMCIHandle handle);
+static int QueuePairSaveHeaders(QPBrokerEntry *entry);
+static void QueuePairResetSavedHeaders(QPBrokerEntry *entry);
+
#if !defined(VMKERNEL)
static int QueuePairNotifyPeerLocal(Bool attach, VMCIHandle handle);
VMCIId peer, // IN
uint32 flags, // IN
VMCIPrivilegeFlags privFlags, // IN
- Bool guestEndpoint) // IN
+ Bool guestEndpoint, // IN
+ VMCIEventReleaseCB wakeupCB, // IN
+ void *clientData) // IN
{
if (!handle || !produceQ || !consumeQ || (!produceSize && !consumeSize) ||
(flags & ~VMCI_QP_ALL_FLAGS)) {
#endif
} else {
return VMCIQueuePairAllocHostWork(handle, produceQ, produceSize, consumeQ,
- consumeSize, peer, flags, privFlags);
+ consumeSize, peer, flags, privFlags,
+ wakeupCB, clientData);
}
}
{
return VMCIQPBrokerAllocInt(handle, peer, flags, privFlags,
produceSize, consumeSize,
- pageStore, context, NULL, NULL);
+ pageStore, context, NULL, NULL,
+ NULL, NULL);
}
uint64 consumeSize, // IN
VMCIId peer, // IN
uint32 flags, // IN
- VMCIPrivilegeFlags privFlags) // IN
+ VMCIPrivilegeFlags privFlags, // IN
+ VMCIEventReleaseCB wakeupCB, // IN
+ void *clientData) // IN
{
VMCIContext *context;
QPBrokerEntry *entry;
entry = NULL;
VMCIQPBroker_Lock();
result = VMCIQPBrokerAllocInt(*handle, peer, flags, privFlags, produceSize,
- consumeSize, NULL, context, &entry, &swap);
+ consumeSize, NULL, context, wakeupCB, clientData,
+ &entry, &swap);
if (result == VMCI_SUCCESS) {
if (swap) {
/*
uint64 consumeSize, // IN
QueuePairPageStore *pageStore, // IN/OUT
VMCIContext *context, // IN: Caller
+ VMCIEventReleaseCB wakeupCB, // IN
+ void *clientData, // IN
QPBrokerEntry **ent, // OUT
Bool *swap) // OUT: swap queues?
{
if (!entry) {
create = TRUE;
result = VMCIQPBrokerCreate(handle, peer, flags, privFlags, produceSize,
- consumeSize, pageStore, context, ent);
+ consumeSize, pageStore, context, wakeupCB,
+ clientData, ent);
} else {
create = FALSE;
result = VMCIQPBrokerAttach(entry, peer, flags, privFlags, produceSize,
- consumeSize, pageStore, context, ent);
+ consumeSize, pageStore, context, wakeupCB,
+ clientData, ent);
}
if (swap) {
uint64 consumeSize, // IN
QueuePairPageStore *pageStore, // IN
VMCIContext *context, // IN: Caller
+ VMCIEventReleaseCB wakeupCB, // IN
+ void *clientData, // IN
QPBrokerEntry **ent) // OUT
{
QPBrokerEntry *entry = NULL;
entry->createdByTrusted =
(privFlags & VMCI_PRIVILEGE_FLAG_TRUSTED) ? TRUE : FALSE;
entry->vmciPageFiles = FALSE;
+ entry->wakeupCB = wakeupCB;
+ entry->clientData = clientData;
entry->produceQ = VMCIHost_AllocQueue(produceSize);
if (entry->produceQ == NULL) {
result = VMCI_ERROR_NO_MEM;
goto error;
}
-
entry->consumeQ = VMCIHost_AllocQueue(consumeSize);
if (entry->consumeQ == NULL) {
result = VMCI_ERROR_NO_MEM;
uint64 consumeSize, // IN
QueuePairPageStore *pageStore, // IN/OUT
VMCIContext *context, // IN: Caller
+ VMCIEventReleaseCB wakeupCB, // IN
+ void *clientData, // IN
QPBrokerEntry **ent) // OUT
{
const VMCIId contextId = VMCIContext_GetId(context);
entry->attachId = contextId;
entry->qp.refCount++;
+ if (wakeupCB) {
+ ASSERT(!entry->wakeupCB);
+ entry->wakeupCB = wakeupCB;
+ entry->clientData = clientData;
+ }
/*
* When attaching to local queue pairs, the context already has
VMCIHost_UnregisterUserMemory(entry->produceQ, entry->consumeQ);
}
VMCI_ReleaseQueueMutex(entry->produceQ);
+ } else {
+ VMCI_AcquireQueueMutex(entry->produceQ);
+ QueuePairResetSavedHeaders(entry);
+ VMCI_ReleaseQueueMutex(entry->produceQ);
+ if (entry->wakeupCB) {
+ entry->wakeupCB(entry->clientData);
+ }
+ }
+ } else {
+ if (entry->wakeupCB) {
+ entry->wakeupCB = NULL;
+ entry->clientData = NULL;
}
}
Bool isLocal = FALSE;
int result;
- if (vmkernel) {
- ASSERT(FALSE);
- return VMCI_ERROR_UNAVAILABLE;
- }
-
if (VMCI_HANDLE_INVALID(handle) || !context || contextId == VMCI_INVALID_ID) {
return VMCI_ERROR_INVALID_ARGS;
}
isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
- if (contextId != VMCI_HOST_CONTEXT_ID) {
+ if (vmkernel) {
+ /*
+ * On vmkernel, the readiness of the queue pair can be signalled
+ * immediately since the guest memory is already registered.
+ */
+
+ VMCI_AcquireQueueMutex(entry->produceQ);
+ QueuePairResetSavedHeaders(entry);
+ VMCI_ReleaseQueueMutex(entry->produceQ);
+ if (entry->wakeupCB) {
+ entry->wakeupCB(entry->clientData);
+ }
+ result = VMCI_SUCCESS;
+ } else if (contextId != VMCI_HOST_CONTEXT_ID) {
QueuePairPageStore pageStore;
ASSERT(entry->state == VMCIQPB_CREATED_NO_MEM ||
pageStore.len = QPE_NUM_PAGES(entry->qp);
VMCI_AcquireQueueMutex(entry->produceQ);
-
+ QueuePairResetSavedHeaders(entry);
result = VMCIHost_RegisterUserMemory(&pageStore, entry->produceQ, entry->consumeQ);
+ VMCI_ReleaseQueueMutex(entry->produceQ);
if (result == VMCI_SUCCESS) {
/*
* Move state from *_NO_MEM to *_MEM.
ASSERT(entry->state == VMCIQPB_CREATED_MEM ||
entry->state == VMCIQPB_SHUTDOWN_MEM ||
entry->state == VMCIQPB_ATTACHED_MEM);
+
+ if (entry->wakeupCB) {
+ entry->wakeupCB(entry->clientData);
+ }
}
- VMCI_ReleaseQueueMutex(entry->produceQ);
} else {
result = VMCI_SUCCESS;
}
return result;
}
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairSaveHeaders --
+ *
+ * Saves a snapshot of the queue headers for the given QP broker
+ * entry. Should be used when guest memory is unmapped.
+ *
+ * Results:
+ * VMCI_SUCCESS on success, appropriate error code if guest memory
+ * can't be accessed..
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static int
+QueuePairSaveHeaders(QPBrokerEntry *entry) // IN
+{
+ int result;
+
+ if (NULL == entry->produceQ->qHeader || NULL == entry->consumeQ->qHeader) {
+ result = VMCIHost_MapQueueHeaders(entry->produceQ, entry->consumeQ);
+ if (result < VMCI_SUCCESS) {
+ return result;
+ }
+ }
+ memcpy(&entry->savedProduceQ, entry->produceQ->qHeader, sizeof entry->savedProduceQ);
+ entry->produceQ->savedHeader = &entry->savedProduceQ;
+ memcpy(&entry->savedConsumeQ, entry->consumeQ->qHeader, sizeof entry->savedConsumeQ);
+ entry->consumeQ->savedHeader = &entry->savedConsumeQ;
+
+ return VMCI_SUCCESS;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * QueuePairResetSavedHeaders --
+ *
+ * Resets saved queue headers for the given QP broker
+ * entry. Should be used when guest memory becomes available
+ * again, or the guest detaches.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+QueuePairResetSavedHeaders(QPBrokerEntry *entry) // IN
+{
+ entry->produceQ->savedHeader = NULL;
+ entry->consumeQ->savedHeader = NULL;
+}
+
+
/*
*-----------------------------------------------------------------------------
*
isLocal = entry->qp.flags & VMCI_QPFLAG_LOCAL;
if (contextId != VMCI_HOST_CONTEXT_ID) {
+ int result;
+
ASSERT(entry->state != VMCIQPB_CREATED_NO_MEM &&
entry->state != VMCIQPB_SHUTDOWN_NO_MEM &&
entry->state != VMCIQPB_ATTACHED_NO_MEM);
ASSERT(!isLocal);
VMCI_AcquireQueueMutex(entry->produceQ);
-
+ result = QueuePairSaveHeaders(entry);
+ if (result < VMCI_SUCCESS) {
+ VMCI_WARNING((LGPFX"Failed to save queue headers for queue pair "
+ "(handle=0x%x:0x%x,result=%d).\n", handle.context,
+ handle.resource, result));
+ }
VMCIHost_UnmapQueueHeaders(gid,
entry->produceQ,
entry->consumeQ);