Exemplo n.º 1
0
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;
}
Exemplo n.º 4
0
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;
}