static void tstRTPipe2(void) { RTTestISub("Negative"); RTPIPE hPipeR = (RTPIPE)1; RTPIPE hPipeW = (RTPIPE)1; RTTESTI_CHECK_RC(RTPipeCreate(&hPipeR, &hPipeW, ~0), VERR_INVALID_PARAMETER); RTTESTI_CHECK_RC(RTPipeCreate(NULL, &hPipeW, 0), VERR_INVALID_POINTER); RTTESTI_CHECK_RC(RTPipeCreate(&hPipeR, NULL, 0), VERR_INVALID_POINTER); RTTESTI_CHECK(hPipeR == (RTPIPE)1); RTTESTI_CHECK(hPipeW == (RTPIPE)1); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); char abBuf[_4K]; size_t cbRead = ~(size_t)3; RTTESTI_CHECK_RC(RTPipeRead(hPipeW, abBuf, 0, &cbRead), VERR_ACCESS_DENIED); RTTESTI_CHECK_RC(RTPipeRead(hPipeW, abBuf, 1, &cbRead), VERR_ACCESS_DENIED); RTTESTI_CHECK(cbRead == ~(size_t)3); RTTESTI_CHECK_RC(RTPipeReadBlocking(hPipeW, abBuf, 0, NULL), VERR_ACCESS_DENIED); RTTESTI_CHECK_RC(RTPipeReadBlocking(hPipeW, abBuf, 1, NULL), VERR_ACCESS_DENIED); size_t cbWrite = ~(size_t)5; RTTESTI_CHECK_RC(RTPipeWrite(hPipeR, "asdf", 0, &cbWrite), VERR_ACCESS_DENIED); RTTESTI_CHECK_RC(RTPipeWrite(hPipeR, "asdf", 4, &cbWrite), VERR_ACCESS_DENIED); RTTESTI_CHECK(cbWrite == ~(size_t)5); RTTESTI_CHECK_RC(RTPipeWriteBlocking(hPipeR, "asdf", 0, NULL), VERR_ACCESS_DENIED); RTTESTI_CHECK_RC(RTPipeWriteBlocking(hPipeR, "asdf", 4, NULL), VERR_ACCESS_DENIED); RTTESTI_CHECK_RC(RTPipeFlush(hPipeR), VERR_ACCESS_DENIED); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); }
/** * Reads from a pipe. * * @returns @a rc or other status code. * @param rc The current status of the operation. Error status * are preserved and returned. * @param phPipeR Pointer to the pipe handle. * @param pcbAllocated Pointer to the buffer size variable. * @param poffCur Pointer to the buffer offset variable. * @param ppszBuffer Pointer to the buffer pointer variable. */ static int rtProcProcessOutput(int rc, PRTPIPE phPipeR, size_t *pcbAllocated, size_t *poffCur, char **ppszBuffer, RTPOLLSET hPollSet, uint32_t idPollSet) { size_t cbRead; char szTmp[_4K - 1]; for (;;) { int rc2 = RTPipeRead(*phPipeR, szTmp, sizeof(szTmp), &cbRead); if (RT_SUCCESS(rc2) && cbRead) { /* Resize the buffer. */ if (*poffCur + cbRead >= *pcbAllocated) { if (*pcbAllocated >= _1G) { RTPollSetRemove(hPollSet, idPollSet); rc2 = RTPipeClose(*phPipeR); AssertRC(rc2); *phPipeR = NIL_RTPIPE; return RT_SUCCESS(rc) ? VERR_TOO_MUCH_DATA : rc; } size_t cbNew = *pcbAllocated ? *pcbAllocated * 2 : sizeof(szTmp) + 1; Assert(*poffCur + cbRead < cbNew); rc2 = RTStrRealloc(ppszBuffer, cbNew); if (RT_FAILURE(rc2)) { RTPollSetRemove(hPollSet, idPollSet); rc2 = RTPipeClose(*phPipeR); AssertRC(rc2); *phPipeR = NIL_RTPIPE; return RT_SUCCESS(rc) ? rc2 : rc; } *pcbAllocated = cbNew; } /* Append the new data, terminating it. */ memcpy(*ppszBuffer + *poffCur, szTmp, cbRead); *poffCur += cbRead; (*ppszBuffer)[*poffCur] = '\0'; /* Check for null terminators in the string. */ if (RT_SUCCESS(rc) && memchr(szTmp, '\0', cbRead)) rc = VERR_NO_TRANSLATION; /* If we read a full buffer, try read some more. */ if (RT_SUCCESS(rc) && cbRead == sizeof(szTmp)) continue; } else if (rc2 != VINF_TRY_AGAIN) { if (RT_FAILURE(rc) && rc2 != VERR_BROKEN_PIPE) rc = rc2; RTPollSetRemove(hPollSet, idPollSet); rc2 = RTPipeClose(*phPipeR); AssertRC(rc2); *phPipeR = NIL_RTPIPE; } return rc; } }
static DECLCALLBACK(int) drvHostParallelMonitorThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) { PDRVHOSTPARALLEL pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTPARALLEL); struct pollfd aFDs[2]; /* * We can wait for interrupts using poll on linux hosts. */ while (pThread->enmState == PDMTHREADSTATE_RUNNING) { int rc; aFDs[0].fd = RTFileToNative(pThis->hFileDevice); aFDs[0].events = POLLIN; aFDs[0].revents = 0; aFDs[1].fd = RTPipeToNative(pThis->hWakeupPipeR); aFDs[1].events = POLLIN | POLLERR | POLLHUP; aFDs[1].revents = 0; rc = poll(aFDs, RT_ELEMENTS(aFDs), -1); if (rc < 0) { AssertMsgFailed(("poll failed with rc=%d\n", RTErrConvertFromErrno(errno))); return RTErrConvertFromErrno(errno); } if (pThread->enmState != PDMTHREADSTATE_RUNNING) break; if (rc > 0 && aFDs[1].revents) { if (aFDs[1].revents & (POLLHUP | POLLERR | POLLNVAL)) break; /* notification to terminate -- drain the pipe */ char ch; size_t cbRead; RTPipeRead(pThis->hWakeupPipeR, &ch, 1, &cbRead); continue; } /* Interrupt occurred. */ rc = pThis->pDrvHostParallelPort->pfnNotifyInterrupt(pThis->pDrvHostParallelPort); AssertRC(rc); } return VINF_SUCCESS; }
static void tstRTPipe3(void) { RTTestISub("Full write buffer"); RTPIPE hPipeR = (RTPIPE)999999; RTPIPE hPipeW = (RTPIPE)999999; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); static char s_abBuf[_256K]; int rc = VINF_SUCCESS; size_t cbTotal = 0; memset(s_abBuf, 0xff, sizeof(s_abBuf)); for (;;) { RTTESTI_CHECK(cbTotal < _1G); if (cbTotal > _1G) break; size_t cbWritten = _1G; rc = RTPipeWrite(hPipeW, s_abBuf, sizeof(s_abBuf), &cbWritten); RTTESTI_CHECK_MSG(rc == VINF_SUCCESS || rc == VINF_TRY_AGAIN, ("rc=%Rrc\n", rc)); if (rc != VINF_SUCCESS) break; cbTotal += cbWritten; } if (rc == VINF_TRY_AGAIN) { RTTestIPrintf(RTTESTLVL_ALWAYS, "cbTotal=%zu (%#zx)\n", cbTotal, cbTotal); RTTESTI_CHECK_RC(RTPipeSelectOne(hPipeW, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC(RTPipeSelectOne(hPipeW, 1), VERR_TIMEOUT); size_t cbRead; RTTESTI_CHECK_RC(RTPipeRead(hPipeR, s_abBuf, RT_MIN(sizeof(s_abBuf), cbTotal) / 2, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeSelectOne(hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeSelectOne(hPipeW, 1), VINF_SUCCESS); size_t cbWritten = _1G; rc = RTPipeWrite(hPipeW, s_abBuf, sizeof(s_abBuf), &cbWritten); RTTESTI_CHECK(rc == VINF_SUCCESS); } RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); }
static void tstRTPipe1(void) { RTTestISub("Basics"); RTPIPE hPipeR = NIL_RTPIPE; RTPIPE hPipeW = NIL_RTPIPE; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RETV(hPipeR != NIL_RTPIPE); RTTESTI_CHECK_RETV(hPipeW != NIL_RTPIPE); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(NIL_RTPIPE), VINF_SUCCESS); hPipeR = NIL_RTPIPE; hPipeW = NIL_RTPIPE; RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_READ | RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS); int rc = RTPipeFlush(hPipeW); RTTESTI_CHECK_MSG(rc == VERR_NOT_SUPPORTED || rc == VINF_SUCCESS, ("%Rrc\n", rc)); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_READ), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeSelectOne(hPipeR, 0), VERR_TIMEOUT); RTTESTI_CHECK_RC_RETV(RTPipeSelectOne(hPipeR, 1), VERR_TIMEOUT); RTTESTI_CHECK_RC_RETV(RTPipeSelectOne(hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeSelectOne(hPipeW, 1), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_WRITE), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, RTPIPE_C_INHERIT_READ), VINF_SUCCESS); size_t cbRead = ~(size_t)0; char abBuf[_64K + _4K]; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, sizeof(abBuf), &cbRead), VINF_TRY_AGAIN); RTTESTI_CHECK_RETV(cbRead == 0); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, 1, &cbRead), VINF_TRY_AGAIN); RTTESTI_CHECK_RETV(cbRead == 0); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, 0, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 0); size_t cbWritten = ~(size_t)2; RTTESTI_CHECK_RC_RETV(RTPipeWrite(hPipeW, abBuf, 0, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbWritten == 0); /* We can write a number of bytes without blocking (see PIPE_BUF on POSIX systems). */ cbWritten = ~(size_t)2; RTTESTI_CHECK_RC_RETV(RTPipeWrite(hPipeW, "42", 2, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK_MSG_RETV(cbWritten == 2, ("cbWritten=%zu\n", cbWritten)); cbWritten = ~(size_t)2; RTTESTI_CHECK_RC_RETV(RTPipeWrite(hPipeW, "!", 1, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbWritten == 1); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, 3, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 3); RTTESTI_CHECK_RETV(!memcmp(abBuf, "42!", 3)); cbWritten = ~(size_t)2; RTTESTI_CHECK_RC_RETV(RTPipeWrite(hPipeW, "BigQ", 4, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbWritten == 4); RTTESTI_CHECK_RC_RETV(RTPipeSelectOne(hPipeR, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeSelectOne(hPipeR, 1), VINF_SUCCESS); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeQueryReadable(hPipeR, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_MSG(cbRead == cbWritten, ("cbRead=%zu cbWritten=%zu\n", cbRead, cbWritten)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, sizeof(abBuf), &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 4); RTTESTI_CHECK_RETV(!memcmp(abBuf, "BigQ", 4)); cbWritten = ~(size_t)2; RTTESTI_CHECK_RC_RETV(RTPipeWrite(hPipeW, "H2G2", 4, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbWritten == 4); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeQueryReadable(hPipeR, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_MSG(cbRead == cbWritten, ("cbRead=%zu cbWritten=%zu\n", cbRead, cbWritten)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, &abBuf[0], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 1); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeQueryReadable(hPipeR, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_MSG(cbRead == cbWritten - 1, ("cbRead=%zu cbWritten=%zu\n", cbRead, cbWritten)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, &abBuf[1], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 1); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeQueryReadable(hPipeR, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_MSG(cbRead == cbWritten - 2, ("cbRead=%zu cbWritten=%zu\n", cbRead, cbWritten)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, &abBuf[2], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 1); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeQueryReadable(hPipeR, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_MSG(cbRead == cbWritten - 3, ("cbRead=%zu cbWritten=%zu\n", cbRead, cbWritten)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, &abBuf[3], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_RETV(cbRead == 1); RTTESTI_CHECK_RETV(!memcmp(abBuf, "H2G2", 4)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeQueryReadable(hPipeR, &cbRead), VINF_SUCCESS); RTTESTI_CHECK_MSG(cbRead == cbWritten - 4, ("cbRead=%zu cbWritten=%zu\n", cbRead, cbWritten)); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); RTTestISub("VERR_BROKEN_PIPE"); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeR), VINF_SUCCESS); cbWritten = ~(size_t)2; RTTESTI_CHECK_RC(RTPipeWrite(hPipeW, "", 0, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK(cbWritten == 0); cbWritten = ~(size_t)2; RTTESTI_CHECK_RC(RTPipeWrite(hPipeW, "4", 1, &cbWritten), VERR_BROKEN_PIPE); RTTESTI_CHECK(cbWritten == ~(size_t)2); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); cbRead = ~(size_t)0; RTTESTI_CHECK_RC(RTPipeRead(hPipeR, abBuf, 0, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 0); cbRead = ~(size_t)3; RTTESTI_CHECK_RC(RTPipeRead(hPipeR, abBuf, sizeof(abBuf), &cbRead), VERR_BROKEN_PIPE); RTTESTI_CHECK(cbRead == ~(size_t)3); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); cbWritten = ~(size_t)2; RTTESTI_CHECK_RC(RTPipeWrite(hPipeW, "42", 2, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK(cbWritten == 2); RTTESTI_CHECK_RC_RETV(RTPipeClose(hPipeW), VINF_SUCCESS); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, 0, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 0); cbRead = ~(size_t)0; RTTESTI_CHECK_RC(RTPipeRead(hPipeR, &abBuf[0], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 1); cbRead = ~(size_t)0; RTTESTI_CHECK_RC(RTPipeRead(hPipeR, &abBuf[1], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 1); RTTESTI_CHECK(!memcmp(abBuf, "42", 2)); cbRead = ~(size_t)0; RTTESTI_CHECK_RC(RTPipeRead(hPipeR, abBuf, 0, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 0); cbRead = ~(size_t)3; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, abBuf, sizeof(abBuf), &cbRead), VERR_BROKEN_PIPE); RTTESTI_CHECK(cbRead == ~(size_t)3); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTestISub("Blocking"); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeWrite(hPipeW, "42!", 3, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK(cbWritten == 3); RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, abBuf, 3, NULL), VINF_SUCCESS); RTTESTI_CHECK(!memcmp(abBuf, "42!", 3)); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, &abBuf[0], 0, NULL), VINF_SUCCESS); cbRead = ~(size_t)42; RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, &abBuf[0], 0, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 0); RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, &abBuf[0], 1, NULL), VERR_BROKEN_PIPE); cbRead = ~(size_t)42; RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, &abBuf[0], 1, &cbRead), VERR_BROKEN_PIPE); RTTESTI_CHECK(cbRead == 0); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeCreate(&hPipeR, &hPipeW, 0), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeWriteBlocking(hPipeW, "42!", 3, NULL), VINF_SUCCESS); RTTESTI_CHECK(cbWritten == 3); cbRead = ~(size_t)0; RTTESTI_CHECK_RC_RETV(RTPipeRead(hPipeR, &abBuf[0], 1, &cbRead), VINF_SUCCESS); RTTESTI_CHECK(cbRead == 1); RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, &abBuf[1], 1, NULL), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeReadBlocking(hPipeR, &abBuf[2], 1, NULL), VINF_SUCCESS); RTTESTI_CHECK(!memcmp(abBuf, "42!", 3)); RTTESTI_CHECK_RC(RTPipeClose(hPipeR), VINF_SUCCESS); RTTESTI_CHECK_RC_RETV(RTPipeWriteBlocking(hPipeW, "", 0, NULL), VINF_SUCCESS); cbWritten = ~(size_t)9; RTTESTI_CHECK_RC_RETV(RTPipeWriteBlocking(hPipeW, "", 0, &cbWritten), VINF_SUCCESS); RTTESTI_CHECK(cbWritten == 0); RTTESTI_CHECK_RC_RETV(RTPipeWriteBlocking(hPipeW, "42", 2, NULL), VERR_BROKEN_PIPE); cbWritten = ~(size_t)9; RTTESTI_CHECK_RC_RETV(RTPipeWriteBlocking(hPipeW, "42", 2, &cbWritten), VERR_BROKEN_PIPE); RTTESTI_CHECK(cbWritten == 0); RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS); }
/** * Reap URBs in-flight on a device. * * @returns Pointer to a completed URB. * @returns NULL if no URB was completed. * @param pProxyDev The device. * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all. */ static DECLCALLBACK(PVUSBURB) usbProxyFreeBSDUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies) { struct usb_fs_endpoint *pXferEndpoint; PUSBPROXYDEVFBSD pDevFBSD = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVFBSD); PUSBENDPOINTFBSD pEndpointFBSD; PVUSBURB pUrb; struct usb_fs_complete UsbFsComplete; struct pollfd pfd[2]; int rc; LogFlow(("usbProxyFreeBSDUrbReap: pProxyDev=%p, cMillies=%u\n", pProxyDev, cMillies)); repeat: pUrb = NULL; /* check for cancelled transfers */ if (pDevFBSD->fCancelling) { for (unsigned n = 0; n < USBFBSD_MAXENDPOINTS; n++) { pEndpointFBSD = &pDevFBSD->aSwEndpoint[n]; if (pEndpointFBSD->fCancelling) { pEndpointFBSD->fCancelling = false; pUrb = pEndpointFBSD->pUrb; pEndpointFBSD->pUrb = NULL; if (pUrb != NULL) break; } } if (pUrb != NULL) { pUrb->enmStatus = VUSBSTATUS_INVALID; pUrb->Dev.pvPrivate = NULL; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: pUrb->cbData = 0; break; case VUSBXFERTYPE_ISOC: pUrb->cbData = 0; for (int n = 0; n < (int)pUrb->cIsocPkts; n++) pUrb->aIsocPkts[n].cb = 0; break; default: pUrb->cbData = 0; break; } return pUrb; } pDevFBSD->fCancelling = false; } /* Zero default */ memset(&UsbFsComplete, 0, sizeof(UsbFsComplete)); /* Check if any endpoints are complete */ rc = usbProxyFreeBSDDoIoCtl(pProxyDev, USB_FS_COMPLETE, &UsbFsComplete, true); if (RT_SUCCESS(rc)) { pXferEndpoint = &pDevFBSD->aHwEndpoint[UsbFsComplete.ep_index]; pEndpointFBSD = &pDevFBSD->aSwEndpoint[UsbFsComplete.ep_index]; LogFlow(("usbProxyFreeBSDUrbReap: Reaped " "URB %#p\n", pEndpointFBSD->pUrb)); if (pXferEndpoint->status == USB_ERR_CANCELLED) goto repeat; pUrb = pEndpointFBSD->pUrb; pEndpointFBSD->pUrb = NULL; if (pUrb == NULL) goto repeat; switch (pXferEndpoint->status) { case USB_ERR_NORMAL_COMPLETION: pUrb->enmStatus = VUSBSTATUS_OK; break; case USB_ERR_STALLED: pUrb->enmStatus = VUSBSTATUS_STALL; break; default: pUrb->enmStatus = VUSBSTATUS_INVALID; break; } pUrb->Dev.pvPrivate = NULL; switch (pUrb->enmType) { case VUSBXFERTYPE_MSG: pUrb->cbData = pEndpointFBSD->acbData[0] + pEndpointFBSD->acbData[1]; break; case VUSBXFERTYPE_ISOC: { int n; if (pUrb->enmDir == VUSBDIRECTION_OUT) break; pUrb->cbData = 0; for (n = 0; n < (int)pUrb->cIsocPkts; n++) { if (n >= (int)pEndpointFBSD->cMaxFrames) break; pUrb->cbData += pEndpointFBSD->acbData[n]; pUrb->aIsocPkts[n].cb = pEndpointFBSD->acbData[n]; } for (; n < (int)pUrb->cIsocPkts; n++) pUrb->aIsocPkts[n].cb = 0; break; } default: pUrb->cbData = pEndpointFBSD->acbData[0]; break; } LogFlow(("usbProxyFreeBSDUrbReap: Status=%d epindex=%u " "len[0]=%d len[1]=%d\n", (int)pXferEndpoint->status, (unsigned)UsbFsComplete.ep_index, (unsigned)pEndpointFBSD->acbData[0], (unsigned)pEndpointFBSD->acbData[1])); } else if (cMillies != 0 && rc == VERR_RESOURCE_BUSY) { for (;;) { pfd[0].fd = RTFileToNative(pDevFBSD->hFile); pfd[0].events = POLLIN | POLLRDNORM; pfd[0].revents = 0; pfd[1].fd = RTPipeToNative(pDevFBSD->hPipeWakeupR); pfd[1].events = POLLIN | POLLRDNORM; pfd[1].revents = 0; rc = poll(pfd, 2, (cMillies == RT_INDEFINITE_WAIT) ? INFTIM : cMillies); if (rc > 0) { if (pfd[1].revents & POLLIN) { /* Got woken up, drain pipe. */ uint8_t bRead; size_t cbIgnored = 0; RTPipeRead(pDevFBSD->hPipeWakeupR, &bRead, 1, &cbIgnored); /* Make sure we return from this function */ cMillies = 0; } break; } if (rc == 0) return NULL; if (errno != EAGAIN) return NULL; } goto repeat; } return pUrb; }
/** * Reap URBs in-flight on a device. * * @returns Pointer to a completed URB. * @returns NULL if no URB was completed. * @param pProxyDev The device. * @param cMillies Number of milliseconds to wait. Use 0 to not wait at all. */ static DECLCALLBACK(PVUSBURB) usbProxySolarisUrbReap(PUSBPROXYDEV pProxyDev, RTMSINTERVAL cMillies) { //LogFlowFunc((USBPROXY ":usbProxySolarisUrbReap pProxyDev=%p cMillies=%u\n", pProxyDev, cMillies)); PUSBPROXYDEVSOL pDevSol = USBPROXYDEV_2_DATA(pProxyDev, PUSBPROXYDEVSOL); /* * Don't block if nothing is in the air. */ if (!pDevSol->pInFlightHead) return NULL; /* * Deque URBs inflight or those landed. */ if (cMillies > 0) { for (;;) { int cMilliesWait = cMillies == RT_INDEFINITE_WAIT ? -1 : cMillies; struct pollfd pfd[2]; pfd[0].fd = RTFileToNative(pDevSol->hFile); pfd[0].events = POLLIN; pfd[0].revents = 0; pfd[1].fd = RTPipeToNative(pDevSol->hPipeWakeupR); pfd[1].events = POLLIN; pfd[1].revents = 0; int rc = poll(&pfd[0], 2, cMilliesWait); if (rc > 0) { if (pfd[0].revents & POLLHUP) { LogRel((USBPROXY ":Reaping failed, USB Device '%s' disconnected!\n", pDevSol->pProxyDev->pUsbIns->pszName)); pProxyDev->fDetached = true; usbProxySolarisCloseFile(pDevSol); } if (pfd[1].revents & POLLIN) { /* Got woken up, drain pipe. */ uint8_t bRead; size_t cbIgnored = 0; RTPipeRead(pDevSol->hPipeWakeupR, &bRead, 1, &cbIgnored); /* * It is possible that we got woken up and have an URB pending * for completion. Do it on the way out. Otherwise return * immediately to the caller. */ if (!(pfd[0].revents & POLLIN)) return NULL; } break; } if (rc == 0) { //LogFlow((USBPROXY ":usbProxySolarisUrbReap: Timed out\n")); return NULL; } else if (rc != EAGAIN) { LogFlow((USBPROXY ":usbProxySolarisUrbReap Poll rc=%d errno=%d\n", rc, errno)); return NULL; } } } usbProxySolarisUrbComplete(pDevSol); /* * Any URBs pending delivery? */ PVUSBURB pUrb = NULL; while (pDevSol->pTaxingHead) { RTCritSectEnter(&pDevSol->CritSect); PUSBPROXYURBSOL pUrbSol = pDevSol->pTaxingHead; if (pUrbSol) { pUrb = pUrbSol->pVUsbUrb; if (pUrb) { pUrb->Dev.pvPrivate = NULL; usbProxySolarisUrbFree(pDevSol, pUrbSol); } } RTCritSectLeave(&pDevSol->CritSect); } return pUrb; }
int USBProxyBackendUsbIp::wait(RTMSINTERVAL aMillies) { int rc = VINF_SUCCESS; bool fDeviceListChangedOrWokenUp = false; /* Try to reconnect once when we enter if we lost the connection earlier. */ if (m->hSocket == NIL_RTSOCKET) rc = reconnect(); /* Query a new device list upon entering. */ if (m->enmRecvState == kUsbIpRecvState_None) { rc = startListExportedDevicesReq(); if (RT_FAILURE(rc)) disconnect(); } /* * Because the USB/IP protocol doesn't specify a way to get notified about * new or removed exported devices we have to poll the host periodically for * a new device list and compare it with the previous one notifying the proxy * service about changes. */ while ( !fDeviceListChangedOrWokenUp && (aMillies == RT_INDEFINITE_WAIT || aMillies > 0) && RT_SUCCESS(rc)) { RTMSINTERVAL msWait = aMillies; uint64_t msPollStart = RTTimeMilliTS(); uint32_t uIdReady = 0; uint32_t fEventsRecv = 0; /* Limit the waiting time to 1sec so we can either reconnect or get a new device list. */ if (m->hSocket == NIL_RTSOCKET || m->enmRecvState == kUsbIpRecvState_None) msWait = RT_MIN(1000, aMillies); rc = RTPoll(m->hPollSet, msWait, &fEventsRecv, &uIdReady); if (RT_SUCCESS(rc)) { if (uIdReady == USBIP_POLL_ID_PIPE) { /* Drain the wakeup pipe. */ char bRead = 0; size_t cbRead = 0; rc = RTPipeRead(m->hWakeupPipeR, &bRead, 1, &cbRead); Assert(RT_SUCCESS(rc) && cbRead == 1); fDeviceListChangedOrWokenUp = true; } else if (uIdReady == USBIP_POLL_ID_SOCKET) { if (fEventsRecv & RTPOLL_EVT_ERROR) rc = VERR_NET_SHUTDOWN; else rc = receiveData(); if (RT_SUCCESS(rc)) { /* * If we are in the none state again we received the previous request * and have a new device list to compare the old against. */ if (m->enmRecvState == kUsbIpRecvState_None) { if (hasDevListChanged(m->pHead)) fDeviceListChangedOrWokenUp = true; /* Update to the new list in any case now that we have it anyway. */ RTSemFastMutexRequest(m->hMtxDevices); freeDeviceList(m->pUsbDevicesCur); m->cUsbDevicesCur = m->cDevicesCur; m->pUsbDevicesCur = m->pHead; RTSemFastMutexRelease(m->hMtxDevices); m->pHead = NULL; resetRecvState(); } } else if (rc == VERR_NET_SHUTDOWN || rc == VERR_BROKEN_PIPE) { LogRelMax(10, ("USB/IP: Lost connection to host \"%s\", trying to reconnect...\n", m->pszHost)); disconnect(); rc = VINF_SUCCESS; } } else { AssertMsgFailed(("Invalid poll ID returned\n")); rc = VERR_INVALID_STATE; } aMillies -= (RTTimeMilliTS() - msPollStart); } else if (rc == VERR_TIMEOUT) { aMillies -= msWait; if (aMillies) { /* Try to reconnect and start a new request if we lost the connection before. */ if (m->hSocket == NIL_RTSOCKET) rc = reconnect(); if (RT_SUCCESS(rc)) rc = startListExportedDevicesReq(); } } } return rc; }
/** @interface_method_impl{PDMISTREAM,pfnPoll} */ static DECLCALLBACK(int) drvTcpPoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies) { int rc = VINF_SUCCESS; PDRVTCP pThis = RT_FROM_MEMBER(pInterface, DRVTCP, IStream); if (pThis->hTcpSock != NIL_RTSOCKET) { if (!pThis->fTcpSockInPollSet) { rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, fEvts, DRVTCP_POLLSET_ID_SOCKET); if (RT_SUCCESS(rc)) { pThis->fTcpSockInPollSet = true; pThis->fXmitBufFull = false; } } else { /* Always include error event. */ fEvts |= RTPOLL_EVT_ERROR; rc = RTPollSetEventsChange(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET, fEvts); AssertRC(rc); } } if (RT_SUCCESS(rc)) { while (RT_SUCCESS(rc)) { uint32_t fEvtsRecv = 0; uint32_t idHnd = 0; /* * Just check for data available to be read if the send buffer wasn't full till now and * the caller wants to check whether writing is possible with the event set. * * On Windows the write event is only posted after a send operation returned * WSAEWOULDBLOCK. So without this we would block in the poll call below waiting * for an event which would never happen if the buffer has space left. */ if ( (fEvts & RTPOLL_EVT_WRITE) && !pThis->fXmitBufFull && pThis->fTcpSockInPollSet) cMillies = 0; rc = RTPoll(pThis->hPollSet, cMillies, &fEvtsRecv, &idHnd); if (RT_SUCCESS(rc)) { if (idHnd == DRVTCP_POLLSET_ID_WAKEUP) { /* We got woken up, drain the pipe and return. */ uint8_t bReason; size_t cbRead = 0; rc = RTPipeRead(pThis->hPipeWakeR, &bReason, 1, &cbRead); AssertRC(rc); if (bReason == DRVTCP_WAKEUP_REASON_EXTERNAL) rc = VERR_INTERRUPTED; else if (bReason == DRVTCP_WAKEUP_REASON_NEW_CONNECTION) { Assert(!pThis->fTcpSockInPollSet); rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hTcpSock, fEvts, DRVTCP_POLLSET_ID_SOCKET); if (RT_SUCCESS(rc)) pThis->fTcpSockInPollSet = true; } else AssertMsgFailed(("Unknown wakeup reason in pipe %u\n", bReason)); } else { Assert(idHnd == DRVTCP_POLLSET_ID_SOCKET); /* On error we close the socket here. */ if (fEvtsRecv & RTPOLL_EVT_ERROR) { rc = RTPollSetRemove(pThis->hPollSet, DRVTCP_POLLSET_ID_SOCKET); AssertRC(rc); if (pThis->fIsServer) RTTcpServerDisconnectClient2(pThis->hTcpSock); else RTSocketClose(pThis->hTcpSock); pThis->hTcpSock = NIL_RTSOCKET; pThis->fTcpSockInPollSet = false; /* Continue with polling. */ } else { if (fEvtsRecv & RTPOLL_EVT_WRITE) pThis->fXmitBufFull = false; else if (!pThis->fXmitBufFull) fEvtsRecv |= RTPOLL_EVT_WRITE; *pfEvts = fEvtsRecv; break; } } } else if ( rc == VERR_TIMEOUT && !pThis->fXmitBufFull) { *pfEvts = RTPOLL_EVT_WRITE; rc = VINF_SUCCESS; break; } } } return rc; }