static ipcConnectionState * ConnCreate(PRFileDesc *fd) { ipcConnectionState *s = new ipcConnectionState; if (!s) return NULL; s->lock = PR_NewLock(); s->fds[SOCK].fd = NULL; s->fds[POLL].fd = PR_NewPollableEvent(); s->send_offset = 0; s->in_msg = NULL; s->shutdown = PR_FALSE; if (!s->lock || !s->fds[1].fd) { ConnDestroy(s); return NULL; } // disable inheritance of the IPC socket by children started // using non-NSPR process API PRStatus status = PR_SetFDInheritable(fd, PR_FALSE); if (status != PR_SUCCESS) { LOG(("coudn't make IPC socket non-inheritable [err=%d]\n", PR_GetError())); return NULL; } // store this only if we are going to succeed. s->fds[SOCK].fd = fd; return s; }
// called from main thread only NS_IMETHODIMP nsSocketTransportService::Init() { NS_ASSERTION(nsIThread::IsMainThread(), "wrong thread"); if (mInitialized) return NS_OK; if (!mThreadEvent) { mThreadEvent = PR_NewPollableEvent(); // // NOTE: per bug 190000, this failure could be caused by Zone-Alarm // or similar software. // // NOTE: per bug 191739, this failure could also be caused by lack // of a loopback device on Windows and OS/2 platforms (NSPR creates // a loopback socket pair on these platforms to implement a pollable // event object). if we can't create a pollable event, then we'll // have to "busy wait" to implement the socket event queue :-( // if (!mThreadEvent) { NS_WARNING("running socket transport thread without a pollable event"); LOG(("running socket transport thread without a pollable event")); } } nsresult rv = NS_NewThread(&mThread, this, 0, PR_JOINABLE_THREAD); if (NS_FAILED(rv)) return rv; mInitialized = PR_TRUE; return NS_OK; }
// called from main thread only NS_IMETHODIMP nsSocketTransportService::Init() { NS_ENSURE_TRUE(mLock, NS_ERROR_OUT_OF_MEMORY); if (!NS_IsMainThread()) { NS_ERROR("wrong thread"); return NS_ERROR_UNEXPECTED; } if (mInitialized) return NS_OK; if (mShuttingDown) return NS_ERROR_UNEXPECTED; if (!mThreadEvent) { mThreadEvent = PR_NewPollableEvent(); // // NOTE: per bug 190000, this failure could be caused by Zone-Alarm // or similar software. // // NOTE: per bug 191739, this failure could also be caused by lack // of a loopback device on Windows and OS/2 platforms (NSPR creates // a loopback socket pair on these platforms to implement a pollable // event object). if we can't create a pollable event, then we'll // have to "busy wait" to implement the socket event queue :-( // if (!mThreadEvent) { NS_WARNING("running socket transport thread without a pollable event"); LOG(("running socket transport thread without a pollable event")); } } nsCOMPtr<nsIThread> thread; nsresult rv = NS_NewThread(getter_AddRefs(thread), this); if (NS_FAILED(rv)) return rv; { nsAutoLock lock(mLock); // Install our mThread, protecting against concurrent readers thread.swap(mThread); } nsCOMPtr<nsIPrefBranch2> tmpPrefService = do_GetService(NS_PREFSERVICE_CONTRACTID); if (tmpPrefService) tmpPrefService->AddObserver(SEND_BUFFER_PREF, this, PR_FALSE); UpdatePrefs(); mInitialized = PR_TRUE; return NS_OK; }
static PRThreadPool * alloc_threadpool(void) { PRThreadPool *tp; tp = (PRThreadPool *) PR_CALLOC(sizeof(*tp)); if (NULL == tp) goto failed; tp->jobq.lock = PR_NewLock(); if (NULL == tp->jobq.lock) goto failed; tp->jobq.cv = PR_NewCondVar(tp->jobq.lock); if (NULL == tp->jobq.cv) goto failed; tp->join_lock = PR_NewLock(); if (NULL == tp->join_lock) goto failed; #ifdef OPT_WINNT tp->jobq.nt_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if (NULL == tp->jobq.nt_completion_port) goto failed; #endif tp->ioq.lock = PR_NewLock(); if (NULL == tp->ioq.lock) goto failed; /* Timer queue */ tp->timerq.lock = PR_NewLock(); if (NULL == tp->timerq.lock) goto failed; tp->timerq.cv = PR_NewCondVar(tp->timerq.lock); if (NULL == tp->timerq.cv) goto failed; tp->shutdown_cv = PR_NewCondVar(tp->jobq.lock); if (NULL == tp->shutdown_cv) goto failed; tp->ioq.notify_fd = PR_NewPollableEvent(); if (NULL == tp->ioq.notify_fd) goto failed; return tp; failed: delete_threadpool(tp); PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; }
NS_IMETHODIMP nsSocketTransportService::Run() { LOG(("nsSocketTransportService::Run")); gSocketThread = PR_GetCurrentThread(); // // add thread event to poll list (mThreadEvent may be NULL) // mPollList[0].fd = mThreadEvent; mPollList[0].in_flags = PR_POLL_READ; mPollList[0].out_flags = 0; PRInt32 i, count; // // poll loop // PRBool active = PR_TRUE; while (active) { // // walk active list backwards to see if any sockets should actually be // idle, then walk the idle list backwards to see if any idle sockets // should become active. take care to check only idle sockets that // were idle to begin with ;-) // count = mIdleCount; for (i=mActiveCount-1; i>=0; --i) { //--- LOG((" active [%u] { handler=%x condition=%x pollflags=%hu }\n", i, mActiveList[i].mHandler, mActiveList[i].mHandler->mCondition, mActiveList[i].mHandler->mPollFlags)); //--- if (NS_FAILED(mActiveList[i].mHandler->mCondition)) DetachSocket(&mActiveList[i]); else { PRUint16 in_flags = mActiveList[i].mHandler->mPollFlags; if (in_flags == 0) MoveToIdleList(&mActiveList[i]); else { // update poll flags mPollList[i+1].in_flags = in_flags; mPollList[i+1].out_flags = 0; } } } for (i=count-1; i>=0; --i) { //--- LOG((" idle [%u] { handler=%x condition=%x pollflags=%hu }\n", i, mIdleList[i].mHandler, mIdleList[i].mHandler->mCondition, mIdleList[i].mHandler->mPollFlags)); //--- if (NS_FAILED(mIdleList[i].mHandler->mCondition)) DetachSocket(&mIdleList[i]); else if (mIdleList[i].mHandler->mPollFlags != 0) MoveToPollList(&mIdleList[i]); } LOG((" calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount)); // Measures seconds spent while blocked on PR_Poll PRUint32 pollInterval; PRInt32 n = Poll(&pollInterval); if (n < 0) { LOG((" PR_Poll error [%d]\n", PR_GetError())); active = PR_FALSE; } else { // // service "active" sockets... // for (i=0; i<PRInt32(mActiveCount); ++i) { PRPollDesc &desc = mPollList[i+1]; SocketContext &s = mActiveList[i]; if (n > 0 && desc.out_flags != 0) { s.mElapsedTime = 0; s.mHandler->OnSocketReady(desc.fd, desc.out_flags); } // check for timeout errors unless disabled... else if (s.mHandler->mPollTimeout != PR_UINT16_MAX) { // update elapsed time counter if (NS_UNLIKELY(pollInterval > (PR_UINT16_MAX - s.mElapsedTime))) s.mElapsedTime = PR_UINT16_MAX; else s.mElapsedTime += PRUint16(pollInterval); // check for timeout expiration if (s.mElapsedTime >= s.mHandler->mPollTimeout) { s.mElapsedTime = 0; s.mHandler->OnSocketReady(desc.fd, -1); } } } // // check for "dead" sockets and remove them (need to do this in // reverse order obviously). // for (i=mActiveCount-1; i>=0; --i) { if (NS_FAILED(mActiveList[i].mHandler->mCondition)) DetachSocket(&mActiveList[i]); } // // service the event queue (mPollList[0].fd == mThreadEvent) // if (n == 0) active = ServiceEventQ(); else if (mPollList[0].out_flags == PR_POLL_READ) { // acknowledge pollable event (wait should not block) if (PR_WaitForPollableEvent(mThreadEvent) != PR_SUCCESS) { // On Windows, the TCP loopback connection in the // pollable event may become broken when a laptop // switches between wired and wireless networks or // wakes up from hibernation. We try to create a // new pollable event. If that fails, we fall back // on "busy wait". { nsAutoLock lock(mEventQLock); PR_DestroyPollableEvent(mThreadEvent); mThreadEvent = PR_NewPollableEvent(); } if (!mThreadEvent) { NS_WARNING("running socket transport thread without " "a pollable event"); LOG(("running socket transport thread without " "a pollable event")); } mPollList[0].fd = mThreadEvent; // mPollList[0].in_flags was already set to PR_POLL_READ // at the beginning of this method. mPollList[0].out_flags = 0; } active = ServiceEventQ(); } } } // // shutdown thread // LOG(("shutting down socket transport thread...\n")); mShuttingDown = PR_TRUE; // detach any sockets for (i=mActiveCount-1; i>=0; --i) DetachSocket(&mActiveList[i]); for (i=mIdleCount-1; i>=0; --i) DetachSocket(&mIdleList[i]); mShuttingDown = PR_FALSE; // Final pass over the event queue. This makes sure that events posted by // socket detach handlers get processed. ServiceEventQ(); gSocketThread = nsnull; return NS_OK; }