From 7fc5a0ea7eaa544343c80bbd5fc1a85cef2fdb02 Mon Sep 17 00:00:00 2001 From: "dougt%netscape.com" Date: Fri, 31 May 2002 20:40:11 +0000 Subject: [PATCH] fixes crash in js_FreeStack caused by a race condition in necko. see 139556 for the details. r=rpotts, sr=darin --- netwerk/base/src/nsFileTransport.cpp | 67 +++++-- netwerk/base/src/nsFileTransport.h | 175 ------------------ netwerk/base/src/nsFileTransportService.cpp | 9 + netwerk/base/src/nsFileTransportService.h | 85 --------- netwerk/base/src/nsSocketTransport.cpp | 21 ++- netwerk/base/src/nsSocketTransport.h | 4 + netwerk/base/src/nsSocketTransportService.cpp | 17 +- netwerk/base/src/nsSocketTransportService.h | 5 +- netwerk/dns/src/nsDnsService.cpp | 26 ++- xpcom/proxy/public/MANIFEST | 6 - xpcom/proxy/public/Makefile.in | 1 + xpcom/proxy/public/makefile.win | 38 ---- xpcom/proxy/public/nsProxyRelease.h | 42 ++++- 13 files changed, 168 insertions(+), 328 deletions(-) diff --git a/netwerk/base/src/nsFileTransport.cpp b/netwerk/base/src/nsFileTransport.cpp index e04defa0548..58c2ee5e418 100644 --- a/netwerk/base/src/nsFileTransport.cpp +++ b/netwerk/base/src/nsFileTransport.cpp @@ -49,6 +49,7 @@ #include "nsReadableUtils.h" #include "nsIProxyObjectManager.h" #include "nsNetUtil.h" +#include "nsProxyRelease.h" static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID); @@ -520,6 +521,10 @@ nsFileTransport::AsyncRead(nsIStreamListener *aListener, mTransferAmount = aTransferCount; mXferState = OPEN_FOR_READ; + nsIEventQueueService* eqService = mService->GetCachedEventQueueService(); + eqService->GetSpecialEventQueue(nsIEventQueueService::CURRENT_THREAD_EVENT_QUEUE, getter_AddRefs(mEventQ)); + NS_ASSERTION(mEventQ, "No Event Queue on calling thread"); + LOG(("nsFileTransport: AsyncRead [this=%x %s] mOffset=%d mTransferAmount=%d\n", this, mStreamName.get(), mOffset, mTransferAmount)); @@ -563,6 +568,10 @@ nsFileTransport::AsyncWrite(nsIStreamProvider *aProvider, mTransferAmount = aTransferCount; mXferState = OPEN_FOR_WRITE; + nsIEventQueueService* eqService = mService->GetCachedEventQueueService(); + eqService->GetSpecialEventQueue(nsIEventQueueService::CURRENT_THREAD_EVENT_QUEUE, getter_AddRefs(mEventQ)); + NS_ASSERTION(mEventQ, "No Event Queue on calling thread"); + LOG(("nsFileTransport: AsyncWrite [this=%x %s] mOffset=%d mTransferAmount=%d\n", this, mStreamName.get(), mOffset, mTransferAmount)); @@ -823,27 +832,38 @@ nsFileTransport::Process(nsIProgressEventSink *progressSink) // is reusing the stream. mXferState = CLOSING; DoClose(); - nsCOMPtr saveContext = mContext; - nsCOMPtr saveListener = mListener; - mListener = nsnull; - mContext = nsnull; // close the data source NS_IF_RELEASE(mSourceWrapper); mSourceWrapper = nsnull; if (progressSink) { - progressSink->OnStatus(this, saveContext, - NS_NET_STATUS_READ_FROM, - NS_ConvertASCIItoUCS2(mStreamName).get()); + progressSink->OnStatus(this, + mContext, + NS_NET_STATUS_READ_FROM, + NS_ConvertASCIItoUCS2(mStreamName).get()); } - if (saveListener) { - saveListener->OnStopRequest(this, saveContext, mStatus); - saveListener = 0; + if (mListener) { + mListener->OnStopRequest(this, mContext, mStatus); + mListener = 0; } - saveContext = 0; + // if we have a context, we have to ensure that it is released on the + // proper thread. + if (mContext) { + if (mEventQ) { + // see http://bugzilla.mozilla.org/show_bug.cgi?id=139556#c64 + // for the reason behind this evil reference counting. + nsISupports* doomed = mContext.get(); + NS_ADDREF(doomed); + mContext = 0; + NS_ProxyRelease(mEventQ, doomed); + } + else { + mContext = nsnull; + } + } break; } @@ -1002,16 +1022,31 @@ nsFileTransport::Process(nsIProgressEventSink *progressSink) NS_IF_RELEASE(mSinkWrapper); mSinkWrapper = nsnull; - if (mProvider) { - mProvider->OnStopRequest(this, mContext, mStatus); - mProvider = 0; - } if (progressSink) progressSink->OnStatus(this, mContext, NS_NET_STATUS_WROTE_TO, NS_ConvertASCIItoUCS2(mStreamName).get()); - mContext = 0; + if (mProvider) { + mProvider->OnStopRequest(this, mContext, mStatus); + mProvider = 0; + } + + // if we have a context, we have to ensure that it is released on the + // proper thread. + if (mContext) { + if (mEventQ) { + // see http://bugzilla.mozilla.org/show_bug.cgi?id=139556#c64 + // for the reason behind this evil reference counting. + nsISupports* doomed = mContext.get(); + NS_ADDREF(doomed); + mContext = 0; + NS_ProxyRelease(mEventQ, doomed); + } + else { + mContext = nsnull; + } + } mXferState = CLOSING; break; } diff --git a/netwerk/base/src/nsFileTransport.h b/netwerk/base/src/nsFileTransport.h index b67be33daad..e69de29bb2d 100644 --- a/netwerk/base/src/nsFileTransport.h +++ b/netwerk/base/src/nsFileTransport.h @@ -1,175 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Darin Fisher - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsFileTransport_h__ -#define nsFileTransport_h__ - -#include "nsITransport.h" -#include "nsIRequest.h" -#include "nsIRunnable.h" -#include "nsFileSpec.h" -#include "prlock.h" -#include "nsIEventQueueService.h" -#include "nsIPipe.h" -#include "nsILoadGroup.h" -#include "nsCOMPtr.h" -#include "nsIStreamListener.h" -#include "nsIStreamProvider.h" -#include "nsIProgressEventSink.h" -#include "nsIInputStream.h" -#include "nsIOutputStream.h" -#include "nsIStreamIO.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIFile.h" -#include "prlog.h" -#include "nsFileTransportService.h" - -//#define TIMING - -class nsIInterfaceRequestor; - -class nsFileTransportSourceWrapper; -class nsFileTransportSinkWrapper; - -class nsFileTransport : public nsITransport, - public nsITransportRequest, - public nsIRunnable -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSITRANSPORT - NS_DECL_NSIREQUEST - NS_DECL_NSITRANSPORTREQUEST - NS_DECL_NSIRUNNABLE - - nsFileTransport(); - // Always make the destructor virtual: - virtual ~nsFileTransport(); - - // Define a Create method to be used with a factory: - static NS_METHOD - Create(nsISupports* aOuter, const nsIID& aIID, void* *aResult); - - nsresult Init(nsFileTransportService *aService, nsIFile* file, - PRInt32 ioFlags, - PRInt32 perm, - PRBool closeStreamWhenDone); - nsresult Init(nsFileTransportService *aService, const nsACString &name, - nsIInputStream *fromStream, - const nsACString &contentType, - const nsACString &contentCharset, - PRInt32 contentLength, - PRBool closeStreamWhenDone); - nsresult Init(nsFileTransportService *aService, - nsIStreamIO* io, - PRBool closeStreamWhenDone); - - void Process(nsIProgressEventSink *); - void DoClose(void); - - enum XferState { - CLOSED, - OPEN_FOR_READ, - START_READ, - READING, - END_READ, - OPEN_FOR_WRITE, - START_WRITE, - WRITING, - END_WRITE, - CLOSING - }; - - enum RunState { - RUNNING, - SUSPENDED, - CANCELED - }; - -protected: - nsCOMPtr mProgressSink; - nsCOMPtr mNotificationCallbacks; - nsCOMPtr mStreamIO; - PRUint32 mBufferSegmentSize; - PRUint32 mBufferMaxSize; - - nsCOMPtr mContext; - - // mXferState is only changed by the file transport thread: - XferState mXferState; - - // mRunState is only changed by the user's thread, but looked at by the - // file transport thread: - RunState mRunState; - nsresult mCancelStatus; - PRInt32 mSuspendCount; - PRLock *mLock; - - // The transport is active if it is currently being processed by a thread. - PRBool mActive; - - // If FALSE, then the caller can reuse the file transport - PRBool mCloseStreamWhenDone; - // state variables: - nsresult mStatus; - PRUint32 mOffset; - PRInt32 mTotalAmount; - PRInt32 mTransferAmount; - - // reading state variables: - nsCOMPtr mListener; - nsFileTransportSourceWrapper *mSourceWrapper; - - // writing state variables: - nsCOMPtr mProvider; - nsCOMPtr mSink; - nsFileTransportSinkWrapper *mSinkWrapper; - - nsCString mStreamName; - nsFileTransportService *mService; - -#ifdef TIMING - PRIntervalTime mStartTime; -#endif -}; - -#define NS_FILE_TRANSPORT_DEFAULT_SEGMENT_SIZE (4096) -#define NS_FILE_TRANSPORT_DEFAULT_BUFFER_SIZE (4*4096) // 16k max - -#endif // nsFileTransport_h__ diff --git a/netwerk/base/src/nsFileTransportService.cpp b/netwerk/base/src/nsFileTransportService.cpp index 97417aa474c..9eee2112c8d 100644 --- a/netwerk/base/src/nsFileTransportService.cpp +++ b/netwerk/base/src/nsFileTransportService.cpp @@ -122,6 +122,15 @@ nsFileTransportService::GetCachedMimeService() return mMimeService.get(); } +nsIEventQueueService* +nsFileTransportService::GetCachedEventQueueService() +{ + if (!mEventQService) { + mEventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID); + } + return mEventQService.get(); +} + //////////////////////////////////////////////////////////////////////////////// NS_IMETHODIMP diff --git a/netwerk/base/src/nsFileTransportService.h b/netwerk/base/src/nsFileTransportService.h index 41baae98de2..e69de29bb2d 100644 --- a/netwerk/base/src/nsFileTransportService.h +++ b/netwerk/base/src/nsFileTransportService.h @@ -1,85 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: NPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Netscape Public License - * Version 1.1 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at - * http://www.mozilla.org/NPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the NPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the NPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsFileTransportService_h___ -#define nsFileTransportService_h___ - -#include "nsIFileTransportService.h" -#include "nsIThreadPool.h" -#include "nsSupportsArray.h" -#include "nsIMIMEService.h" - -#define NS_FILE_TRANSPORT_WORKER_COUNT_MIN 1 -#define NS_FILE_TRANSPORT_WORKER_COUNT_MAX 4//16 - -class nsFileTransportService : public nsIFileTransportService -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIFILETRANSPORTSERVICE - - // nsFileTransportService methods: - nsFileTransportService(); - virtual ~nsFileTransportService(); - - static NS_METHOD - Create(nsISupports *aOuter, REFNSIID aIID, void **aResult); - - nsresult Init(); - - static nsFileTransportService *GetInstance() { return mInstance; } - - nsIMIMEService* GetCachedMimeService(); - - PRInt32 mConnectedTransports; - PRInt32 mTotalTransports; - PRInt32 mInUseTransports; - - nsresult AddSuspendedTransport(nsITransport* trans); - nsresult RemoveSuspendedTransport(nsITransport* trans); - - nsSupportsArray mSuspendedTransportList; - -protected: - PRBool mShuttingDown; - nsCOMPtr mPool; - PRLock* mLock; - nsCOMPtr mMimeService; - static nsFileTransportService* mInstance; -}; - -#endif /* nsFileTransportService_h___ */ diff --git a/netwerk/base/src/nsSocketTransport.cpp b/netwerk/base/src/nsSocketTransport.cpp index 3e2051e33c5..0ee7de7f525 100644 --- a/netwerk/base/src/nsSocketTransport.cpp +++ b/netwerk/base/src/nsSocketTransport.cpp @@ -61,6 +61,7 @@ #include "nsITransportSecurityInfo.h" #include "nsMemory.h" #include "nsIProxyInfo.h" +#include "nsProxyRelease.h" #if defined(PR_LOGGING) static PRLogModuleInfo *gSocketTransportLog = nsnull; @@ -2637,6 +2638,12 @@ nsSocketRequest::SetTransport(nsSocketTransport *aTransport) // NS_IF_RELEASE(mTransport); NS_IF_ADDREF(mTransport = aTransport); + + // + // Set the event queue + // + nsIEventQueueService* eqService = aTransport->mService->GetCachedEventQueueService(); + eqService->GetSpecialEventQueue(nsIEventQueueService::CURRENT_THREAD_EVENT_QUEUE, getter_AddRefs(mEventQ)); } nsresult @@ -2657,9 +2664,21 @@ nsSocketRequest::OnStop() mObserver->OnStartRequest(this, mContext); mStartFired = PR_TRUE; } + mObserver->OnStopRequest(this, mContext, mStatus); mObserver = 0; - mContext = 0; + + if (mContext) { + if (mEventQ) { + nsISupports* doomed = mContext.get(); + NS_ADDREF(doomed); + mContext = 0; + NS_ProxyRelease(mEventQ, doomed); + } + else { + mContext = 0; + } + } mStopFired = PR_TRUE; } return NS_OK; diff --git a/netwerk/base/src/nsSocketTransport.h b/netwerk/base/src/nsSocketTransport.h index 8ced37acd75..6782ac3ad3b 100644 --- a/netwerk/base/src/nsSocketTransport.h +++ b/netwerk/base/src/nsSocketTransport.h @@ -309,6 +309,8 @@ protected: nsSocketBOS *mBOS; // weak reference nsSocketReadRequest *mReadRequest; nsSocketWriteRequest *mWriteRequest; + + friend nsSocketRequest; }; /** @@ -453,6 +455,8 @@ protected: nsSocketTransport *mTransport; nsCOMPtr mObserver; nsCOMPtr mContext; + // Queue where release of context, listener, and/or provider should occur. + nsCOMPtr mEventQ; nsresult mStatus; PRIntn mSuspendCount; PRPackedBool mCanceled; diff --git a/netwerk/base/src/nsSocketTransportService.cpp b/netwerk/base/src/nsSocketTransportService.cpp index 932d03bd00a..100304edada 100644 --- a/netwerk/base/src/nsSocketTransportService.cpp +++ b/netwerk/base/src/nsSocketTransportService.cpp @@ -211,6 +211,15 @@ nsSocketTransportService::Init(void) rv = NS_ERROR_UNEXPECTED; } } + + + if (NS_SUCCEEDED(rv) && !mEventQService) { + mEventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID); + if (!mEventQService) { + rv = NS_ERROR_UNEXPECTED; + } + } + return rv; } @@ -791,22 +800,22 @@ nsSocketTransportService::GetNeckoStringByName (const char *aName, PRUnichar **a nsresult res; nsAutoString resultString; resultString.AssignWithConversion(aName); - if (!m_stringBundle) { + if (!mStringBundle) { const char propertyURL[] = NECKO_MSGS_URL; // make sure that we get this service on the UI thread. NS_WITH_PROXIED_SERVICE(nsIStringBundleService, sBundleService, kStringBundleServiceCID, NS_UI_THREAD_EVENTQ, &res); if (NS_SUCCEEDED (res) && (nsnull != sBundleService)) { - res = sBundleService->CreateBundle(propertyURL, getter_AddRefs(m_stringBundle)); + res = sBundleService->CreateBundle(propertyURL, getter_AddRefs(mStringBundle)); } } - if (m_stringBundle) + if (mStringBundle) { nsAutoString unicodeName; unicodeName.AssignWithConversion(aName); PRUnichar *ptrv = nsnull; - res = m_stringBundle->GetStringFromName(unicodeName.get(), &ptrv); + res = mStringBundle->GetStringFromName(unicodeName.get(), &ptrv); if (NS_FAILED(res)) { diff --git a/netwerk/base/src/nsSocketTransportService.h b/netwerk/base/src/nsSocketTransportService.h index 2cb8418a72b..66e365fd23d 100644 --- a/netwerk/base/src/nsSocketTransportService.h +++ b/netwerk/base/src/nsSocketTransportService.h @@ -46,6 +46,7 @@ #include "nsCOMPtr.h" #include "nsIStringBundle.h" #include "nsIDNSService.h" +#include "nsIEventQueueService.h" #if defined(XP_PC) || defined(XP_UNIX) || defined(XP_BEOS) || defined(XP_MAC) // @@ -99,6 +100,7 @@ public: nsresult GetNeckoStringByName (const char *aName, PRUnichar **aString); nsIDNSService* GetCachedDNSService() { return mDNSService.get(); } + nsIEventQueueService* GetCachedEventQueueService() { return mEventQService.get(); } protected: nsIThread* mThread; @@ -111,8 +113,9 @@ protected: PRInt32 mSelectFDSetCount; PRPollDesc* mSelectFDSet; nsSocketTransport** mActiveTransportList; - nsCOMPtr m_stringBundle; + nsCOMPtr mStringBundle; nsCOMPtr mDNSService; + nsCOMPtr mEventQService; }; diff --git a/netwerk/dns/src/nsDnsService.cpp b/netwerk/dns/src/nsDnsService.cpp index c38c68fca84..2d26869fe73 100644 --- a/netwerk/dns/src/nsDnsService.cpp +++ b/netwerk/dns/src/nsDnsService.cpp @@ -1026,6 +1026,15 @@ nsDNSService::Init() rv = InstallPrefObserver(); if (NS_FAILED(rv)) return rv; + // install xpcom shutdown observer + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_FAILED(rv)) return rv; + + rv = observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE); + if (NS_FAILED(rv)) return rv; + + mState = DNS_ONLINE; return NS_OK; @@ -1265,6 +1274,13 @@ nsDNSService::Observe(nsISupports * subject, { nsresult rv = NS_OK; + if (!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, topic)) + { + // we need to shutdown! + ShutdownInternal(); + return NS_OK; + } + if (nsCRT::strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, topic)) return NS_OK; @@ -1302,7 +1318,6 @@ nsDNSService::Observe(nsISupports * subject, mIDNConverter = nsnull; } } - return rv; } @@ -1829,6 +1844,15 @@ nsDNSService::ShutdownInternal() (void) RemovePrefObserver(); + + // remove xpcom shutdown observer + nsCOMPtr observerService = + do_GetService("@mozilla.org/observer-service;1", &rv); + if (NS_FAILED(rv)) return rv; + + rv = observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); + if (NS_FAILED(rv)) return rv; + // reset hashtable // XXX assert hashtable is empty PL_DHashTableFinish(&mHashTable); diff --git a/xpcom/proxy/public/MANIFEST b/xpcom/proxy/public/MANIFEST index 9b7909a54fc..e69de29bb2d 100644 --- a/xpcom/proxy/public/MANIFEST +++ b/xpcom/proxy/public/MANIFEST @@ -1,6 +0,0 @@ -# -# This is a list of local files which get copied to the mozilla:dist directory -# - -nsProxyEvent.h -nsProxiedService.h diff --git a/xpcom/proxy/public/Makefile.in b/xpcom/proxy/public/Makefile.in index 3045ebc846c..306941e0b24 100644 --- a/xpcom/proxy/public/Makefile.in +++ b/xpcom/proxy/public/Makefile.in @@ -35,6 +35,7 @@ endif EXPORTS = \ nsProxyEvent.h \ + nsProxyRelease.h \ nsProxiedService.h \ $(NULL) diff --git a/xpcom/proxy/public/makefile.win b/xpcom/proxy/public/makefile.win index 57868c647cf..e69de29bb2d 100644 --- a/xpcom/proxy/public/makefile.win +++ b/xpcom/proxy/public/makefile.win @@ -1,38 +0,0 @@ -#!nmake -# -# The contents of this file are subject to the Netscape Public -# License Version 1.1 (the "License"); you may not use this file -# except in compliance with the License. You may obtain a copy of -# the License at http://www.mozilla.org/NPL/ -# -# Software distributed under the License is distributed on an "AS -# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or -# implied. See the License for the specific language governing -# rights and limitations under the License. -# -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is Netscape -# Communications Corporation. Portions created by Netscape are -# Copyright (C) 1998 Netscape Communications Corporation. All -# Rights Reserved. -# -# Contributor(s): - -DEPTH=..\..\.. - -MODULE=xpcom - -EXPORTS = \ - nsProxyEvent.h \ - nsProxiedService.h \ - $(NULL) - -XPIDL_MODULE = proxyObject - -XPIDLSRCS = \ - .\nsIProxyCreateInstance.idl \ - .\nsIProxyObjectManager.idl \ - $(NULL) - -include <$(DEPTH)\config\rules.mak> diff --git a/xpcom/proxy/public/nsProxyRelease.h b/xpcom/proxy/public/nsProxyRelease.h index 0fa97f0ab6b..0f8e779d340 100644 --- a/xpcom/proxy/public/nsProxyRelease.h +++ b/xpcom/proxy/public/nsProxyRelease.h @@ -50,7 +50,7 @@ static void* PR_CALLBACK ReleaseDestructorEventHandler(PLEvent *self) { nsISupports* owner = (nsISupports*) PL_GetEventOwner(self); - NS_DELETEXPCOM(owner); + NS_RELEASE(owner); return nsnull; } @@ -60,6 +60,44 @@ ReleaseDestructorDestroyHandler(PLEvent *self) PR_DELETE(self); } +static void +NS_ProxyRelease(nsIEventQueue *eventQ, nsISupports *doomed, PRBool alwaysProxy=PR_FALSE) +{ + if (!doomed) + return; + + if (!eventQ) { + NS_RELEASE(doomed); + return; + } + + if (!alwaysProxy) { + PRBool onCurrentThread = PR_FALSE; + eventQ->IsQueueOnCurrentThread(&onCurrentThread); + if (onCurrentThread) { + NS_RELEASE(doomed); + return; + } + } + + PLEvent *ev = new PLEvent; + if (!ev) { + NS_ERROR("failed to allocate PLEvent"); + // we do not release doomed here since it may cause a delete on the the + // wrong thread. better to leak than crash. + return; + } + + PL_InitEvent(ev, + (void *) doomed, + ReleaseDestructorEventHandler, + ReleaseDestructorDestroyHandler); + + PRStatus rv = eventQ->PostEvent(ev); + NS_ASSERTION(rv == PR_SUCCESS, "PostEvent failed"); +} + + #define NS_IMPL_PROXY_RELEASE(_class) \ NS_IMETHODIMP_(nsrefcnt) _class::Release(void) \ { \ @@ -106,5 +144,7 @@ NS_IMETHODIMP_(nsrefcnt) _class::Release(void) return count; \ } \ + + #endif