prpolevt.c (7411B)
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 ********************************************************************* 8 * 9 * Pollable events 10 * 11 * Pollable events are implemented using layered I/O. The only 12 * I/O methods that are implemented for pollable events are poll 13 * and close. No other methods can be invoked on a pollable 14 * event. 15 * 16 * A pipe or socket pair is created and the pollable event layer 17 * is pushed onto the read end. A pointer to the write end is 18 * saved in the PRFilePrivate structure of the pollable event. 19 * 20 ********************************************************************* 21 */ 22 23 #include "prinit.h" 24 #include "prio.h" 25 #include "prmem.h" 26 #include "prerror.h" 27 #include "prlog.h" 28 29 /* 30 * These internal functions are declared in primpl.h, 31 * but we can't include primpl.h because the definition 32 * of struct PRFilePrivate in this file (for the pollable 33 * event layer) will conflict with the definition of 34 * struct PRFilePrivate in primpl.h (for the NSPR layer). 35 */ 36 extern PRIntn _PR_InvalidInt(void); 37 extern PRInt64 _PR_InvalidInt64(void); 38 extern PRStatus _PR_InvalidStatus(void); 39 extern PRFileDesc* _PR_InvalidDesc(void); 40 41 /* 42 * PRFilePrivate structure for the NSPR pollable events layer 43 */ 44 struct PRFilePrivate { 45 PRFileDesc* writeEnd; /* the write end of the pipe/socketpair */ 46 }; 47 48 static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc* fd); 49 50 static PRInt16 PR_CALLBACK _pr_PolEvtPoll(PRFileDesc* fd, PRInt16 in_flags, 51 PRInt16* out_flags); 52 53 static PRIOMethods _pr_polevt_methods = {PR_DESC_LAYERED, 54 _pr_PolEvtClose, 55 (PRReadFN)_PR_InvalidInt, 56 (PRWriteFN)_PR_InvalidInt, 57 (PRAvailableFN)_PR_InvalidInt, 58 (PRAvailable64FN)_PR_InvalidInt64, 59 (PRFsyncFN)_PR_InvalidStatus, 60 (PRSeekFN)_PR_InvalidInt, 61 (PRSeek64FN)_PR_InvalidInt64, 62 (PRFileInfoFN)_PR_InvalidStatus, 63 (PRFileInfo64FN)_PR_InvalidStatus, 64 (PRWritevFN)_PR_InvalidInt, 65 (PRConnectFN)_PR_InvalidStatus, 66 (PRAcceptFN)_PR_InvalidDesc, 67 (PRBindFN)_PR_InvalidStatus, 68 (PRListenFN)_PR_InvalidStatus, 69 (PRShutdownFN)_PR_InvalidStatus, 70 (PRRecvFN)_PR_InvalidInt, 71 (PRSendFN)_PR_InvalidInt, 72 (PRRecvfromFN)_PR_InvalidInt, 73 (PRSendtoFN)_PR_InvalidInt, 74 _pr_PolEvtPoll, 75 (PRAcceptreadFN)_PR_InvalidInt, 76 (PRTransmitfileFN)_PR_InvalidInt, 77 (PRGetsocknameFN)_PR_InvalidStatus, 78 (PRGetpeernameFN)_PR_InvalidStatus, 79 (PRReservedFN)_PR_InvalidInt, 80 (PRReservedFN)_PR_InvalidInt, 81 (PRGetsocketoptionFN)_PR_InvalidStatus, 82 (PRSetsocketoptionFN)_PR_InvalidStatus, 83 (PRSendfileFN)_PR_InvalidInt, 84 (PRConnectcontinueFN)_PR_InvalidStatus, 85 (PRReservedFN)_PR_InvalidInt, 86 (PRReservedFN)_PR_InvalidInt, 87 (PRReservedFN)_PR_InvalidInt, 88 (PRReservedFN)_PR_InvalidInt}; 89 90 static PRDescIdentity _pr_polevt_id; 91 static PRCallOnceType _pr_polevt_once_control; 92 static PRStatus PR_CALLBACK _pr_PolEvtInit(void); 93 94 static PRInt16 PR_CALLBACK _pr_PolEvtPoll(PRFileDesc* fd, PRInt16 in_flags, 95 PRInt16* out_flags) { 96 return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags); 97 } 98 99 static PRStatus PR_CALLBACK _pr_PolEvtInit(void) { 100 _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events"); 101 if (PR_INVALID_IO_LAYER == _pr_polevt_id) { 102 return PR_FAILURE; 103 } 104 return PR_SUCCESS; 105 } 106 107 #if !defined(XP_UNIX) 108 # define USE_TCP_SOCKETPAIR 109 #endif 110 111 PR_IMPLEMENT(PRFileDesc*) PR_NewPollableEvent(void) { 112 PRFileDesc* event; 113 PRFileDesc* fd[2]; /* fd[0] is the read end; fd[1] is the write end */ 114 #ifdef USE_TCP_SOCKETPAIR 115 PRSocketOptionData socket_opt; 116 PRStatus rv; 117 #endif 118 119 fd[0] = fd[1] = NULL; 120 121 if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) { 122 return NULL; 123 } 124 125 event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods); 126 if (NULL == event) { 127 goto errorExit; 128 } 129 event->secret = PR_NEW(PRFilePrivate); 130 if (event->secret == NULL) { 131 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 132 goto errorExit; 133 } 134 135 #ifndef USE_TCP_SOCKETPAIR 136 if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) { 137 fd[0] = fd[1] = NULL; 138 goto errorExit; 139 } 140 #else 141 if (PR_NewTCPSocketPair(fd) == PR_FAILURE) { 142 fd[0] = fd[1] = NULL; 143 goto errorExit; 144 } 145 /* 146 * set the TCP_NODELAY option to reduce notification latency 147 */ 148 socket_opt.option = PR_SockOpt_NoDelay; 149 socket_opt.value.no_delay = PR_TRUE; 150 rv = PR_SetSocketOption(fd[1], &socket_opt); 151 PR_ASSERT(PR_SUCCESS == rv); 152 #endif 153 154 event->secret->writeEnd = fd[1]; 155 if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) { 156 goto errorExit; 157 } 158 159 return fd[0]; 160 161 errorExit: 162 if (fd[0]) { 163 PR_Close(fd[0]); 164 PR_Close(fd[1]); 165 } 166 if (event) { 167 PR_DELETE(event->secret); 168 event->dtor(event); 169 } 170 return NULL; 171 } 172 173 static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc* fd) { 174 PRFileDesc* event; 175 176 event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); 177 PR_ASSERT(NULL == event->higher && NULL == event->lower); 178 PR_Close(fd); 179 PR_Close(event->secret->writeEnd); 180 PR_DELETE(event->secret); 181 event->dtor(event); 182 return PR_SUCCESS; 183 } 184 185 PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc* event) { 186 return PR_Close(event); 187 } 188 189 static const char magicChar = '\x38'; 190 191 PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc* event) { 192 if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) { 193 return PR_FAILURE; 194 } 195 return PR_SUCCESS; 196 } 197 198 PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc* event) { 199 char buf[1024]; 200 PRInt32 nBytes; 201 #ifdef DEBUG 202 PRIntn i; 203 #endif 204 205 nBytes = PR_Read(event->lower, buf, sizeof(buf)); 206 if (nBytes == -1) { 207 return PR_FAILURE; 208 } 209 210 #ifdef DEBUG 211 /* 212 * Make sure people do not write to the pollable event fd 213 * directly. 214 */ 215 for (i = 0; i < nBytes; i++) { 216 PR_ASSERT(buf[i] == magicChar); 217 } 218 #endif 219 220 return PR_SUCCESS; 221 }