1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/io/prpolevt.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,230 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + ********************************************************************* 1.11 + * 1.12 + * Pollable events 1.13 + * 1.14 + * Pollable events are implemented using layered I/O. The only 1.15 + * I/O methods that are implemented for pollable events are poll 1.16 + * and close. No other methods can be invoked on a pollable 1.17 + * event. 1.18 + * 1.19 + * A pipe or socket pair is created and the pollable event layer 1.20 + * is pushed onto the read end. A pointer to the write end is 1.21 + * saved in the PRFilePrivate structure of the pollable event. 1.22 + * 1.23 + ********************************************************************* 1.24 + */ 1.25 + 1.26 +#include "prinit.h" 1.27 +#include "prio.h" 1.28 +#include "prmem.h" 1.29 +#include "prerror.h" 1.30 +#include "prlog.h" 1.31 + 1.32 +/* 1.33 + * These internal functions are declared in primpl.h, 1.34 + * but we can't include primpl.h because the definition 1.35 + * of struct PRFilePrivate in this file (for the pollable 1.36 + * event layer) will conflict with the definition of 1.37 + * struct PRFilePrivate in primpl.h (for the NSPR layer). 1.38 + */ 1.39 +extern PRIntn _PR_InvalidInt(void); 1.40 +extern PRInt64 _PR_InvalidInt64(void); 1.41 +extern PRStatus _PR_InvalidStatus(void); 1.42 +extern PRFileDesc *_PR_InvalidDesc(void); 1.43 + 1.44 +/* 1.45 + * PRFilePrivate structure for the NSPR pollable events layer 1.46 + */ 1.47 +struct PRFilePrivate { 1.48 + PRFileDesc *writeEnd; /* the write end of the pipe/socketpair */ 1.49 +}; 1.50 + 1.51 +static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd); 1.52 + 1.53 +static PRInt16 PR_CALLBACK _pr_PolEvtPoll( 1.54 + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags); 1.55 + 1.56 +static PRIOMethods _pr_polevt_methods = { 1.57 + PR_DESC_LAYERED, 1.58 + _pr_PolEvtClose, 1.59 + (PRReadFN)_PR_InvalidInt, 1.60 + (PRWriteFN)_PR_InvalidInt, 1.61 + (PRAvailableFN)_PR_InvalidInt, 1.62 + (PRAvailable64FN)_PR_InvalidInt64, 1.63 + (PRFsyncFN)_PR_InvalidStatus, 1.64 + (PRSeekFN)_PR_InvalidInt, 1.65 + (PRSeek64FN)_PR_InvalidInt64, 1.66 + (PRFileInfoFN)_PR_InvalidStatus, 1.67 + (PRFileInfo64FN)_PR_InvalidStatus, 1.68 + (PRWritevFN)_PR_InvalidInt, 1.69 + (PRConnectFN)_PR_InvalidStatus, 1.70 + (PRAcceptFN)_PR_InvalidDesc, 1.71 + (PRBindFN)_PR_InvalidStatus, 1.72 + (PRListenFN)_PR_InvalidStatus, 1.73 + (PRShutdownFN)_PR_InvalidStatus, 1.74 + (PRRecvFN)_PR_InvalidInt, 1.75 + (PRSendFN)_PR_InvalidInt, 1.76 + (PRRecvfromFN)_PR_InvalidInt, 1.77 + (PRSendtoFN)_PR_InvalidInt, 1.78 + _pr_PolEvtPoll, 1.79 + (PRAcceptreadFN)_PR_InvalidInt, 1.80 + (PRTransmitfileFN)_PR_InvalidInt, 1.81 + (PRGetsocknameFN)_PR_InvalidStatus, 1.82 + (PRGetpeernameFN)_PR_InvalidStatus, 1.83 + (PRReservedFN)_PR_InvalidInt, 1.84 + (PRReservedFN)_PR_InvalidInt, 1.85 + (PRGetsocketoptionFN)_PR_InvalidStatus, 1.86 + (PRSetsocketoptionFN)_PR_InvalidStatus, 1.87 + (PRSendfileFN)_PR_InvalidInt, 1.88 + (PRConnectcontinueFN)_PR_InvalidStatus, 1.89 + (PRReservedFN)_PR_InvalidInt, 1.90 + (PRReservedFN)_PR_InvalidInt, 1.91 + (PRReservedFN)_PR_InvalidInt, 1.92 + (PRReservedFN)_PR_InvalidInt 1.93 +}; 1.94 + 1.95 +static PRDescIdentity _pr_polevt_id; 1.96 +static PRCallOnceType _pr_polevt_once_control; 1.97 +static PRStatus PR_CALLBACK _pr_PolEvtInit(void); 1.98 + 1.99 +static PRInt16 PR_CALLBACK _pr_PolEvtPoll( 1.100 + PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) 1.101 +{ 1.102 + return (fd->lower->methods->poll)(fd->lower, in_flags, out_flags); 1.103 +} 1.104 + 1.105 +static PRStatus PR_CALLBACK _pr_PolEvtInit(void) 1.106 +{ 1.107 + _pr_polevt_id = PR_GetUniqueIdentity("NSPR pollable events"); 1.108 + if (PR_INVALID_IO_LAYER == _pr_polevt_id) { 1.109 + return PR_FAILURE; 1.110 + } 1.111 + return PR_SUCCESS; 1.112 +} 1.113 + 1.114 +#if !defined(XP_UNIX) 1.115 +#define USE_TCP_SOCKETPAIR 1.116 +#endif 1.117 + 1.118 +PR_IMPLEMENT(PRFileDesc *) PR_NewPollableEvent(void) 1.119 +{ 1.120 + PRFileDesc *event; 1.121 + PRFileDesc *fd[2]; /* fd[0] is the read end; fd[1] is the write end */ 1.122 +#ifdef USE_TCP_SOCKETPAIR 1.123 + PRSocketOptionData socket_opt; 1.124 + PRStatus rv; 1.125 +#endif 1.126 + 1.127 + fd[0] = fd[1] = NULL; 1.128 + 1.129 + if (PR_CallOnce(&_pr_polevt_once_control, _pr_PolEvtInit) == PR_FAILURE) { 1.130 + return NULL; 1.131 + } 1.132 + 1.133 + event = PR_CreateIOLayerStub(_pr_polevt_id, &_pr_polevt_methods); 1.134 + if (NULL == event) { 1.135 + goto errorExit; 1.136 + } 1.137 + event->secret = PR_NEW(PRFilePrivate); 1.138 + if (event->secret == NULL) { 1.139 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.140 + goto errorExit; 1.141 + } 1.142 + 1.143 +#ifndef USE_TCP_SOCKETPAIR 1.144 + if (PR_CreatePipe(&fd[0], &fd[1]) == PR_FAILURE) { 1.145 + fd[0] = fd[1] = NULL; 1.146 + goto errorExit; 1.147 + } 1.148 +#else 1.149 + if (PR_NewTCPSocketPair(fd) == PR_FAILURE) { 1.150 + fd[0] = fd[1] = NULL; 1.151 + goto errorExit; 1.152 + } 1.153 + /* 1.154 + * set the TCP_NODELAY option to reduce notification latency 1.155 + */ 1.156 + socket_opt.option = PR_SockOpt_NoDelay; 1.157 + socket_opt.value.no_delay = PR_TRUE; 1.158 + rv = PR_SetSocketOption(fd[1], &socket_opt); 1.159 + PR_ASSERT(PR_SUCCESS == rv); 1.160 +#endif 1.161 + 1.162 + event->secret->writeEnd = fd[1]; 1.163 + if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, event) == PR_FAILURE) { 1.164 + goto errorExit; 1.165 + } 1.166 + 1.167 + return fd[0]; 1.168 + 1.169 +errorExit: 1.170 + if (fd[0]) { 1.171 + PR_Close(fd[0]); 1.172 + PR_Close(fd[1]); 1.173 + } 1.174 + if (event) { 1.175 + PR_DELETE(event->secret); 1.176 + event->dtor(event); 1.177 + } 1.178 + return NULL; 1.179 +} 1.180 + 1.181 +static PRStatus PR_CALLBACK _pr_PolEvtClose(PRFileDesc *fd) 1.182 +{ 1.183 + PRFileDesc *event; 1.184 + 1.185 + event = PR_PopIOLayer(fd, PR_TOP_IO_LAYER); 1.186 + PR_ASSERT(NULL == event->higher && NULL == event->lower); 1.187 + PR_Close(fd); 1.188 + PR_Close(event->secret->writeEnd); 1.189 + PR_DELETE(event->secret); 1.190 + event->dtor(event); 1.191 + return PR_SUCCESS; 1.192 +} 1.193 + 1.194 +PR_IMPLEMENT(PRStatus) PR_DestroyPollableEvent(PRFileDesc *event) 1.195 +{ 1.196 + return PR_Close(event); 1.197 +} 1.198 + 1.199 +static const char magicChar = '\x38'; 1.200 + 1.201 +PR_IMPLEMENT(PRStatus) PR_SetPollableEvent(PRFileDesc *event) 1.202 +{ 1.203 + if (PR_Write(event->secret->writeEnd, &magicChar, 1) != 1) { 1.204 + return PR_FAILURE; 1.205 + } 1.206 + return PR_SUCCESS; 1.207 +} 1.208 + 1.209 +PR_IMPLEMENT(PRStatus) PR_WaitForPollableEvent(PRFileDesc *event) 1.210 +{ 1.211 + char buf[1024]; 1.212 + PRInt32 nBytes; 1.213 +#ifdef DEBUG 1.214 + PRIntn i; 1.215 +#endif 1.216 + 1.217 + nBytes = PR_Read(event->lower, buf, sizeof(buf)); 1.218 + if (nBytes == -1) { 1.219 + return PR_FAILURE; 1.220 + } 1.221 + 1.222 +#ifdef DEBUG 1.223 + /* 1.224 + * Make sure people do not write to the pollable event fd 1.225 + * directly. 1.226 + */ 1.227 + for (i = 0; i < nBytes; i++) { 1.228 + PR_ASSERT(buf[i] == magicChar); 1.229 + } 1.230 +#endif 1.231 + 1.232 + return PR_SUCCESS; 1.233 +}