1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
39 * This file implements _PR_MD_PR_POLL for Win32.
42 /* The default value of FD_SETSIZE is 64. */
43 #define FD_SETSIZE 1024
47 #if !defined(_PR_GLOBAL_THREADS_ONLY)
49 struct select_data_s {
53 const struct timeval *tv;
57 _PR_MD_select_thread(void *cdata)
59 struct select_data_s *cd = (struct select_data_s *)cdata;
61 cd->status = select(0, cd->rd, cd->wt, cd->ex, cd->tv);
63 if (cd->status == SOCKET_ERROR) {
64 cd->error = WSAGetLastError();
68 int _PR_NTFiberSafeSelect(
73 const struct timeval *timeout)
75 PRThread *me = _PR_MD_CURRENT_THREAD();
78 if (_PR_IS_NATIVE_THREAD(me)) {
79 ready = _MD_SELECT(nfds, readfds, writefds, exceptfds, timeout);
84 ** Creating a new thread on each call!!
85 ** I guess web server doesn't use non-block I/O.
87 PRThread *selectThread;
88 struct select_data_s data;
96 selectThread = PR_CreateThread(
97 PR_USER_THREAD, _PR_MD_select_thread, &data,
98 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
99 if (selectThread == NULL) return -1;
101 PR_JoinThread(selectThread);
103 if (ready == SOCKET_ERROR) WSASetLastError(data.error);
108 #endif /* !defined(_PR_GLOBAL_THREADS_ONLY) */
110 PRInt32 _PR_MD_PR_POLL(PRPollDesc *pds, PRIntn npds, PRIntervalTime timeout)
114 fd_set *rdp, *wtp, *exp;
117 PRPollDesc *pd, *epd;
118 PRThread *me = _PR_MD_CURRENT_THREAD();
120 struct timeval tv, *tvp = NULL;
122 if (_PR_PENDING_INTERRUPT(me))
124 me->flags &= ~_PR_INTERRUPT;
125 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
130 ** Is it an empty set? If so, just sleep for the timeout and return
144 for (pd = pds, epd = pd + npds; pd < epd; pd++)
147 PRInt16 in_flags_read = 0, in_flags_write = 0;
148 PRInt16 out_flags_read = 0, out_flags_write = 0;
150 if ((NULL != pd->fd) && (0 != pd->in_flags))
152 if (pd->in_flags & PR_POLL_READ)
154 in_flags_read = (pd->fd->methods->poll)(
155 pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_WRITE),
158 if (pd->in_flags & PR_POLL_WRITE)
160 in_flags_write = (pd->fd->methods->poll)(
161 pd->fd, (PRInt16)(pd->in_flags & ~PR_POLL_READ),
164 if ((0 != (in_flags_read & out_flags_read))
165 || (0 != (in_flags_write & out_flags_write)))
167 /* this one's ready right now (buffered input) */
171 * We will have to return without calling the
172 * system poll/select function. So zero the
173 * out_flags fields of all the poll descriptors
177 for (prev = pds; prev < pd; prev++)
183 pd->out_flags = out_flags_read | out_flags_write;
187 pd->out_flags = 0; /* pre-condition */
188 /* make sure this is an NSPR supported stack */
189 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
190 PR_ASSERT(NULL != bottom); /* what to do about that? */
192 && (_PR_FILEDESC_OPEN == bottom->secret->state))
196 osfd = (SOCKET) bottom->secret->md.osfd;
197 if (in_flags_read & PR_POLL_READ)
199 pd->out_flags |= _PR_POLL_READ_SYS_READ;
203 if (in_flags_read & PR_POLL_WRITE)
205 pd->out_flags |= _PR_POLL_READ_SYS_WRITE;
209 if (in_flags_write & PR_POLL_READ)
211 pd->out_flags |= _PR_POLL_WRITE_SYS_READ;
215 if (in_flags_write & PR_POLL_WRITE)
217 pd->out_flags |= _PR_POLL_WRITE_SYS_WRITE;
221 if (pd->in_flags & PR_POLL_EXCEPT) {
232 for (prev = pds; prev < pd; prev++)
237 ready += 1; /* this will cause an abrupt return */
238 pd->out_flags = PR_POLL_NVAL; /* bogii */
248 if (0 != ready) return ready; /* no need to block */
251 * FD_SET does nothing if the fd_set's internal fd_array is full. If
252 * nrd, nwt, or nex is greater than FD_SETSIZE, we know FD_SET must
253 * have failed to insert an osfd into the corresponding fd_set, and
254 * therefore we should fail.
256 if ((nrd > FD_SETSIZE) || (nwt > FD_SETSIZE) || (nex > FD_SETSIZE)) {
257 PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
261 rdp = (0 == nrd) ? NULL : &rd;
262 wtp = (0 == nwt) ? NULL : &wt;
263 exp = (0 == nex) ? NULL : &ex;
265 if ((NULL == rdp) && (NULL == wtp) && (NULL == exp)) {
270 if (timeout != PR_INTERVAL_NO_TIMEOUT)
272 PRInt32 ticksPerSecond = PR_TicksPerSecond();
273 tv.tv_sec = timeout / ticksPerSecond;
274 tv.tv_usec = PR_IntervalToMicroseconds( timeout % ticksPerSecond );
278 #if defined(_PR_GLOBAL_THREADS_ONLY)
279 ready = _MD_SELECT(0, rdp, wtp, exp, tvp);
281 ready = _PR_NTFiberSafeSelect(0, rdp, wtp, exp, tvp);
285 ** Now to unravel the select sets back into the client's poll
286 ** descriptor list. Is this possibly an area for pissing away
287 ** a few cycles or what?
292 for (pd = pds, epd = pd + npds; pd < epd; pd++)
294 PRInt16 out_flags = 0;
295 if ((NULL != pd->fd) && (0 != pd->in_flags))
298 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
299 PR_ASSERT(NULL != bottom);
301 osfd = (SOCKET) bottom->secret->md.osfd;
303 if (FD_ISSET(osfd, &rd))
305 if (pd->out_flags & _PR_POLL_READ_SYS_READ)
306 out_flags |= PR_POLL_READ;
307 if (pd->out_flags & _PR_POLL_WRITE_SYS_READ)
308 out_flags |= PR_POLL_WRITE;
310 if (FD_ISSET(osfd, &wt))
312 if (pd->out_flags & _PR_POLL_READ_SYS_WRITE)
313 out_flags |= PR_POLL_READ;
314 if (pd->out_flags & _PR_POLL_WRITE_SYS_WRITE)
315 out_flags |= PR_POLL_WRITE;
317 if (FD_ISSET(osfd, &ex)) out_flags |= PR_POLL_EXCEPT;
319 pd->out_flags = out_flags;
320 if (out_flags) ready++;
322 PR_ASSERT(ready > 0);
324 else if (ready == SOCKET_ERROR)
326 err = WSAGetLastError();
327 if (err == WSAENOTSOCK)
329 /* Find the bad fds */
331 int optlen = sizeof(optval);
333 for (pd = pds, epd = pd + npds; pd < epd; pd++)
336 if ((NULL != pd->fd) && (0 != pd->in_flags))
338 bottom = PR_GetIdentitiesLayer(pd->fd, PR_NSPR_IO_LAYER);
339 if (getsockopt(bottom->secret->md.osfd, SOL_SOCKET,
340 SO_TYPE, (char *) &optval, &optlen) == -1)
342 PR_ASSERT(WSAGetLastError() == WSAENOTSOCK);
343 if (WSAGetLastError() == WSAENOTSOCK)
345 pd->out_flags = PR_POLL_NVAL;
351 PR_ASSERT(ready > 0);
353 else _PR_MD_MAP_SELECT_ERROR(err);