| OLD | NEW |
| (Empty) |
| 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
| 2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
| 3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
| 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
| 5 | |
| 6 /* | |
| 7 * This file implements _PR_MD_PR_POLL for Win32. | |
| 8 */ | |
| 9 | |
| 10 /* The default value of FD_SETSIZE is 64. */ | |
| 11 #define FD_SETSIZE 1024 | |
| 12 | |
| 13 #include "primpl.h" | |
| 14 | |
| 15 #if !defined(_PR_GLOBAL_THREADS_ONLY) | |
| 16 | |
| 17 struct select_data_s { | |
| 18 PRInt32 status; | |
| 19 PRInt32 error; | |
| 20 fd_set *rd, *wt, *ex; | |
| 21 const struct timeval *tv; | |
| 22 }; | |
| 23 | |
| 24 static void | |
| 25 _PR_MD_select_thread(void *cdata) | |
| 26 { | |
| 27 struct select_data_s *cd = (struct select_data_s *)cdata; | |
| 28 | |
| 29 cd->status = select(0, cd->rd, cd->wt, cd->ex, cd->tv); | |
| 30 | |
| 31 if (cd->status == SOCKET_ERROR) { | |
| 32 cd->error = WSAGetLastError(); | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 int _PR_NTFiberSafeSelect( | |
| 37 int nfds, | |
| 38 fd_set *readfds, | |
| 39 fd_set *writefds, | |
| 40 fd_set *exceptfds, | |
| 41 const struct timeval *timeout) | |
| 42 { | |
| 43 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 44 int ready; | |
| 45 | |
| 46 if (_PR_IS_NATIVE_THREAD(me)) { | |
| 47 ready = _MD_SELECT(nfds, readfds, writefds, exceptfds, timeout); | |
| 48 } | |
| 49 else | |
| 50 { | |
| 51 /* | |
| 52 ** Creating a new thread on each call!! | |
| 53 ** I guess web server doesn't use non-block I/O. | |
| 54 */ | |
| 55 PRThread *selectThread; | |
| 56 struct select_data_s data; | |
| 57 data.status = 0; | |
| 58 data.error = 0; | |
| 59 data.rd = readfds; | |
| 60 data.wt = writefds; | |
| 61 data.ex = exceptfds; | |
| 62 data.tv = timeout; | |
| 63 | |
| 64 selectThread = PR_CreateThread( | |
| 65 PR_USER_THREAD, _PR_MD_select_thread, &data, | |
| 66 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0); | |
| 67 if (selectThread == NULL) return -1; | |
| 68 | |
| 69 PR_JoinThread(selectThread); | |
| 70 ready = data.status; | |
| 71 if (ready == SOCKET_ERROR) WSASetLastError(data.error); | |
| 72 } | |
| 73 return ready; | |
| 74 } | |
| 75 | |
| 76 #endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */ | |
| 77 | |
| 78 PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) | |
| 79 { | |
| 80 int ready, err; | |
| 81 fd_set rd, wt, ex; | |
| 82 fd_set *rdp, *wtp, *exp; | |
| 83 int nrd, nwt, nex; | |
| 84 PRFileDesc *bottom; | |
| 85 PRPollDesc *pd, *epd; | |
| 86 PRThread *me = _PR_MD_CURRENT_THREAD(); | |
| 87 | |
| 88 struct timeval tv, *tvp = NULL; | |
| 89 | |
| 90 if (_PR_PENDING_INTERRUPT(me)) | |
| 91 { | |
| 92 me->flags &= ~_PR_INTERRUPT; | |
| 93 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
| 94 return -1; | |
| 95 } | |
| 96 | |
| 97 /* | |
| 98 ** Is it an empty set? If so, just sleep for the timeout and return | |
| 99 */ | |
| 100 if (0 == npds) | |
| 101 { | |
| 102 PR_Sleep(timeout); | |
| 103 return 0; | |
| 104 } | |
| 105 | |
| 106 nrd = nwt = nex = 0; | |
| 107 FD_ZERO(&rd); | |
| 108 FD_ZERO(&wt); | |
| 109 FD_ZERO(&ex); | |
| 110 | |
| 111 ready = 0; | |
| 112 for (pd = pds, epd = pd + npds; pd < epd; pd++) | |
| 113 { | |
| 114 SOCKET osfd; | |
| 115 PRInt16 in_flags_read = 0, in_flags_write = 0; | |
| 116 PRInt16 out_flags_read = 0, out_flags_write = 0; | |
| 117 | |
| 118 if ((NULL != pd->fd) && (0 != pd->in_flags)) | |
| 119 { | |
| 120 if (pd->in_flags & PR_POLL_READ) | |
| 121 { | |
| 122 in_flags_read = (pd->fd->methods->poll)( | |
| 123 pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE), | |
| 124 &out_flags_read); | |
| 125 } | |
| 126 if (pd->in_flags & PR_POLL_WRITE) | |
| 127 { | |
| 128 in_flags_write = (pd->fd->methods->poll)( | |
| 129 pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ), | |
| 130 &out_flags_write); | |
| 131 } | |
| 132 if ((0 != (in_flags_read & out_flags_read)) | |
| 133 || (0 != (in_flags_write & out_flags_write))) | |
| 134 { | |
| 135 /* this one's ready right now (buffered input) */ | |
| 136 if (0 == ready) | |
| 137 { | |
| 138 /* | |
| 139 * We will have to return without calling the | |
| 140 * system poll/select function. So zero the | |
| 141 * out_flags fields of all the poll descriptors | |
| 142 * before this one. | |
| 143 */ | |
| 144 PRPollDesc *prev; | |
| 145 for (prev = pds; prev < pd; prev++) | |
| 146 { | |
| 147 prev->out_flags = 0; | |
| 148 } | |
| 149 } | |
| 150 ready += 1; | |
| 151 pd->out_flags = out_flags_read | out_flags_write; | |
| 152 } | |
| 153 else | |
| 154 { | |
| 155 pd->out_flags = 0; /* pre-condition */ | |
| 156 /* make sure this is an NSPR supported stack */ | |
| 157 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); | |
| 158 PR_ASSERT(NULL != bottom); /* what to do about that? */ | |
| 159 if ((NULL != bottom) | |
| 160 && (_PR_FILEDESC_OPEN == bottom->secret->state)) | |
| 161 { | |
| 162 if (0 == ready) | |
| 163 { | |
| 164 osfd = (SOCKET) bottom->secret->md.osfd; | |
| 165 if (in_flags_read & PR_POLL_READ) | |
| 166 { | |
| 167 pd->out_flags |= _PR_POLL_READ_SYS_READ; | |
| 168 FD_SET(osfd, &rd); | |
| 169 nrd++; | |
| 170 } | |
| 171 if (in_flags_read & PR_POLL_WRITE) | |
| 172 { | |
| 173 pd->out_flags |= _PR_POLL_READ_SYS_WRITE; | |
| 174 FD_SET(osfd, &wt); | |
| 175 nwt++; | |
| 176 } | |
| 177 if (in_flags_write & PR_POLL_READ) | |
| 178 { | |
| 179 pd->out_flags |= _PR_POLL_WRITE_SYS_READ; | |
| 180 FD_SET(osfd, &rd); | |
| 181 nrd++; | |
| 182 } | |
| 183 if (in_flags_write & PR_POLL_WRITE) | |
| 184 { | |
| 185 pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; | |
| 186 FD_SET(osfd, &wt); | |
| 187 nwt++; | |
| 188 } | |
| 189 if (pd->in_flags & PR_POLL_EXCEPT) { | |
| 190 FD_SET(osfd, &ex); | |
| 191 nex++; | |
| 192 } | |
| 193 } | |
| 194 } | |
| 195 else | |
| 196 { | |
| 197 if (0 == ready) | |
| 198 { | |
| 199 PRPollDesc *prev; | |
| 200 for (prev = pds; prev < pd; prev++) | |
| 201 { | |
| 202 prev->out_flags = 0; | |
| 203 } | |
| 204 } | |
| 205 ready += 1; /* this will cause an abrupt return */ | |
| 206 pd->out_flags = PR_POLL_NVAL; /* bogii */ | |
| 207 } | |
| 208 } | |
| 209 } | |
| 210 else | |
| 211 { | |
| 212 pd->out_flags = 0; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 if (0 != ready) return ready; /* no need to block */ | |
| 217 | |
| 218 /* | |
| 219 * FD_SET does nothing if the fd_set's internal fd_array is full. If | |
| 220 * nrd, nwt, or nex is greater than FD_SETSIZE, we know FD_SET must | |
| 221 * have failed to insert an osfd into the corresponding fd_set, and | |
| 222 * therefore we should fail. | |
| 223 */ | |
| 224 if ((nrd > FD_SETSIZE) || (nwt > FD_SETSIZE) || (nex > FD_SETSIZE)) { | |
| 225 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); | |
| 226 return -1; | |
| 227 } | |
| 228 | |
| 229 rdp = (0 == nrd) ? NULL : &rd; | |
| 230 wtp = (0 == nwt) ? NULL : &wt; | |
| 231 exp = (0 == nex) ? NULL : &ex; | |
| 232 | |
| 233 if ((NULL == rdp) && (NULL == wtp) && (NULL == exp)) { | |
| 234 PR_Sleep(timeout); | |
| 235 return 0; | |
| 236 } | |
| 237 | |
| 238 if (timeout != PR_INTERVAL_NO_TIMEOUT) | |
| 239 { | |
| 240 PRInt32 ticksPerSecond = PR_TicksPerSecond(); | |
| 241 tv.tv_sec = timeout / ticksPerSecond; | |
| 242 tv.tv_usec = PR_IntervalToMicroseconds( timeout % ticksPerSecond ); | |
| 243 tvp = &tv; | |
| 244 } | |
| 245 | |
| 246 #if defined(_PR_GLOBAL_THREADS_ONLY) | |
| 247 ready = _MD_SELECT(0, rdp, wtp, exp, tvp); | |
| 248 #else | |
| 249 ready = _PR_NTFiberSafeSelect(0, rdp, wtp, exp, tvp); | |
| 250 #endif | |
| 251 | |
| 252 /* | |
| 253 ** Now to unravel the select sets back into the client's poll | |
| 254 ** descriptor list. Is this possibly an area for pissing away | |
| 255 ** a few cycles or what? | |
| 256 */ | |
| 257 if (ready > 0) | |
| 258 { | |
| 259 ready = 0; | |
| 260 for (pd = pds, epd = pd + npds; pd < epd; pd++) | |
| 261 { | |
| 262 PRInt16 out_flags = 0; | |
| 263 if ((NULL != pd->fd) && (0 != pd->in_flags)) | |
| 264 { | |
| 265 SOCKET osfd; | |
| 266 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); | |
| 267 PR_ASSERT(NULL != bottom); | |
| 268 | |
| 269 osfd = (SOCKET) bottom->secret->md.osfd; | |
| 270 | |
| 271 if (FD_ISSET(osfd, &rd)) | |
| 272 { | |
| 273 if (pd->out_flags & _PR_POLL_READ_SYS_READ) | |
| 274 out_flags |= PR_POLL_READ; | |
| 275 if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) | |
| 276 out_flags |= PR_POLL_WRITE; | |
| 277 } | |
| 278 if (FD_ISSET(osfd, &wt)) | |
| 279 { | |
| 280 if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) | |
| 281 out_flags |= PR_POLL_READ; | |
| 282 if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) | |
| 283 out_flags |= PR_POLL_WRITE; | |
| 284 } | |
| 285 if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; | |
| 286 } | |
| 287 pd->out_flags = out_flags; | |
| 288 if (out_flags) ready++; | |
| 289 } | |
| 290 PR_ASSERT(ready > 0); | |
| 291 } | |
| 292 else if (ready == SOCKET_ERROR) | |
| 293 { | |
| 294 err = WSAGetLastError(); | |
| 295 if (err == WSAENOTSOCK) | |
| 296 { | |
| 297 /* Find the bad fds */ | |
| 298 int optval; | |
| 299 int optlen = sizeof(optval); | |
| 300 ready = 0; | |
| 301 for (pd = pds, epd = pd + npds; pd < epd; pd++) | |
| 302 { | |
| 303 pd->out_flags = 0; | |
| 304 if ((NULL != pd->fd) && (0 != pd->in_flags)) | |
| 305 { | |
| 306 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); | |
| 307 if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET, | |
| 308 SO_TYPE, (char *) &optval, &optlen) == -1) | |
| 309 { | |
| 310 PR_ASSERT(WSAGetLastError() == WSAENOTSOCK); | |
| 311 if (WSAGetLastError() == WSAENOTSOCK) | |
| 312 { | |
| 313 pd->out_flags = PR_POLL_NVAL; | |
| 314 ready++; | |
| 315 } | |
| 316 } | |
| 317 } | |
| 318 } | |
| 319 PR_ASSERT(ready > 0); | |
| 320 } | |
| 321 else _PR_MD_MAP_SELECT_ERROR(err); | |
| 322 } | |
| 323 | |
| 324 return ready; | |
| 325 } | |
| OLD | NEW |