Changeset 27431 in vbox
- Timestamp:
- Mar 17, 2010 1:33:58 AM (15 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/err.h
r26801 r27431 1251 1251 /** The handle ID was not found in the set. */ 1252 1252 #define VERR_POLL_HANDLE_ID_NOT_FOUND (-952) 1253 /** The poll set is full. */ 1254 #define VERR_POLL_SET_IS_FULL (-953) 1253 1255 /** @} */ 1254 1256 -
trunk/src/VBox/Runtime/r3/win/pipe-win.cpp
r27388 r27431 44 44 #include <iprt/mem.h> 45 45 #include <iprt/string.h> 46 #include <iprt/poll.h> 46 47 #include <iprt/process.h> 47 48 #include <iprt/thread.h> 48 49 #include <iprt/time.h> 50 #include "internal/pipe.h" 49 51 #include "internal/magics.h" 52 53 54 /******************************************************************************* 55 * Defined Constants And Macros * 56 *******************************************************************************/ 57 /** The pipe buffer size we prefere. */ 58 #define RTPIPE_NT_SIZE _64K 50 59 51 60 … … 63 72 /** Set if there is already pending I/O. */ 64 73 bool fIOPending; 74 /** Set if the zero byte read that the poll code using is pending. */ 75 bool fZeroByteRead; 76 /** Set if the pipe is broken. */ 77 bool fBrokenPipe; 78 /** Set if we've promised that the handle is writable. */ 79 bool fPromisedWritable; 65 80 /** The number of users of the current mode. */ 66 81 uint32_t cModeUsers; … … 73 88 /** Amount of allocated buffer space. */ 74 89 size_t cbBounceBufAlloc; 90 /** The handle of the poll set currently polling on this pipe. 91 * We can only have one poller at the time (lazy bird). */ 92 RTPOLLSET hPollSet; 93 /** The number of references to the handle in hPollSet. */ 94 uint32_t cPolls; 75 95 /** Critical section protecting the above members. 76 96 * (Taking the lazy/simple approach.) */ 77 97 RTCRITSECT CritSect; 98 /** Buffer for the zero byte read. */ 99 uint8_t abBuf[8]; 78 100 } RTPIPEINTERNAL; 101 102 103 /* from ntdef.h */ 104 typedef LONG NTSTATUS; 105 106 /* from ntddk.h */ 107 typedef struct _IO_STATUS_BLOCK { 108 union { 109 NTSTATUS Status; 110 PVOID Pointer; 111 }; 112 ULONG_PTR Information; 113 } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; 114 115 typedef enum _FILE_INFORMATION_CLASS { 116 FilePipeInformation = 23, 117 FilePipeLocalInformation = 24, 118 FilePipeRemoteInformation = 25, 119 } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; 120 121 /* from ntifs.h */ 122 typedef struct _FILE_PIPE_LOCAL_INFORMATION { 123 ULONG NamedPipeType; 124 ULONG NamedPipeConfiguration; 125 ULONG MaximumInstances; 126 ULONG CurrentInstances; 127 ULONG InboundQuota; 128 ULONG ReadDataAvailable; 129 ULONG OutboundQuota; 130 ULONG WriteQuotaAvailable; 131 ULONG NamedPipeState; 132 ULONG NamedPipeEnd; 133 } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; 134 135 #define FILE_PIPE_DISCONNECTED_STATE 0x00000001 136 #define FILE_PIPE_LISTENING_STATE 0x00000002 137 #define FILE_PIPE_CONNECTED_STATE 0x00000003 138 #define FILE_PIPE_CLOSING_STATE 0x00000004 139 140 141 extern "C" NTSYSAPI NTSTATUS WINAPI NtQueryInformationFile(HANDLE, PIO_STATUS_BLOCK, PVOID, LONG, FILE_INFORMATION_CLASS); 142 143 144 /** 145 * Wrapper for getting FILE_PIPE_LOCAL_INFORMATION via the NT API. 146 * 147 * @returns Success inidicator (true/false). 148 * @param pThis The pipe. 149 * @param pInfo The info structure. 150 */ 151 static bool rtPipeQueryInfo(RTPIPEINTERNAL *pThis, FILE_PIPE_LOCAL_INFORMATION *pInfo) 152 { 153 IO_STATUS_BLOCK Ios; 154 RT_ZERO(Ios); 155 RT_ZERO(*pInfo); 156 NTSTATUS rcNt = NtQueryInformationFile(pThis->hPipe, &Ios, pInfo, sizeof(*pInfo), FilePipeLocalInformation); 157 return rcNt >= 0; 158 } 79 159 80 160 … … 118 198 #endif 119 199 120 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, _64K, _64K,200 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, RTPIPE_NT_SIZE, RTPIPE_NT_SIZE, 121 201 NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes); 122 202 #ifdef PIPE_REJECT_REMOTE_CLIENTS … … 124 204 { 125 205 dwPipeMode &= ~PIPE_REJECT_REMOTE_CLIENTS; 126 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, _64K, _64K,206 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, RTPIPE_NT_SIZE, RTPIPE_NT_SIZE, 127 207 NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes); 128 208 } … … 132 212 { 133 213 dwOpenMode &= ~FILE_FLAG_FIRST_PIPE_INSTANCE; 134 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, _64K, _64K,214 hPipeR = CreateNamedPipeA(szName, dwOpenMode, dwPipeMode, 1 /*nMaxInstances*/, RTPIPE_NT_SIZE, RTPIPE_NT_SIZE, 135 215 NMPWAIT_USE_DEFAULT_WAIT, pSecurityAttributes); 136 216 } … … 201 281 pThisR->fRead = true; 202 282 pThisW->fRead = false; 203 pThisR->fIOPending = false; 204 pThisW->fIOPending = false; 283 //pThisR->fIOPending = false; 284 //pThisW->fIOPending = false; 285 //pThisR->fZeroByteRead = false; 286 //pThisW->fZeroByteRead = false; 287 //pThisR->fBrokenPipe = false; 288 //pThisW->fBrokenPipe = false; 289 //pThisW->fPromisedWritable= false; 290 //pThisR->fPromisedWritable= false; 205 291 //pThisR->cModeUsers = 0; 206 292 //pThisW->cModeUsers = 0; … … 211 297 //pThisR->cbBounceBufAlloc= 0; 212 298 //pThisW->cbBounceBufAlloc= 0; 299 pThisR->hPollSet = NIL_RTPOLLSET; 300 pThisW->hPollSet = NIL_RTPOLLSET; 301 //pThisW->cPolls = 0; 302 //pThisR->cPolls = 0; 213 303 214 304 *phPipeRead = pThisR; … … 278 368 else 279 369 rc = RTErrConvertFromWin32(GetLastError()); 370 if (rc == VERR_BROKEN_PIPE) 371 pThis->fBrokenPipe = true; 280 372 } 281 373 break; … … 408 500 else 409 501 rc = RTErrConvertFromWin32(GetLastError()); 502 if (rc == VERR_BROKEN_PIPE) 503 pThis->fBrokenPipe = true; 410 504 411 505 pThis->cModeUsers--; … … 474 568 } 475 569 570 if (rc == VERR_BROKEN_PIPE) 571 pThis->fBrokenPipe = true; 572 476 573 if (pcbRead) 477 574 { … … 519 616 Assert(!pThis->fIOPending); 520 617 618 /* Adjust the number of bytes to write to fit into the current 619 buffer quota, unless we've promissed stuff in RTPipeSelectOne. 620 WriteQuotaAvailable better not be zero when it shouldn't!! */ 621 FILE_PIPE_LOCAL_INFORMATION Info; 622 if ( !pThis->fPromisedWritable 623 && cbToWrite > 0 624 && rtPipeQueryInfo(pThis, &Info)) 625 { 626 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE) 627 rc = VERR_BROKEN_PIPE; 628 else if ( cbToWrite >= Info.WriteQuotaAvailable 629 && Info.OutboundQuota != 0) 630 { 631 cbToWrite = Info.WriteQuotaAvailable; 632 if (!cbToWrite) 633 rc = VINF_TRY_AGAIN; 634 } 635 } 636 pThis->fPromisedWritable = false; 637 521 638 /* Do the bounce buffering. */ 522 639 if ( pThis->cbBounceBufAlloc < cbToWrite 523 && pThis->cbBounceBufAlloc < _64K)524 { 525 if (cbToWrite > _64K)526 cbToWrite = _64K;640 && pThis->cbBounceBufAlloc < RTPIPE_NT_SIZE) 641 { 642 if (cbToWrite > RTPIPE_NT_SIZE) 643 cbToWrite = RTPIPE_NT_SIZE; 527 644 void *pv = RTMemRealloc(pThis->pbBounceBuf, RT_ALIGN_Z(cbToWrite, _1K)); 528 645 if (pv) … … 534 651 rc = VERR_NO_MEMORY; 535 652 } 536 else if (cbToWrite > _64K)537 cbToWrite = _64K;653 else if (cbToWrite > RTPIPE_NT_SIZE) 654 cbToWrite = RTPIPE_NT_SIZE; 538 655 if (RT_SUCCESS(rc) && cbToWrite) 539 656 { … … 567 684 *pcbWritten = 0; 568 685 686 if (rc == VERR_BROKEN_PIPE) 687 pThis->fBrokenPipe = true; 688 569 689 pThis->cModeUsers--; 570 690 } … … 612 732 { 613 733 Assert(!pThis->fIOPending); 734 pThis->fPromisedWritable = false; 614 735 615 736 /* … … 663 784 } 664 785 786 if (rc == VERR_BROKEN_PIPE) 787 pThis->fBrokenPipe = true; 788 665 789 pThis->cModeUsers--; 666 790 } … … 717 841 718 842 if (!FlushFileBuffers(pThis->hPipe)) 719 return RTErrConvertFromWin32(GetLastError()); 843 { 844 int rc = RTErrConvertFromWin32(GetLastError()); 845 if (rc == VERR_BROKEN_PIPE) 846 pThis->fBrokenPipe = true; 847 return rc; 848 } 720 849 return VINF_SUCCESS; 721 850 } … … 735 864 for (unsigned iLoop = 0;; iLoop++) 736 865 { 737 uint8_t abBuf[4]; 738 bool fPendingRead = false; 739 HANDLE hWait = INVALID_HANDLE_VALUE; 866 HANDLE hWait = INVALID_HANDLE_VALUE; 740 867 if (pThis->fRead) 741 868 { … … 762 889 rc = ResetEvent(pThis->Overlapped.hEvent); Assert(rc == TRUE); 763 890 DWORD cbRead = 0; 764 if (ReadFile(pThis->hPipe, &abBuf[0], 0, &cbRead, &pThis->Overlapped))891 if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped)) 765 892 { 766 893 rc = VINF_SUCCESS; … … 772 899 pThis->cModeUsers++; 773 900 pThis->fIOPending = true; 774 fPendingRead = true;901 pThis->fZeroByteRead = true; 775 902 hWait = pThis->Overlapped.hEvent; 776 903 } … … 781 908 else 782 909 { 910 if (pThis->fIOPending) 911 { 912 rc = rtPipeWriteCheckCompletion(pThis); 913 if (RT_FAILURE(rc)) 914 break; 915 } 783 916 if (pThis->fIOPending) 784 917 hWait = pThis->Overlapped.hEvent; 785 918 else 786 919 { 787 /* If nothing pending, the next write will succeed because 788 we buffer it and pretend that it does... */ 789 rc = VINF_SUCCESS; 790 break; 920 FILE_PIPE_LOCAL_INFORMATION Info; 921 if (rtPipeQueryInfo(pThis, &Info)) 922 { 923 /* Check for broken pipe. */ 924 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE) 925 { 926 rc = VERR_BROKEN_PIPE; 927 break; 928 } 929 /* Check for available write buffer space. */ 930 else if (Info.WriteQuotaAvailable > 0) 931 { 932 pThis->fPromisedWritable = false; 933 rc = VINF_SUCCESS; 934 break; 935 } 936 /* delayed buffer alloc or timeout: phony promise 937 later: See if we still can associate a semaphore with 938 the pipe, like on OS/2. */ 939 else if ( Info.OutboundQuota == 0 940 || cMillies) 941 { 942 pThis->fPromisedWritable = true; 943 rc = VINF_SUCCESS; 944 break; 945 } 946 } 947 else 948 { 949 pThis->fPromisedWritable = true; 950 rc = VINF_SUCCESS; 951 break; 952 } 791 953 } 792 954 } … … 833 995 834 996 RTCritSectEnter(&pThis->CritSect); 835 if ( fPendingRead)997 if (pThis->fZeroByteRead) 836 998 { 837 999 pThis->cModeUsers--; … … 847 1009 } 848 1010 1011 if (rc == VERR_BROKEN_PIPE) 1012 pThis->fBrokenPipe = true; 1013 849 1014 RTCritSectLeave(&pThis->CritSect); 850 1015 return rc; 851 1016 } 852 1017 1018 1019 /** 1020 * Internal RTPollSetAdd helper that returns one or two handles that should be 1021 * added to the pollset. 1022 * 1023 * @returns Valid handle on success, INVALID_HANDLE_VALUE on failure. 1024 * @param hPipe The pipe handle. 1025 * @param fEvents The events we're polling for. 1026 * @param ph1 wher to put the primary handle. 1027 * @param ph2 Where to optionally return a 2nd handle. 1028 */ 1029 int rtPipePollGetHandles(RTPIPE hPipe, uint32_t fEvents, PHANDLE ph1, PHANDLE ph2) 1030 { 1031 RTPIPEINTERNAL *pThis = hPipe; 1032 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 1033 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, VERR_INVALID_HANDLE); 1034 1035 AssertReturn(!(fEvents & RTPOLL_EVT_READ) || pThis->fRead, VERR_INVALID_PARAMETER); 1036 AssertReturn(!(fEvents & RTPOLL_EVT_WRITE) || !pThis->fRead, VERR_INVALID_PARAMETER); 1037 1038 *ph1 = pThis->Overlapped.hEvent; 1039 /* Later: Try register an event handle with the pipe like on OS/2, there is 1040 a file control for doing this obviously intended for the OS/2 subsys. 1041 The question is whether this still exists on Vista and W7. */ 1042 *ph2 = INVALID_HANDLE_VALUE; 1043 return VINF_SUCCESS; 1044 } 1045 1046 1047 /** 1048 * Checks for pending events. 1049 * 1050 * @returns Event mask or 0. 1051 * @param pThis The pipe handle. 1052 * @param fEvents The desired events. 1053 */ 1054 static uint32_t rtPipePollCheck(RTPIPEINTERNAL *pThis, uint32_t fEvents) 1055 { 1056 uint32_t fRetEvents = 0; 1057 if (pThis->fBrokenPipe) 1058 fRetEvents |= RTPOLL_EVT_ERROR; 1059 else if (pThis->fRead) 1060 { 1061 if (!pThis->fIOPending) 1062 { 1063 DWORD cbAvailable; 1064 if (PeekNamedPipe(pThis->hPipe, NULL, 0, NULL, &cbAvailable, NULL)) 1065 { 1066 if ( (fEvents & RTPOLL_EVT_READ) 1067 && cbAvailable > 0) 1068 fRetEvents |= RTPOLL_EVT_READ; 1069 } 1070 else 1071 { 1072 if (GetLastError() == ERROR_BROKEN_PIPE) 1073 pThis->fBrokenPipe = true; 1074 fRetEvents |= RTPOLL_EVT_ERROR; 1075 } 1076 } 1077 } 1078 else 1079 { 1080 if (pThis->fIOPending) 1081 { 1082 rtPipeWriteCheckCompletion(pThis); 1083 if (pThis->fBrokenPipe) 1084 fRetEvents |= RTPOLL_EVT_ERROR; 1085 } 1086 if ( !pThis->fIOPending 1087 && !fRetEvents) 1088 { 1089 FILE_PIPE_LOCAL_INFORMATION Info; 1090 if (rtPipeQueryInfo(pThis, &Info)) 1091 { 1092 /* Check for broken pipe. */ 1093 if (Info.NamedPipeState == FILE_PIPE_CLOSING_STATE) 1094 { 1095 fRetEvents = RTPOLL_EVT_ERROR; 1096 pThis->fBrokenPipe = true; 1097 } 1098 1099 /* Check if there is available buffer space. */ 1100 if ( !fRetEvents 1101 && ( Info.WriteQuotaAvailable > 0 1102 || Info.OutboundQuota == 0) 1103 ) 1104 fRetEvents |= RTPOLL_EVT_WRITE; 1105 } 1106 else if ( !fRetEvents 1107 && (fEvents & RTPOLL_EVT_WRITE)) 1108 fRetEvents |= RTPOLL_EVT_WRITE; 1109 } 1110 } 1111 1112 return fRetEvents; 1113 } 1114 1115 1116 /** 1117 * Internal RTPoll helper that polls the pipe handle and, if @a fNoWait is 1118 * clear, starts whatever actions we've got running during the poll call. 1119 * 1120 * @returns 0 if no pending events, actions initiated if @a fNoWait is clear. 1121 * Event mask (in @a fEvents) and no actions if the handle is ready 1122 * already. 1123 * UINT32_MAX (asserted) if the pipe handle is busy in I/O or a 1124 * different poll set. 1125 * 1126 * @param hPipe The pipe handle. 1127 * @param hPollSet The poll set handle (for access checks). 1128 * @param fEvents The events we're polling for. 1129 * @param fNoWait Set if it's a zero-wait poll call. Clear if 1130 * we'll wait for an event to occur. 1131 */ 1132 uint32_t rtPipePollStart(RTPIPE hPipe, RTPOLLSET hPollSet, uint32_t fEvents, bool fNoWait) 1133 { 1134 /** @todo All this polling code could be optimized to make fewer system 1135 * calls; like for instance the ResetEvent calls. */ 1136 RTPIPEINTERNAL *pThis = hPipe; 1137 AssertPtrReturn(pThis, UINT32_MAX); 1138 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, UINT32_MAX); 1139 1140 int rc = RTCritSectEnter(&pThis->CritSect); 1141 AssertRCReturn(rc, UINT32_MAX); 1142 1143 /* Check that this is the only current use of this pipe. */ 1144 uint32_t fRetEvents; 1145 if ( ( pThis->cPolls == 0 1146 && pThis->cModeUsers == 0) 1147 || pThis->hPollSet == hPollSet 1148 ) 1149 { 1150 /* Check what the current events are. */ 1151 fRetEvents = rtPipePollCheck(pThis, fEvents); 1152 if ( !fRetEvents 1153 && !fNoWait) 1154 { 1155 /* Make sure the event semaphore has been reset. */ 1156 if (!pThis->fIOPending) 1157 { 1158 rc = ResetEvent(pThis->Overlapped.hEvent); 1159 Assert(rc == TRUE); 1160 } 1161 1162 /* Kick off the zero byte read thing if applicable. */ 1163 if ( !pThis->fIOPending 1164 && pThis->fRead 1165 && (fEvents & RTPOLL_EVT_READ) 1166 ) 1167 { 1168 DWORD cbRead = 0; 1169 if (ReadFile(pThis->hPipe, pThis->abBuf, 0, &cbRead, &pThis->Overlapped)) 1170 fRetEvents = rtPipePollCheck(pThis, fEvents); 1171 else if (GetLastError() == ERROR_IO_PENDING) 1172 { 1173 pThis->fIOPending = true; 1174 pThis->fZeroByteRead = true; 1175 } 1176 else 1177 fRetEvents = RTPOLL_EVT_ERROR; 1178 } 1179 1180 /* If we're still set for the waiting, record the poll set and 1181 mark the pipe used. */ 1182 if (!fRetEvents) 1183 { 1184 pThis->cPolls++; 1185 pThis->cModeUsers++; 1186 pThis->hPollSet = hPollSet; 1187 } 1188 } 1189 } 1190 else 1191 { 1192 AssertFailed(); 1193 fRetEvents = UINT32_MAX; 1194 } 1195 1196 RTCritSectLeave(&pThis->CritSect); 1197 return fRetEvents; 1198 } 1199 1200 1201 /** 1202 * Called after a WaitForMultipleObjects returned in order to check for pending 1203 * events and stop whatever actions that rtPipePollStart() initiated. 1204 * 1205 * @returns Event mask or 0. 1206 * 1207 * @param hPipe The pipe handle. 1208 * @param fEvents The events we're polling for. 1209 */ 1210 uint32_t rtPipePollDone(RTPIPE hPipe, uint32_t fEvents) 1211 { 1212 RTPIPEINTERNAL *pThis = hPipe; 1213 AssertPtrReturn(pThis, 0); 1214 AssertReturn(pThis->u32Magic == RTPIPE_MAGIC, 0); 1215 1216 int rc = RTCritSectEnter(&pThis->CritSect); 1217 AssertRCReturn(rc, 0); 1218 1219 Assert(pThis->cPolls > 0); 1220 Assert(pThis->cModeUsers > 0); 1221 1222 1223 /* Cancel the zero byte read. */ 1224 uint32_t fRetEvents = 0; 1225 if (pThis->fZeroByteRead) 1226 { 1227 CancelIo(pThis->hPipe); 1228 DWORD cbRead = 0; 1229 if ( !GetOverlappedResult(pThis->hPipe, &pThis->Overlapped, &cbRead, TRUE /*fWait*/) 1230 && GetLastError() != ERROR_OPERATION_ABORTED) 1231 fRetEvents = RTPOLL_EVT_ERROR; 1232 1233 pThis->fIOPending = false; 1234 pThis->fZeroByteRead = false; 1235 } 1236 1237 /* harvest events. */ 1238 fRetEvents |= rtPipePollCheck(pThis, fEvents); 1239 1240 /* update counters. */ 1241 pThis->cPolls--; 1242 if (!pThis->cPolls) 1243 pThis->hPollSet = NIL_RTPOLLSET; 1244 pThis->cModeUsers--; 1245 1246 RTCritSectLeave(&pThis->CritSect); 1247 return fRetEvents; 1248 } 1249 -
trunk/src/VBox/Runtime/r3/win/poll-win.cpp
r26844 r27431 33 33 * Header Files * 34 34 *******************************************************************************/ 35 #include <Windows.h> 36 35 37 #include <iprt/poll.h> 36 38 #include "internal/iprt.h" 37 39 40 #include <iprt/asm.h> 38 41 #include <iprt/assert.h> 39 42 #include <iprt/err.h> 43 #include <iprt/mem.h> 44 #include <iprt/pipe.h> 45 #include <iprt/string.h> 46 #include <iprt/thread.h> 47 #include <iprt/time.h> 48 #include "internal/pipe.h" 40 49 #include "internal/magics.h" 41 50 42 51 52 /******************************************************************************* 53 * Structures and Typedefs * 54 *******************************************************************************/ 55 /** 56 * Handle entry in a poll set. 57 */ 58 typedef struct RTPOLLSETHNDENT 59 { 60 /** The handle type. */ 61 RTHANDLETYPE enmType; 62 /** The handle ID. */ 63 uint32_t id; 64 /** The events we're waiting for here. */ 65 uint32_t fEvents; 66 /** The handle union. */ 67 RTHANDLEUNION u; 68 } RTPOLLSETHNDENT; 69 /** Pointer to a handle entry. */ 70 typedef RTPOLLSETHNDENT *PRTPOLLSETHNDENT; 71 72 73 /** 74 * Poll set data, Windows. 75 */ 76 typedef struct RTPOLLSETINTERNAL 77 { 78 /** The magic value (RTPOLLSET_MAGIC). */ 79 uint32_t u32Magic; 80 /** Set when someone is polling or making changes. */ 81 bool volatile fBusy; 82 83 /** The number of valid handles in the set. */ 84 uint32_t cHandles; 85 /** The native handles. */ 86 HANDLE ahNative[MAXIMUM_WAIT_OBJECTS]; 87 /** Array of handles and IDs. */ 88 RTPOLLSETHNDENT aHandles[MAXIMUM_WAIT_OBJECTS]; 89 } RTPOLLSETINTERNAL; 90 91 92 /** 93 * Common worker for RTPoll and RTPollNoResume 94 */ 95 static int rtPollNoResumeWorker(RTPOLLSETINTERNAL *pThis, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) 96 { 97 int rc; 98 99 if (RT_UNLIKELY(pThis->cHandles == 0 && cMillies == RT_INDEFINITE_WAIT)) 100 return VERR_DEADLOCK; 101 102 /* 103 * Check for special case, RTThreadSleep... 104 */ 105 uint32_t const cHandles = pThis->cHandles; 106 if (cHandles == 0) 107 { 108 rc = RTThreadSleep(cMillies); 109 if (RT_SUCCESS(rc)) 110 rc = VERR_TIMEOUT; 111 return rc; 112 } 113 114 /* 115 * Check + prepare the handles before waiting. 116 */ 117 uint32_t fEvents = 0; 118 bool const fNoWait = cMillies == 0; 119 uint32_t i; 120 for (i = 0; i < cHandles; i++) 121 { 122 switch (pThis->aHandles[i].enmType) 123 { 124 case RTHANDLETYPE_PIPE: 125 fEvents = rtPipePollStart(pThis->aHandles[i].u.hPipe, pThis, pThis->aHandles[i].fEvents, fNoWait); 126 break; 127 128 default: 129 AssertFailed(); 130 fEvents = UINT32_MAX; 131 break; 132 } 133 if (fEvents) 134 break; 135 } 136 if ( fEvents 137 || fNoWait) 138 { 139 140 if (pid) 141 *pid = pThis->aHandles[i].id; 142 if (pfEvents) 143 *pfEvents = fEvents; 144 rc = !fEvents 145 ? VERR_TIMEOUT 146 : fEvents != UINT32_MAX 147 ? VINF_SUCCESS 148 : VERR_INTERNAL_ERROR_4; 149 150 /* clean up */ 151 if (!fNoWait) 152 while (i-- > 0) 153 { 154 switch (pThis->aHandles[i].enmType) 155 { 156 case RTHANDLETYPE_PIPE: 157 rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents); 158 break; 159 default: 160 AssertFailed(); 161 break; 162 } 163 } 164 165 return rc; 166 } 167 168 /* 169 * Wait. 170 */ 171 DWORD dwRc = WaitForMultipleObjectsEx(cHandles, &pThis->ahNative[0], 172 FALSE /*fWaitAll */, 173 cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies, 174 TRUE /*fAlertable*/); 175 if ( dwRc >= WAIT_OBJECT_0 176 && dwRc < WAIT_OBJECT_0 + cHandles) 177 rc = VINF_SUCCESS; 178 else if (dwRc == WAIT_TIMEOUT) 179 rc = VERR_TIMEOUT; 180 else if (dwRc == WAIT_IO_COMPLETION) 181 rc = VERR_INTERRUPTED; 182 else if (dwRc == WAIT_FAILED) 183 rc = RTErrConvertFromWin32(GetLastError()); 184 else 185 { 186 AssertMsgFailed(("%u (%#x)\n", dwRc, dwRc)); 187 rc = VERR_INTERNAL_ERROR_5; 188 } 189 190 /* 191 * Get event (if pending) and do wait cleanup. 192 */ 193 i = cHandles; 194 while (i-- > 0) 195 { 196 fEvents = 0; 197 switch (pThis->aHandles[i].enmType) 198 { 199 case RTHANDLETYPE_PIPE: 200 fEvents = rtPipePollDone(pThis->aHandles[i].u.hPipe, pThis->aHandles[i].fEvents); 201 break; 202 default: 203 AssertFailed(); 204 break; 205 } 206 if (fEvents) 207 { 208 Assert(fEvents != UINT32_MAX); 209 if (pfEvents) 210 *pfEvents = fEvents; 211 if (pid) 212 *pid = pThis->aHandles[i].id; 213 rc = VINF_SUCCESS; 214 } 215 } 216 217 return rc; 218 } 219 220 43 221 RTDECL(int) RTPoll(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) 44 222 { 45 return VERR_NOT_IMPLEMENTED; 223 RTPOLLSETINTERNAL *pThis = hPollSet; 224 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 225 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); 226 AssertPtrNull(pfEvents); 227 AssertPtrNull(pid); 228 229 /* 230 * Set the busy flag and do the job. 231 */ 232 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_WRONG_ORDER); 233 234 int rc; 235 if (cMillies == RT_INDEFINITE_WAIT || cMillies == 0) 236 { 237 do rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); 238 while (rc == VERR_INTERRUPTED); 239 } 240 else 241 { 242 uint64_t MsStart = RTTimeMilliTS(); 243 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); 244 while (RT_UNLIKELY(rc == VERR_INTERRUPTED)) 245 { 246 if (RTTimeMilliTS() - MsStart >= cMillies) 247 { 248 rc = VERR_TIMEOUT; 249 break; 250 } 251 rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); 252 } 253 } 254 255 ASMAtomicWriteBool(&pThis->fBusy, false); 256 257 return rc; 46 258 } 47 259 … … 49 261 RTDECL(int) RTPollNoResume(RTPOLLSET hPollSet, RTMSINTERVAL cMillies, uint32_t *pfEvents, uint32_t *pid) 50 262 { 51 return VERR_NOT_IMPLEMENTED; 52 } 53 54 55 RTDECL(int) RTPollSetCreate(PRTPOLLSET hPollSet) 56 { 57 return VERR_NOT_IMPLEMENTED; 58 } 59 60 61 RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet) 62 { 63 return VERR_NOT_IMPLEMENTED; 263 RTPOLLSETINTERNAL *pThis = hPollSet; 264 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 265 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); 266 AssertPtrNull(pfEvents); 267 AssertPtrNull(pid); 268 269 /* 270 * Set the busy flag and do the job. 271 */ 272 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_WRONG_ORDER); 273 274 int rc = rtPollNoResumeWorker(pThis, cMillies, pfEvents, pid); 275 276 ASMAtomicWriteBool(&pThis->fBusy, false); 277 278 return rc; 279 } 280 281 282 RTDECL(int) RTPollSetCreate(PRTPOLLSET phPollSet) 283 { 284 AssertPtrReturn(phPollSet, VERR_INVALID_POINTER); 285 RTPOLLSETINTERNAL *pThis = (RTPOLLSETINTERNAL *)RTMemAllocZ(sizeof(RTPOLLSETINTERNAL)); 286 if (!pThis) 287 return VERR_NO_MEMORY; 288 289 pThis->u32Magic = RTPOLLSET_MAGIC; 290 pThis->fBusy = false; 291 pThis->cHandles = 0; 292 for (size_t i = 0; i < RT_ELEMENTS(pThis->ahNative); i++) 293 pThis->ahNative[i] = INVALID_HANDLE_VALUE; 294 295 *phPollSet = pThis; 296 return VINF_SUCCESS; 297 } 298 299 300 RTDECL(int) RTPollSetDestroy(RTPOLLSET hPollSet) 301 { 302 RTPOLLSETINTERNAL *pThis = hPollSet; 303 if (pThis == NIL_RTPOLLSET) 304 return VINF_SUCCESS; 305 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 306 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); 307 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_WRONG_ORDER); 308 309 ASMAtomicWriteU32(&pThis->u32Magic, ~RTPOLLSET_MAGIC); 310 RTMemFree(pThis); 311 312 return VINF_SUCCESS; 64 313 } 65 314 … … 67 316 RTDECL(int) RTPollSetAdd(RTPOLLSET hPollSet, PCRTHANDLE pHandle, uint32_t fEvents, uint32_t id) 68 317 { 69 return VERR_NOT_IMPLEMENTED; 318 /* 319 * Validate the input (tedious). 320 */ 321 RTPOLLSETINTERNAL *pThis = hPollSet; 322 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 323 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); 324 AssertReturn(!(fEvents & ~RTPOLL_EVT_VALID_MASK), VERR_INVALID_PARAMETER); 325 AssertReturn(fEvents, VERR_INVALID_PARAMETER); 326 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); 327 328 if (!pHandle) 329 return VINF_SUCCESS; 330 AssertPtrReturn(pHandle, VERR_INVALID_POINTER); 331 AssertReturn(pHandle->enmType > RTHANDLETYPE_INVALID && pHandle->enmType < RTHANDLETYPE_END, VERR_INVALID_PARAMETER); 332 333 /* 334 * Set the busy flag and do the job. 335 */ 336 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_WRONG_ORDER); 337 338 int rc = VINF_SUCCESS; 339 HANDLE hNative = INVALID_HANDLE_VALUE; 340 HANDLE hNative2 = INVALID_HANDLE_VALUE; 341 switch (pHandle->enmType) 342 { 343 case RTHANDLETYPE_PIPE: 344 if (pHandle->u.hPipe != NIL_RTPIPE) 345 rc = rtPipePollGetHandles(pHandle->u.hPipe, fEvents, &hNative, &hNative2); 346 break; 347 348 case RTHANDLETYPE_SOCKET: 349 if (pHandle->u.hSocket != NIL_RTSOCKET) 350 rc = VERR_NOT_IMPLEMENTED; 351 break; 352 353 case RTHANDLETYPE_FILE: 354 AssertMsgFailed(("Files are always ready for reading/writing and thus not pollable. Use native APIs for special devices.\n")); 355 rc = VERR_POLL_HANDLE_NOT_POLLABLE; 356 break; 357 358 case RTHANDLETYPE_THREAD: 359 AssertMsgFailed(("Thread handles are currently not pollable\n")); 360 rc = VERR_POLL_HANDLE_NOT_POLLABLE; 361 break; 362 363 default: 364 AssertMsgFailed(("\n")); 365 rc = VERR_POLL_HANDLE_NOT_POLLABLE; 366 break; 367 } 368 if ( RT_SUCCESS(rc) 369 && hNative != INVALID_HANDLE_VALUE) 370 { 371 uint32_t const i = pThis->cHandles; 372 373 /* Check that the handle ID doesn't exist already. */ 374 uint32_t j = i; 375 while (j-- > 0) 376 if (pThis->aHandles[j].id == id) 377 { 378 rc = VERR_POLL_HANDLE_ID_EXISTS; 379 break; 380 } 381 382 /* Check that we won't overflow the poll set now. */ 383 if ( RT_SUCCESS(rc) 384 && i + 1 + (hNative2 != INVALID_HANDLE_VALUE) > RT_ELEMENTS(pThis->ahNative)) 385 rc = VERR_POLL_SET_IS_FULL; 386 if (RT_SUCCESS(rc)) 387 { 388 /* Add the handles to the two parallel arrays. */ 389 pThis->ahNative[i] = hNative; 390 pThis->aHandles[i].enmType = pHandle->enmType; 391 pThis->aHandles[i].u = pHandle->u; 392 pThis->aHandles[i].id = id; 393 pThis->aHandles[i].fEvents = fEvents; 394 if (hNative2 == INVALID_HANDLE_VALUE) 395 pThis->cHandles = i + 1; 396 else 397 { 398 pThis->ahNative[i + 1] = hNative2; 399 pThis->aHandles[i + 1] = pThis->aHandles[i]; 400 pThis->cHandles = i + 2; 401 } 402 403 rc = VINF_SUCCESS; 404 } 405 } 406 407 ASMAtomicWriteBool(&pThis->fBusy, false); 408 return rc; 70 409 } 71 410 … … 73 412 RTDECL(int) RTPollSetRemove(RTPOLLSET hPollSet, uint32_t id) 74 413 { 75 return VERR_NOT_IMPLEMENTED; 414 /* 415 * Validate the input. 416 */ 417 RTPOLLSETINTERNAL *pThis = hPollSet; 418 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 419 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); 420 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); 421 422 /* 423 * Set the busy flag and do the job. 424 */ 425 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_WRONG_ORDER); 426 427 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; 428 uint32_t i = pThis->cHandles; 429 while (i-- > 0) 430 if (pThis->aHandles[i].id == id) 431 { 432 pThis->cHandles--; 433 size_t const cToMove = pThis->cHandles - i; 434 if (cToMove) 435 { 436 memmove(&pThis->aHandles[i], &pThis->aHandles[i + 1], cToMove * sizeof(pThis->aHandles[i])); 437 memmove(&pThis->ahNative[i], &pThis->ahNative[i + 1], cToMove * sizeof(pThis->ahNative[i])); 438 } 439 rc = VINF_SUCCESS; 440 } 441 442 ASMAtomicWriteBool(&pThis->fBusy, false); 443 return rc; 76 444 } 77 445 … … 79 447 RTDECL(int) RTPollSetQueryHandle(RTPOLLSET hPollSet, uint32_t id, PRTHANDLE pHandle) 80 448 { 81 return VERR_NOT_IMPLEMENTED; 449 /* 450 * Validate the input. 451 */ 452 RTPOLLSETINTERNAL *pThis = hPollSet; 453 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 454 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, VERR_INVALID_HANDLE); 455 AssertReturn(id != UINT32_MAX, VERR_INVALID_PARAMETER); 456 AssertPtrNullReturn(pHandle, VERR_INVALID_POINTER); 457 458 /* 459 * Set the busy flag and do the job. 460 */ 461 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), VERR_WRONG_ORDER); 462 463 int rc = VERR_POLL_HANDLE_ID_NOT_FOUND; 464 uint32_t i = pThis->cHandles; 465 while (i-- > 0) 466 if (pThis->aHandles[i].id == id) 467 { 468 if (pHandle) 469 { 470 pHandle->enmType = pThis->aHandles[i].enmType; 471 pHandle->u = pThis->aHandles[i].u; 472 } 473 rc = VINF_SUCCESS; 474 break; 475 } 476 477 ASMAtomicWriteBool(&pThis->fBusy, false); 478 return rc; 82 479 } 83 480 … … 85 482 RTDECL(uint32_t) RTPollSetCount(RTPOLLSET hPollSet) 86 483 { 87 return UINT32_MAX; 88 } 89 484 /* 485 * Validate the input. 486 */ 487 RTPOLLSETINTERNAL *pThis = hPollSet; 488 AssertPtrReturn(pThis, UINT32_MAX); 489 AssertReturn(pThis->u32Magic == RTPOLLSET_MAGIC, UINT32_MAX); 490 491 /* 492 * Set the busy flag and do the job. 493 */ 494 AssertReturn(ASMAtomicCmpXchgBool(&pThis->fBusy, true, false), UINT32_MAX); 495 uint32_t cHandles = pThis->cHandles; 496 ASMAtomicWriteBool(&pThis->fBusy, false); 497 498 return cHandles; 499 } 500 501
Note:
See TracChangeset
for help on using the changeset viewer.