Added synchronization to socket transport APIs... Added access methods for getting the PRCList from a transport...

This commit is contained in:
rpotts%netscape.com 1999-06-01 21:37:52 +00:00
parent fe34d14c41
commit 3b7139d78f
3 changed files with 93 additions and 18 deletions

View File

@ -103,11 +103,12 @@ nsSocketTransport::nsSocketTransport()
{
NS_INIT_REFCNT();
PR_INIT_CLIST(this);
PR_INIT_CLIST(&mListLink);
mHostName = nsnull;
mPort = 0;
mSocketFD = nsnull;
mLock = nsnull;
mCurrentState = eSocketState_Created;
mOperation = eSocketOperation_None;
@ -160,6 +161,11 @@ nsSocketTransport::~nsSocketTransport()
PR_Close(mSocketFD);
mSocketFD = nsnull;
}
if (mLock) {
PR_DestroyLock(mLock);
mLock = nsnull;
}
}
@ -184,6 +190,16 @@ nsresult nsSocketTransport::Init(nsSocketTransportService* aService,
rv = NS_ERROR_NULL_POINTER;
}
//
// Create the lock used for synchronizing access to the transport instance.
//
if (NS_SUCCEEDED(rv)) {
mLock = PR_NewLock();
if (!mLock) {
rv = NS_ERROR_OUT_OF_MEMORY;
}
}
return rv;
}
@ -193,6 +209,12 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
nsresult rv = NS_OK;
PRBool done = PR_FALSE;
//
// Enter the socket transport lock...
// This lock protects access to socket transport member data...
//
Lock();
while (!done)
{
switch (mCurrentState) {
@ -300,16 +322,22 @@ nsresult nsSocketTransport::Process(PRInt16 aSelectFlags)
//
aSelectFlags = 0;
}
// Leave the socket transport lock...
Unlock();
return rv;
}
//-----
//
// doResolveHost:
// doResolveHost:
//
// Return Codes:
// This method is called while holding the SocketTransport lock. It is
// always called on the socket transport thread...
//
// Return Codes:
// NS_OK
// NS_ERROR_HOST_NOT_FOUND
// NS_ERROR_FAILURE
@ -355,9 +383,12 @@ nsresult nsSocketTransport::doResolveHost(void)
//-----
//
// doConnection:
// doConnection:
//
// Return values:
// This method is called while holding the SocketTransport lock. It is
// always called on the socket transport thread...
//
// Return values:
// NS_OK
// NS_BASE_STREAM_WOULD_BLOCK
//
@ -448,7 +479,10 @@ nsresult nsSocketTransport::doConnection(PRInt16 aSelectFlags)
rv = NS_ERROR_CONNECTION_REFUSED;
}
//
// The connection was successful...
// The connection was successful...
//
// PR_Poll(...) returns PR_POLL_WRITE to indicate that the connection is
// established...
//
else if (PR_POLL_WRITE & aSelectFlags) {
rv = NS_OK;
@ -461,9 +495,12 @@ nsresult nsSocketTransport::doConnection(PRInt16 aSelectFlags)
//-----
//
// doRead:
// doRead:
//
// Return values:
// This method is called while holding the SocketTransport lock. It is
// always called on the socket transport thread...
//
// Return values:
// NS_OK
// NS_BASE_STREAM_WOULD_BLOCK
//
@ -564,9 +601,12 @@ nsresult nsSocketTransport::doRead(PRInt16 aSelectFlags)
//-----
//
// doWrite:
// doWrite:
//
// Return values:
// This method is called while holding the SocketTransport lock. It is
// always called on the socket transport thread...
//
// Return values:
// NS_OK
// NS_BASE_STREAM_WOULD_BLOCK
//
@ -696,20 +736,27 @@ nsSocketTransport::AsyncRead(nsISupports* aContext,
{
nsresult rv = NS_OK;
// Enter the socket transport lock...
Lock();
// If a read is already in progress then fail...
if (mReadListener) {
rv = NS_ERROR_IN_PROGRESS;
}
// Create a new input stream for reading data into...
if (NS_SUCCEEDED(rv) && !mReadStream) {
rv = NS_NewByteBufferInputStream(&mReadStream, PR_FALSE,
MAX_IO_BUFFER_SIZE);
}
if (NS_SUCCEEDED(rv)) {
// Store the context used for this read...
NS_IF_RELEASE(mReadContext);
mReadContext = aContext;
NS_IF_ADDREF(mReadContext);
// Create a marshalling stream listener to receive notifications...
rv = NS_NewAsyncStreamListener(&mReadListener, aAppEventQueue, aListener);
}
@ -719,6 +766,9 @@ nsSocketTransport::AsyncRead(nsISupports* aContext,
rv = mService->AddToWorkQ(this);
}
// Leave the socket transport lock...
Unlock();
return rv;
}
@ -731,6 +781,10 @@ nsSocketTransport::AsyncWrite(nsIInputStream* aFromStream,
{
nsresult rv = NS_OK;
// Enter the socket transport lock...
Lock();
// If a write is already in progress then fail...
if (mWriteStream) {
rv = NS_ERROR_IN_PROGRESS;
}
@ -743,8 +797,11 @@ nsSocketTransport::AsyncWrite(nsIInputStream* aFromStream,
mWriteContext = aContext;
NS_IF_ADDREF(mWriteContext);
// Create a marshalling stream observer to receive notifications...
NS_IF_RELEASE(mWriteObserver);
rv = NS_NewAsyncStreamObserver(&mWriteObserver, aAppEventQueue, aObserver);
if (aObserver) {
rv = NS_NewAsyncStreamObserver(&mWriteObserver, aAppEventQueue, aObserver);
}
}
if (NS_SUCCEEDED(rv)) {
@ -752,6 +809,9 @@ nsSocketTransport::AsyncWrite(nsIInputStream* aFromStream,
rv = mService->AddToWorkQ(this);
}
// Leave the socket transport lock...
Unlock();
return rv;
}

View File

@ -52,8 +52,7 @@ enum nsSocketOperation {
class nsSocketTransportService;
class nsSocketTransport : public PRCList,
public nsITransport
class nsSocketTransport : public nsITransport
{
public:
// nsISupports methods:
@ -95,7 +94,18 @@ public:
PRFileDesc* GetSocket(void) { return mSocketFD; }
PRInt16 GetSelectFlags(void) { return mSelectFlags; }
PRCList* GetListNode(void) { return &mListLink; }
static nsSocketTransport* GetInstance(PRCList* qp) { return (nsSocketTransport*)((char*)qp - offsetof(nsSocketTransport, mListLink)); }
protected:
// Inline helpers...
void Lock (void) { NS_ASSERTION(mLock, "Lock null."); PR_Lock(mLock); }
void Unlock(void) { NS_ASSERTION(mLock, "Lock null."); PR_Unlock(mLock); }
protected:
PRCList mListLink;
PRLock* mLock;
nsSocketState mCurrentState;
nsSocketOperation mOperation;

View File

@ -147,15 +147,17 @@ nsresult nsSocketTransportService::AddToWorkQ(nsSocketTransport* aTransport)
PRStatus status;
PRBool bFireEvent = PR_FALSE;
nsresult rv = NS_OK;
PRCList* qp;
Lock();
//
// Only add the transport if it is *not* already on the list...
//
if (PR_CLIST_IS_EMPTY(aTransport)) {
qp = aTransport->GetListNode();
if (PR_CLIST_IS_EMPTY(qp)) {
NS_ADDREF(aTransport);
bFireEvent = PR_CLIST_IS_EMPTY(&mWorkQ);
PR_APPEND_LINK(aTransport, &mWorkQ);
PR_APPEND_LINK(qp, &mWorkQ);
}
Unlock();
//
@ -176,6 +178,7 @@ nsresult nsSocketTransportService::AddToWorkQ(nsSocketTransport* aTransport)
nsresult nsSocketTransportService::ProcessWorkQ(void)
{
nsresult rv = NS_OK;
PRCList* qp;
//
// Only process pending operations while there is space available in the
@ -190,8 +193,10 @@ nsresult nsSocketTransportService::ProcessWorkQ(void)
nsSocketTransport* transport;
// Get the next item off of the workQ...
transport = (nsSocketTransport*)PR_LIST_HEAD(&mWorkQ);
PR_REMOVE_AND_INIT_LINK(transport);
qp = PR_LIST_HEAD(&mWorkQ);
transport = nsSocketTransport::GetInstance(qp);
PR_REMOVE_AND_INIT_LINK(qp);
// Try to perform the operation...
//