Back to index

lightning-sunbird  0.9+nobinonly
nsSocketTransportService2.cpp
Go to the documentation of this file.
00001 // vim:set sw=4 sts=4 et cin:
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Darin Fisher <darin@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #ifdef MOZ_LOGGING
00040 #define FORCE_PR_LOG
00041 #endif
00042 
00043 #include "nsSocketTransportService2.h"
00044 #include "nsSocketTransport2.h"
00045 #include "nsReadableUtils.h"
00046 #include "nsAutoLock.h"
00047 #include "nsNetError.h"
00048 #include "prnetdb.h"
00049 #include "prlock.h"
00050 #include "prerror.h"
00051 #include "plstr.h"
00052 
00053 #if defined(PR_LOGGING)
00054 PRLogModuleInfo *gSocketTransportLog = nsnull;
00055 #endif
00056 
00057 nsSocketTransportService *gSocketTransportService = nsnull;
00058 PRThread                 *gSocketThread           = nsnull;
00059 
00060 #define PLEVENT_FROM_LINK(_link) \
00061     ((PLEvent*) ((char*) (_link) - offsetof(PLEvent, link)))
00062 
00063 static inline void
00064 MoveCList(PRCList &from, PRCList &to)
00065 {
00066     if (!PR_CLIST_IS_EMPTY(&from)) {
00067         to.next = from.next;
00068         to.prev = from.prev;
00069         to.next->prev = &to;
00070         to.prev->next = &to;
00071         PR_INIT_CLIST(&from);
00072     }             
00073 }
00074 
00075 //-----------------------------------------------------------------------------
00076 // ctor/dtor (called on the main/UI thread by the service manager)
00077 
00078 nsSocketTransportService::nsSocketTransportService()
00079     : mInitialized(PR_FALSE)
00080     , mThread(nsnull)
00081     , mThreadEvent(nsnull)
00082     , mAutodialEnabled(PR_FALSE)
00083     , mShuttingDown(PR_FALSE)
00084     , mEventQLock(PR_NewLock())
00085     , mActiveCount(0)
00086     , mIdleCount(0)
00087 {
00088 #if defined(PR_LOGGING)
00089     gSocketTransportLog = PR_NewLogModule("nsSocketTransport");
00090 #endif
00091 
00092     NS_ASSERTION(nsIThread::IsMainThread(), "wrong thread");
00093 
00094     PR_INIT_CLIST(&mEventQ);
00095     PR_INIT_CLIST(&mPendingSocketQ);
00096 
00097     NS_ASSERTION(!gSocketTransportService, "must not instantiate twice");
00098     gSocketTransportService = this;
00099 }
00100 
00101 nsSocketTransportService::~nsSocketTransportService()
00102 {
00103     NS_ASSERTION(nsIThread::IsMainThread(), "wrong thread");
00104     NS_ASSERTION(!mInitialized, "not shutdown properly");
00105 
00106     PR_DestroyLock(mEventQLock);
00107     
00108     if (mThreadEvent)
00109         PR_DestroyPollableEvent(mThreadEvent);
00110 
00111     gSocketTransportService = nsnull;
00112 }
00113 
00114 //-----------------------------------------------------------------------------
00115 // event queue (any thread)
00116 
00117 NS_IMETHODIMP
00118 nsSocketTransportService::PostEvent(PLEvent *event)
00119 {
00120     LOG(("nsSocketTransportService::PostEvent [event=%p]\n", event));
00121 
00122     NS_ASSERTION(event, "null event");
00123 
00124     nsAutoLock lock(mEventQLock);
00125     if (!mInitialized) {
00126         // Allow socket detach handlers to post events
00127         if (!mShuttingDown || (PR_GetCurrentThread() != gSocketThread)) {
00128             NS_WARN_IF_FALSE(PR_GetCurrentThread() != gSocketThread,
00129                             "Rejecting event posted to uninitialized sts");
00130             return NS_ERROR_OFFLINE;
00131         }
00132 
00133     }
00134 
00135     PR_APPEND_LINK(&event->link, &mEventQ);
00136 
00137     if (mThreadEvent)
00138         PR_SetPollableEvent(mThreadEvent);
00139     // else wait for Poll timeout
00140     return NS_OK;
00141 }
00142 
00143 NS_IMETHODIMP
00144 nsSocketTransportService::IsOnCurrentThread(PRBool *result)
00145 {
00146     *result = (PR_GetCurrentThread() == gSocketThread);
00147     return NS_OK;
00148 }
00149 
00150 //-----------------------------------------------------------------------------
00151 // socket api (socket thread only)
00152 
00153 nsresult
00154 nsSocketTransportService::NotifyWhenCanAttachSocket(PLEvent *event)
00155 {
00156     LOG(("nsSocketTransportService::NotifyWhenCanAttachSocket\n"));
00157 
00158     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
00159 
00160     if (CanAttachSocket()) {
00161         NS_WARNING("should have called CanAttachSocket");
00162         return PostEvent(event);
00163     }
00164 
00165     PR_APPEND_LINK(&event->link, &mPendingSocketQ);
00166     return NS_OK;
00167 }
00168 
00169 nsresult
00170 nsSocketTransportService::AttachSocket(PRFileDesc *fd, nsASocketHandler *handler)
00171 {
00172     LOG(("nsSocketTransportService::AttachSocket [handler=%x]\n", handler));
00173 
00174     NS_ASSERTION(PR_GetCurrentThread() == gSocketThread, "wrong thread");
00175 
00176     SocketContext sock;
00177     sock.mFD = fd;
00178     sock.mHandler = handler;
00179     sock.mElapsedTime = 0;
00180 
00181     nsresult rv = AddToIdleList(&sock);
00182     if (NS_SUCCEEDED(rv))
00183         NS_ADDREF(handler);
00184     return rv;
00185 }
00186 
00187 nsresult
00188 nsSocketTransportService::DetachSocket(SocketContext *sock)
00189 {
00190     LOG(("nsSocketTransportService::DetachSocket [handler=%x]\n", sock->mHandler));
00191 
00192     // inform the handler that this socket is going away
00193     sock->mHandler->OnSocketDetached(sock->mFD);
00194 
00195     // cleanup
00196     sock->mFD = nsnull;
00197     NS_RELEASE(sock->mHandler);
00198 
00199     // find out what list this is on.
00200     PRUint32 index = sock - mActiveList;
00201     if (index < NS_SOCKET_MAX_COUNT)
00202         RemoveFromPollList(sock);
00203     else
00204         RemoveFromIdleList(sock);
00205 
00206     // NOTE: sock is now an invalid pointer
00207     
00208     //
00209     // notify the first element on the pending socket queue...
00210     //
00211     if (!PR_CLIST_IS_EMPTY(&mPendingSocketQ)) {
00212         // move event from pending queue to event queue
00213         PLEvent *event = PLEVENT_FROM_LINK(PR_LIST_HEAD(&mPendingSocketQ));
00214         PR_REMOVE_AND_INIT_LINK(&event->link);
00215         PostEvent(event);
00216     }
00217     return NS_OK;
00218 }
00219 
00220 nsresult
00221 nsSocketTransportService::AddToPollList(SocketContext *sock)
00222 {
00223     LOG(("nsSocketTransportService::AddToPollList [handler=%x]\n", sock->mHandler));
00224 
00225     if (mActiveCount == NS_SOCKET_MAX_COUNT) {
00226         NS_ERROR("too many active sockets");
00227         return NS_ERROR_UNEXPECTED;
00228     }
00229 
00230     mActiveList[mActiveCount] = *sock;
00231     mActiveCount++;
00232 
00233     mPollList[mActiveCount].fd = sock->mFD;
00234     mPollList[mActiveCount].in_flags = sock->mHandler->mPollFlags;
00235     mPollList[mActiveCount].out_flags = 0;
00236 
00237     LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
00238     return NS_OK;
00239 }
00240 
00241 void
00242 nsSocketTransportService::RemoveFromPollList(SocketContext *sock)
00243 {
00244     LOG(("nsSocketTransportService::RemoveFromPollList [handler=%x]\n", sock->mHandler));
00245 
00246     PRUint32 index = sock - mActiveList;
00247     NS_ASSERTION(index < NS_SOCKET_MAX_COUNT, "invalid index");
00248 
00249     LOG(("  index=%u mActiveCount=%u\n", index, mActiveCount));
00250 
00251     if (index != mActiveCount-1) {
00252         mActiveList[index] = mActiveList[mActiveCount-1];
00253         mPollList[index+1] = mPollList[mActiveCount];
00254     }
00255     mActiveCount--;
00256 
00257     LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
00258 }
00259 
00260 nsresult
00261 nsSocketTransportService::AddToIdleList(SocketContext *sock)
00262 {
00263     LOG(("nsSocketTransportService::AddToIdleList [handler=%x]\n", sock->mHandler));
00264 
00265     if (mIdleCount == NS_SOCKET_MAX_COUNT) {
00266         NS_ERROR("too many idle sockets");
00267         return NS_ERROR_UNEXPECTED;
00268     }
00269 
00270     mIdleList[mIdleCount] = *sock;
00271     mIdleCount++;
00272 
00273     LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
00274     return NS_OK;
00275 }
00276 
00277 void
00278 nsSocketTransportService::RemoveFromIdleList(SocketContext *sock)
00279 {
00280     LOG(("nsSocketTransportService::RemoveFromIdleList [handler=%x]\n", sock->mHandler));
00281 
00282     PRUint32 index = sock - &mIdleList[0];
00283     NS_ASSERTION(index < NS_SOCKET_MAX_COUNT, "invalid index");
00284 
00285     if (index != mIdleCount-1)
00286         mIdleList[index] = mIdleList[mIdleCount-1];
00287     mIdleCount--;
00288 
00289     LOG(("  active=%u idle=%u\n", mActiveCount, mIdleCount));
00290 }
00291 
00292 void
00293 nsSocketTransportService::MoveToIdleList(SocketContext *sock)
00294 {
00295     nsresult rv = AddToIdleList(sock);
00296     if (NS_FAILED(rv))
00297         DetachSocket(sock);
00298     else
00299         RemoveFromPollList(sock);
00300 }
00301 
00302 void
00303 nsSocketTransportService::MoveToPollList(SocketContext *sock)
00304 {
00305     nsresult rv = AddToPollList(sock);
00306     if (NS_FAILED(rv))
00307         DetachSocket(sock);
00308     else
00309         RemoveFromIdleList(sock);
00310 }
00311 
00312 PRIntervalTime
00313 nsSocketTransportService::PollTimeout()
00314 {
00315     if (mActiveCount == 0)
00316         return NS_SOCKET_POLL_TIMEOUT;
00317 
00318     // compute minimum time before any socket timeout expires.
00319     PRUint32 minR = PR_UINT16_MAX;
00320     for (PRUint32 i=0; i<mActiveCount; ++i) {
00321         const SocketContext &s = mActiveList[i];
00322         // mPollTimeout could be less than mElapsedTime if setTimeout
00323         // was called with a value smaller than mElapsedTime.
00324         PRUint32 r = (s.mElapsedTime < s.mHandler->mPollTimeout)
00325           ? s.mHandler->mPollTimeout - s.mElapsedTime
00326           : 0;
00327         if (r < minR)
00328             minR = r;
00329     }
00330     LOG(("poll timeout: %lu\n", minR));
00331     return PR_SecondsToInterval(minR);
00332 }
00333 
00334 PRInt32
00335 nsSocketTransportService::Poll(PRUint32 *interval)
00336 {
00337     PRPollDesc *pollList;
00338     PRUint32 pollCount;
00339     PRIntervalTime pollTimeout;
00340 
00341     if (mPollList[0].fd) {
00342         mPollList[0].out_flags = 0;
00343         pollList = mPollList;
00344         pollCount = mActiveCount + 1;
00345         pollTimeout = PollTimeout();
00346     }
00347     else {
00348         // no pollable event, so busy wait...
00349         pollCount = mActiveCount;
00350         if (pollCount)
00351             pollList = &mPollList[1];
00352         else
00353             pollList = nsnull;
00354         pollTimeout = PR_MillisecondsToInterval(25);
00355     }
00356 
00357     PRIntervalTime ts = PR_IntervalNow();
00358 
00359     LOG(("    timeout = %i milliseconds\n",
00360          PR_IntervalToMilliseconds(pollTimeout)));
00361     PRInt32 rv = PR_Poll(pollList, pollCount, pollTimeout);
00362 
00363     PRIntervalTime passedInterval = PR_IntervalNow() - ts;
00364 
00365     LOG(("    ...returned after %i milliseconds\n",
00366          PR_IntervalToMilliseconds(passedInterval))); 
00367 
00368     *interval = PR_IntervalToSeconds(passedInterval);
00369     return rv;
00370 }
00371 
00372 PRBool
00373 nsSocketTransportService::ServiceEventQ()
00374 {
00375     PRBool keepGoing;
00376 
00377     // grab the event queue
00378     PRCList eq;
00379     PR_INIT_CLIST(&eq);
00380     {
00381         nsAutoLock lock(mEventQLock);
00382 
00383         MoveCList(mEventQ, eq);
00384 
00385         // check to see if we're supposed to shutdown
00386         keepGoing = mInitialized;
00387     }
00388     // service the event queue
00389     PLEvent *event;
00390     while (!PR_CLIST_IS_EMPTY(&eq)) {
00391         event = PLEVENT_FROM_LINK(PR_LIST_HEAD(&eq));
00392         PR_REMOVE_AND_INIT_LINK(&event->link);
00393 
00394         PL_HandleEvent(event);
00395     }
00396     return keepGoing;
00397 }
00398 
00399 
00400 //-----------------------------------------------------------------------------
00401 // xpcom api
00402 
00403 NS_IMPL_THREADSAFE_ISUPPORTS4(nsSocketTransportService,
00404                               nsISocketTransportService,
00405                               nsIEventTarget,
00406                               nsIRunnable,
00407                               nsPISocketTransportService)
00408 
00409 // called from main thread only
00410 NS_IMETHODIMP
00411 nsSocketTransportService::Init()
00412 {
00413     NS_ASSERTION(nsIThread::IsMainThread(), "wrong thread");
00414 
00415     if (mInitialized)
00416         return NS_OK;
00417 
00418     if (!mThreadEvent) {
00419         mThreadEvent = PR_NewPollableEvent();
00420         //
00421         // NOTE: per bug 190000, this failure could be caused by Zone-Alarm
00422         // or similar software.
00423         //
00424         // NOTE: per bug 191739, this failure could also be caused by lack
00425         // of a loopback device on Windows and OS/2 platforms (NSPR creates
00426         // a loopback socket pair on these platforms to implement a pollable
00427         // event object).  if we can't create a pollable event, then we'll
00428         // have to "busy wait" to implement the socket event queue :-(
00429         //
00430         if (!mThreadEvent) {
00431             NS_WARNING("running socket transport thread without a pollable event");
00432             LOG(("running socket transport thread without a pollable event"));
00433         }
00434     }
00435 
00436     nsresult rv = NS_NewThread(&mThread, this, 0, PR_JOINABLE_THREAD);
00437     if (NS_FAILED(rv)) return rv;
00438 
00439     mInitialized = PR_TRUE;
00440     return NS_OK;
00441 }
00442 
00443 // called from main thread only
00444 NS_IMETHODIMP
00445 nsSocketTransportService::Shutdown()
00446 {
00447     LOG(("nsSocketTransportService::Shutdown\n"));
00448 
00449     NS_ASSERTION(nsIThread::IsMainThread(), "wrong thread");
00450 
00451     if (!mInitialized)
00452         return NS_OK;
00453 
00454     {
00455         nsAutoLock lock(mEventQLock);
00456 
00457         // signal uninitialized to block further events
00458         mInitialized = PR_FALSE;
00459 
00460         if (mThreadEvent)
00461             PR_SetPollableEvent(mThreadEvent);
00462         // else wait for Poll timeout
00463     }
00464 
00465     // join with thread
00466     mThread->Join();
00467     NS_RELEASE(mThread);
00468 
00469     return NS_OK;
00470 }
00471 
00472 NS_IMETHODIMP
00473 nsSocketTransportService::CreateTransport(const char **types,
00474                                           PRUint32 typeCount,
00475                                           const nsACString &host,
00476                                           PRInt32 port,
00477                                           nsIProxyInfo *proxyInfo,
00478                                           nsISocketTransport **result)
00479 {
00480     NS_ENSURE_TRUE(mInitialized, NS_ERROR_OFFLINE);
00481     NS_ENSURE_TRUE(port >= 0 && port <= 0xFFFF, NS_ERROR_ILLEGAL_VALUE);
00482 
00483     nsSocketTransport *trans = new nsSocketTransport();
00484     if (!trans)
00485         return NS_ERROR_OUT_OF_MEMORY;
00486     NS_ADDREF(trans);
00487 
00488     nsresult rv = trans->Init(types, typeCount, host, port, proxyInfo);
00489     if (NS_FAILED(rv)) {
00490         NS_RELEASE(trans);
00491         return rv;
00492     }
00493 
00494     *result = trans;
00495     return NS_OK;
00496 }
00497 
00498 NS_IMETHODIMP
00499 nsSocketTransportService::GetAutodialEnabled(PRBool *value)
00500 {
00501     *value = mAutodialEnabled;
00502     return NS_OK;
00503 }
00504 
00505 NS_IMETHODIMP
00506 nsSocketTransportService::SetAutodialEnabled(PRBool value)
00507 {
00508     mAutodialEnabled = value;
00509     return NS_OK;
00510 }
00511 
00512 NS_IMETHODIMP
00513 nsSocketTransportService::Run()
00514 {
00515     LOG(("nsSocketTransportService::Run"));
00516 
00517     gSocketThread = PR_GetCurrentThread();
00518 
00519     //
00520     // add thread event to poll list (mThreadEvent may be NULL)
00521     //
00522     mPollList[0].fd = mThreadEvent;
00523     mPollList[0].in_flags = PR_POLL_READ;
00524     mPollList[0].out_flags = 0;
00525 
00526     PRInt32 i, count;
00527 
00528     //
00529     // poll loop
00530     //
00531     PRBool active = PR_TRUE;
00532     while (active) {
00533         //
00534         // walk active list backwards to see if any sockets should actually be
00535         // idle, then walk the idle list backwards to see if any idle sockets
00536         // should become active.  take care to check only idle sockets that
00537         // were idle to begin with ;-)
00538         //
00539         count = mIdleCount;
00540         for (i=mActiveCount-1; i>=0; --i) {
00541             //---
00542             LOG(("  active [%u] { handler=%x condition=%x pollflags=%hu }\n", i,
00543                 mActiveList[i].mHandler,
00544                 mActiveList[i].mHandler->mCondition,
00545                 mActiveList[i].mHandler->mPollFlags));
00546             //---
00547             if (NS_FAILED(mActiveList[i].mHandler->mCondition))
00548                 DetachSocket(&mActiveList[i]);
00549             else {
00550                 PRUint16 in_flags = mActiveList[i].mHandler->mPollFlags;
00551                 if (in_flags == 0)
00552                     MoveToIdleList(&mActiveList[i]);
00553                 else {
00554                     // update poll flags
00555                     mPollList[i+1].in_flags = in_flags;
00556                     mPollList[i+1].out_flags = 0;
00557                 }
00558             }
00559         }
00560         for (i=count-1; i>=0; --i) {
00561             //---
00562             LOG(("  idle [%u] { handler=%x condition=%x pollflags=%hu }\n", i,
00563                 mIdleList[i].mHandler,
00564                 mIdleList[i].mHandler->mCondition,
00565                 mIdleList[i].mHandler->mPollFlags));
00566             //---
00567             if (NS_FAILED(mIdleList[i].mHandler->mCondition))
00568                 DetachSocket(&mIdleList[i]);
00569             else if (mIdleList[i].mHandler->mPollFlags != 0)
00570                 MoveToPollList(&mIdleList[i]);
00571         }
00572 
00573         LOG(("  calling PR_Poll [active=%u idle=%u]\n", mActiveCount, mIdleCount));
00574 
00575         // Measures seconds spent while blocked on PR_Poll
00576         PRUint32 pollInterval;
00577 
00578         PRInt32 n = Poll(&pollInterval);
00579         if (n < 0) {
00580             LOG(("  PR_Poll error [%d]\n", PR_GetError()));
00581             active = PR_FALSE;
00582         }
00583         else {
00584             //
00585             // service "active" sockets...
00586             //
00587             for (i=0; i<PRInt32(mActiveCount); ++i) {
00588                 PRPollDesc &desc = mPollList[i+1];
00589                 SocketContext &s = mActiveList[i];
00590                 if (n > 0 && desc.out_flags != 0) {
00591                     s.mElapsedTime = 0;
00592                     s.mHandler->OnSocketReady(desc.fd, desc.out_flags);
00593                 }
00594                 // check for timeout errors unless disabled...
00595                 else if (s.mHandler->mPollTimeout != PR_UINT16_MAX) {
00596                     // update elapsed time counter
00597                     if (NS_UNLIKELY(pollInterval > (PR_UINT16_MAX - s.mElapsedTime)))
00598                         s.mElapsedTime = PR_UINT16_MAX;
00599                     else
00600                         s.mElapsedTime += PRUint16(pollInterval);
00601                     // check for timeout expiration 
00602                     if (s.mElapsedTime >= s.mHandler->mPollTimeout) {
00603                         s.mElapsedTime = 0;
00604                         s.mHandler->OnSocketReady(desc.fd, -1);
00605                     }
00606                 }
00607             }
00608 
00609             //
00610             // check for "dead" sockets and remove them (need to do this in
00611             // reverse order obviously).
00612             //
00613             for (i=mActiveCount-1; i>=0; --i) {
00614                 if (NS_FAILED(mActiveList[i].mHandler->mCondition))
00615                     DetachSocket(&mActiveList[i]);
00616             }
00617 
00618             //
00619             // service the event queue (mPollList[0].fd == mThreadEvent)
00620             //
00621             if (n == 0)
00622                 active = ServiceEventQ();
00623             else if (mPollList[0].out_flags == PR_POLL_READ) {
00624                 // acknowledge pollable event (wait should not block)
00625                 if (PR_WaitForPollableEvent(mThreadEvent) != PR_SUCCESS) {
00626                     // On Windows, the TCP loopback connection in the
00627                     // pollable event may become broken when a laptop
00628                     // switches between wired and wireless networks or
00629                     // wakes up from hibernation.  We try to create a
00630                     // new pollable event.  If that fails, we fall back
00631                     // on "busy wait".
00632                     {
00633                         nsAutoLock lock(mEventQLock);
00634                         PR_DestroyPollableEvent(mThreadEvent);
00635                         mThreadEvent = PR_NewPollableEvent();
00636                     }
00637                     if (!mThreadEvent) {
00638                         NS_WARNING("running socket transport thread without "
00639                                    "a pollable event");
00640                         LOG(("running socket transport thread without "
00641                              "a pollable event"));
00642                     }
00643                     mPollList[0].fd = mThreadEvent;
00644                     // mPollList[0].in_flags was already set to PR_POLL_READ
00645                     // at the beginning of this method.
00646                     mPollList[0].out_flags = 0;
00647                 }
00648                 active = ServiceEventQ();
00649             }
00650         }
00651     }
00652 
00653     //
00654     // shutdown thread
00655     //
00656     
00657     LOG(("shutting down socket transport thread...\n"));
00658 
00659     mShuttingDown = PR_TRUE;
00660 
00661     // detach any sockets
00662     for (i=mActiveCount-1; i>=0; --i)
00663         DetachSocket(&mActiveList[i]);
00664     for (i=mIdleCount-1; i>=0; --i)
00665         DetachSocket(&mIdleList[i]);
00666 
00667     mShuttingDown = PR_FALSE;
00668 
00669     // Final pass over the event queue. This makes sure that events posted by
00670     // socket detach handlers get processed.
00671     ServiceEventQ();
00672 
00673     gSocketThread = nsnull;
00674     return NS_OK;
00675 }