channel now runs async on a worker thread

This commit is contained in:
dmose%mozilla.org 2000-05-18 02:37:42 +00:00
parent 73e90d4a30
commit 9f9a4819d7
3 changed files with 125 additions and 76 deletions

View File

@ -33,7 +33,6 @@
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#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

View File

@ -17,6 +17,7 @@
* Rights Reserved.
*
* Contributor(s): Dan Mosedale <dmose@mozilla.org>
* Warren Harris <warren@netscape.com>
*
* 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;
}

View File

@ -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<nsIStreamListener> mAsyncListener; // since we can't call mListener
// directly from the worker thread
nsCOMPtr<nsIThread> mThread; // worker thread for this channer
nsCOMPtr<nsIStreamListener> mListener; // whoever is listening to us
nsCOMPtr<nsISupports> mResponseContext;
nsCOMPtr<nsIBufferInputStream> mReadPipeIn; // this end given to the listener
nsCOMPtr<nsIBufferOutputStream> mReadPipeOut; // for writes from the channel
PRUint32 mReadPipeOffset; // how many bytes written so far?
};
#endif // nsLDAPChannel_h__