/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim:set ts=2 sw=2 sts=2 et cindent: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
staticbool NewTCPSocketPair(PRFileDesc* fd[], bool aSetRecvBuff) { // this is a replacement for PR_NewTCPSocketPair that manually // sets the recv buffer to 64K. A windows bug (1248358) // can result in using an incompatible rwin and window // scale option on localhost pipes if not set before connect.
failed: if (listener) {
PR_Close(listener);
} if (reader) {
PR_Close(reader);
} if (writer) {
PR_Close(writer);
} returnfalse;
}
#endif
PollableEvent::PollableEvent()
{
MOZ_COUNT_CTOR(PollableEvent);
MOZ_ASSERT(OnSocketThread(), "not on socket thread"); // create pair of prfiledesc that can be used as a poll()ble // signal. on windows use a localhost socket pair, and on // unix use a pipe. #ifdef USEPIPE
SOCKET_LOG(("PollableEvent() using pipe\n")); if (PR_CreatePipe(&mReadFD, &mWriteFD) == PR_SUCCESS) { // make the pipe non blocking. NSPR asserts at // trying to use SockOpt here
PROsfd fd = PR_FileDesc2NativeHandle(mReadFD); int flags = fcntl(fd, F_GETFL, 0);
(void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
fd = PR_FileDesc2NativeHandle(mWriteFD);
flags = fcntl(fd, F_GETFL, 0);
(void)fcntl(fd, F_SETFL, flags | O_NONBLOCK);
} else {
mReadFD = nullptr;
mWriteFD = nullptr;
SOCKET_LOG(("PollableEvent() pipe failed\n"));
} #else
SOCKET_LOG(("PollableEvent() using socket pair\n"));
PRFileDesc* fd[2];
LazyInitSocket();
// Try with a increased recv buffer first (bug 1248358). if (NewTCPSocketPair(fd, true)) {
mReadFD = fd[0];
mWriteFD = fd[1]; // If the previous fails try without recv buffer increase (bug 1305436).
} elseif (NewTCPSocketPair(fd, false)) {
mReadFD = fd[0];
mWriteFD = fd[1]; // If both fail, try the old version.
} elseif (PR_NewTCPSocketPair(fd) == PR_SUCCESS) {
mReadFD = fd[0];
mWriteFD = fd[1];
if (mReadFD && mWriteFD) { // compatibility with LSPs such as McAfee that assume a NSPR // layer for read ala the nspr Pollable Event - Bug 698882. This layer is a // nop.
PRFileDesc* topLayer = PR_CreateIOLayerStub(sPollableEventLayerIdentity,
sPollableEventLayerMethodsPtr); if (topLayer) { if (PR_PushIOLayer(fd[0], PR_TOP_IO_LAYER, topLayer) == PR_FAILURE) {
topLayer->dtor(topLayer);
} else {
SOCKET_LOG(("PollableEvent() nspr layer ok\n"));
mReadFD = topLayer;
}
}
if (mReadFD && mWriteFD) { // prime the system to deal with races invovled in [dc]tor cycle
SOCKET_LOG(("PollableEvent() ctor ok\n"));
mSignaled = true;
MarkFirstSignalTimestamp();
PR_Write(mWriteFD, "I", 1);
}
}
PollableEvent::~PollableEvent() {
MOZ_COUNT_DTOR(PollableEvent); if (mWriteFD) { #ifdefined(XP_WIN)
AttachShutdownLayer(mWriteFD); #endif
PR_Close(mWriteFD);
} if (mReadFD) { #ifdefined(XP_WIN)
AttachShutdownLayer(mReadFD); #endif
PR_Close(mReadFD);
}
}
// we do not record signals on the socket thread // because the socket thread can reliably look at its // own runnable queue before selecting a poll time // this is the "service the network without blocking" comment in // nsSocketTransportService2.cpp bool PollableEvent::Signal() {
SOCKET_LOG(("PollableEvent::Signal\n"));
if (!mWriteFD) {
SOCKET_LOG(("PollableEvent::Signal Failed on no FD\n")); returnfalse;
} #ifndef XP_WIN // On windows poll can hang and this became worse when we introduced the // patch for bug 698882 (see also bug 1292181), therefore we reverted the // behavior on windows to be as before bug 698882, e.g. write to the socket // also if an event dispatch is on the socket thread and writing to the // socket for each event. See bug 1292181. if (OnSocketThread()) {
SOCKET_LOG(("PollableEvent::Signal OnSocketThread nop\n")); returntrue;
} #endif
#ifndef XP_WIN // To wake up the poll writing once is enough, but for Windows that can cause // hangs so we will write for every event. // For non-Windows systems it is enough to write just once. if (mSignaled) { returntrue;
} #endif
if (!mSignaled) {
mSignaled = true;
MarkFirstSignalTimestamp();
}
bool PollableEvent::Clear() { // necessary because of the "dont signal on socket thread" optimization
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
SOCKET_LOG(("PollableEvent::Clear\n"));
if (!mFirstSignalAfterClear.IsNull()) {
SOCKET_LOG(("PollableEvent::Clear time to signal %ums",
(uint32_t)(TimeStamp::NowLoRes() - mFirstSignalAfterClear)
.ToMilliseconds()));
}
if (!mReadFD) {
SOCKET_LOG(("PollableEvent::Clear mReadFD is null\n")); returnfalse;
}
char buf[2048];
int32_t status; #ifdef XP_WIN // On Windows we are writing to the socket for each event, to be sure that we // do not have any deadlock read from the socket as much as we can. while (true) {
status = PR_Read(mReadFD, buf, 2048);
SOCKET_LOG(("PollableEvent::Clear PR_Read %d\n", status)); if (status == 0) {
SOCKET_LOG(("PollableEvent::Clear EOF!\n")); returnfalse;
} if (status < 0) {
PRErrorCode code = PR_GetError(); if (code == PR_WOULD_BLOCK_ERROR) { returntrue;
} else {
SOCKET_LOG(("PollableEvent::Clear unexpected error %d\n", code)); returnfalse;
}
}
} #else
status = PR_Read(mReadFD, buf, 2048);
SOCKET_LOG(("PollableEvent::Clear PR_Read %d\n", status));
bool PollableEvent::IsSignallingAlive(TimeDuration const& timeout) { if (mWriteFailed) { returnfalse;
}
#ifdef DEBUG // The timeout would be just a disturbance in a debug build. returntrue; #else if (!mSignaled || mFirstSignalAfterClear.IsNull() ||
timeout == TimeDuration()) { returntrue;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.