Changeset 58298 in vbox
- Timestamp:
- Oct 18, 2015 7:19:52 PM (9 years ago)
- svn:sync-xref-src-repo-rev:
- 103494
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/win/localipc-win.cpp
r58293 r58298 29 29 * Header Files * 30 30 *********************************************************************************************************************************/ 31 #define RTMEM_WRAP_TO_EF_APIS 32 #define LOG_GROUP RTLOGGROUP_LOCALIPC 31 33 /* 32 34 * We have to force NT 5.0 here because of … … 40 42 # define _WIN32_WINNT 0x0500 41 43 #endif 44 #define UNICODE /* For the SDDL_ strings. */ 42 45 #include <Windows.h> 43 46 #include <sddl.h> 44 47 45 #include <iprt/alloc.h> 48 #include "internal/iprt.h" 49 #include <iprt/localipc.h> 50 46 51 #include <iprt/asm.h> 47 52 #include <iprt/assert.h> 48 53 #include <iprt/critsect.h> 54 #include <iprt/ctype.h> 49 55 #include <iprt/err.h> 50 56 #include <iprt/ldr.h> 51 #include <iprt/localipc.h> 57 #include <iprt/log.h> 58 #include <iprt/mem.h> 52 59 #include <iprt/param.h> 53 60 #include <iprt/string.h> … … 56 63 57 64 #include "internal/magics.h" 65 #include "internal-r3-win.h" 66 58 67 59 68 … … 62 71 *********************************************************************************************************************************/ 63 72 /** Pipe prefix string. */ 64 #define RTLOCALIPC_WIN_PREFIX "\\\\.\\pipe\\IPRT-"73 #define RTLOCALIPC_WIN_PREFIX L"\\\\.\\pipe\\IPRT-" 65 74 66 75 /** DACL for block all network access and local users other than the creator/owner. … … 97 106 #define RTLOCALIPC_WIN_SDDL_BASE \ 98 107 SDDL_DACL SDDL_DELIMINATOR \ 99 SDDL_ACE_BEGIN SDDL_ACCESS_DENIED ";;" SDDL_GENERIC_ALL";;;" SDDL_NETWORK SDDL_ACE_END \100 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END108 SDDL_ACE_BEGIN SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK SDDL_ACE_END \ 109 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END 101 110 102 111 #define RTLOCALIPC_WIN_SDDL_SERVER \ 103 112 RTLOCALIPC_WIN_SDDL_BASE \ 104 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019f"";;;" SDDL_EVERYONE SDDL_ACE_END113 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019f" L";;;" SDDL_EVERYONE SDDL_ACE_END 105 114 106 115 #define RTLOCALIPC_WIN_SDDL_CLIENT \ 107 116 RTLOCALIPC_WIN_SDDL_BASE \ 108 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b"";;;" SDDL_EVERYONE SDDL_ACE_END109 110 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \111 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";CIOI;" SDDL_GENERIC_ALL";;;" SDDL_CREATOR_OWNER SDDL_ACE_END112 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b"";;;" SDDL_EVERYONE SDDL_ACE_END113 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END117 SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b" L";;;" SDDL_EVERYONE SDDL_ACE_END 118 119 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \ 120 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";CIOI;" SDDL_GENERIC_ALL L";;;" SDDL_CREATOR_OWNER SDDL_ACE_END 121 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b" L";;;" SDDL_EVERYONE SDDL_ACE_END 122 // SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END 114 123 115 124 … … 139 148 /** The overlapped I/O structure. */ 140 149 OVERLAPPED OverlappedIO; 141 /** The pipe name. */142 charszName[1];150 /** The full pipe name (variable length). */ 151 RTUTF16 wszName[1]; 143 152 } RTLOCALIPCSERVERINT; 144 153 /** Pointer to a local IPC server instance (Windows). */ … … 148 157 /** 149 158 * Local IPC session instance, Windows. 159 * 160 * This is a named pipe and we should probably merge the pipe code with this to 161 * save work and code duplication. 150 162 */ 151 163 typedef struct RTLOCALIPCSESSIONINT … … 158 170 * @remarks The reference counting isn't race proof. */ 159 171 uint32_t volatile cRefs; 160 /** Set if there is already pending I/O. */161 bool fIOPending;162 172 /** Set if the zero byte read that the poll code using is pending. */ 163 173 bool fZeroByteRead; 164 174 /** Indicates that there is a pending cancel request. */ 165 175 bool volatile fCancelled; 176 /** Set if this is the server side, clear if the client. */ 177 bool fServerSide; 166 178 /** The named pipe handle. */ 167 179 HANDLE hNmPipe; 168 /** The handle to the event object we're using for overlapped I/O. */ 169 HANDLE hEvent; 170 /** The overlapped I/O structure. */ 171 OVERLAPPED OverlappedIO; 180 struct 181 { 182 RTTHREAD hActiveThread; 183 /** The handle to the event object we're using for overlapped I/O. */ 184 HANDLE hEvent; 185 /** The overlapped I/O structure. */ 186 OVERLAPPED OverlappedIO; 187 } 188 /** Overlapped reads. */ 189 Read, 190 /** Overlapped writes. */ 191 Write; 192 #if 0 /* Non-blocking writes are not yet supported. */ 172 193 /** Bounce buffer for writes. */ 173 194 uint8_t *pbBounceBuf; … … 176 197 /** Amount of allocated buffer space. */ 177 198 size_t cbBounceBufAlloc; 199 #endif 178 200 /** Buffer for the zero byte read. 179 * 201 * Used in RTLocalIpcSessionWaitForData(). */ 180 202 uint8_t abBuf[8]; 181 203 } RTLOCALIPCSESSIONINT; … … 183 205 typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT; 184 206 185 typedef BOOL WINAPI FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR(LPCTSTR, DWORD, PSECURITY_DESCRIPTOR, PULONG);186 typedef FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR187 *PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR; /* No, nobody fell on the keyboard, really! */188 189 207 190 208 /********************************************************************************************************************************* 191 209 * Internal Functions * 192 210 *********************************************************************************************************************************/ 193 static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession); 211 static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession); 212 213 214 /********************************************************************************************************************************* 215 * Global Variables * 216 *********************************************************************************************************************************/ 217 static bool volatile g_fResolvedApis = false; 218 /** advapi32.dll API ConvertStringSecurityDescriptorToSecurityDescriptorW. */ 219 static decltype(ConvertStringSecurityDescriptorToSecurityDescriptorW) *g_pfnSSDLToSecDescW = NULL; 194 220 195 221 … … 204 230 static int rtLocalIpcServerWinAllocSecurityDescriptior(PSECURITY_DESCRIPTOR *ppDesc, bool fServer) 205 231 { 206 /** @todo Stuff this into RTInitOnce? Later. */ 207 PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR 208 pfnConvertStringSecurityDescriptorToSecurityDescriptor = NULL; 209 210 RTLDRMOD hAdvApi32 = NIL_RTLDRMOD; 211 int rc = RTLdrLoadSystem("Advapi32.dll", true /*fNoUnload*/, &hAdvApi32); 212 if (RT_SUCCESS(rc)) 213 rc = RTLdrGetSymbol(hAdvApi32, "ConvertStringSecurityDescriptorToSecurityDescriptorW", 214 (void**)&pfnConvertStringSecurityDescriptorToSecurityDescriptor); 215 232 /* 233 * Resolve the API the first time around. 234 */ 235 if (!g_fResolvedApis) 236 { 237 g_pfnSSDLToSecDescW = (decltype(g_pfnSSDLToSecDescW))RTLdrGetSystemSymbol("advapi32.dll", "ConvertStringSecurityDescriptorToSecurityDescriptorW"); 238 ASMCompilerBarrier(); 239 g_fResolvedApis = true; 240 } 241 242 int rc; 216 243 PSECURITY_DESCRIPTOR pSecDesc = NULL; 217 if (RT_SUCCESS(rc)) 218 { 219 AssertPtr(pfnConvertStringSecurityDescriptorToSecurityDescriptor); 220 244 if (g_pfnSSDLToSecDescW) 245 { 221 246 /* 222 247 * We'll create a security descriptor from a SDDL that denies … … 225 250 * users from screwing around. 226 251 */ 227 /** @todo r=bird: Why do you convert a string litteral? the 'L' prefix should 228 * be sufficient, shouldn't it?? */ 229 PRTUTF16 pwszSDDL; 230 rc = RTStrToUtf16(fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT, &pwszSDDL); 231 if (RT_SUCCESS(rc)) 232 { 233 if (!pfnConvertStringSecurityDescriptorToSecurityDescriptor((LPCTSTR)pwszSDDL, 234 SDDL_REVISION_1, 235 &pSecDesc, 236 NULL)) 237 { 238 rc = RTErrConvertFromWin32(GetLastError()); 239 } 240 241 RTUtf16Free(pwszSDDL); 242 } 252 PCRTUTF16 pwszSDDL = fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT; 253 if (g_pfnSSDLToSecDescW(pwszSDDL, SDDL_REVISION_1, &pSecDesc, NULL)) 254 { 255 AssertPtr(pSecDesc); 256 *ppDesc = pSecDesc; 257 return VINF_SUCCESS; 258 } 259 260 rc = RTErrConvertFromWin32(GetLastError()); 243 261 } 244 262 else … … 248 266 rc = VERR_NOT_SUPPORTED; 249 267 } 250 251 if (hAdvApi32 != NIL_RTLDRMOD)252 RTLdrClose(hAdvApi32);253 254 if (RT_SUCCESS(rc))255 {256 AssertPtr(pSecDesc);257 *ppDesc = pSecDesc;258 }259 260 268 return rc; 261 269 } 262 270 271 263 272 /** 264 273 * Creates a named pipe instance. … … 267 276 * 268 277 * @return IPRT status code. 269 * @param phNmPipe Where to store the named pipe handle on success. This 270 * will be set to INVALID_HANDLE_VALUE on failure. 271 * @param pszFullPipeName The full named pipe name. 272 * @param fFirst Set on the first call (from RTLocalIpcServerCreate), otherwise clear. 273 * Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag. 274 */ 275 static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst) 278 * @param phNmPipe Where to store the named pipe handle on success. 279 * This will be set to INVALID_HANDLE_VALUE on failure. 280 * @param pwszPipeName The named pipe name, full, UTF-16 encoded. 281 * @param fFirst Set on the first call (from RTLocalIpcServerCreate), 282 * otherwise clear. Governs the 283 * FILE_FLAG_FIRST_PIPE_INSTANCE flag. 284 */ 285 static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, PCRTUTF16 pwszPipeName, bool fFirst) 276 286 { 277 287 *phNmPipe = INVALID_HANDLE_VALUE; … … 282 292 { 283 293 SECURITY_ATTRIBUTES SecAttrs; 284 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);294 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES); 285 295 SecAttrs.lpSecurityDescriptor = pSecDesc; 286 SecAttrs.bInheritHandle = FALSE;296 SecAttrs.bInheritHandle = FALSE; 287 297 288 298 DWORD fOpenMode = PIPE_ACCESS_DUPLEX 289 299 | PIPE_WAIT 290 300 | FILE_FLAG_OVERLAPPED; 291 292 bool fSupportsFirstInstance = false; 293 294 OSVERSIONINFOEX OSInfoEx; 295 RT_ZERO(OSInfoEx); 296 OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); 297 if ( GetVersionEx((LPOSVERSIONINFO) &OSInfoEx) 298 && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT) 299 { 300 if ( /* Vista+. */ 301 OSInfoEx.dwMajorVersion >= 6 302 /* Windows XP+. */ 303 || ( OSInfoEx.dwMajorVersion == 5 304 && OSInfoEx.dwMinorVersion > 0) 305 /* Windows 2000. */ 306 || ( OSInfoEx.dwMajorVersion == 5 307 && OSInfoEx.dwMinorVersion == 0 308 && OSInfoEx.wServicePackMajor >= 2)) 309 { 310 /* Requires at least W2K (5.0) SP2+. This is non-fatal. */ 311 fSupportsFirstInstance = true; 312 } 313 } 314 315 if (fFirst && fSupportsFirstInstance) 316 fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; 317 318 HANDLE hNmPipe = CreateNamedPipe(pszFullPipeName, /* lpName */ 319 fOpenMode, /* dwOpenMode */ 320 PIPE_TYPE_BYTE, /* dwPipeMode */ 321 PIPE_UNLIMITED_INSTANCES, /* nMaxInstances */ 322 PAGE_SIZE, /* nOutBufferSize (advisory) */ 323 PAGE_SIZE, /* nInBufferSize (ditto) */ 324 30*1000, /* nDefaultTimeOut = 30 sec */ 325 &SecAttrs); /* lpSecurityAttributes */ 301 if ( fFirst 302 && ( g_enmWinVer >= kRTWinOSType_XP 303 || ( g_enmWinVer == kRTWinOSType_2K 304 && g_WinOsInfoEx.wServicePackMajor >= 2) ) ) 305 fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; /* Introduced with W2K SP2 */ 306 307 HANDLE hNmPipe = CreateNamedPipeW(pwszPipeName, /* lpName */ 308 fOpenMode, /* dwOpenMode */ 309 PIPE_TYPE_BYTE, /* dwPipeMode */ 310 PIPE_UNLIMITED_INSTANCES, /* nMaxInstances */ 311 PAGE_SIZE, /* nOutBufferSize (advisory) */ 312 PAGE_SIZE, /* nInBufferSize (ditto) */ 313 30*1000, /* nDefaultTimeOut = 30 sec */ 314 &SecAttrs); /* lpSecurityAttributes */ 326 315 LocalFree(pSecDesc); 327 316 if (hNmPipe != INVALID_HANDLE_VALUE) 328 {329 317 *phNmPipe = hNmPipe; 330 }331 318 else 332 319 rc = RTErrConvertFromWin32(GetLastError()); … … 337 324 338 325 326 /** 327 * Validates the user specified name. 328 * 329 * @returns IPRT status code. 330 * @param pszName The name to validate. 331 * @param pcwcFullName Where to return the UTF-16 length of the full name. 332 * @param fNative Whether it's a native name or a portable name. 333 */ 334 static int rtLocalIpcWinValidateName(const char *pszName, size_t *pcwcFullName, bool fNative) 335 { 336 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 337 AssertReturn(*pszName, VERR_INVALID_NAME); 338 339 if (!fNative) 340 { 341 size_t cwcName = RT_ELEMENTS(RTLOCALIPC_WIN_PREFIX) - 1; 342 for (;;) 343 { 344 char ch = *pszName++; 345 if (!ch) 346 break; 347 AssertReturn(!RT_C_IS_CNTRL(ch), VERR_INVALID_NAME); 348 AssertReturn((unsigned)ch < 0x80, VERR_INVALID_NAME); 349 AssertReturn(ch != '\\', VERR_INVALID_NAME); 350 AssertReturn(ch != '/', VERR_INVALID_NAME); 351 cwcName++; 352 } 353 *pcwcFullName = cwcName; 354 } 355 else 356 { 357 int rc = RTStrCalcUtf16LenEx(pszName, RTSTR_MAX, pcwcFullName); 358 AssertRCReturn(rc, rc); 359 } 360 361 return VINF_SUCCESS; 362 } 363 364 365 /** 366 * Constructs the full pipe name as UTF-16. 367 * 368 * @returns IPRT status code. 369 * @param pszName The user supplied name. 370 * @param pwszFullName The output buffer. 371 * @param cwcFullName The output buffer size excluding the terminator. 372 * @param fNative Whether the user supplied name is a native or 373 * portable one. 374 */ 375 static int rtLocalIpcWinConstructName(const char *pszName, PRTUTF16 pwszFullName, size_t cwcFullName, bool fNative) 376 { 377 if (!fNative) 378 { 379 static RTUTF16 const s_wszPrefix[] = RTLOCALIPC_WIN_PREFIX; 380 Assert(cwcFullName * sizeof(RTUTF16) > sizeof(s_wszPrefix)); 381 memcpy(pwszFullName, s_wszPrefix, sizeof(s_wszPrefix)); 382 cwcFullName -= RT_ELEMENTS(s_wszPrefix) - 1; 383 pwszFullName += RT_ELEMENTS(s_wszPrefix) - 1; 384 } 385 return RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszFullName, cwcFullName + 1, NULL); 386 } 387 388 339 389 RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags) 340 390 { 341 391 /* 342 * Basic parameter validation.392 * Validate parameters. 343 393 */ 344 394 AssertPtrReturn(phServer, VERR_INVALID_POINTER); 345 395 346 396 AssertReturn(!(fFlags & ~RTLOCALIPC_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 347 AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_INVALID_FLAGS); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */ 348 349 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 350 AssertReturn(*pszName, VERR_INVALID_NAME); 351 352 /* 353 * Allocate and initialize the instance data. 354 * 355 * We align the size on pointer size here to make sure we get naturally 356 * aligned members in the critsect when the electric fence heap is active. 357 */ 358 size_t cchName = strlen(pszName); 359 size_t cbThis = RT_OFFSETOF(RTLOCALIPCSERVERINT, szName[cchName + sizeof(RTLOCALIPC_WIN_PREFIX)]); 360 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocVar(cbThis); 361 if (!pThis) 362 return VERR_NO_MEMORY; 363 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC; 364 pThis->cRefs = 1; /* the one we return */ 365 pThis->fCancelled = false; 366 memcpy(pThis->szName, RTLOCALIPC_WIN_PREFIX, sizeof(RTLOCALIPC_WIN_PREFIX) - 1); 367 memcpy(&pThis->szName[sizeof(RTLOCALIPC_WIN_PREFIX) - 1], pszName, cchName + 1); 368 int rc = RTCritSectInit(&pThis->CritSect); 397 AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_NOT_IMPLEMENTED); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */ 398 399 size_t cwcFullName; 400 int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME)); 369 401 if (RT_SUCCESS(rc)) 370 402 { 371 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, 372 FALSE /*bInitialState*/, NULL /*lpName*/); 373 if (pThis->hEvent != NULL) 374 { 375 RT_ZERO(pThis->OverlappedIO); 376 pThis->OverlappedIO.Internal = STATUS_PENDING; 377 pThis->OverlappedIO.hEvent = pThis->hEvent; 378 379 rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, 380 pThis->szName, true /* fFirst */); 403 /* 404 * Allocate and initialize the instance data. 405 */ 406 size_t cbThis = RT_OFFSETOF(RTLOCALIPCSERVERINT, wszName[cwcFullName + 1]); 407 PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocVar(cbThis); 408 AssertReturn(pThis, VERR_NO_MEMORY); 409 410 pThis->u32Magic = RTLOCALIPCSERVER_MAGIC; 411 pThis->cRefs = 1; /* the one we return */ 412 pThis->fCancelled = false; 413 414 rc = rtLocalIpcWinConstructName(pszName, pThis->wszName, cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME)); 415 if (RT_SUCCESS(rc)) 416 { 417 rc = RTCritSectInit(&pThis->CritSect); 381 418 if (RT_SUCCESS(rc)) 382 419 { 383 *phServer = pThis; 384 return VINF_SUCCESS; 420 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, 421 FALSE /*bInitialState*/, NULL /*lpName*/); 422 if (pThis->hEvent != NULL) 423 { 424 RT_ZERO(pThis->OverlappedIO); 425 pThis->OverlappedIO.Internal = STATUS_PENDING; 426 pThis->OverlappedIO.hEvent = pThis->hEvent; 427 428 rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, pThis->wszName, true /* fFirst */); 429 if (RT_SUCCESS(rc)) 430 { 431 *phServer = pThis; 432 return VINF_SUCCESS; 433 } 434 435 BOOL fRc = CloseHandle(pThis->hEvent); 436 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 437 } 438 else 439 rc = RTErrConvertFromWin32(GetLastError()); 440 441 int rc2 = RTCritSectDelete(&pThis->CritSect); 442 AssertRC(rc2); 385 443 } 386 387 BOOL fRc = CloseHandle(pThis->hEvent); 388 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 389 } 390 else 391 rc = RTErrConvertFromWin32(GetLastError()); 392 393 int rc2 = RTCritSectDelete(&pThis->CritSect); 394 AssertRC(rc2); 395 } 396 RTMemFree(pThis); 444 } 445 RTMemFree(pThis); 446 } 397 447 return rc; 448 } 449 450 451 /** 452 * Retains a reference to the server instance. 453 * 454 * @returns 455 * @param pThis The server instance. 456 */ 457 DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis) 458 { 459 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); 460 Assert(cRefs < UINT32_MAX / 2 && cRefs); 398 461 } 399 462 … … 407 470 * @param pThis The instance to destroy. 408 471 */ 409 static int rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis) 410 { 472 DECL_NO_INLINE(static, int) rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis) 473 { 474 Assert(pThis->u32Magic == ~RTLOCALIPCSERVER_MAGIC); 475 pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC; 476 411 477 BOOL fRc = CloseHandle(pThis->hNmPipe); 412 478 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); … … 423 489 return VINF_OBJECT_DESTROYED; 424 490 } 491 492 493 /** 494 * Server instance destructor. 495 * 496 * @returns VINF_OBJECT_DESTROYED 497 * @param pThis The server instance. 498 */ 499 DECL_NO_INLINE(static, int) rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis) 500 { 501 RTCritSectEnter(&pThis->CritSect); 502 return rtLocalIpcServerWinDestroy(pThis); 503 } 504 505 506 /** 507 * Releases a reference to the server instance. 508 * 509 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed. 510 * @param pThis The server instance. 511 */ 512 DECLINLINE(int) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis) 513 { 514 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); 515 Assert(cRefs < UINT32_MAX / 2); 516 if (!cRefs) 517 return rtLocalIpcServerDtor(pThis); 518 return VINF_SUCCESS; 519 } 520 521 522 /** 523 * Releases a reference to the server instance and leaves the critsect. 524 * 525 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed. 526 * @param pThis The server instance. 527 */ 528 DECLINLINE(int) rtLocalIpcServerReleaseAndUnlock(PRTLOCALIPCSERVERINT pThis) 529 { 530 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); 531 Assert(cRefs < UINT32_MAX / 2); 532 if (!cRefs) 533 return rtLocalIpcServerWinDestroy(pThis); 534 return RTCritSectLeave(&pThis->CritSect); 535 } 536 425 537 426 538 … … 440 552 * leaving the cleanup to it. 441 553 */ 554 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER); 555 442 556 RTCritSectEnter(&pThis->CritSect); 443 ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC); 557 558 /* Cancel everything. */ 444 559 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 445 Assert(pThis->cRefs); 446 pThis->cRefs--; 447 448 if (pThis->cRefs) 560 if (pThis->cRefs > 1) 449 561 { 450 562 BOOL fRc = SetEvent(pThis->hEvent); 451 563 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 452 453 RTCritSectLeave(&pThis->CritSect); 454 } 455 else 456 return rtLocalIpcServerWinDestroy(pThis); 457 return VINF_SUCCESS; 564 } 565 566 return rtLocalIpcServerReleaseAndUnlock(pThis); 458 567 } 459 568 … … 467 576 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 468 577 AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE); 578 AssertPtrReturn(phClientSession, VERR_INVALID_POINTER); 469 579 470 580 /* 471 581 * Enter the critsect before inspecting the object further. 472 582 */ 473 int rc; 474 RTCritSectEnter(&pThis->CritSect); 475 if (pThis->fCancelled) 476 { 477 pThis->fCancelled = false; 478 rc = VERR_CANCELLED; 479 RTCritSectLeave(&pThis->CritSect); 480 } 481 else 482 { 483 pThis->cRefs++; 583 int rc = RTCritSectEnter(&pThis->CritSect); 584 AssertRCReturn(rc, rc); 585 586 rtLocalIpcServerRetain(pThis); 587 if (!pThis->fCancelled) 588 { 484 589 ResetEvent(pThis->hEvent); 590 485 591 RTCritSectLeave(&pThis->CritSect); 486 592 … … 516 622 { 517 623 HANDLE hNmPipe; 518 rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis-> szName, false /* fFirst */);624 rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->wszName, false /* fFirst */); 519 625 if (RT_SUCCESS(rc)) 520 626 { … … 539 645 { 540 646 /* 541 * Cancelled or destroyed.647 * Cancelled. 542 648 * 543 649 * Cancel the overlapped io if it didn't complete (must be done 544 650 * in the this thread) or disconnect the client. 545 651 */ 652 Assert(pThis->fCancelled); 546 653 if ( fRc 547 654 || dwErr == ERROR_PIPE_CONNECTED) … … 554 661 rc = VERR_CANCELLED; 555 662 } 556 557 pThis->cRefs--; 558 if (pThis->cRefs) 559 RTCritSectLeave(&pThis->CritSect); 560 else 561 rtLocalIpcServerWinDestroy(pThis); 562 } 563 663 } 664 else 665 { 666 /*pThis->fCancelled = false; - Terrible interface idea. Add API to clear fCancelled if ever required. */ 667 rc = VERR_CANCELLED; 668 } 669 rtLocalIpcServerReleaseAndUnlock(pThis); 564 670 return rc; 565 671 } … … 579 685 * and signal the event (to wake up anyone in/at WaitForSingleObject). 580 686 */ 687 rtLocalIpcServerRetain(pThis); 581 688 int rc = RTCritSectEnter(&pThis->CritSect); 582 689 if (RT_SUCCESS(rc)) 583 690 { 584 691 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 692 585 693 BOOL fRc = SetEvent(pThis->hEvent); 586 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 587 588 rc = RTCritSectLeave(&pThis->CritSect); 589 } 590 694 if (fRc) 695 rc = VINF_SUCCESS; 696 else 697 { 698 DWORD dwErr = GetLastError(); 699 AssertMsgFailed(("dwErr=%u\n", dwErr)); 700 rc = RTErrConvertFromWin32(dwErr); 701 } 702 703 rtLocalIpcServerReleaseAndUnlock(pThis); 704 } 705 else 706 rtLocalIpcServerRelease(pThis); 591 707 return rc; 592 708 } … … 594 710 595 711 /** 596 * Create a session instance .712 * Create a session instance for a new server client or a client connect. 597 713 * 598 714 * @returns IPRT status code. 599 715 * 600 * @param phClientSession Where to store the session handle on success. 601 * @param hNmPipeSession The named pipe handle. This will be consumed by this session, meaning on failure 602 * to create the session it will be closed. 603 */ 604 static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession) 605 { 606 AssertPtrReturn(phClientSession, VERR_INVALID_POINTER); 607 AssertReturn(hNmPipeSession != INVALID_HANDLE_VALUE, VERR_INVALID_HANDLE); 608 609 int rc; 716 * @param ppSession Where to store the session handle on success. 717 * @param hNmPipeSession The named pipe handle if server calling, 718 * INVALID_HANDLE_VALUE if client connect. This will 719 * be consumed by this session, meaning on failure to 720 * create the session it will be closed. 721 */ 722 static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession) 723 { 724 AssertPtr(ppSession); 610 725 611 726 /* 612 727 * Allocate and initialize the session instance data. 613 728 */ 614 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis)); 729 int rc; 730 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis)); 615 731 if (pThis) 616 732 { 617 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC; 618 pThis->cRefs = 1; /* our ref */ 619 pThis->fCancelled = false; 620 pThis->fIOPending = false; 621 pThis->fZeroByteRead = false; 622 pThis->hNmPipe = hNmPipeSession; 623 733 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC; 734 pThis->cRefs = 1; /* our ref */ 735 pThis->fCancelled = false; 736 pThis->fZeroByteRead = false; 737 pThis->fServerSide = hNmPipeSession != INVALID_HANDLE_VALUE; 738 pThis->hNmPipe = hNmPipeSession; 739 #if 0 /* Non-blocking writes are not yet supported. */ 740 pThis->pbBounceBuf = NULL; 741 pThis->cbBounceBufAlloc = 0; 742 pThis->cbBounceBufUsed = 0; 743 #endif 624 744 rc = RTCritSectInit(&pThis->CritSect); 625 745 if (RT_SUCCESS(rc)) 626 746 { 627 pThis-> hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,628 FALSE /*bInitialState*/, NULL /*lpName*/);629 if (pThis-> hEvent != NULL)747 pThis->Read.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, 748 FALSE /*bInitialState*/, NULL /*lpName*/); 749 if (pThis->Read.hEvent != NULL) 630 750 { 631 RT_ZERO(pThis->OverlappedIO); 632 pThis->OverlappedIO.Internal = STATUS_PENDING; 633 pThis->OverlappedIO.hEvent = pThis->hEvent; 634 635 *phClientSession = pThis; 636 return VINF_SUCCESS; 751 pThis->Read.OverlappedIO.Internal = STATUS_PENDING; 752 pThis->Read.OverlappedIO.hEvent = pThis->Read.hEvent; 753 pThis->Read.hActiveThread = NIL_RTTHREAD; 754 755 pThis->Write.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, 756 FALSE /*bInitialState*/, NULL /*lpName*/); 757 if (pThis->Write.hEvent != NULL) 758 { 759 pThis->Write.OverlappedIO.Internal = STATUS_PENDING; 760 pThis->Write.OverlappedIO.hEvent = pThis->Write.hEvent; 761 pThis->Write.hActiveThread = NIL_RTTHREAD; 762 763 *ppSession = pThis; 764 return VINF_SUCCESS; 765 } 766 767 CloseHandle(pThis->Read.hEvent); 637 768 } 638 769 … … 646 777 rc = VERR_NO_MEMORY; 647 778 648 BOOL fRc = CloseHandle(hNmPipeSession); 649 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 779 if (hNmPipeSession != INVALID_HANDLE_VALUE) 780 { 781 BOOL fRc = CloseHandle(hNmPipeSession); 782 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 783 } 650 784 return rc; 651 785 } 652 786 787 653 788 RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags) 654 789 { 790 /* 791 * Validate input. 792 */ 655 793 AssertPtrReturn(phSession, VERR_INVALID_POINTER); 656 AssertPtrReturn(pszName, VERR_INVALID_POINTER); 657 AssertReturn(*pszName, VERR_INVALID_NAME); 658 AssertReturn(!fFlags, VERR_INVALID_FLAGS); /* Flags currently unused, must be 0. */ 659 660 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis)); 661 if (!pThis) 662 return VERR_NO_MEMORY; 663 664 pThis->u32Magic = RTLOCALIPCSESSION_MAGIC; 665 pThis->cRefs = 1; /* The one we return. */ 666 pThis->fIOPending = false; 667 pThis->fZeroByteRead = false; 668 pThis->fCancelled = false; 669 pThis->pbBounceBuf = NULL; 670 pThis->cbBounceBufAlloc = 0; 671 pThis->cbBounceBufUsed = 0; 672 673 int rc = RTCritSectInit(&pThis->CritSect); 794 AssertReturn(!(fFlags & ~RTLOCALIPC_C_FLAGS_VALID_MASK), VERR_INVALID_FLAGS); 795 796 size_t cwcFullName; 797 int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME)); 674 798 if (RT_SUCCESS(rc)) 675 799 { 676 pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, 677 FALSE /*bInitialState*/, NULL /*lpName*/); 678 if (pThis->hEvent != NULL) 679 { 680 RT_ZERO(pThis->OverlappedIO); 681 pThis->OverlappedIO.Internal = STATUS_PENDING; 682 pThis->OverlappedIO.hEvent = pThis->hEvent; 683 800 /* 801 * Create a session (shared with server client session creation). 802 */ 803 PRTLOCALIPCSESSIONINT pThis; 804 rc = rtLocalIpcWinCreateSession(&pThis, INVALID_HANDLE_VALUE); 805 if (RT_SUCCESS(rc)) 806 { 807 /* 808 * Try open the pipe. 809 */ 684 810 PSECURITY_DESCRIPTOR pSecDesc; 685 rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, false /* Client*/);811 rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, false /*fServer*/); 686 812 if (RT_SUCCESS(rc)) 687 813 { 688 char *pszPipe; 689 if (RTStrAPrintf(&pszPipe, "%s%s", RTLOCALIPC_WIN_PREFIX, pszName)) 814 PRTUTF16 pwszFullName = RTUtf16Alloc((cwcFullName + 1) * sizeof(RTUTF16)); 815 if (pwszFullName) 816 rc = rtLocalIpcWinConstructName(pszName, pwszFullName, cwcFullName, 817 RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME)); 818 else 819 rc = VERR_NO_UTF16_MEMORY; 820 if (RT_SUCCESS(rc)) 690 821 { 691 822 SECURITY_ATTRIBUTES SecAttrs; 692 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);823 SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES); 693 824 SecAttrs.lpSecurityDescriptor = pSecDesc; 694 SecAttrs.bInheritHandle = FALSE; 695 696 HANDLE hPipe = CreateFile(pszPipe, /* pipe name */ 697 GENERIC_READ /* read and write access */ 698 | GENERIC_WRITE, 699 0, /* no sharing */ 700 &SecAttrs, /* lpSecurityAttributes */ 701 OPEN_EXISTING, /* opens existing pipe */ 702 FILE_FLAG_OVERLAPPED, /* default attributes */ 703 NULL); /* no template file */ 704 RTStrFree(pszPipe); 705 825 SecAttrs.bInheritHandle = FALSE; 826 827 HANDLE hPipe = CreateFileW(pwszFullName, 828 GENERIC_READ | GENERIC_WRITE, 829 0 /*no sharing*/, 830 &SecAttrs, 831 OPEN_EXISTING, 832 FILE_FLAG_OVERLAPPED, 833 NULL /*no template hanlde*/); 706 834 if (hPipe != INVALID_HANDLE_VALUE) 707 835 { 836 pThis->hNmPipe = hPipe; 837 708 838 LocalFree(pSecDesc); 709 710 pThis->hNmPipe = hPipe; 839 RTUtf16Free(pwszFullName); 840 841 /* 842 * We're done! 843 */ 711 844 *phSession = pThis; 712 845 return VINF_SUCCESS; 713 846 } 714 else 715 847 848 rc = RTErrConvertFromWin32(GetLastError()); 716 849 } 717 else 718 rc = VERR_NO_MEMORY; 719 850 851 RTUtf16Free(pwszFullName); 720 852 LocalFree(pSecDesc); 721 853 } 722 854 723 BOOL fRc = CloseHandle(pThis->hEvent); 724 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 725 } 726 else 727 rc = RTErrConvertFromWin32(GetLastError()); 728 729 int rc2 = RTCritSectDelete(&pThis->CritSect); 730 AssertRC(rc2); 731 } 732 733 RTMemFree(pThis); 855 /* destroy the session handle. */ 856 CloseHandle(pThis->Read.hEvent); 857 CloseHandle(pThis->Write.hEvent); 858 RTCritSectDelete(&pThis->CritSect); 859 860 RTMemFree(pThis); 861 } 862 } 734 863 return rc; 864 } 865 866 867 /** 868 * Cancells all pending I/O operations, forcing the methods to return with 869 * VERR_CANCELLED (unless they've got actual data to return). 870 * 871 * Used by RTLocalIpcSessionCancel and RTLocalIpcSessionClose. 872 * 873 * @returns IPRT status code. 874 * @param pThis The client session instance. 875 */ 876 static int rtLocalIpcWinCancel(PRTLOCALIPCSESSIONINT pThis) 877 { 878 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 879 880 /* 881 * Call CancelIo since this call cancels both read and write oriented operations. 882 */ 883 if ( pThis->fZeroByteRead 884 || pThis->Read.hActiveThread != NIL_RTTHREAD 885 || pThis->Write.hActiveThread != NIL_RTTHREAD) 886 CancelIo(pThis->hNmPipe); 887 888 /* 889 * Set both event semaphores. 890 */ 891 BOOL fRc = SetEvent(pThis->Read.hEvent); 892 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 893 fRc = SetEvent(pThis->Write.hEvent); 894 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 895 896 return VINF_SUCCESS; 897 } 898 899 900 /** 901 * Retains a reference to the session instance. 902 * 903 * @param pThis The client session instance. 904 */ 905 DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis) 906 { 907 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); 908 Assert(cRefs < UINT32_MAX / 2 && cRefs); 735 909 } 736 910 … … 744 918 * @param pThis The instance to destroy. 745 919 */ 746 static intrtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis)920 DECL_NO_INLINE(static, int) rtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis) 747 921 { 748 922 BOOL fRc = CloseHandle(pThis->hNmPipe); … … 750 924 pThis->hNmPipe = INVALID_HANDLE_VALUE; 751 925 752 fRc = CloseHandle(pThis->hEvent); 753 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 754 pThis->hEvent = NULL; 755 756 RTCritSectLeave(&pThis->CritSect); 926 fRc = CloseHandle(pThis->Write.hEvent); 927 AssertMsg(fRc, ("%d\n", GetLastError())); 928 pThis->Write.hEvent = NULL; 929 930 fRc = CloseHandle(pThis->Read.hEvent); 931 AssertMsg(fRc, ("%d\n", GetLastError())); 932 pThis->Read.hEvent = NULL; 933 934 int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2); 757 935 RTCritSectDelete(&pThis->CritSect); 758 936 759 937 RTMemFree(pThis); 760 938 return VINF_OBJECT_DESTROYED; 939 } 940 941 942 /** 943 * Session instance destructor. 944 * 945 * @returns VINF_OBJECT_DESTROYED 946 * @param pThis The server instance. 947 */ 948 DECL_NO_INLINE(static, int) rtLocalIpcSessionDtor(PRTLOCALIPCSESSIONINT pThis) 949 { 950 RTCritSectEnter(&pThis->CritSect); 951 return rtLocalIpcSessionWinDestroy(pThis); 952 } 953 954 955 /** 956 * Releases a reference to the session instance. 957 * 958 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate. 959 * @param pThis The session instance. 960 */ 961 DECLINLINE(int) rtLocalIpcSessionRelease(PRTLOCALIPCSESSIONINT pThis) 962 { 963 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); 964 Assert(cRefs < UINT32_MAX / 2); 965 if (!cRefs) 966 return rtLocalIpcSessionDtor(pThis); 967 Log(("rtLocalIpcSessionRelease: %u refs left\n", cRefs)); 968 return VINF_SUCCESS; 969 } 970 971 972 /** 973 * Releases a reference to the session instance and unlock it. 974 * 975 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate. 976 * @param pThis The session instance. 977 */ 978 DECLINLINE(int) rtLocalIpcSessionReleaseAndUnlock(PRTLOCALIPCSESSIONINT pThis) 979 { 980 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs); 981 Assert(cRefs < UINT32_MAX / 2); 982 if (!cRefs) 983 return rtLocalIpcSessionWinDestroy(pThis); 984 985 int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2); 986 Log(("rtLocalIpcSessionRelease: %u refs left\n", cRefs)); 987 return VINF_SUCCESS; 761 988 } 762 989 … … 774 1001 775 1002 /* 776 * Cancel any thread currently busy using the session, 777 * leaving the cleanup to it. 1003 * Invalidate the instance, cancel all outstanding I/O and drop our reference. 778 1004 */ 1005 AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSESSION_MAGIC, RTLOCALIPCSESSION_MAGIC), VERR_WRONG_ORDER); 1006 779 1007 RTCritSectEnter(&pThis->CritSect); 780 ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSESSION_MAGIC); 781 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 782 pThis->cRefs--; 783 784 if (pThis->cRefs > 0) 785 { 786 BOOL fRc = SetEvent(pThis->hEvent); 787 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 788 789 RTCritSectLeave(&pThis->CritSect); 1008 rtLocalIpcWinCancel(pThis); 1009 return rtLocalIpcSessionReleaseAndUnlock(pThis); 1010 } 1011 1012 1013 /** 1014 * Handles WaitForSingleObject return value when waiting for a zero byte read. 1015 * 1016 * The zero byte read is started by the RTLocalIpcSessionWaitForData method and 1017 * left pending when the function times out. This saves us the problem of 1018 * CancelIo messing with all active I/O operations and the trouble of restarting 1019 * the zero byte read the next time the method is called. However should 1020 * RTLocalIpcSessionRead be called after a failed RTLocalIpcSessionWaitForData 1021 * call, the zero byte read will still be pending and it must wait for it to 1022 * complete before the OVERLAPPEDIO structure can be reused. 1023 * 1024 * Thus, both functions will do WaitForSingleObject and share this routine to 1025 * handle the outcome. 1026 * 1027 * @returns IPRT status code. 1028 * @param pThis The session instance. 1029 * @param rcWait The WaitForSingleObject return code. 1030 */ 1031 static int rtLocalIpcWinGetZeroReadResult(PRTLOCALIPCSESSIONINT pThis, DWORD rcWait) 1032 { 1033 int rc; 1034 DWORD cbRead = 42; 1035 if (rcWait == WAIT_OBJECT_0) 1036 { 1037 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, !pThis->fCancelled /*fWait*/)) 1038 { 1039 Assert(cbRead == 0); 1040 rc = VINF_SUCCESS; 1041 pThis->fZeroByteRead = false; 1042 } 1043 else if (pThis->fCancelled) 1044 rc = VERR_CANCELLED; 1045 else 1046 rc = RTErrConvertFromWin32(GetLastError()); 790 1047 } 791 1048 else 792 return rtLocalIpcSessionWinDestroy(pThis); 793 return VINF_SUCCESS; 1049 { 1050 /* We try get the result here too, just in case we're lucky, but no waiting. */ 1051 DWORD dwErr = GetLastError(); 1052 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, FALSE /*fWait*/)) 1053 { 1054 Assert(cbRead == 0); 1055 rc = VINF_SUCCESS; 1056 pThis->fZeroByteRead = false; 1057 } 1058 else if (rcWait == WAIT_TIMEOUT) 1059 rc = VERR_TIMEOUT; 1060 else if (rcWait == WAIT_ABANDONED) 1061 rc = VERR_INVALID_HANDLE; 1062 else 1063 rc = RTErrConvertFromWin32(dwErr); 1064 } 1065 return rc; 794 1066 } 795 1067 … … 806 1078 if (RT_SUCCESS(rc)) 807 1079 { 808 /* No concurrent readers, sorry. */ 809 if (pThis->cRefs == 1) 810 { 811 pThis->cRefs++; 1080 rtLocalIpcSessionRetain(pThis); 1081 if (pThis->Read.hActiveThread == NIL_RTTHREAD) 1082 { 1083 pThis->Read.hActiveThread = RTThreadSelf(); 1084 Assert(!pThis->fZeroByteRead); 812 1085 813 1086 size_t cbTotalRead = 0; 814 1087 while (cbToRead > 0) 815 1088 { 816 /*817 * Kick of a an overlapped read. It should return immediately if818 * there is bytes in the buffer. If not, we'll cancel it and see819 * what we get back.820 */821 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);822 1089 DWORD cbRead = 0; 823 pThis->fIOPending = true; 824 RTCritSectLeave(&pThis->CritSect); 825 826 if (ReadFile(pThis->hNmPipe, pvBuf, 827 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0, 828 &cbRead, &pThis->OverlappedIO)) 829 rc = VINF_SUCCESS; 830 else if (GetLastError() == ERROR_IO_PENDING) 1090 if (!pThis->fCancelled) 831 1091 { 832 WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE); 833 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, 834 &cbRead, TRUE /*fWait*/)) 835 rc = VINF_SUCCESS; 1092 /* 1093 * Wait for pending zero byte read, if necessary. 1094 * Note! It cannot easily be cancelled due to concurrent current writes. 1095 */ 1096 if (!pThis->fZeroByteRead) 1097 { /* likely */ } 836 1098 else 837 1099 { 838 DWORD dwErr = GetLastError(); 839 AssertMsgFailed(("err=%ld\n", dwErr)); 840 rc = RTErrConvertFromWin32(dwErr); 1100 RTCritSectLeave(&pThis->CritSect); 1101 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, RT_MS_1MIN); 1102 RTCritSectEnter(&pThis->CritSect); 1103 1104 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait); 1105 if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT) 1106 continue; 1107 break; 1108 } 1109 1110 /* 1111 * Kick of a an overlapped read. It should return immediately if 1112 * there is bytes in the buffer. If not, we'll cancel it and see 1113 * what we get back. 1114 */ 1115 rc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(rc == TRUE); 1116 RTCritSectLeave(&pThis->CritSect); 1117 1118 if (ReadFile(pThis->hNmPipe, pvBuf, 1119 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0, 1120 &cbRead, &pThis->Read.OverlappedIO)) 1121 { 1122 RTCritSectEnter(&pThis->CritSect); 1123 rc = VINF_SUCCESS; 1124 } 1125 else if (GetLastError() == ERROR_IO_PENDING) 1126 { 1127 DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, INFINITE); 1128 1129 RTCritSectEnter(&pThis->CritSect); 1130 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, 1131 rcWait == WAIT_OBJECT_0 && !pThis->fCancelled /*fWait*/)) 1132 rc = VINF_SUCCESS; 1133 else 1134 { 1135 if (pThis->fCancelled) 1136 rc = VERR_CANCELLED; 1137 else 1138 rc = RTErrConvertFromWin32(GetLastError()); 1139 break; 1140 } 1141 } 1142 else 1143 { 1144 rc = RTErrConvertFromWin32(GetLastError()); 1145 AssertMsgFailedBreak(("%Rrc\n", rc)); 841 1146 } 842 1147 } 843 1148 else 844 1149 { 845 DWORD dwErr = GetLastError(); 846 AssertMsgFailed(("err2=%ld\n", dwErr)); 847 rc = RTErrConvertFromWin32(dwErr); 1150 rc = VERR_CANCELLED; 1151 break; 848 1152 } 849 850 RTCritSectEnter(&pThis->CritSect);851 pThis->fIOPending = false;852 if (RT_FAILURE(rc))853 break;854 1153 855 1154 /* Advance. */ … … 868 1167 } 869 1168 870 pThis-> cRefs--;1169 pThis->Read.hActiveThread = NIL_RTTHREAD; 871 1170 } 872 1171 else 873 1172 rc = VERR_WRONG_ORDER; 874 RTCritSectLeave(&pThis->CritSect);1173 rtLocalIpcSessionReleaseAndUnlock(pThis); 875 1174 } 876 1175 … … 879 1178 880 1179 1180 #if 0 /* Non-blocking writes are not yet supported. */ 881 1181 /** 882 1182 * Common worker for handling I/O completion. … … 890 1190 { 891 1191 int rc; 892 DWORD dwRc= WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);893 if ( dwRc== WAIT_OBJECT_0)1192 DWORD rcWait = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0); 1193 if (rcWait == WAIT_OBJECT_0) 894 1194 { 895 1195 DWORD cbWritten = 0; … … 933 1233 } 934 1234 } 935 else if ( dwRc== WAIT_TIMEOUT)1235 else if (rcWait == WAIT_TIMEOUT) 936 1236 rc = VINF_TRY_AGAIN; 937 1237 else 938 1238 { 939 1239 pThis->fIOPending = false; 940 if ( dwRc== WAIT_ABANDONED)1240 if (rcWait == WAIT_ABANDONED) 941 1241 rc = VERR_INVALID_HANDLE; 942 1242 else … … 945 1245 return rc; 946 1246 } 1247 #endif 947 1248 948 1249 … … 958 1259 if (RT_SUCCESS(rc)) 959 1260 { 960 /* No concurrent writers, sorry. */961 if (pThis-> cRefs == 1)962 { 963 pThis-> cRefs++;1261 rtLocalIpcSessionRetain(pThis); 1262 if (pThis->Write.hActiveThread == NIL_RTTHREAD) 1263 { 1264 pThis->Write.hActiveThread = RTThreadSelf(); 964 1265 965 1266 /* 966 * If I/O is pending, wait for it to complete.1267 * Try write everything. No bounce buffering necessary. 967 1268 */ 968 if (pThis->fIOPending) 1269 size_t cbTotalWritten = 0; 1270 while (cbToWrite > 0) 969 1271 { 970 rc = rtLocalIpcSessionWriteCheckCompletion(pThis);971 while (rc == VINF_TRY_AGAIN)1272 DWORD cbWritten = 0; 1273 if (!pThis->fCancelled) 972 1274 { 973 Assert(pThis->fIOPending); 974 HANDLE hEvent = pThis->OverlappedIO.hEvent; 1275 BOOL fRc = ResetEvent(pThis->Write.OverlappedIO.hEvent); Assert(fRc == TRUE); 975 1276 RTCritSectLeave(&pThis->CritSect); 976 WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE); 977 RTCritSectEnter(&pThis->CritSect); 978 } 979 } 980 if (RT_SUCCESS(rc)) 981 { 982 Assert(!pThis->fIOPending); 983 984 /* 985 * Try write everything. 986 * No bounce buffering, cUsers protects us. 987 */ 988 size_t cbTotalWritten = 0; 989 while (cbToWrite > 0) 990 { 991 BOOL fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE); 992 pThis->fIOPending = true; 993 RTCritSectLeave(&pThis->CritSect); 994 995 DWORD cbWritten = 0; 1277 996 1278 fRc = WriteFile(pThis->hNmPipe, pvBuf, 997 1279 cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0, 998 &cbWritten, &pThis-> OverlappedIO);1280 &cbWritten, &pThis->Write.OverlappedIO); 999 1281 if (fRc) 1000 {1001 1282 rc = VINF_SUCCESS; 1002 }1003 1283 else 1004 1284 { … … 1006 1286 if (dwErr == ERROR_IO_PENDING) 1007 1287 { 1008 DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);1009 if ( dwRc== WAIT_OBJECT_0)1288 DWORD rcWait = WaitForSingleObject(pThis->Write.OverlappedIO.hEvent, INFINITE); 1289 if (rcWait == WAIT_OBJECT_0) 1010 1290 { 1011 if (GetOverlappedResult(pThis->hNmPipe, &pThis-> OverlappedIO, &cbWritten, TRUE /*fWait*/))1291 if (GetOverlappedResult(pThis->hNmPipe, &pThis->Write.OverlappedIO, &cbWritten, TRUE /*fWait*/)) 1012 1292 rc = VINF_SUCCESS; 1013 1293 else 1014 1294 rc = RTErrConvertFromWin32(GetLastError()); 1015 1295 } 1016 else if ( dwRc== WAIT_TIMEOUT)1296 else if (rcWait == WAIT_TIMEOUT) 1017 1297 rc = VERR_TIMEOUT; 1018 else if ( dwRc== WAIT_ABANDONED)1298 else if (rcWait == WAIT_ABANDONED) 1019 1299 rc = VERR_INVALID_HANDLE; 1020 1300 else … … 1028 1308 1029 1309 RTCritSectEnter(&pThis->CritSect); 1030 pThis->fIOPending = false;1031 1310 if (RT_FAILURE(rc)) 1032 1311 break; 1033 1034 /* Advance. */1035 pvBuf = (char const *)pvBuf + cbWritten;1036 cbTotalWritten += cbWritten;1037 cbToWrite -= cbWritten;1038 1312 } 1313 else 1314 { 1315 rc = VERR_CANCELLED; 1316 break; 1317 } 1318 1319 /* Advance. */ 1320 pvBuf = (char const *)pvBuf + cbWritten; 1321 cbTotalWritten += cbWritten; 1322 cbToWrite -= cbWritten; 1039 1323 } 1040 1324 1041 pThis->cRefs--; 1325 pThis->Write.hActiveThread = NIL_RTTHREAD; 1326 } 1327 else 1328 rc = VERR_WRONG_ORDER; 1329 rtLocalIpcSessionReleaseAndUnlock(pThis); 1330 } 1331 1332 return rc; 1333 } 1334 1335 1336 RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession) 1337 { 1338 PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession; 1339 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 1340 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); 1341 1342 int rc = RTCritSectEnter(&pThis->CritSect); 1343 if (RT_SUCCESS(rc)) 1344 { 1345 if (pThis->Write.hActiveThread == NIL_RTTHREAD) 1346 { 1347 /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until 1348 * all data was written (or an error occurred). */ 1349 /** @todo r=bird: above comment is misinformed. 1350 /* Implement this as soon as we want an explicit asynchronous version of 1351 * RTLocalIpcSessionWrite on Windows. */ 1352 rc = VINF_SUCCESS; 1042 1353 } 1043 1354 else … … 1045 1356 RTCritSectLeave(&pThis->CritSect); 1046 1357 } 1047 1048 1358 return rc; 1049 }1050 1051 1052 RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)1053 {1054 /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until1055 * all data was written (or an error occurred). */1056 /** @todo Implement this as soon as we want an explicit asynchronous version of1057 * RTLocalIpcSessionWrite on Windows. */1058 return VINF_SUCCESS;1059 1359 } 1060 1360 … … 1066 1366 AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE); 1067 1367 1068 uint64_t const StartMsTS= RTTimeMilliTS();1368 uint64_t const msStart = RTTimeMilliTS(); 1069 1369 1070 1370 int rc = RTCritSectEnter(&pThis->CritSect); 1071 if (RT_FAILURE(rc)) 1072 return rc; 1073 for (unsigned iLoop = 0;; iLoop++) 1074 { 1075 HANDLE hWait = INVALID_HANDLE_VALUE; 1076 1077 if (pThis->fIOPending) 1078 hWait = pThis->OverlappedIO.hEvent; 1079 else 1080 { 1081 /* Peek at the pipe buffer and see how many bytes it contains. */ 1082 DWORD cbAvailable; 1083 BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL); 1084 if ( fRc 1085 && cbAvailable) 1371 if (RT_SUCCESS(rc)) 1372 { 1373 rtLocalIpcSessionRetain(pThis); 1374 if (pThis->Read.hActiveThread == NIL_RTTHREAD) 1375 { 1376 pThis->Read.hActiveThread = RTThreadSelf(); 1377 1378 /* 1379 * Wait loop. 1380 */ 1381 for (unsigned iLoop = 0;; iLoop++) 1086 1382 { 1087 rc = VINF_SUCCESS; 1088 break; 1089 } 1090 else if (!fRc) 1091 { 1092 rc = RTErrConvertFromWin32(GetLastError()); 1093 break; 1094 } 1095 1096 /* Start a zero byte read operation that we can wait on. */ 1097 if (cMillies == 0) 1098 { 1099 rc = VERR_TIMEOUT; 1100 break; 1101 } 1102 AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER); 1103 fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE); 1104 DWORD cbRead = 0; 1105 if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO)) 1106 { 1107 rc = VINF_SUCCESS; 1108 if (iLoop > 10) 1109 RTThreadYield(); 1110 } 1111 else if (GetLastError() == ERROR_IO_PENDING) 1112 { 1113 pThis->cRefs++; 1114 pThis->fIOPending = true; 1115 pThis->fZeroByteRead = true; 1116 hWait = pThis->OverlappedIO.hEvent; 1117 } 1118 else 1119 rc = RTErrConvertFromWin32(GetLastError()); 1120 } 1121 1122 if (RT_FAILURE(rc)) 1123 break; 1124 1125 /* 1126 * Check for timeout. 1127 */ 1128 DWORD cMsMaxWait = INFINITE; 1129 if ( cMillies != RT_INDEFINITE_WAIT 1130 && ( hWait != INVALID_HANDLE_VALUE 1131 || iLoop > 10) 1132 ) 1133 { 1134 uint64_t cElapsed = RTTimeMilliTS() - StartMsTS; 1135 if (cElapsed >= cMillies) 1136 { 1137 rc = VERR_TIMEOUT; 1138 break; 1139 } 1140 cMsMaxWait = cMillies - (uint32_t)cElapsed; 1141 } 1142 1143 /* 1144 * Wait. 1145 */ 1146 if (hWait != INVALID_HANDLE_VALUE) 1147 { 1148 RTCritSectLeave(&pThis->CritSect); 1149 1150 DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait); 1151 if (dwRc == WAIT_OBJECT_0) 1152 rc = VINF_SUCCESS; 1153 else if (dwRc == WAIT_TIMEOUT) 1154 rc = VERR_TIMEOUT; 1155 else if (dwRc == WAIT_ABANDONED) 1156 rc = VERR_INVALID_HANDLE; 1157 else 1158 rc = RTErrConvertFromWin32(GetLastError()); 1159 1160 if ( RT_FAILURE(rc) 1161 && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC) 1162 return rc; 1163 1164 int rc2 = RTCritSectEnter(&pThis->CritSect); 1165 AssertRC(rc2); 1166 if (pThis->fZeroByteRead) 1167 { 1168 Assert(pThis->cRefs); 1169 pThis->cRefs--; 1170 pThis->fIOPending = false; 1171 1172 if (rc != VINF_SUCCESS) 1383 /* 1384 * Check for cancellation before we continue. 1385 */ 1386 if (!pThis->fCancelled) 1387 { /* likely */ } 1388 else 1173 1389 { 1174 BOOL fRc = CancelIo(pThis->hNmPipe);1175 Assert(fRc == TRUE);1390 rc = VERR_CANCELLED; 1391 break; 1176 1392 } 1177 1393 1178 DWORD cbRead = 0; 1179 BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/); 1180 if ( !fRc 1181 && RT_SUCCESS(rc)) 1394 /* 1395 * Prep something we can wait on. 1396 */ 1397 HANDLE hWait = INVALID_HANDLE_VALUE; 1398 if (pThis->fZeroByteRead) 1399 hWait = pThis->Read.OverlappedIO.hEvent; 1400 else 1182 1401 { 1183 DWORD dwRc = GetLastError(); 1184 if (dwRc == ERROR_OPERATION_ABORTED) 1185 rc = VERR_CANCELLED; 1402 /* Peek at the pipe buffer and see how many bytes it contains. */ 1403 DWORD cbAvailable; 1404 if ( PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL) 1405 && cbAvailable) 1406 { 1407 rc = VINF_SUCCESS; 1408 break; 1409 } 1410 1411 /* Start a zero byte read operation that we can wait on. */ 1412 if (cMillies == 0) 1413 { 1414 rc = VERR_TIMEOUT; 1415 break; 1416 } 1417 BOOL fRc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(fRc == TRUE); 1418 DWORD cbRead = 0; 1419 if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0 /*cbToRead*/, &cbRead, &pThis->Read.OverlappedIO)) 1420 { 1421 rc = VINF_SUCCESS; 1422 if (iLoop > 10) 1423 RTThreadYield(); 1424 } 1425 else if (GetLastError() == ERROR_IO_PENDING) 1426 { 1427 pThis->fZeroByteRead = true; 1428 hWait = pThis->Read.OverlappedIO.hEvent; 1429 } 1186 1430 else 1187 rc = RTErrConvertFromWin32(dwRc); 1431 rc = RTErrConvertFromWin32(GetLastError()); 1432 if (RT_FAILURE(rc)) 1433 break; 1434 } 1435 1436 /* 1437 * Check for timeout. 1438 */ 1439 DWORD cMsMaxWait; 1440 if (cMillies == RT_INDEFINITE_WAIT) 1441 cMsMaxWait = INFINITE; 1442 else if ( hWait != INVALID_HANDLE_VALUE 1443 || iLoop > 10) 1444 { 1445 uint64_t cMsElapsed = RTTimeMilliTS() - msStart; 1446 if (cMsElapsed <= cMillies) 1447 cMsMaxWait = cMillies - (uint32_t)cMsElapsed; 1448 else if (iLoop == 0) 1449 cMsMaxWait = cMillies ? 1 : 0; 1450 else 1451 { 1452 rc = VERR_TIMEOUT; 1453 break; 1454 } 1455 } 1456 1457 /* 1458 * Wait and collect the result. 1459 */ 1460 if (hWait != INVALID_HANDLE_VALUE) 1461 { 1462 RTCritSectLeave(&pThis->CritSect); 1463 1464 DWORD rcWait = WaitForSingleObject(hWait, cMsMaxWait); 1465 1466 int rc2 = RTCritSectEnter(&pThis->CritSect); 1467 AssertRC(rc2); 1468 1469 rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait); 1470 break; 1188 1471 } 1189 1472 } 1190 1473 1191 if (RT_FAILURE(rc)) 1192 break; 1193 } 1194 } 1195 1196 int rc2 = RTCritSectLeave(&pThis->CritSect); 1197 if (RT_SUCCESS(rc)) 1198 rc = rc2; 1474 pThis->Read.hActiveThread = NIL_RTTHREAD; 1475 } 1476 1477 rtLocalIpcSessionReleaseAndUnlock(pThis); 1478 } 1199 1479 1200 1480 return rc; … … 1215 1495 if (RT_SUCCESS(rc)) 1216 1496 { 1217 ASMAtomicUoWriteBool(&pThis->fCancelled, true); 1218 BOOL fRc = SetEvent(pThis->hEvent); 1219 AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc); 1220 1221 RTCritSectLeave(&pThis->CritSect); 1497 rtLocalIpcSessionRetain(pThis); 1498 rc = rtLocalIpcWinCancel(pThis); 1499 rtLocalIpcSessionReleaseAndUnlock(pThis); 1222 1500 } 1223 1501
Note:
See TracChangeset
for help on using the changeset viewer.