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 *********************************************************************
43 * Pollable events are implemented using layered I/O. The only
44 * I/O methods that are implemented for pollable events are poll
45 * and close. No other methods can be invoked on a pollable
48 * A pipe or socket pair is created and the pollable event layer
49 * is pushed onto the read end. A pointer to the write end is
50 * saved in the PRFilePrivate structure of the pollable event.
52 *********************************************************************
64 * On OpenVMS we use an event flag instead of a pipe or a socket since
65 * event flags are much more efficient on OpenVMS.
68 #include <lib$routines.h>
72 PR_IMPLEMENT(PRFileDesc
*) PR_NewPollableEvent(void)
79 ** Allocate an event flag and clear it.
81 status
= lib$
get_ef(&flag
);
82 if ((!$
VMS_STATUS_SUCCESS(status
)) || (flag
== -1)) {
83 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR
, status
);
89 ** Give NSPR the event flag's negative value. We do this because our
90 ** select interprets a negative fd as an event flag rather than a
93 event
= PR_CreateSocketPollFd(-flag
);
102 PR_IMPLEMENT(PRStatus
) PR_DestroyPollableEvent(PRFileDesc
*event
)
104 int flag
= -PR_FileDesc2NativeHandle(event
);
105 PR_DestroySocketPollFd(event
);
110 PR_IMPLEMENT(PRStatus
) PR_SetPollableEvent(PRFileDesc
*event
)
113 ** Just set the event flag.
116 status
= sys$
setef(-PR_FileDesc2NativeHandle(event
));
117 if (!$
VMS_STATUS_SUCCESS(status
)) {
118 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, status
);
124 PR_IMPLEMENT(PRStatus
) PR_WaitForPollableEvent(PRFileDesc
*event
)
127 ** Just clear the event flag.
130 status
= sys$
clref(-PR_FileDesc2NativeHandle(event
));
131 if (!$
VMS_STATUS_SUCCESS(status
)) {
132 PR_SetError(PR_INVALID_ARGUMENT_ERROR
, status
);
138 #elif defined (XP_MAC)
143 * On Mac, local sockets cannot be used, because the networking stack
144 * closes them when the machine goes to sleep. Instead, we'll use a simple
150 * PRFilePrivate structure for the NSPR pollable events layer
152 typedef struct PRPollableDesc
{
154 PRThread
*pollingThread
;
157 static PRStatus PR_CALLBACK
_pr_MacPolEvtClose(PRFileDesc
*fd
);
159 static PRInt16 PR_CALLBACK
_pr_MacPolEvtPoll(
160 PRFileDesc
*fd
, PRInt16 in_flags
, PRInt16
*out_flags
);
162 static PRIOMethods _pr_mac_polevt_methods
= {
165 (PRReadFN
)_PR_InvalidInt
,
166 (PRWriteFN
)_PR_InvalidInt
,
167 (PRAvailableFN
)_PR_InvalidInt
,
168 (PRAvailable64FN
)_PR_InvalidInt64
,
169 (PRFsyncFN
)_PR_InvalidStatus
,
170 (PRSeekFN
)_PR_InvalidInt
,
171 (PRSeek64FN
)_PR_InvalidInt64
,
172 (PRFileInfoFN
)_PR_InvalidStatus
,
173 (PRFileInfo64FN
)_PR_InvalidStatus
,
174 (PRWritevFN
)_PR_InvalidInt
,
175 (PRConnectFN
)_PR_InvalidStatus
,
176 (PRAcceptFN
)_PR_InvalidDesc
,
177 (PRBindFN
)_PR_InvalidStatus
,
178 (PRListenFN
)_PR_InvalidStatus
,
179 (PRShutdownFN
)_PR_InvalidStatus
,
180 (PRRecvFN
)_PR_InvalidInt
,
181 (PRSendFN
)_PR_InvalidInt
,
182 (PRRecvfromFN
)_PR_InvalidInt
,
183 (PRSendtoFN
)_PR_InvalidInt
,
185 (PRAcceptreadFN
)_PR_InvalidInt
,
186 (PRTransmitfileFN
)_PR_InvalidInt
,
187 (PRGetsocknameFN
)_PR_InvalidStatus
,
188 (PRGetpeernameFN
)_PR_InvalidStatus
,
189 (PRReservedFN
)_PR_InvalidInt
,
190 (PRReservedFN
)_PR_InvalidInt
,
191 (PRGetsocketoptionFN
)_PR_InvalidStatus
,
192 (PRSetsocketoptionFN
)_PR_InvalidStatus
,
193 (PRSendfileFN
)_PR_InvalidInt
,
194 (PRConnectcontinueFN
)_PR_InvalidStatus
,
195 (PRReservedFN
)_PR_InvalidInt
,
196 (PRReservedFN
)_PR_InvalidInt
,
197 (PRReservedFN
)_PR_InvalidInt
,
198 (PRReservedFN
)_PR_InvalidInt
201 static PRDescIdentity _pr_mac_polevt_id
;
202 static PRCallOnceType _pr_mac_polevt_once_control
;
203 static PRStatus PR_CALLBACK
_pr_MacPolEvtInit(void);
205 static PRInt16 PR_CALLBACK
_pr_MacPolEvtPoll(
206 PRFileDesc
*fd
, PRInt16 in_flags
, PRInt16
*out_flags
)
208 PRPollableDesc
*pollDesc
= (PRPollableDesc
*)fd
->secret
;
211 // set the current thread so that we can wake up the poll thread
212 pollDesc
->pollingThread
= PR_GetCurrentThread();
214 if ((in_flags
& PR_POLL_READ
) && pollDesc
->gotEvent
)
215 *out_flags
= PR_POLL_READ
;
218 return pollDesc
->gotEvent
? 1 : 0;
221 static PRStatus PR_CALLBACK
_pr_MacPolEvtInit(void)
223 _pr_mac_polevt_id
= PR_GetUniqueIdentity("NSPR pollable events");
224 if (PR_INVALID_IO_LAYER
== _pr_mac_polevt_id
) {
230 static PRStatus PR_CALLBACK
_pr_MacPolEvtClose(PRFileDesc
*fd
)
232 PRPollableDesc
*pollDesc
= (PRPollableDesc
*)fd
->secret
;
233 PR_ASSERT(NULL
== fd
->higher
&& NULL
== fd
->lower
);
240 PR_IMPLEMENT(PRFileDesc
*) PR_NewPollableEvent(void)
243 PRPollableDesc
*pollDesc
;
245 if (PR_CallOnce(&_pr_mac_polevt_once_control
, _pr_MacPolEvtInit
) == PR_FAILURE
) {
249 event
= PR_CreateIOLayerStub(_pr_mac_polevt_id
, &_pr_mac_polevt_methods
);
255 ** Allocate an event flag and clear it.
257 pollDesc
= PR_NEW(PRPollableDesc
);
259 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
263 pollDesc
->gotEvent
= PR_FALSE
;
264 pollDesc
->pollingThread
= NULL
;
266 event
->secret
= (PRFilePrivate
*)pollDesc
;
272 PR_DELETE(event
->secret
);
278 PR_IMPLEMENT(PRStatus
) PR_DestroyPollableEvent(PRFileDesc
*event
)
280 return PR_Close(event
);
283 /* from macsockotpt.c. I wish there was a cleaner way */
284 extern void WakeUpNotifiedThread(PRThread
*thread
, OTResult result
);
286 PR_IMPLEMENT(PRStatus
) PR_SetPollableEvent(PRFileDesc
*event
)
288 PRPollableDesc
*pollDesc
= (PRPollableDesc
*)event
->secret
;
290 PR_ASSERT(pollDesc
->pollingThread
->state
!= _PR_DEAD_STATE
);
292 if (pollDesc
->pollingThread
->state
== _PR_DEAD_STATE
)
295 pollDesc
->gotEvent
= PR_TRUE
;
297 if (pollDesc
->pollingThread
)
298 WakeUpNotifiedThread(pollDesc
->pollingThread
, noErr
);
303 PR_IMPLEMENT(PRStatus
) PR_WaitForPollableEvent(PRFileDesc
*event
)
305 PRPollableDesc
*pollDesc
= (PRPollableDesc
*)event
->secret
;
310 FIXME: Danger Will Robinson!
312 The current implementation of PR_WaitForPollableEvent is somewhat
313 bogus; it makes the assumption that, in Mozilla, this will only
314 ever be called when PR_Poll has returned, telling us that an
318 PR_ASSERT(pollDesc
->gotEvent
);
320 status
= (pollDesc
->gotEvent
) ? PR_SUCCESS
: PR_FAILURE
;
321 pollDesc
->gotEvent
= PR_FALSE
;
328 * These internal functions are declared in primpl.h,
329 * but we can't include primpl.h because the definition
330 * of struct PRFilePrivate in this file (for the pollable
331 * event layer) will conflict with the definition of
332 * struct PRFilePrivate in primpl.h (for the NSPR layer).
334 extern PRIntn
_PR_InvalidInt(void);
335 extern PRInt64
_PR_InvalidInt64(void);
336 extern PRStatus
_PR_InvalidStatus(void);
337 extern PRFileDesc
*_PR_InvalidDesc(void);
340 * PRFilePrivate structure for the NSPR pollable events layer
342 struct PRFilePrivate
{
343 PRFileDesc
*writeEnd
; /* the write end of the pipe/socketpair */
346 static PRStatus PR_CALLBACK
_pr_PolEvtClose(PRFileDesc
*fd
);
348 static PRInt16 PR_CALLBACK
_pr_PolEvtPoll(
349 PRFileDesc
*fd
, PRInt16 in_flags
, PRInt16
*out_flags
);
351 static PRIOMethods _pr_polevt_methods
= {
354 (PRReadFN
)_PR_InvalidInt
,
355 (PRWriteFN
)_PR_InvalidInt
,
356 (PRAvailableFN
)_PR_InvalidInt
,
357 (PRAvailable64FN
)_PR_InvalidInt64
,
358 (PRFsyncFN
)_PR_InvalidStatus
,
359 (PRSeekFN
)_PR_InvalidInt
,
360 (PRSeek64FN
)_PR_InvalidInt64
,
361 (PRFileInfoFN
)_PR_InvalidStatus
,
362 (PRFileInfo64FN
)_PR_InvalidStatus
,
363 (PRWritevFN
)_PR_InvalidInt
,
364 (PRConnectFN
)_PR_InvalidStatus
,
365 (PRAcceptFN
)_PR_InvalidDesc
,
366 (PRBindFN
)_PR_InvalidStatus
,
367 (PRListenFN
)_PR_InvalidStatus
,
368 (PRShutdownFN
)_PR_InvalidStatus
,
369 (PRRecvFN
)_PR_InvalidInt
,
370 (PRSendFN
)_PR_InvalidInt
,
371 (PRRecvfromFN
)_PR_InvalidInt
,
372 (PRSendtoFN
)_PR_InvalidInt
,
374 (PRAcceptreadFN
)_PR_InvalidInt
,
375 (PRTransmitfileFN
)_PR_InvalidInt
,
376 (PRGetsocknameFN
)_PR_InvalidStatus
,
377 (PRGetpeernameFN
)_PR_InvalidStatus
,
378 (PRReservedFN
)_PR_InvalidInt
,
379 (PRReservedFN
)_PR_InvalidInt
,
380 (PRGetsocketoptionFN
)_PR_InvalidStatus
,
381 (PRSetsocketoptionFN
)_PR_InvalidStatus
,
382 (PRSendfileFN
)_PR_InvalidInt
,
383 (PRConnectcontinueFN
)_PR_InvalidStatus
,
384 (PRReservedFN
)_PR_InvalidInt
,
385 (PRReservedFN
)_PR_InvalidInt
,
386 (PRReservedFN
)_PR_InvalidInt
,
387 (PRReservedFN
)_PR_InvalidInt
390 static PRDescIdentity _pr_polevt_id
;
391 static PRCallOnceType _pr_polevt_once_control
;
392 static PRStatus PR_CALLBACK
_pr_PolEvtInit(void);
394 static PRInt16 PR_CALLBACK
_pr_PolEvtPoll(
395 PRFileDesc
*fd
, PRInt16 in_flags
, PRInt16
*out_flags
)
397 return (fd
->lower
->methods
->poll
)(fd
->lower
, in_flags
, out_flags
);
400 static PRStatus PR_CALLBACK
_pr_PolEvtInit(void)
402 _pr_polevt_id
= PR_GetUniqueIdentity("NSPR pollable events");
403 if (PR_INVALID_IO_LAYER
== _pr_polevt_id
) {
409 #if !defined(XP_UNIX)
410 #define USE_TCP_SOCKETPAIR
413 PR_IMPLEMENT(PRFileDesc
*) PR_NewPollableEvent(void)
416 PRFileDesc
*fd
[2]; /* fd[0] is the read end; fd[1] is the write end */
417 #ifdef USE_TCP_SOCKETPAIR
418 PRSocketOptionData socket_opt
;
422 fd
[0] = fd
[1] = NULL
;
424 if (PR_CallOnce(&_pr_polevt_once_control
, _pr_PolEvtInit
) == PR_FAILURE
) {
428 event
= PR_CreateIOLayerStub(_pr_polevt_id
, &_pr_polevt_methods
);
432 event
->secret
= PR_NEW(PRFilePrivate
);
433 if (event
->secret
== NULL
) {
434 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
438 #ifndef USE_TCP_SOCKETPAIR
439 if (PR_CreatePipe(&fd
[0], &fd
[1]) == PR_FAILURE
) {
440 fd
[0] = fd
[1] = NULL
;
444 if (PR_NewTCPSocketPair(fd
) == PR_FAILURE
) {
445 fd
[0] = fd
[1] = NULL
;
449 * set the TCP_NODELAY option to reduce notification latency
451 socket_opt
.option
= PR_SockOpt_NoDelay
;
452 socket_opt
.value
.no_delay
= PR_TRUE
;
453 rv
= PR_SetSocketOption(fd
[1], &socket_opt
);
454 PR_ASSERT(PR_SUCCESS
== rv
);
457 event
->secret
->writeEnd
= fd
[1];
458 if (PR_PushIOLayer(fd
[0], PR_TOP_IO_LAYER
, event
) == PR_FAILURE
) {
470 PR_DELETE(event
->secret
);
476 static PRStatus PR_CALLBACK
_pr_PolEvtClose(PRFileDesc
*fd
)
480 event
= PR_PopIOLayer(fd
, PR_TOP_IO_LAYER
);
481 PR_ASSERT(NULL
== event
->higher
&& NULL
== event
->lower
);
483 PR_Close(event
->secret
->writeEnd
);
484 PR_DELETE(event
->secret
);
489 PR_IMPLEMENT(PRStatus
) PR_DestroyPollableEvent(PRFileDesc
*event
)
491 return PR_Close(event
);
494 static const char magicChar
= '\x38';
496 PR_IMPLEMENT(PRStatus
) PR_SetPollableEvent(PRFileDesc
*event
)
498 if (PR_Write(event
->secret
->writeEnd
, &magicChar
, 1) != 1) {
504 PR_IMPLEMENT(PRStatus
) PR_WaitForPollableEvent(PRFileDesc
*event
)
512 nBytes
= PR_Read(event
->lower
, buf
, sizeof(buf
));
519 * Make sure people do not write to the pollable event fd
522 for (i
= 0; i
< nBytes
; i
++) {
523 PR_ASSERT(buf
[i
] == magicChar
);