Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #if defined(_PR_PTHREADS) |
michael@0 | 7 | |
michael@0 | 8 | #error "This file should not be compiled" |
michael@0 | 9 | |
michael@0 | 10 | #else /* defined(_PR_PTHREADS) */ |
michael@0 | 11 | |
michael@0 | 12 | #include "primpl.h" |
michael@0 | 13 | |
michael@0 | 14 | #include <sys/time.h> |
michael@0 | 15 | |
michael@0 | 16 | #include <fcntl.h> |
michael@0 | 17 | #ifdef _PR_USE_POLL |
michael@0 | 18 | #include <poll.h> |
michael@0 | 19 | #endif |
michael@0 | 20 | |
michael@0 | 21 | #if defined(_PR_USE_POLL) |
michael@0 | 22 | static PRInt32 NativeThreadPoll( |
michael@0 | 23 | PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) |
michael@0 | 24 | { |
michael@0 | 25 | /* |
michael@0 | 26 | * This function is mostly duplicated from ptio.s's PR_Poll(). |
michael@0 | 27 | */ |
michael@0 | 28 | PRInt32 ready = 0; |
michael@0 | 29 | /* |
michael@0 | 30 | * For restarting poll() if it is interrupted by a signal. |
michael@0 | 31 | * We use these variables to figure out how much time has |
michael@0 | 32 | * elapsed and how much of the timeout still remains. |
michael@0 | 33 | */ |
michael@0 | 34 | PRIntn index, msecs; |
michael@0 | 35 | struct pollfd *syspoll = NULL; |
michael@0 | 36 | PRIntervalTime start, elapsed, remaining; |
michael@0 | 37 | |
michael@0 | 38 | syspoll = (struct pollfd*)PR_MALLOC(npds * sizeof(struct pollfd)); |
michael@0 | 39 | if (NULL == syspoll) |
michael@0 | 40 | { |
michael@0 | 41 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
michael@0 | 42 | return -1; |
michael@0 | 43 | } |
michael@0 | 44 | for (index = 0; index < npds; ++index) |
michael@0 | 45 | { |
michael@0 | 46 | PRFileDesc *bottom; |
michael@0 | 47 | PRInt16 in_flags_read = 0, in_flags_write = 0; |
michael@0 | 48 | PRInt16 out_flags_read = 0, out_flags_write = 0; |
michael@0 | 49 | |
michael@0 | 50 | if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) |
michael@0 | 51 | { |
michael@0 | 52 | if (pds[index].in_flags & PR_POLL_READ) |
michael@0 | 53 | { |
michael@0 | 54 | in_flags_read = (pds[index].fd->methods->poll)( |
michael@0 | 55 | pds[index].fd, |
michael@0 | 56 | pds[index].in_flags & ~PR_POLL_WRITE, |
michael@0 | 57 | &out_flags_read); |
michael@0 | 58 | } |
michael@0 | 59 | if (pds[index].in_flags & PR_POLL_WRITE) |
michael@0 | 60 | { |
michael@0 | 61 | in_flags_write = (pds[index].fd->methods->poll)( |
michael@0 | 62 | pds[index].fd, |
michael@0 | 63 | pds[index].in_flags & ~PR_POLL_READ, |
michael@0 | 64 | &out_flags_write); |
michael@0 | 65 | } |
michael@0 | 66 | if ((0 != (in_flags_read & out_flags_read)) |
michael@0 | 67 | || (0 != (in_flags_write & out_flags_write))) |
michael@0 | 68 | { |
michael@0 | 69 | /* this one is ready right now */ |
michael@0 | 70 | if (0 == ready) |
michael@0 | 71 | { |
michael@0 | 72 | /* |
michael@0 | 73 | * We will return without calling the system |
michael@0 | 74 | * poll function. So zero the out_flags |
michael@0 | 75 | * fields of all the poll descriptors before |
michael@0 | 76 | * this one. |
michael@0 | 77 | */ |
michael@0 | 78 | int i; |
michael@0 | 79 | for (i = 0; i < index; i++) |
michael@0 | 80 | { |
michael@0 | 81 | pds[i].out_flags = 0; |
michael@0 | 82 | } |
michael@0 | 83 | } |
michael@0 | 84 | ready += 1; |
michael@0 | 85 | pds[index].out_flags = out_flags_read | out_flags_write; |
michael@0 | 86 | } |
michael@0 | 87 | else |
michael@0 | 88 | { |
michael@0 | 89 | pds[index].out_flags = 0; /* pre-condition */ |
michael@0 | 90 | /* now locate the NSPR layer at the bottom of the stack */ |
michael@0 | 91 | bottom = PR_GetIdentitiesLayer(pds[index].fd, PR_NSPR_IO_LAYER); |
michael@0 | 92 | PR_ASSERT(NULL != bottom); /* what to do about that? */ |
michael@0 | 93 | if ((NULL != bottom) |
michael@0 | 94 | && (_PR_FILEDESC_OPEN == bottom->secret->state)) |
michael@0 | 95 | { |
michael@0 | 96 | if (0 == ready) |
michael@0 | 97 | { |
michael@0 | 98 | syspoll[index].fd = bottom->secret->md.osfd; |
michael@0 | 99 | syspoll[index].events = 0; /* pre-condition */ |
michael@0 | 100 | if (in_flags_read & PR_POLL_READ) |
michael@0 | 101 | { |
michael@0 | 102 | pds[index].out_flags |= |
michael@0 | 103 | _PR_POLL_READ_SYS_READ; |
michael@0 | 104 | syspoll[index].events |= POLLIN; |
michael@0 | 105 | } |
michael@0 | 106 | if (in_flags_read & PR_POLL_WRITE) |
michael@0 | 107 | { |
michael@0 | 108 | pds[index].out_flags |= |
michael@0 | 109 | _PR_POLL_READ_SYS_WRITE; |
michael@0 | 110 | syspoll[index].events |= POLLOUT; |
michael@0 | 111 | } |
michael@0 | 112 | if (in_flags_write & PR_POLL_READ) |
michael@0 | 113 | { |
michael@0 | 114 | pds[index].out_flags |= |
michael@0 | 115 | _PR_POLL_WRITE_SYS_READ; |
michael@0 | 116 | syspoll[index].events |= POLLIN; |
michael@0 | 117 | } |
michael@0 | 118 | if (in_flags_write & PR_POLL_WRITE) |
michael@0 | 119 | { |
michael@0 | 120 | pds[index].out_flags |= |
michael@0 | 121 | _PR_POLL_WRITE_SYS_WRITE; |
michael@0 | 122 | syspoll[index].events |= POLLOUT; |
michael@0 | 123 | } |
michael@0 | 124 | if (pds[index].in_flags & PR_POLL_EXCEPT) |
michael@0 | 125 | syspoll[index].events |= POLLPRI; |
michael@0 | 126 | } |
michael@0 | 127 | } |
michael@0 | 128 | else |
michael@0 | 129 | { |
michael@0 | 130 | if (0 == ready) |
michael@0 | 131 | { |
michael@0 | 132 | int i; |
michael@0 | 133 | for (i = 0; i < index; i++) |
michael@0 | 134 | { |
michael@0 | 135 | pds[i].out_flags = 0; |
michael@0 | 136 | } |
michael@0 | 137 | } |
michael@0 | 138 | ready += 1; /* this will cause an abrupt return */ |
michael@0 | 139 | pds[index].out_flags = PR_POLL_NVAL; /* bogii */ |
michael@0 | 140 | } |
michael@0 | 141 | } |
michael@0 | 142 | } |
michael@0 | 143 | else |
michael@0 | 144 | { |
michael@0 | 145 | /* make poll() ignore this entry */ |
michael@0 | 146 | syspoll[index].fd = -1; |
michael@0 | 147 | syspoll[index].events = 0; |
michael@0 | 148 | pds[index].out_flags = 0; |
michael@0 | 149 | } |
michael@0 | 150 | } |
michael@0 | 151 | |
michael@0 | 152 | if (0 == ready) |
michael@0 | 153 | { |
michael@0 | 154 | switch (timeout) |
michael@0 | 155 | { |
michael@0 | 156 | case PR_INTERVAL_NO_WAIT: msecs = 0; break; |
michael@0 | 157 | case PR_INTERVAL_NO_TIMEOUT: msecs = -1; break; |
michael@0 | 158 | default: |
michael@0 | 159 | msecs = PR_IntervalToMilliseconds(timeout); |
michael@0 | 160 | start = PR_IntervalNow(); |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | retry: |
michael@0 | 164 | ready = _MD_POLL(syspoll, npds, msecs); |
michael@0 | 165 | if (-1 == ready) |
michael@0 | 166 | { |
michael@0 | 167 | PRIntn oserror = errno; |
michael@0 | 168 | |
michael@0 | 169 | if (EINTR == oserror) |
michael@0 | 170 | { |
michael@0 | 171 | if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; |
michael@0 | 172 | else if (timeout == PR_INTERVAL_NO_WAIT) ready = 0; |
michael@0 | 173 | else |
michael@0 | 174 | { |
michael@0 | 175 | elapsed = (PRIntervalTime)(PR_IntervalNow() - start); |
michael@0 | 176 | if (elapsed > timeout) ready = 0; /* timed out */ |
michael@0 | 177 | else |
michael@0 | 178 | { |
michael@0 | 179 | remaining = timeout - elapsed; |
michael@0 | 180 | msecs = PR_IntervalToMilliseconds(remaining); |
michael@0 | 181 | goto retry; |
michael@0 | 182 | } |
michael@0 | 183 | } |
michael@0 | 184 | } |
michael@0 | 185 | else _PR_MD_MAP_POLL_ERROR(oserror); |
michael@0 | 186 | } |
michael@0 | 187 | else if (ready > 0) |
michael@0 | 188 | { |
michael@0 | 189 | for (index = 0; index < npds; ++index) |
michael@0 | 190 | { |
michael@0 | 191 | PRInt16 out_flags = 0; |
michael@0 | 192 | if ((NULL != pds[index].fd) && (0 != pds[index].in_flags)) |
michael@0 | 193 | { |
michael@0 | 194 | if (0 != syspoll[index].revents) |
michael@0 | 195 | { |
michael@0 | 196 | /* |
michael@0 | 197 | ** Set up the out_flags so that it contains the |
michael@0 | 198 | ** bits that the highest layer thinks are nice |
michael@0 | 199 | ** to have. Then the client of that layer will |
michael@0 | 200 | ** call the appropriate I/O function and maybe |
michael@0 | 201 | ** the protocol will make progress. |
michael@0 | 202 | */ |
michael@0 | 203 | if (syspoll[index].revents & POLLIN) |
michael@0 | 204 | { |
michael@0 | 205 | if (pds[index].out_flags |
michael@0 | 206 | & _PR_POLL_READ_SYS_READ) |
michael@0 | 207 | { |
michael@0 | 208 | out_flags |= PR_POLL_READ; |
michael@0 | 209 | } |
michael@0 | 210 | if (pds[index].out_flags |
michael@0 | 211 | & _PR_POLL_WRITE_SYS_READ) |
michael@0 | 212 | { |
michael@0 | 213 | out_flags |= PR_POLL_WRITE; |
michael@0 | 214 | } |
michael@0 | 215 | } |
michael@0 | 216 | if (syspoll[index].revents & POLLOUT) |
michael@0 | 217 | { |
michael@0 | 218 | if (pds[index].out_flags |
michael@0 | 219 | & _PR_POLL_READ_SYS_WRITE) |
michael@0 | 220 | { |
michael@0 | 221 | out_flags |= PR_POLL_READ; |
michael@0 | 222 | } |
michael@0 | 223 | if (pds[index].out_flags |
michael@0 | 224 | & _PR_POLL_WRITE_SYS_WRITE) |
michael@0 | 225 | { |
michael@0 | 226 | out_flags |= PR_POLL_WRITE; |
michael@0 | 227 | } |
michael@0 | 228 | } |
michael@0 | 229 | if (syspoll[index].revents & POLLPRI) |
michael@0 | 230 | out_flags |= PR_POLL_EXCEPT; |
michael@0 | 231 | if (syspoll[index].revents & POLLERR) |
michael@0 | 232 | out_flags |= PR_POLL_ERR; |
michael@0 | 233 | if (syspoll[index].revents & POLLNVAL) |
michael@0 | 234 | out_flags |= PR_POLL_NVAL; |
michael@0 | 235 | if (syspoll[index].revents & POLLHUP) |
michael@0 | 236 | out_flags |= PR_POLL_HUP; |
michael@0 | 237 | } |
michael@0 | 238 | } |
michael@0 | 239 | pds[index].out_flags = out_flags; |
michael@0 | 240 | } |
michael@0 | 241 | } |
michael@0 | 242 | } |
michael@0 | 243 | |
michael@0 | 244 | PR_DELETE(syspoll); |
michael@0 | 245 | return ready; |
michael@0 | 246 | |
michael@0 | 247 | } /* NativeThreadPoll */ |
michael@0 | 248 | #endif /* defined(_PR_USE_POLL) */ |
michael@0 | 249 | |
michael@0 | 250 | #if !defined(_PR_USE_POLL) |
michael@0 | 251 | static PRInt32 NativeThreadSelect( |
michael@0 | 252 | PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) |
michael@0 | 253 | { |
michael@0 | 254 | /* |
michael@0 | 255 | * This code is almost a duplicate of w32poll.c's _PR_MD_PR_POLL(). |
michael@0 | 256 | */ |
michael@0 | 257 | fd_set rd, wt, ex; |
michael@0 | 258 | PRFileDesc *bottom; |
michael@0 | 259 | PRPollDesc *pd, *epd; |
michael@0 | 260 | PRInt32 maxfd = -1, ready, err; |
michael@0 | 261 | PRIntervalTime remaining, elapsed, start; |
michael@0 | 262 | |
michael@0 | 263 | struct timeval tv, *tvp = NULL; |
michael@0 | 264 | |
michael@0 | 265 | FD_ZERO(&rd); |
michael@0 | 266 | FD_ZERO(&wt); |
michael@0 | 267 | FD_ZERO(&ex); |
michael@0 | 268 | |
michael@0 | 269 | ready = 0; |
michael@0 | 270 | for (pd = pds, epd = pd + npds; pd < epd; pd++) |
michael@0 | 271 | { |
michael@0 | 272 | PRInt16 in_flags_read = 0, in_flags_write = 0; |
michael@0 | 273 | PRInt16 out_flags_read = 0, out_flags_write = 0; |
michael@0 | 274 | |
michael@0 | 275 | if ((NULL != pd->fd) && (0 != pd->in_flags)) |
michael@0 | 276 | { |
michael@0 | 277 | if (pd->in_flags & PR_POLL_READ) |
michael@0 | 278 | { |
michael@0 | 279 | in_flags_read = (pd->fd->methods->poll)( |
michael@0 | 280 | pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); |
michael@0 | 281 | } |
michael@0 | 282 | if (pd->in_flags & PR_POLL_WRITE) |
michael@0 | 283 | { |
michael@0 | 284 | in_flags_write = (pd->fd->methods->poll)( |
michael@0 | 285 | pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); |
michael@0 | 286 | } |
michael@0 | 287 | if ((0 != (in_flags_read & out_flags_read)) |
michael@0 | 288 | || (0 != (in_flags_write & out_flags_write))) |
michael@0 | 289 | { |
michael@0 | 290 | /* this one's ready right now */ |
michael@0 | 291 | if (0 == ready) |
michael@0 | 292 | { |
michael@0 | 293 | /* |
michael@0 | 294 | * We will have to return without calling the |
michael@0 | 295 | * system poll/select function. So zero the |
michael@0 | 296 | * out_flags fields of all the poll descriptors |
michael@0 | 297 | * before this one. |
michael@0 | 298 | */ |
michael@0 | 299 | PRPollDesc *prev; |
michael@0 | 300 | for (prev = pds; prev < pd; prev++) |
michael@0 | 301 | { |
michael@0 | 302 | prev->out_flags = 0; |
michael@0 | 303 | } |
michael@0 | 304 | } |
michael@0 | 305 | ready += 1; |
michael@0 | 306 | pd->out_flags = out_flags_read | out_flags_write; |
michael@0 | 307 | } |
michael@0 | 308 | else |
michael@0 | 309 | { |
michael@0 | 310 | pd->out_flags = 0; /* pre-condition */ |
michael@0 | 311 | |
michael@0 | 312 | /* make sure this is an NSPR supported stack */ |
michael@0 | 313 | bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
michael@0 | 314 | PR_ASSERT(NULL != bottom); /* what to do about that? */ |
michael@0 | 315 | if ((NULL != bottom) |
michael@0 | 316 | && (_PR_FILEDESC_OPEN == bottom->secret->state)) |
michael@0 | 317 | { |
michael@0 | 318 | if (0 == ready) |
michael@0 | 319 | { |
michael@0 | 320 | PRInt32 osfd = bottom->secret->md.osfd; |
michael@0 | 321 | if (osfd > maxfd) maxfd = osfd; |
michael@0 | 322 | if (in_flags_read & PR_POLL_READ) |
michael@0 | 323 | { |
michael@0 | 324 | pd->out_flags |= _PR_POLL_READ_SYS_READ; |
michael@0 | 325 | FD_SET(osfd, &rd); |
michael@0 | 326 | } |
michael@0 | 327 | if (in_flags_read & PR_POLL_WRITE) |
michael@0 | 328 | { |
michael@0 | 329 | pd->out_flags |= _PR_POLL_READ_SYS_WRITE; |
michael@0 | 330 | FD_SET(osfd, &wt); |
michael@0 | 331 | } |
michael@0 | 332 | if (in_flags_write & PR_POLL_READ) |
michael@0 | 333 | { |
michael@0 | 334 | pd->out_flags |= _PR_POLL_WRITE_SYS_READ; |
michael@0 | 335 | FD_SET(osfd, &rd); |
michael@0 | 336 | } |
michael@0 | 337 | if (in_flags_write & PR_POLL_WRITE) |
michael@0 | 338 | { |
michael@0 | 339 | pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; |
michael@0 | 340 | FD_SET(osfd, &wt); |
michael@0 | 341 | } |
michael@0 | 342 | if (pd->in_flags & PR_POLL_EXCEPT) FD_SET(osfd, &ex); |
michael@0 | 343 | } |
michael@0 | 344 | } |
michael@0 | 345 | else |
michael@0 | 346 | { |
michael@0 | 347 | if (0 == ready) |
michael@0 | 348 | { |
michael@0 | 349 | PRPollDesc *prev; |
michael@0 | 350 | for (prev = pds; prev < pd; prev++) |
michael@0 | 351 | { |
michael@0 | 352 | prev->out_flags = 0; |
michael@0 | 353 | } |
michael@0 | 354 | } |
michael@0 | 355 | ready += 1; /* this will cause an abrupt return */ |
michael@0 | 356 | pd->out_flags = PR_POLL_NVAL; /* bogii */ |
michael@0 | 357 | } |
michael@0 | 358 | } |
michael@0 | 359 | } |
michael@0 | 360 | else |
michael@0 | 361 | { |
michael@0 | 362 | pd->out_flags = 0; |
michael@0 | 363 | } |
michael@0 | 364 | } |
michael@0 | 365 | |
michael@0 | 366 | if (0 != ready) return ready; /* no need to block */ |
michael@0 | 367 | |
michael@0 | 368 | remaining = timeout; |
michael@0 | 369 | start = PR_IntervalNow(); |
michael@0 | 370 | |
michael@0 | 371 | retry: |
michael@0 | 372 | if (timeout != PR_INTERVAL_NO_TIMEOUT) |
michael@0 | 373 | { |
michael@0 | 374 | PRInt32 ticksPerSecond = PR_TicksPerSecond(); |
michael@0 | 375 | tv.tv_sec = remaining / ticksPerSecond; |
michael@0 | 376 | tv.tv_usec = PR_IntervalToMicroseconds( remaining % ticksPerSecond ); |
michael@0 | 377 | tvp = &tv; |
michael@0 | 378 | } |
michael@0 | 379 | |
michael@0 | 380 | ready = _MD_SELECT(maxfd + 1, &rd, &wt, &ex, tvp); |
michael@0 | 381 | |
michael@0 | 382 | if (ready == -1 && errno == EINTR) |
michael@0 | 383 | { |
michael@0 | 384 | if (timeout == PR_INTERVAL_NO_TIMEOUT) goto retry; |
michael@0 | 385 | else |
michael@0 | 386 | { |
michael@0 | 387 | elapsed = (PRIntervalTime) (PR_IntervalNow() - start); |
michael@0 | 388 | if (elapsed > timeout) ready = 0; /* timed out */ |
michael@0 | 389 | else |
michael@0 | 390 | { |
michael@0 | 391 | remaining = timeout - elapsed; |
michael@0 | 392 | goto retry; |
michael@0 | 393 | } |
michael@0 | 394 | } |
michael@0 | 395 | } |
michael@0 | 396 | |
michael@0 | 397 | /* |
michael@0 | 398 | ** Now to unravel the select sets back into the client's poll |
michael@0 | 399 | ** descriptor list. Is this possibly an area for pissing away |
michael@0 | 400 | ** a few cycles or what? |
michael@0 | 401 | */ |
michael@0 | 402 | if (ready > 0) |
michael@0 | 403 | { |
michael@0 | 404 | ready = 0; |
michael@0 | 405 | for (pd = pds, epd = pd + npds; pd < epd; pd++) |
michael@0 | 406 | { |
michael@0 | 407 | PRInt16 out_flags = 0; |
michael@0 | 408 | if ((NULL != pd->fd) && (0 != pd->in_flags)) |
michael@0 | 409 | { |
michael@0 | 410 | PRInt32 osfd; |
michael@0 | 411 | bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
michael@0 | 412 | PR_ASSERT(NULL != bottom); |
michael@0 | 413 | |
michael@0 | 414 | osfd = bottom->secret->md.osfd; |
michael@0 | 415 | |
michael@0 | 416 | if (FD_ISSET(osfd, &rd)) |
michael@0 | 417 | { |
michael@0 | 418 | if (pd->out_flags & _PR_POLL_READ_SYS_READ) |
michael@0 | 419 | out_flags |= PR_POLL_READ; |
michael@0 | 420 | if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) |
michael@0 | 421 | out_flags |= PR_POLL_WRITE; |
michael@0 | 422 | } |
michael@0 | 423 | if (FD_ISSET(osfd, &wt)) |
michael@0 | 424 | { |
michael@0 | 425 | if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) |
michael@0 | 426 | out_flags |= PR_POLL_READ; |
michael@0 | 427 | if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) |
michael@0 | 428 | out_flags |= PR_POLL_WRITE; |
michael@0 | 429 | } |
michael@0 | 430 | if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT; |
michael@0 | 431 | } |
michael@0 | 432 | pd->out_flags = out_flags; |
michael@0 | 433 | if (out_flags) ready++; |
michael@0 | 434 | } |
michael@0 | 435 | PR_ASSERT(ready > 0); |
michael@0 | 436 | } |
michael@0 | 437 | else if (ready < 0) |
michael@0 | 438 | { |
michael@0 | 439 | err = _MD_ERRNO(); |
michael@0 | 440 | if (err == EBADF) |
michael@0 | 441 | { |
michael@0 | 442 | /* Find the bad fds */ |
michael@0 | 443 | ready = 0; |
michael@0 | 444 | for (pd = pds, epd = pd + npds; pd < epd; pd++) |
michael@0 | 445 | { |
michael@0 | 446 | pd->out_flags = 0; |
michael@0 | 447 | if ((NULL != pd->fd) && (0 != pd->in_flags)) |
michael@0 | 448 | { |
michael@0 | 449 | bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
michael@0 | 450 | if (fcntl(bottom->secret->md.osfd, F_GETFL, 0) == -1) |
michael@0 | 451 | { |
michael@0 | 452 | pd->out_flags = PR_POLL_NVAL; |
michael@0 | 453 | ready++; |
michael@0 | 454 | } |
michael@0 | 455 | } |
michael@0 | 456 | } |
michael@0 | 457 | PR_ASSERT(ready > 0); |
michael@0 | 458 | } |
michael@0 | 459 | else _PR_MD_MAP_SELECT_ERROR(err); |
michael@0 | 460 | } |
michael@0 | 461 | |
michael@0 | 462 | return ready; |
michael@0 | 463 | } /* NativeThreadSelect */ |
michael@0 | 464 | #endif /* !defined(_PR_USE_POLL) */ |
michael@0 | 465 | |
michael@0 | 466 | static PRInt32 LocalThreads( |
michael@0 | 467 | PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) |
michael@0 | 468 | { |
michael@0 | 469 | PRPollDesc *pd, *epd; |
michael@0 | 470 | PRInt32 ready, pdcnt; |
michael@0 | 471 | _PRUnixPollDesc *unixpds, *unixpd; |
michael@0 | 472 | |
michael@0 | 473 | /* |
michael@0 | 474 | * XXX |
michael@0 | 475 | * PRPollDesc has a PRFileDesc field, fd, while the IOQ |
michael@0 | 476 | * is a list of PRPollQueue structures, each of which contains |
michael@0 | 477 | * a _PRUnixPollDesc. A _PRUnixPollDesc struct contains |
michael@0 | 478 | * the OS file descriptor, osfd, and not a PRFileDesc. |
michael@0 | 479 | * So, we have allocate memory for _PRUnixPollDesc structures, |
michael@0 | 480 | * copy the flags information from the pds list and have pq |
michael@0 | 481 | * point to this list of _PRUnixPollDesc structures. |
michael@0 | 482 | * |
michael@0 | 483 | * It would be better if the memory allocation can be avoided. |
michael@0 | 484 | */ |
michael@0 | 485 | |
michael@0 | 486 | unixpd = unixpds = (_PRUnixPollDesc*) |
michael@0 | 487 | PR_MALLOC(npds * sizeof(_PRUnixPollDesc)); |
michael@0 | 488 | if (NULL == unixpds) |
michael@0 | 489 | { |
michael@0 | 490 | PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
michael@0 | 491 | return -1; |
michael@0 | 492 | } |
michael@0 | 493 | |
michael@0 | 494 | ready = 0; |
michael@0 | 495 | for (pdcnt = 0, pd = pds, epd = pd + npds; pd < epd; pd++) |
michael@0 | 496 | { |
michael@0 | 497 | PRFileDesc *bottom; |
michael@0 | 498 | PRInt16 in_flags_read = 0, in_flags_write = 0; |
michael@0 | 499 | PRInt16 out_flags_read = 0, out_flags_write = 0; |
michael@0 | 500 | |
michael@0 | 501 | if ((NULL != pd->fd) && (0 != pd->in_flags)) |
michael@0 | 502 | { |
michael@0 | 503 | if (pd->in_flags & PR_POLL_READ) |
michael@0 | 504 | { |
michael@0 | 505 | in_flags_read = (pd->fd->methods->poll)( |
michael@0 | 506 | pd->fd, pd->in_flags & ~PR_POLL_WRITE, &out_flags_read); |
michael@0 | 507 | } |
michael@0 | 508 | if (pd->in_flags & PR_POLL_WRITE) |
michael@0 | 509 | { |
michael@0 | 510 | in_flags_write = (pd->fd->methods->poll)( |
michael@0 | 511 | pd->fd, pd->in_flags & ~PR_POLL_READ, &out_flags_write); |
michael@0 | 512 | } |
michael@0 | 513 | if ((0 != (in_flags_read & out_flags_read)) |
michael@0 | 514 | || (0 != (in_flags_write & out_flags_write))) |
michael@0 | 515 | { |
michael@0 | 516 | /* this one's ready right now */ |
michael@0 | 517 | if (0 == ready) |
michael@0 | 518 | { |
michael@0 | 519 | /* |
michael@0 | 520 | * We will have to return without calling the |
michael@0 | 521 | * system poll/select function. So zero the |
michael@0 | 522 | * out_flags fields of all the poll descriptors |
michael@0 | 523 | * before this one. |
michael@0 | 524 | */ |
michael@0 | 525 | PRPollDesc *prev; |
michael@0 | 526 | for (prev = pds; prev < pd; prev++) |
michael@0 | 527 | { |
michael@0 | 528 | prev->out_flags = 0; |
michael@0 | 529 | } |
michael@0 | 530 | } |
michael@0 | 531 | ready += 1; |
michael@0 | 532 | pd->out_flags = out_flags_read | out_flags_write; |
michael@0 | 533 | } |
michael@0 | 534 | else |
michael@0 | 535 | { |
michael@0 | 536 | pd->out_flags = 0; /* pre-condition */ |
michael@0 | 537 | bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER); |
michael@0 | 538 | PR_ASSERT(NULL != bottom); /* what to do about that? */ |
michael@0 | 539 | if ((NULL != bottom) |
michael@0 | 540 | && (_PR_FILEDESC_OPEN == bottom->secret->state)) |
michael@0 | 541 | { |
michael@0 | 542 | if (0 == ready) |
michael@0 | 543 | { |
michael@0 | 544 | unixpd->osfd = bottom->secret->md.osfd; |
michael@0 | 545 | unixpd->in_flags = 0; |
michael@0 | 546 | if (in_flags_read & PR_POLL_READ) |
michael@0 | 547 | { |
michael@0 | 548 | unixpd->in_flags |= _PR_UNIX_POLL_READ; |
michael@0 | 549 | pd->out_flags |= _PR_POLL_READ_SYS_READ; |
michael@0 | 550 | } |
michael@0 | 551 | if (in_flags_read & PR_POLL_WRITE) |
michael@0 | 552 | { |
michael@0 | 553 | unixpd->in_flags |= _PR_UNIX_POLL_WRITE; |
michael@0 | 554 | pd->out_flags |= _PR_POLL_READ_SYS_WRITE; |
michael@0 | 555 | } |
michael@0 | 556 | if (in_flags_write & PR_POLL_READ) |
michael@0 | 557 | { |
michael@0 | 558 | unixpd->in_flags |= _PR_UNIX_POLL_READ; |
michael@0 | 559 | pd->out_flags |= _PR_POLL_WRITE_SYS_READ; |
michael@0 | 560 | } |
michael@0 | 561 | if (in_flags_write & PR_POLL_WRITE) |
michael@0 | 562 | { |
michael@0 | 563 | unixpd->in_flags |= _PR_UNIX_POLL_WRITE; |
michael@0 | 564 | pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE; |
michael@0 | 565 | } |
michael@0 | 566 | if ((in_flags_read | in_flags_write) & PR_POLL_EXCEPT) |
michael@0 | 567 | { |
michael@0 | 568 | unixpd->in_flags |= _PR_UNIX_POLL_EXCEPT; |
michael@0 | 569 | } |
michael@0 | 570 | unixpd++; pdcnt++; |
michael@0 | 571 | } |
michael@0 | 572 | } |
michael@0 | 573 | else |
michael@0 | 574 | { |
michael@0 | 575 | if (0 == ready) |
michael@0 | 576 | { |
michael@0 | 577 | PRPollDesc *prev; |
michael@0 | 578 | for (prev = pds; prev < pd; prev++) |
michael@0 | 579 | { |
michael@0 | 580 | prev->out_flags = 0; |
michael@0 | 581 | } |
michael@0 | 582 | } |
michael@0 | 583 | ready += 1; /* this will cause an abrupt return */ |
michael@0 | 584 | pd->out_flags = PR_POLL_NVAL; /* bogii */ |
michael@0 | 585 | } |
michael@0 | 586 | } |
michael@0 | 587 | } |
michael@0 | 588 | } |
michael@0 | 589 | |
michael@0 | 590 | if (0 != ready) |
michael@0 | 591 | { |
michael@0 | 592 | /* no need to block */ |
michael@0 | 593 | PR_DELETE(unixpds); |
michael@0 | 594 | return ready; |
michael@0 | 595 | } |
michael@0 | 596 | |
michael@0 | 597 | ready = _PR_WaitForMultipleFDs(unixpds, pdcnt, timeout); |
michael@0 | 598 | |
michael@0 | 599 | /* |
michael@0 | 600 | * Copy the out_flags from the _PRUnixPollDesc structures to the |
michael@0 | 601 | * user's PRPollDesc structures and free the allocated memory |
michael@0 | 602 | */ |
michael@0 | 603 | unixpd = unixpds; |
michael@0 | 604 | for (pd = pds, epd = pd + npds; pd < epd; pd++) |
michael@0 | 605 | { |
michael@0 | 606 | PRInt16 out_flags = 0; |
michael@0 | 607 | if ((NULL != pd->fd) && (0 != pd->in_flags)) |
michael@0 | 608 | { |
michael@0 | 609 | /* |
michael@0 | 610 | * take errors from the poll operation, |
michael@0 | 611 | * the R/W bits from the request |
michael@0 | 612 | */ |
michael@0 | 613 | if (0 != unixpd->out_flags) |
michael@0 | 614 | { |
michael@0 | 615 | if (unixpd->out_flags & _PR_UNIX_POLL_READ) |
michael@0 | 616 | { |
michael@0 | 617 | if (pd->out_flags & _PR_POLL_READ_SYS_READ) |
michael@0 | 618 | out_flags |= PR_POLL_READ; |
michael@0 | 619 | if (pd->out_flags & _PR_POLL_WRITE_SYS_READ) |
michael@0 | 620 | out_flags |= PR_POLL_WRITE; |
michael@0 | 621 | } |
michael@0 | 622 | if (unixpd->out_flags & _PR_UNIX_POLL_WRITE) |
michael@0 | 623 | { |
michael@0 | 624 | if (pd->out_flags & _PR_POLL_READ_SYS_WRITE) |
michael@0 | 625 | out_flags |= PR_POLL_READ; |
michael@0 | 626 | if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE) |
michael@0 | 627 | out_flags |= PR_POLL_WRITE; |
michael@0 | 628 | } |
michael@0 | 629 | if (unixpd->out_flags & _PR_UNIX_POLL_EXCEPT) |
michael@0 | 630 | out_flags |= PR_POLL_EXCEPT; |
michael@0 | 631 | if (unixpd->out_flags & _PR_UNIX_POLL_ERR) |
michael@0 | 632 | out_flags |= PR_POLL_ERR; |
michael@0 | 633 | if (unixpd->out_flags & _PR_UNIX_POLL_NVAL) |
michael@0 | 634 | out_flags |= PR_POLL_NVAL; |
michael@0 | 635 | if (unixpd->out_flags & _PR_UNIX_POLL_HUP) |
michael@0 | 636 | out_flags |= PR_POLL_HUP; |
michael@0 | 637 | } |
michael@0 | 638 | unixpd++; |
michael@0 | 639 | } |
michael@0 | 640 | pd->out_flags = out_flags; |
michael@0 | 641 | } |
michael@0 | 642 | |
michael@0 | 643 | PR_DELETE(unixpds); |
michael@0 | 644 | |
michael@0 | 645 | return ready; |
michael@0 | 646 | } /* LocalThreads */ |
michael@0 | 647 | |
michael@0 | 648 | #if defined(_PR_USE_POLL) |
michael@0 | 649 | #define NativeThreads NativeThreadPoll |
michael@0 | 650 | #else |
michael@0 | 651 | #define NativeThreads NativeThreadSelect |
michael@0 | 652 | #endif |
michael@0 | 653 | |
michael@0 | 654 | PRInt32 _MD_pr_poll(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout) |
michael@0 | 655 | { |
michael@0 | 656 | PRInt32 rv = 0; |
michael@0 | 657 | PRThread *me = _PR_MD_CURRENT_THREAD(); |
michael@0 | 658 | |
michael@0 | 659 | if (_PR_PENDING_INTERRUPT(me)) |
michael@0 | 660 | { |
michael@0 | 661 | me->flags &= ~_PR_INTERRUPT; |
michael@0 | 662 | PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); |
michael@0 | 663 | return -1; |
michael@0 | 664 | } |
michael@0 | 665 | if (0 == npds) PR_Sleep(timeout); |
michael@0 | 666 | else if (_PR_IS_NATIVE_THREAD(me)) |
michael@0 | 667 | rv = NativeThreads(pds, npds, timeout); |
michael@0 | 668 | else rv = LocalThreads(pds, npds, timeout); |
michael@0 | 669 | |
michael@0 | 670 | return rv; |
michael@0 | 671 | } /* _MD_pr_poll */ |
michael@0 | 672 | |
michael@0 | 673 | #endif /* defined(_PR_PTHREADS) */ |
michael@0 | 674 | |
michael@0 | 675 | /* uxpoll.c */ |
michael@0 | 676 |