Changeset 47122 in vbox for trunk/src/VBox
- Timestamp:
- Jul 12, 2013 2:34:26 PM (12 years ago)
- svn:sync-xref-src-repo-rev:
- 87216
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/localipc-win.cpp
r47083 r47122 52 52 #include <iprt/string.h> 53 53 #include <iprt/thread.h> 54 #include <iprt/time.h> 54 55 55 56 #include "internal/magics.h" … … 148 149 /** Set if there is already pending I/O. */ 149 150 bool fIOPending; 151 /** Set if the zero byte read that the poll code using is pending. */ 152 bool fZeroByteRead; 150 153 /** Indicates that there is a pending cancel request. */ 151 154 bool volatile fCancelled; … … 162 165 /** Amount of allocated buffer space. */ 163 166 size_t cbBounceBufAlloc; 167 /** Buffer for the zero byte read. 168 * Used in RTLocalIpcSessionWaitForData(). */ 169 uint8_t abBuf[8]; 164 170 } RTLOCALIPCSESSIONINT; 165 171 /** Pointer to a local IPC session instance (Windows). */ … … 414 420 ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC); 415 421 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 422 Assert(pThis->cRefs); 416 423 pThis->cRefs--; 417 424 418 if (pThis->cRefs > 0)425 if (pThis->cRefs) 419 426 { 420 427 BOOL fRc = SetEvent(pThis->hEvent); … … 462 469 SetLastError(NO_ERROR); 463 470 BOOL fRc = ConnectNamedPipe(pThis->hNmPipe, &pThis->OverlappedIO); 464 DWORD err = fRc ? NO_ERROR : GetLastError();471 DWORD dwErr = fRc ? NO_ERROR : GetLastError(); 465 472 if ( !fRc 466 && err == ERROR_IO_PENDING)473 && dwErr == ERROR_IO_PENDING) 467 474 { 468 475 WaitForSingleObject(pThis->hEvent, INFINITE); 469 476 DWORD dwIgnored; 470 477 fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &dwIgnored, FALSE /* bWait*/); 471 err = fRc ? NO_ERROR : GetLastError();478 dwErr = fRc ? NO_ERROR : GetLastError(); 472 479 } 473 480 … … 484 491 */ 485 492 if ( fRc 486 || err == ERROR_PIPE_CONNECTED)493 || dwErr == ERROR_PIPE_CONNECTED) 487 494 { 488 495 HANDLE hNmPipe; … … 505 512 } 506 513 else 507 rc = RTErrConvertFromWin32( err);514 rc = RTErrConvertFromWin32(dwErr); 508 515 } 509 516 else … … 516 523 */ 517 524 if ( fRc 518 || err == ERROR_PIPE_CONNECTED)525 || dwErr == ERROR_PIPE_CONNECTED) 519 526 fRc = DisconnectNamedPipe(pThis->hNmPipe); 520 else if ( err == ERROR_IO_PENDING)527 else if (dwErr == ERROR_IO_PENDING) 521 528 fRc = CancelIo(pThis->hNmPipe); 522 529 else … … 550 557 * and signal the event (to wake up anyone in/at WaitForSingleObject). 551 558 */ 552 RTCritSectEnter(&pThis->CritSect); 553 554 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 555 BOOL fRc = SetEvent(pThis->hEvent); 556 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 557 558 RTCritSectLeave(&pThis->CritSect); 559 560 return VINF_SUCCESS; 559 int rc = RTCritSectEnter(&pThis->CritSect); 560 if (RT_SUCCESS(rc)) 561 { 562 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 563 BOOL fRc = SetEvent(pThis->hEvent); 564 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 565 566 rc = RTCritSectLeave(&pThis->CritSect); 567 } 568 569 return rc; 561 570 } 562 571 … … 632 641 pThis->cRefs = 1; /* The one we return. */ 633 642 pThis->fIOPending = false; 643 pThis->fZeroByteRead = false; 634 644 pThis->fCancelled = false; 635 645 pThis->pbBounceBuf = NULL; … … 767 777 { 768 778 /* No concurrent readers, sorry. */ 769 if (pThis->cRefs == 0)779 if (pThis->cRefs == 1) 770 780 { 771 781 pThis->cRefs++; … … 915 925 { 916 926 /* No concurrent writers, sorry. */ 917 if (pThis->cRefs == 0)927 if (pThis->cRefs == 1) 918 928 { 919 929 pThis->cRefs++; … … 1006 1016 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); 1007 1017 1018 uint64_t const StartMsTS = RTTimeMilliTS(); 1019 1008 1020 int rc = RTCritSectEnter(&pThis->CritSect); 1021 if (RT_FAILURE(rc)) 1022 return rc; 1023 for (unsigned iLoop = 0;; iLoop++) 1024 { 1025 HANDLE hWait = INVALID_HANDLE_VALUE; 1026 1027 if (pThis->fIOPending) 1028 hWait = pThis->OverlappedIO.hEvent; 1029 else 1030 { 1031 /* Peek at the pipe buffer and see how many bytes it contains. */ 1032 DWORD cbAvailable; 1033 BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL); 1034 if ( fRc 1035 && cbAvailable) 1036 { 1037 rc = VINF_SUCCESS; 1038 break; 1039 } 1040 else if (!fRc) 1041 { 1042 rc = RTErrConvertFromWin32(GetLastError()); 1043 break; 1044 } 1045 1046 /* Start a zero byte read operation that we can wait on. */ 1047 if (cMillies == 0) 1048 { 1049 rc = VERR_TIMEOUT; 1050 break; 1051 } 1052 AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER); 1053 fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE); 1054 DWORD cbRead = 0; 1055 if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO)) 1056 { 1057 rc = VINF_SUCCESS; 1058 if (iLoop > 10) 1059 RTThreadYield(); 1060 } 1061 else if (GetLastError() == ERROR_IO_PENDING) 1062 { 1063 pThis->cRefs++; 1064 pThis->fIOPending = true; 1065 pThis->fZeroByteRead = true; 1066 hWait = pThis->OverlappedIO.hEvent; 1067 } 1068 else 1069 rc = RTErrConvertFromWin32(GetLastError()); 1070 } 1071 1072 if (RT_FAILURE(rc)) 1073 break; 1074 1075 /* 1076 * Check for timeout. 1077 */ 1078 DWORD cMsMaxWait = INFINITE; 1079 if ( cMillies != RT_INDEFINITE_WAIT 1080 && ( hWait != INVALID_HANDLE_VALUE 1081 || iLoop > 10) 1082 ) 1083 { 1084 uint64_t cElapsed = RTTimeMilliTS() - StartMsTS; 1085 if (cElapsed >= cMillies) 1086 { 1087 rc = VERR_TIMEOUT; 1088 break; 1089 } 1090 cMsMaxWait = cMillies - (uint32_t)cElapsed; 1091 } 1092 1093 /* 1094 * Wait. 1095 */ 1096 if (hWait != INVALID_HANDLE_VALUE) 1097 { 1098 RTCritSectLeave(&pThis->CritSect); 1099 1100 DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait); 1101 if (dwRc == WAIT_OBJECT_0) 1102 rc = VINF_SUCCESS; 1103 else if (dwRc == WAIT_TIMEOUT) 1104 rc = VERR_TIMEOUT; 1105 else if (dwRc == WAIT_ABANDONED) 1106 rc = VERR_INVALID_HANDLE; 1107 else 1108 rc = RTErrConvertFromWin32(GetLastError()); 1109 1110 if ( RT_FAILURE(rc) 1111 && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC) 1112 return rc; 1113 1114 int rc2 = RTCritSectEnter(&pThis->CritSect); 1115 AssertRC(rc2); 1116 if (pThis->fZeroByteRead) 1117 { 1118 Assert(pThis->cRefs); 1119 pThis->cRefs--; 1120 pThis->fIOPending = false; 1121 1122 if (rc != VINF_SUCCESS) 1123 { 1124 BOOL fRc = CancelIo(pThis->hNmPipe); 1125 Assert(fRc == TRUE); 1126 } 1127 1128 DWORD cbRead = 0; 1129 BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/); 1130 if ( !fRc 1131 && RT_SUCCESS(rc)) 1132 { 1133 DWORD dwRc = GetLastError(); 1134 if (dwRc == ERROR_OPERATION_ABORTED) 1135 rc = VERR_CANCELLED; 1136 else 1137 rc = RTErrConvertFromWin32(dwRc); 1138 } 1139 } 1140 1141 if (RT_FAILURE(rc)) 1142 break; 1143 } 1144 } 1145 1146 int rc2 = RTCritSectLeave(&pThis->CritSect); 1009 1147 if (RT_SUCCESS(rc)) 1010 { 1011 /* No concurrent waiters, sorry. */ 1012 if (pThis->cRefs == 0) 1013 { 1014 pThis->cRefs++; 1015 pThis->fCancelled = false; /* Reset canellation status. */ 1016 RTCritSectLeave(&pThis->CritSect); 1017 1018 DWORD dwTimeout = cMillies == RT_INDEFINITE_WAIT 1019 ? INFINITE : cMillies; 1020 DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, dwTimeout); 1021 1022 RTCritSectEnter(&pThis->CritSect); 1023 if (dwRc == WAIT_TIMEOUT) 1024 { 1025 rc = VERR_TIMEOUT; 1026 } 1027 else if (dwRc == WAIT_ABANDONED) 1028 { 1029 rc = VERR_BROKEN_PIPE; 1030 } 1031 else if (dwRc == WAIT_FAILED) 1032 rc = RTErrConvertFromWin32(GetLastError()); 1033 else if (pThis->fCancelled) 1034 rc = VERR_CANCELLED; 1035 1036 pThis->cRefs--; 1037 } 1038 else 1039 rc = VERR_WRONG_ORDER; 1040 RTCritSectLeave(&pThis->CritSect); 1041 } 1148 rc = rc2; 1042 1149 1043 1150 return rc; -
trunk/src/VBox/Runtime/testcase/tstRTLocalIpc.cpp
r47084 r47122 71 71 static int testServerListenAndCancel(RTTEST hTest, const char *pszExecPath) 72 72 { 73 RTTest ISub("testServerListenAndCancel");73 RTTestSub(hTest, "testServerListenAndCancel"); 74 74 75 75 RTLOCALIPCSERVER ipcServer; … … 118 118 RTLOCALIPCSESSION ipcSession; 119 119 rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession); 120 #ifdef DEBUG_andy 121 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionConnectionThread: Listening returned with rc=%Rrc\n", rc); 122 #endif 120 RTTestPrintf(pCtx->hTest, RTTESTLVL_DEBUG, "testSessionConnectionThread: Listening returned with rc=%Rrc\n", rc); 123 121 if (RT_SUCCESS(rc)) 124 122 { … … 151 149 static int testSessionConnection(RTTEST hTest, const char *pszExecPath) 152 150 { 153 RTTest ISub("testSessionConnection");151 RTTestSub(hTest, "testSessionConnection"); 154 152 155 153 RTLOCALIPCSERVER ipcServer; … … 158 156 if (RT_SUCCESS(rc)) 159 157 { 160 #if 0158 #ifndef VBOX_TESTCASES_WITH_NO_THREADING 161 159 LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest }; 162 160 … … 181 179 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread, 182 180 30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS); 183 RTTEST_CHECK_RC_BREAK(hTest, threadRc, V INF_SUCCESS);181 RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED); 184 182 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n"); 185 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), 183 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS); 186 184 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL); 187 185 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0); … … 190 188 } 191 189 else 192 RTTest IFailed("Unable to create thread for cancelling server, rc=%Rrc\n", rc);190 RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc); 193 191 #else 194 192 do … … 205 203 } 206 204 else 207 RTTest IFailed("Error while listening, rc=%Rrc\n", rc);205 RTTestFailed(hTest, "Error while listening, rc=%Rrc\n", rc); 208 206 209 207 } while (0); … … 211 209 } 212 210 else 213 RTTest IFailed("Unable to create IPC server, rc=%Rrc\n", rc);211 RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc); 214 212 215 213 return VINF_SUCCESS; 216 214 } 217 215 216 static DECLCALLBACK(int) testSessionWaitThread(RTTHREAD hSelf, void *pvUser) 217 { 218 PLOCALIPCTHREADCTX pCtx = (PLOCALIPCTHREADCTX)pvUser; 219 AssertPtr(pCtx); 220 221 int rc; 222 for (;;) 223 { 224 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening for incoming connections ...\n"); 225 RTLOCALIPCSESSION ipcSession; 226 rc = RTLocalIpcServerListen(pCtx->hServer, &ipcSession); 227 if (RT_SUCCESS(rc)) 228 { 229 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Got new client connection, waiting a bit ...\n"); 230 RTThreadSleep(2000); 231 rc = RTLocalIpcSessionClose(ipcSession); 232 } 233 else 234 { 235 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Listening ended with rc=%Rrc\n", rc); 236 break; 237 } 238 } 239 240 RTTestPrintf(pCtx->hTest, RTTESTLVL_INFO, "testSessionWaitThread: Ended with rc=%Rrc\n", rc); 241 return rc; 242 } 243 244 static RTEXITCODE testSessionWaitChild(int argc, char **argv, RTTEST hTest) 245 { 246 do 247 { 248 RTThreadSleep(2000); /* Fudge. */ 249 RTLOCALIPCSESSION clientSession; 250 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionConnect(&clientSession, "tstRTLocalIpcSessionWait", 251 0 /* Flags */), VINF_SUCCESS); 252 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 100 /* 100ms timeout */), 253 VERR_TIMEOUT); 254 /* Next, try 60s timeout. Should be returning way earlier because the server closed the 255 * connection after the first client connected. */ 256 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 60 * 1000), 257 VERR_BROKEN_PIPE); 258 /* Last try, also should fail because the server should be not around anymore. */ 259 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionWaitForData(clientSession, 5 * 1000), 260 VERR_BROKEN_PIPE); 261 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcSessionClose(clientSession), VINF_SUCCESS); 262 263 } while (0); 264 265 return !RTTestErrorCount(hTest) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 266 } 267 268 static int testSessionWait(RTTEST hTest, const char *pszExecPath) 269 { 270 RTTestSub(hTest, "testSessionWait"); 271 272 RTLOCALIPCSERVER ipcServer; 273 int rc = RTLocalIpcServerCreate(&ipcServer, "tstRTLocalIpcSessionWait", 274 RTLOCALIPC_FLAGS_MULTI_SESSION); 275 if (RT_SUCCESS(rc)) 276 { 277 LOCALIPCTHREADCTX threadCtx = { ipcServer, hTest }; 278 279 /* Spawn a simple worker thread and let it listen for incoming connections. 280 * In the meanwhile we try to cancel the server and see what happens. */ 281 RTTHREAD hThread; 282 rc = RTThreadCreate(&hThread, testSessionWaitThread, 283 &threadCtx, 0 /* Stack */, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tstIpc3"); 284 if (RT_SUCCESS(rc)) 285 { 286 do 287 { 288 RTPROCESS hProc; 289 const char *apszArgs[4] = { pszExecPath, "child", "tstRTLocalIpcSessionWaitFork", NULL }; 290 RTTEST_CHECK_RC_BREAK(hTest, RTProcCreate(pszExecPath, apszArgs, 291 RTENV_DEFAULT, 0 /* fFlags*/, &hProc), VINF_SUCCESS); 292 RTThreadSleep(5000); /* Let the server run for some time ... */ 293 RTTestPrintf(hTest, RTTESTLVL_INFO, "Cancelling server listening\n"); 294 RTTEST_CHECK_RC_BREAK(hTest, RTLocalIpcServerCancel(ipcServer), VINF_SUCCESS); 295 /* Wait for the server thread to terminate. */ 296 int threadRc; 297 RTTEST_CHECK_RC(hTest, RTThreadWait(hThread, 298 30 * 1000 /* 30s timeout */, &threadRc), VINF_SUCCESS); 299 RTTEST_CHECK_RC_BREAK(hTest, threadRc, VERR_CANCELLED); 300 RTTEST_CHECK_RC(hTest, RTLocalIpcServerDestroy(ipcServer), VINF_SUCCESS); 301 RTTestPrintf(hTest, RTTESTLVL_INFO, "Server thread terminated successfully\n"); 302 /* Check if the child ran successfully. */ 303 RTPROCSTATUS stsChild; 304 RTTEST_CHECK_RC_BREAK(hTest, RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &stsChild), VINF_SUCCESS); 305 RTTestPrintf(hTest, RTTESTLVL_INFO, "Child terminated\n"); 306 RTTEST_CHECK_BREAK(hTest, stsChild.enmReason == RTPROCEXITREASON_NORMAL); 307 RTTEST_CHECK_BREAK(hTest, stsChild.iStatus == 0); 308 } 309 while (0); 310 } 311 else 312 RTTestFailed(hTest, "Unable to create thread for cancelling server, rc=%Rrc\n", rc); 313 } 314 else 315 RTTestFailed(hTest, "Unable to create IPC server, rc=%Rrc\n", rc); 316 317 return VINF_SUCCESS; 318 } 319 218 320 static RTEXITCODE mainChild(int argc, char **argv) 219 321 { 322 if (argc < 3) /* Safety first. */ 323 return RTEXITCODE_FAILURE; 220 324 /* Note: We assume argv[2] always contains the actual test type to perform. */ 221 325 RTTEST hTest; … … 225 329 RTTestBanner(hTest); 226 330 331 RTAssertSetMayPanic(false); 332 #ifdef DEBUG_andy 333 RTAssertSetQuiet(true); 334 #endif 335 227 336 if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionConnectionFork")) 228 337 rcExit = testSessionConnectionChild(argc, argv, hTest); 338 else if (!RTStrICmp(argv[2], "tstRTLocalIpcSessionWaitFork")) 339 rcExit = testSessionWaitChild(argc, argv, hTest); 229 340 230 341 return RTTestSummaryAndDestroy(hTest); … … 283 394 if (RTTestErrorCount(hTest) == 0) 284 395 { 285 #ifndef DEBUG_andy286 396 RTTESTI_CHECK_RC_RET(testServerListenAndCancel(hTest, szExecPath), VINF_SUCCESS, 1); 287 #endif288 397 RTTESTI_CHECK_RC_RET(testSessionConnection(hTest, szExecPath), VINF_SUCCESS, 1); 398 RTTESTI_CHECK_RC_RET(testSessionWait(hTest, szExecPath), VINF_SUCCESS, 1); 289 399 } 290 400
Note:
See TracChangeset
for help on using the changeset viewer.