From 9f9a4819d79fe74a17c136a5d1f466d49ab05b5d Mon Sep 17 00:00:00 2001 From: "dmose%mozilla.org" Date: Thu, 18 May 2000 02:37:42 +0000 Subject: [PATCH] channel now runs async on a worker thread --- directory/xpcom/base/src/ldapSearch.cpp | 56 +++++---- directory/xpcom/base/src/nsLDAPChannel.cpp | 136 +++++++++++++-------- directory/xpcom/base/src/nsLDAPChannel.h | 9 +- 3 files changed, 125 insertions(+), 76 deletions(-) diff --git a/directory/xpcom/base/src/ldapSearch.cpp b/directory/xpcom/base/src/ldapSearch.cpp index 502681223c4c..1885dd947eda 100644 --- a/directory/xpcom/base/src/ldapSearch.cpp +++ b/directory/xpcom/base/src/ldapSearch.cpp @@ -33,7 +33,6 @@ #include #include -#include #include "nspr.h" #include "ldap.h" #include "nsCOMPtr.h" @@ -75,15 +74,19 @@ lds(class nsLDAPChannel *chan, const char *url) NS_ENSURE_SUCCESS(rv, rv); #ifdef NO_URL_SEARCH - fprintf(stderr, "starting bind\n"); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "starting bind\n"); +#endif if ( !myOperation->SimpleBind(NULL, NULL) ) { (void)myConnection->GetErrorString(&errString); - fprintf(stderr, "ldap_simple_bind: %s\n", errString); + PR_fprintf(PR_STDERR, "ldap_simple_bind: %s\n", errString); return NS_ERROR_FAILURE; } - fprintf(stderr, "waiting for bind to complete"); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "waiting for bind to complete"); +#endif myMessage = new nsLDAPMessage(myOperation); returnCode = myOperation->Result(0, &nullTimeval, myMessage); @@ -92,7 +95,9 @@ lds(class nsLDAPChannel *chan, const char *url) returnCode = myOperation->Result(0, &nullTimeval, myMessage); usleep(20); - fputc('.',stderr); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR,"."); +#endif } switch (returnCode) { @@ -101,19 +106,21 @@ lds(class nsLDAPChannel *chan, const char *url) break; case -1: (void)myConnection->GetErrorString(&errString); - fprintf(stderr, - "myOperation->Result() [myOperation->SimpleBind]: %s: errno=%d\n", - errString, errno); + PR_fprintf(PR_STDERR, + "myOperation->Result() [myOperation->SimpleBind]: %s: errno=%d\n", + errString, errno); ldap_memfree(errString); return NS_ERROR_FAILURE; break; default: - fprintf(stderr, "\nmyOperation->Result() returned unexpected value: %d", - returnCode); + PR_fprintf(PR_STDERR, + "\nmyOperation->Result() returned unexpected value: %d", + returnCode); return NS_ERROR_FAILURE; } - - fprintf(stderr, "bound\n"); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "bound\n"); +#endif #endif @@ -135,14 +142,16 @@ lds(class nsLDAPChannel *chan, const char *url) // poll for results // - fprintf(stderr, "polling search operation"); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "polling search operation"); +#endif returnCode = LDAP_SUCCESS; while ( returnCode != LDAP_RES_SEARCH_RESULT ) { char *dn, *attr; int rc2; - fputc('.', stderr); + PR_fprintf(PR_STDERR,"."); // XXX is 0 the right value? // @@ -152,7 +161,7 @@ lds(class nsLDAPChannel *chan, const char *url) switch (returnCode) { case -1: // something went wrong (void)myConnection->GetErrorString(&errString); - fprintf(stderr, + PR_fprintf(PR_STDERR, "\nmyOperation->Result() [URLSearch]: %s: errno=%d\n", errString, errno); ldap_memfree(errString); @@ -161,7 +170,9 @@ lds(class nsLDAPChannel *chan, const char *url) break; case LDAP_RES_SEARCH_ENTRY: - fprintf(stderr, "\nentry returned!\n"); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "\nentry returned!\n"); +#endif // get the DN // XXX better err handling @@ -217,8 +228,9 @@ lds(class nsLDAPChannel *chan, const char *url) if ( lden != LDAP_SUCCESS ) { (void)myConnection->GetErrorString(&errString); - fprintf(stderr, "myMessage: error getting attribute: %s\n", - errString); + PR_fprintf(PR_STDERR, + "myMessage: error getting attribute: %s\n", + errString); return NS_ERROR_FAILURE; } @@ -232,13 +244,15 @@ lds(class nsLDAPChannel *chan, const char *url) break; case LDAP_RES_SEARCH_REFERENCE: // referral - fprintf(stderr, + PR_fprintf(PR_STDERR, "LDAP_RES_SEARCH_REFERENCE returned; not implemented!"); return NS_ERROR_FAILURE; break; case LDAP_RES_SEARCH_RESULT: // all done (the while condition sees this) - fprintf(stderr, "\nresult returned: \n"); +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "\nresult returned: \n"); +#endif // XXX should use GetErrorString here? // @@ -257,7 +271,7 @@ lds(class nsLDAPChannel *chan, const char *url) } myMessage = 0; - usleep(200); + PR_Sleep(200); } #ifdef DEBUG_dmose diff --git a/directory/xpcom/base/src/nsLDAPChannel.cpp b/directory/xpcom/base/src/nsLDAPChannel.cpp index f50fecab0ddf..333a55e86319 100644 --- a/directory/xpcom/base/src/nsLDAPChannel.cpp +++ b/directory/xpcom/base/src/nsLDAPChannel.cpp @@ -17,6 +17,7 @@ * Rights Reserved. * * Contributor(s): Dan Mosedale + * Warren Harris * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -36,10 +37,14 @@ #include "nsMimeTypes.h" #include "nsIPipe.h" #include "nsXPIDLString.h" -#include "nsLDAPService.h" -#include "nsIServiceManager.h" -static NS_DEFINE_CID(kLDAPServiceCID, NS_LDAPSERVICE_CID); +// for NS_NewAsyncStreamListener +// +#include "nsNetUtil.h" + +// for defintion of NS_UI_THREAD_EVENTQ for use with NS_NewAsyncStreamListener +// +#include "nsIEventQueueService.h" #ifdef DEBUG #include "nspr.h" @@ -47,17 +52,16 @@ static NS_DEFINE_CID(kLDAPServiceCID, NS_LDAPSERVICE_CID); NS_METHOD lds(class nsLDAPChannel *chan, const char *); -NS_IMPL_ISUPPORTS2(nsLDAPChannel, nsIChannel, nsIRequest); +NS_IMPL_THREADSAFE_ISUPPORTS3(nsLDAPChannel, nsIChannel, nsIRequest, + nsIRunnable); nsLDAPChannel::nsLDAPChannel() { NS_INIT_ISUPPORTS(); - /* member initializers and constructor code */ } nsLDAPChannel::~nsLDAPChannel() { - /* destructor code */ } nsresult @@ -100,8 +104,7 @@ nsLDAPChannel::IsPending(PRBool *result) NS_IMETHODIMP nsLDAPChannel::GetStatus(nsresult *status) { - NS_NOTYETIMPLEMENTED("nsLDAPChannel::GetStatus"); - return NS_ERROR_NOT_IMPLEMENTED; + return NS_OK; } NS_IMETHODIMP @@ -249,10 +252,7 @@ nsLDAPChannel::SetLoadAttributes(nsLoadFlags aLoadAttributes) NS_IMETHODIMP nsLDAPChannel::GetContentType(char* *aContentType) { - // XXX check for null pointers in setters / in params? - // - if (!aContentType) - return NS_ERROR_NULL_POINTER; + NS_ENSURE_ARG_POINTER(aContentType); *aContentType = nsCRT::strdup(TEXT_PLAIN); if (!*aContentType) { @@ -517,7 +517,6 @@ nsLDAPChannel::AsyncRead(nsIStreamListener* aListener, nsISupports* aCtxt) { nsresult rv; - nsXPIDLCString spec; // deal with the input args // @@ -525,53 +524,17 @@ nsLDAPChannel::AsyncRead(nsIStreamListener* aListener, mResponseContext = aCtxt; // add ourselves to the appropriate loadgroup - // XXX - what happens on the second call to AsyncRead()? // if (mLoadGroup) { mLoadGroup->AddChannel(this, nsnull); } - // since the LDAP SDK does all the socket management, we don't have - // an underlying transport channel to create an nsIInputStream to hand - // back to the nsIStreamListener. So (only on the first call to AsyncRead) - // we do it ourselves: + // kick off a thread to do the work // - if (!mReadPipeIn) { - - // get a new pipe, propagating any error upwards - // - rv = NS_NewPipe(getter_AddRefs(mReadPipeIn), getter_AddRefs(mReadPipeOut)); - NS_ENSURE_SUCCESS(rv, rv); + NS_ASSERTION(!mThread, "nsLDAPChannel thread already exists!"); - NS_ENSURE_SUCCESS(mReadPipeIn->SetNonBlocking(PR_TRUE), - NS_ERROR_UNEXPECTED); - - // XXX - bogus: this makes it synchronous! - // - NS_ENSURE_SUCCESS(mReadPipeOut->SetNonBlocking(PR_FALSE), - NS_ERROR_UNEXPECTED); - } - - // get the transport service - // -#if 0 - NS_WITH_SERVICE(nsLDAPService, ldapService, - kLDAPServiceCID, &rv); + rv = NS_NewThread(getter_AddRefs(mThread), this, 0, PR_JOINABLE_THREAD); NS_ENSURE_SUCCESS(rv, rv); -#endif - - // XXX should this happen earlier? - // - mListener->OnStartRequest(this, mResponseContext); - - // XXX do the search; this should go away - // - NS_ENSURE_SUCCESS(mURI->GetSpec(getter_Copies(spec)), NS_ERROR_UNEXPECTED); - lds(this, spec); - - // all done - // - mListener->OnStopRequest(this, mResponseContext, NS_OK, nsnull); return NS_OK; } @@ -596,6 +559,70 @@ nsLDAPChannel::AsyncWrite(nsIInputStream* fromStream, return NS_ERROR_NOT_IMPLEMENTED; } +// for nsIRunnable. this is the actual LDAP server interaction code for +// AsyncRead(). it gets executed on a worker thread so we don't block +// the main UI thread. +// +NS_IMETHODIMP +nsLDAPChannel::Run(void) +{ + nsresult rv; + nsXPIDLCString spec; + +#ifdef DEBUG_dmose + PR_fprintf(PR_STDERR, "nsLDAPService::Run() entered!\n"); +#endif + + // XXX how does this get destroyed? + // + rv = NS_NewAsyncStreamListener(getter_AddRefs(mAsyncListener), mListener, + NS_UI_THREAD_EVENTQ); + NS_ENSURE_SUCCESS(rv, rv); + + // we already know the content type, so might as well fire this now + // + mAsyncListener->OnStartRequest(this, mResponseContext); + + // since the LDAP SDK does all the socket management, we don't have + // an underlying transport channel to create an nsIInputStream to hand + // back to the nsIStreamListener. So (only on the first call to AsyncRead) + // we do it ourselves: + // + if (!mReadPipeIn) { + + // get a new pipe, propagating any error upwards + // + rv = NS_NewPipe(getter_AddRefs(mReadPipeIn), getter_AddRefs(mReadPipeOut)); + NS_ENSURE_SUCCESS(rv, rv); + + // the side of the pipe used on the main UI thread cannot block + // + NS_ENSURE_SUCCESS(mReadPipeIn->SetNonBlocking(PR_TRUE), + NS_ERROR_UNEXPECTED); + + // but the side of the pipe used by the worker thread can block + // + NS_ENSURE_SUCCESS(mReadPipeOut->SetNonBlocking(PR_FALSE), + NS_ERROR_UNEXPECTED); + } + + // get the URI spec + // + rv = mURI->GetSpec(getter_Copies(spec)); + NS_ENSURE_SUCCESS(rv, rv); + + // do the search + // + rv = lds(this, spec); + NS_ENSURE_SUCCESS(rv, rv); + + // all done + // + mAsyncListener->OnStopRequest(this, mResponseContext, NS_OK, nsnull); + + return NS_OK; +} + // XXX this function should go away // nsresult @@ -607,8 +634,9 @@ nsLDAPChannel::pipeWrite(char *str) rv = mReadPipeOut->Write(str, strlen(str), &bytesWritten); NS_ENSURE_SUCCESS(rv, rv); - mListener->OnDataAvailable(this, mResponseContext, mReadPipeIn, - mReadPipeOffset, strlen(str)); + mAsyncListener->OnDataAvailable(this, mResponseContext, mReadPipeIn, + mReadPipeOffset, strlen(str)); mReadPipeOffset += bytesWritten; return NS_OK; } + diff --git a/directory/xpcom/base/src/nsLDAPChannel.h b/directory/xpcom/base/src/nsLDAPChannel.h index 0170b290087c..4d1cb67148ea 100644 --- a/directory/xpcom/base/src/nsLDAPChannel.h +++ b/directory/xpcom/base/src/nsLDAPChannel.h @@ -35,6 +35,8 @@ #define nsLDAPChannel_h__ #include "nsCOMPtr.h" +#include "nsIRunnable.h" +#include "nsIThread.h" #include "nsIChannel.h" #include "nsIURI.h" #include "nsILoadGroup.h" @@ -44,12 +46,13 @@ #include "nsIBufferOutputStream.h" /* Header file */ -class nsLDAPChannel : public nsIChannel +class nsLDAPChannel : public nsIChannel, public nsIRunnable { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUEST NS_DECL_NSICHANNEL + NS_DECL_NSIRUNNABLE nsLDAPChannel(); virtual ~nsLDAPChannel(); @@ -78,11 +81,15 @@ protected: // various other instance vars // + nsCOMPtr mAsyncListener; // since we can't call mListener + // directly from the worker thread + nsCOMPtr mThread; // worker thread for this channer nsCOMPtr mListener; // whoever is listening to us nsCOMPtr mResponseContext; nsCOMPtr mReadPipeIn; // this end given to the listener nsCOMPtr mReadPipeOut; // for writes from the channel PRUint32 mReadPipeOffset; // how many bytes written so far? + }; #endif // nsLDAPChannel_h__