From 4a0222e731b7a662d4a4b737bc000aa50d11d3e8 Mon Sep 17 00:00:00 2001 From: "dougt%meer.net" Date: Mon, 7 Jul 2003 22:11:36 +0000 Subject: [PATCH] Enables debug stackcrawl support in GRE builds. b=208098. r=dbaron. --- xpcom/base/Makefile.in | 3 + xpcom/base/nsDebugImpl.cpp | 467 ++++++++++++++++++++ xpcom/base/nsDebugImpl.h | 59 +++ xpcom/base/nsIDebug.idl | 62 +++ xpcom/base/nsISupportsObsolete.h | 51 --- xpcom/build/nsXPCOM.h | 6 +- xpcom/build/nsXPCOMPrivate.h | 6 + xpcom/build/nsXPComInit.cpp | 29 +- xpcom/components/nsComponentManager.h | 12 +- xpcom/glue/nsDebug.cpp | 602 ++++---------------------- xpcom/glue/nsDebug.h | 101 +---- xpcom/glue/nsISupportsImpl.h | 13 +- xpcom/glue/standalone/nsXPCOMGlue.cpp | 38 +- 13 files changed, 775 insertions(+), 674 deletions(-) create mode 100644 xpcom/base/nsDebugImpl.cpp create mode 100644 xpcom/base/nsDebugImpl.h create mode 100644 xpcom/base/nsIDebug.idl diff --git a/xpcom/base/Makefile.in b/xpcom/base/Makefile.in index f63e69fd9be..2ff8ff27ce5 100644 --- a/xpcom/base/Makefile.in +++ b/xpcom/base/Makefile.in @@ -43,6 +43,7 @@ CPPSRCS = \ nsCWeakReference.cpp \ nsConsoleService.cpp \ nsConsoleMessage.cpp \ + nsDebugImpl.cpp \ nsExceptionService.cpp \ $(NULL) @@ -59,6 +60,7 @@ EXPORTS = \ nsCom.h \ nsComObsolete.h \ nsCWeakReference.h \ + nsDebugImpl.h \ nsIID.h \ nsISupportsObsolete.h \ nsTraceRefcnt.h \ @@ -83,6 +85,7 @@ SDK_XPIDLSRCS = \ nsISupports.idl \ nsIWeakReference.idl \ nsIMemory.idl \ + nsIDebug.idl \ nsrootidl.idl \ SDK_HEADERS = \ diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp new file mode 100644 index 00000000000..f7edc874c96 --- /dev/null +++ b/xpcom/base/nsDebugImpl.cpp @@ -0,0 +1,467 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * 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): + * IBM Corp. + * Henry Sobotka + */ + +#include "nsDebugImpl.h" +#include "nsDebug.h" +#include "prprf.h" +#include "prlog.h" +#include "prinit.h" +#include "plstr.h" +#include "nsError.h" +#include "prerror.h" +#include "prerr.h" + +#if defined(XP_BEOS) +/* For DEBUGGER macros */ +#include +#endif + +#if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS) +/* for abort() and getenv() */ +#include +#endif + +#if defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) +#include +/* for nsTraceRefcnt::WalkTheStack() */ +#include "nsISupportsUtils.h" +#include "nsTraceRefcnt.h" + +#if defined(__GNUC__) && defined(__i386) +# define DebugBreak() { asm("int $3"); } +#else +# define DebugBreak() +#endif +#endif + +#if defined(XP_OS2) + /* Added definitions for DebugBreak() for 2 different OS/2 compilers. Doing + * the int3 on purpose for Visual Age so that a developer can step over the + * instruction if so desired. Not always possible if trapping due to exception + * handling IBM-AKR + */ + #define INCL_WINDIALOGS // need for WinMessageBox + #include + #include + + #if defined(DEBUG) + #if defined(XP_OS2_VACPP) + #include + #define DebugBreak() { _interrupt(3); } + #else + #define DebugBreak() { asm("int $3"); } + #endif + #else + #define DebugBreak() + #endif /* DEBUG */ +#endif /* XP_OS2 */ + +#if defined(_WIN32) +#include +#include +#elif defined(XP_MAC) + #define TEMP_MAC_HACK + + //------------------------ + #ifdef TEMP_MAC_HACK + #include + #include + #include + + // TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON + // LOGGING ON MACINTOSH + // At this moment, NSPR's logging is a no-op on Macintosh. + + #include + #include + + #undef PR_LOG + #undef PR_LogFlush + #define PR_LOG(module,level,args) dprintf args + #define PR_LogFlush() + static void dprintf(const char *format, ...) + { + va_list ap; + Str255 buffer; + + va_start(ap, format); + buffer[0] = std::vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap); + va_end(ap); + if (PL_strcasestr((char *)&buffer[1], "warning")) + printf("еее%s\n", (char*)buffer + 1); + else + DebugStr(buffer); + } + #endif // TEMP_MAC_HACK + //------------------------ +#elif defined(XP_UNIX) +#include +#endif + +/* + * Determine if debugger is present in windows. + */ +#if defined (_WIN32) + +typedef WINBASEAPI BOOL (WINAPI* LPFNISDEBUGGERPRESENT)(); +PRBool InDebugger() +{ + PRBool fReturn = PR_FALSE; + LPFNISDEBUGGERPRESENT lpfnIsDebuggerPresent = NULL; + HINSTANCE hKernel = LoadLibrary("Kernel32.dll"); + + if(hKernel) + { + lpfnIsDebuggerPresent = + (LPFNISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent"); + if(lpfnIsDebuggerPresent) + { + fReturn = (*lpfnIsDebuggerPresent)(); + } + FreeLibrary(hKernel); + } + + return fReturn; +} + +#endif /* WIN32*/ + +NS_IMPL_ISUPPORTS1(nsDebugImpl, nsIDebug) + +nsDebugImpl::nsDebugImpl() +{ +} + +nsDebugImpl::~nsDebugImpl() +{ +} + +/** + * Implementation of the nsDebug methods. Note that this code is + * always compiled in, in case some other module that uses it is + * compiled with debugging even if this library is not. + */ +static PRLogModuleInfo* gDebugLog; + +static void InitLog(void) +{ + if (0 == gDebugLog) { + gDebugLog = PR_NewLogModule("nsDebug"); + gDebugLog->level = PR_LOG_DEBUG; + } +} + + + +NS_IMETHODIMP +nsDebugImpl::Assertion(const char *aStr, const char *aExpr, const char *aFile, PRInt32 aLine) +{ + InitLog(); + + char buf[1000]; + PR_snprintf(buf, sizeof(buf), + "###!!! ASSERTION: %s: '%s', file %s, line %d", + aStr, aExpr, aFile, aLine); + + // Write out the assertion message to the debug log + PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); + PR_LogFlush(); + + // And write it out to the stderr + fprintf(stderr, "%s\n", buf); + fflush(stderr); + +#if defined(_WIN32) + char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + if (assertBehavior && strcmp(assertBehavior, "warn") == 0) + return NS_OK; + + if(!InDebugger()) + { + DWORD code = IDRETRY; + + /* Create the debug dialog out of process to avoid the crashes caused by + * Windows events leaking into our event loop from an in process dialog. + * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg). + * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792 + */ + PROCESS_INFORMATION pi; + STARTUPINFO si; + char executable[MAX_PATH]; + char* pName; + + memset(&pi, 0, sizeof(pi)); + + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + si.wShowWindow = SW_SHOW; + + if(GetModuleFileName(GetModuleHandle("xpcom.dll"), executable, MAX_PATH) && + NULL != (pName = strrchr(executable, '\\')) && + NULL != strcpy(pName+1, "windbgdlg.exe") && +#ifdef DEBUG_jband + (printf("Launching %s\n", executable), PR_TRUE) && +#endif + CreateProcess(executable, buf, NULL, NULL, PR_FALSE, + DETACHED_PROCESS | NORMAL_PRIORITY_CLASS, + NULL, NULL, &si, &pi) && + WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, INFINITE) && + GetExitCodeProcess(pi.hProcess, &code)) + { + CloseHandle(pi.hProcess); + } + + switch(code) + { + case IDABORT: + //This should exit us + raise(SIGABRT); + //If we are ignored exit this way.. + _exit(3); + break; + + case IDIGNORE: + return NS_OK; + // Fall Through + } + } +#endif + +#if defined(XP_OS2) + char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + if (assertBehavior && strcmp(assertBehavior, "warn") == 0) + return NS_OK; + + char msg[1200]; + PR_snprintf(msg, sizeof(msg), + "%s\n\nClick Cancel to Debug Application.\n" + "Click Enter to continue running the Application.", buf); + ULONG code = MBID_ERROR; + code = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, msg, + "nsDebug::Assertion", 0, + MB_ERROR | MB_ENTERCANCEL); + + /* It is possible that we are executing on a thread that doesn't have a + * message queue. In that case, the message won't appear, and code will + * be 0xFFFF. We'll give the user a chance to debug it by calling + * Break() + * Actually, that's a really bad idea since this happens a lot with threadsafe + * assertions and since it means that you can't actually run the debug build + * outside a debugger without it crashing constantly. + */ + if(( code == MBID_ENTER ) || (code == MBID_ERROR)) + { + return NS_OK; + // If Retry, Fall Through + } +#endif + + Break(aFile, aLine); + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Break(const char *aFile, PRInt32 aLine) +{ +#ifndef TEMP_MAC_HACK + // Write out the assertion message to the debug log + InitLog(); + + PR_LOG(gDebugLog, PR_LOG_ERROR, + ("###!!! Break: at file %s, line %d", aFile, aLine)); + PR_LogFlush(); + + fprintf(stderr, "Break: at file %s, line %d\n",aFile, aLine); fflush(stderr); + fflush(stderr); + +#if defined(_WIN32) +#ifdef _M_IX86 + ::DebugBreak(); +#endif +#elif defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) + fprintf(stderr, "\07"); + + char *assertBehavior = getenv("XPCOM_DEBUG_BREAK"); + + if (!assertBehavior) { + + // the default; nothing else to do + ; + + } else if ( strcmp(assertBehavior, "suspend")== 0 ) { + + // the suspend case is first because we wanna send the signal before + // other threads have had a chance to get too far from the state that + // caused this assertion (in case they happen to have been involved). + // + fprintf(stderr, "Suspending process; attach with the debugger.\n"); + kill(0, SIGSTOP); + + } else if ( strcmp(assertBehavior, "warn")==0 ) { + + // same as default; nothing else to do (see "suspend" case comment for + // why this compare isn't done as part of the default case) + // + ; + + } + else if ( strcmp(assertBehavior,"stack")==0 ) { + + // walk the stack + // + nsTraceRefcnt::WalkTheStack(stderr); + } + else if ( strcmp(assertBehavior,"abort")==0 ) { + + // same as UNIX_CRASH_ON_ASSERT + // + Abort(aFile, aLine); + + } else if ( strcmp(assertBehavior,"trap")==0 ) { + + DebugBreak(); + + } else { + + fprintf(stderr, "unrecognized value of XPCOM_DEBUG_BREAK env var!\n"); + + } + fflush(stderr); // this shouldn't really be necessary, i don't think, + // but maybe there's some lame stdio that buffers stderr + +#elif defined(XP_BEOS) + { +#ifdef UNIX_CRASH_ON_ASSERT + char buf[2000]; + sprintf(buf, "Break: at file %s, line %d", aFile, aLine); + DEBUGGER(buf); +#endif + } +#else + Abort(aFile, aLine); +#endif +#endif // TEMP_MAC_HACK + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Abort(const char *aFile, PRInt32 aLine) +{ + InitLog(); + + PR_LOG(gDebugLog, PR_LOG_ERROR, + ("###!!! Abort: at file %s, line %d", aFile, aLine)); + PR_LogFlush(); + fprintf(stderr, "\07 Abort\n"); fflush(stderr); + fflush(stderr); + +#if defined(_WIN32) +#ifdef _M_IX86 + long* __p = (long*) 0x7; + *__p = 0x7; +#else /* _M_ALPHA */ + PR_Abort(); +#endif +#elif defined(XP_MAC) + ExitToShell(); +#elif defined(XP_UNIX) + PR_Abort(); +#elif defined(XP_OS2) + DebugBreak(); + return NS_OK; +#elif defined(XP_BEOS) + { +#ifndef DEBUG_cls + char buf[2000]; + sprintf(buf, "Abort: at file %s, line %d", aFile, aLine); + DEBUGGER(buf); +#endif + } +#endif + return NS_OK; +} + +NS_IMETHODIMP +nsDebugImpl::Warning(const char* aMessage, + const char* aFile, PRIntn aLine) +{ + InitLog(); + + char buf[1000]; + PR_snprintf(buf, sizeof(buf), + "WARNING: %s, file %s, line %d", + aMessage, aFile, aLine); + + // Write out the warning message to the debug log + PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); + + // And write it out to the stdout + fprintf(stderr, "%s\n", buf); + fflush(stderr); + return NS_OK; +} + +NS_METHOD +nsDebugImpl::Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr) +{ + *aInstancePtr = nsnull; + nsIDebug* debug = new nsDebugImpl(); + if (!debug) + return NS_ERROR_OUT_OF_MEMORY; + + nsresult rv = debug->QueryInterface(aIID, aInstancePtr); + if (NS_FAILED(rv)) { + delete debug; + } + + return rv; +} + +//////////////////////////////////////////////////////////////////////////////// + +NS_COM nsresult +NS_ErrorAccordingToNSPR() +{ + PRErrorCode err = PR_GetError(); + switch (err) { + case PR_OUT_OF_MEMORY_ERROR: return NS_ERROR_OUT_OF_MEMORY; + case PR_WOULD_BLOCK_ERROR: return NS_BASE_STREAM_WOULD_BLOCK; + case PR_FILE_NOT_FOUND_ERROR: return NS_ERROR_FILE_NOT_FOUND; + case PR_READ_ONLY_FILESYSTEM_ERROR: return NS_ERROR_FILE_READ_ONLY; + case PR_NOT_DIRECTORY_ERROR: return NS_ERROR_FILE_NOT_DIRECTORY; + case PR_IS_DIRECTORY_ERROR: return NS_ERROR_FILE_IS_DIRECTORY; + case PR_LOOP_ERROR: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; + case PR_FILE_EXISTS_ERROR: return NS_ERROR_FILE_ALREADY_EXISTS; + case PR_FILE_IS_LOCKED_ERROR: return NS_ERROR_FILE_IS_LOCKED; + case PR_FILE_TOO_BIG_ERROR: return NS_ERROR_FILE_TOO_BIG; + case PR_NO_DEVICE_SPACE_ERROR: return NS_ERROR_FILE_NO_DEVICE_SPACE; + case PR_NAME_TOO_LONG_ERROR: return NS_ERROR_FILE_NAME_TOO_LONG; + case PR_DIRECTORY_NOT_EMPTY_ERROR: return NS_ERROR_FILE_DIR_NOT_EMPTY; + case PR_NO_ACCESS_RIGHTS_ERROR: return NS_ERROR_FILE_ACCESS_DENIED; + default: return NS_ERROR_FAILURE; + } +} + +//////////////////////////////////////////////////////////////////////////////// + diff --git a/xpcom/base/nsDebugImpl.h b/xpcom/base/nsDebugImpl.h new file mode 100644 index 00000000000..056183b9a18 --- /dev/null +++ b/xpcom/base/nsDebugImpl.h @@ -0,0 +1,59 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 MPL, 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 MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDebug.h" + +class nsDebugImpl : public nsIDebug +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIDEBUG + + nsDebugImpl(); + virtual ~nsDebugImpl(); + static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr); +}; + + +#define NS_DEBUG_CONTRACTID "@mozilla.org/xpcom/debug;1" +#define NS_DEBUG_CLASSNAME "nsDebug Interface" +#define NS_DEBUG_CID \ +{ /* a80b1fb3-aaf6-4852-b678-c27eb7a518af */ \ + 0xa80b1fb3, \ + 0xaaf6, \ + 0x4852, \ + {0xb6, 0x78, 0xc2, 0x7e, 0xb7, 0xa5, 0x18, 0xaf} \ +} diff --git a/xpcom/base/nsIDebug.idl b/xpcom/base/nsIDebug.idl new file mode 100644 index 00000000000..0ab3836e990 --- /dev/null +++ b/xpcom/base/nsIDebug.idl @@ -0,0 +1,62 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla 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/MPL/ + * + * 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 XPCOM + * + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 MPL, 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 MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsISupports.idl" + +/** + * @status UNDER_REVIEW + */ + +[scriptable, uuid(3bf0c3d7-3bd9-4cf2-a971-33572c503e1e)] +interface nsIDebug : nsISupports +{ + void assertion(in string aStr, + in string aExpr, + in string aFile, + in long aLine); + + void warning(in string aStr, + in string aFile, + in long aLine); + + void break(in string aFile, + in long aLine); + + void abort(in string aFile, + in long aLine); +}; + diff --git a/xpcom/base/nsISupportsObsolete.h b/xpcom/base/nsISupportsObsolete.h index 6ddc8febe0a..ff60154e53e 100644 --- a/xpcom/base/nsISupportsObsolete.h +++ b/xpcom/base/nsISupportsObsolete.h @@ -44,57 +44,6 @@ #define NS_INIT_REFCNT() NS_INIT_ISUPPORTS() - -#define NS_DECL_ISUPPORTS_EXPORTED \ -public: \ - NS_EXPORT NS_IMETHOD QueryInterface(REFNSIID aIID, \ - void** aInstancePtr); \ - NS_EXPORT NS_IMETHOD_(nsrefcnt) AddRef(void); \ - NS_EXPORT NS_IMETHOD_(nsrefcnt) Release(void); \ -protected: \ - nsrefcnt mRefCnt; \ - NS_DECL_OWNINGTHREAD \ -public: - - -#ifdef NS_DEBUG - -/* - * Adding this debug-only function as per bug #26803. If you are debugging - * and this function returns wrong refcounts, fix the objects |AddRef()| and - * |Release()| to do the right thing. - * - * Of course, this function is only available for debug builds. - */ - -inline -nsrefcnt -NS_DebugGetRefCount( nsISupports* obj ) - // Warning: don't apply this to an object whose refcount is - // |0| or not yet initialized ... it may be destroyed. - { - nsrefcnt ref_count = 0; - - if ( obj ) - { - // |AddRef()| and |Release()| are supposed to return - // the new refcount of the object - obj->AddRef(); - ref_count = obj->Release(); - // Can't use |NS_[ADDREF|RELEASE]| since (a) they _don't_ return - // the refcount, and (b) we don't want to log these guaranteed - // balanced calls. - - NS_ASSERTION(ref_count, - "Oops! Calling |NS_DebugGetRefCount()| probably just " - "destroyed this object."); - } - - return ref_count; - } - -#endif // NS_DEBUG - /** * Macro to free an array of pointers to nsISupports (or classes * derived from it). A convenience wrapper around diff --git a/xpcom/build/nsXPCOM.h b/xpcom/build/nsXPCOM.h index 97af1cd22f9..61fcf617466 100644 --- a/xpcom/build/nsXPCOM.h +++ b/xpcom/build/nsXPCOM.h @@ -51,7 +51,7 @@ class nsIFile; class nsILocalFile; class nsIDirectoryServiceProvider; class nsIMemory; - +class nsIDebug; /** * Initialises XPCOM. You must call this method before proceeding @@ -193,4 +193,8 @@ NS_NewNativeLocalFile(const nsACString &path, PRBool followLinks, nsILocalFile* *result); + +extern "C" NS_COM nsresult +NS_GetDebug(nsIDebug* *result); + #endif diff --git a/xpcom/build/nsXPCOMPrivate.h b/xpcom/build/nsXPCOMPrivate.h index 309a16f5219..dca1b984d29 100644 --- a/xpcom/build/nsXPCOMPrivate.h +++ b/xpcom/build/nsXPCOMPrivate.h @@ -79,6 +79,8 @@ typedef nsresult (PR_CALLBACK *GetComponentRegistrarFunc)(nsIComponentRegistrar* typedef nsresult (PR_CALLBACK *GetMemoryManagerFunc)(nsIMemory* *result); typedef nsresult (PR_CALLBACK *NewLocalFileFunc)(const nsAString &path, PRBool followLinks, nsILocalFile* *result); typedef nsresult (PR_CALLBACK *NewNativeLocalFileFunc)(const nsACString &path, PRBool followLinks, nsILocalFile* *result); + +typedef nsresult (PR_CALLBACK *GetDebugFunc)(nsIDebug* *result); // PRIVATE typedef nsresult (PR_CALLBACK *RegisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine, PRUint32 priority); typedef nsresult (PR_CALLBACK *UnregisterXPCOMExitRoutineFunc)(XPCOMExitRoutine exitRoutine); @@ -98,6 +100,10 @@ typedef struct XPCOMFunctions{ RegisterXPCOMExitRoutineFunc registerExitRoutine; UnregisterXPCOMExitRoutineFunc unregisterExitRoutine; + + // Added Post 1.4 + GetDebugFunc getDebug; + } XPCOMFunctions; typedef nsresult (PR_CALLBACK *GetFrozenFunctionsFunc)(XPCOMFunctions *entryPoints, const char* libraryPath); diff --git a/xpcom/build/nsXPComInit.cpp b/xpcom/build/nsXPComInit.cpp index 272e7a1c139..d9ff1e70c7a 100644 --- a/xpcom/build/nsXPComInit.cpp +++ b/xpcom/build/nsXPComInit.cpp @@ -49,6 +49,7 @@ #include "nsBinaryStream.h" #include "nsMemoryImpl.h" +#include "nsDebugImpl.h" #include "nsErrorService.h" #include "nsByteBuffer.h" @@ -275,10 +276,8 @@ static PRBool gXPCOMHasGlobalsBeenInitalized = PR_TRUE; &NS_CLASSINFO_NAME(Class) } static const nsModuleComponentInfo components[] = { -// ugh -#define NS_MEMORY_CONTRACTID "@mozilla.org/xpcom/memory-service;1" -#define NS_MEMORY_CLASSNAME "Global Memory Service" COMPONENT(MEMORY, nsMemoryImpl::Create), + COMPONENT(DEBUG, nsDebugImpl::Create), #define NS_ERRORSERVICE_CLASSNAME NS_ERRORSERVICE_NAME COMPONENT(ERRORSERVICE, nsErrorService::Create), @@ -371,6 +370,22 @@ nsresult NS_COM NS_GetMemoryManager(nsIMemory* *result) return rv; } +// gDebug will be freed during shutdown. +static nsIDebug* gDebug = nsnull; +nsresult NS_COM NS_GetDebug(nsIDebug** result) +{ + nsresult rv = NS_OK; + if (!gDebug) + { + rv = nsDebugImpl::Create(nsnull, + NS_GET_IID(nsIDebug), + (void**)&gDebug); + } + NS_IF_ADDREF(*result = gDebug); + return rv; +} + + nsresult NS_COM NS_InitXPCOM(nsIServiceManager* *result, nsIFile* binDirectory) { @@ -770,6 +785,8 @@ nsresult NS_COM NS_ShutdownXPCOM(nsIServiceManager* servMgr) NS_ShutdownLeakDetector(); #endif + NS_IF_RELEASE(gDebug); + gXPCOMHasGlobalsBeenInitalized = PR_FALSE; return NS_OK; } @@ -839,6 +856,12 @@ NS_GetFrozenFunctions(XPCOMFunctions *functions, const char* libraryPath) return NS_ERROR_FAILURE; } + functions->getDebug = (GetDebugFunc) PR_FindSymbol(xpcomLib, "NS_GetDebug"); + if (! functions->unregisterExitRoutine) { + PR_UnloadLibrary(xpcomLib); + return NS_ERROR_FAILURE; + } + PR_UnloadLibrary(xpcomLib); // the library is refcnt'ed above by the caller. xpcomLib = nsnull; diff --git a/xpcom/components/nsComponentManager.h b/xpcom/components/nsComponentManager.h index 4ac96f10b85..d3ee4343c50 100644 --- a/xpcom/components/nsComponentManager.h +++ b/xpcom/components/nsComponentManager.h @@ -140,19 +140,14 @@ public: nsresult WritePersistentRegistry(); nsresult ReadPersistentRegistry(); -public: nsresult Shutdown(void); nsresult FreeServices(); - friend class nsFactoryEntry; - friend class nsServiceManager; - - friend nsresult + nsresult NS_GetService(const char *aContractID, const nsIID& aIID, PRBool aDontCreate, nsISupports** result); -protected: nsresult RegisterComponentCommon(const nsCID &aClass, const char *aClassName, const char *aContractID, @@ -196,18 +191,15 @@ protected: // there was an error int AddLoaderType(const char *typeStr); -public: int GetLoaderCount() { return mNLoaderData + 1; } // registers only the files in spec's location by loaders other than the // native loader. This is an optimization method only. nsresult AutoRegisterNonNativeComponents(nsIFile* spec); - -private: nsresult AutoRegisterImpl(PRInt32 when, nsIFile *inDirSpec, PRBool fileIsCompDir=PR_TRUE); + nsresult RemoveEntries(nsIFile* file); -protected: PLDHashTable mFactories; PLDHashTable mContractIDs; PRMonitor* mMon; diff --git a/xpcom/glue/nsDebug.cpp b/xpcom/glue/nsDebug.cpp index b601221cfb9..477ee3d15f8 100644 --- a/xpcom/glue/nsDebug.cpp +++ b/xpcom/glue/nsDebug.cpp @@ -1,529 +1,109 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* - * 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/ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * - * 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 contents of this file are subject to the Mozilla 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/MPL/ * - * The Original Code is mozilla.org code. + * 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 Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1998 Netscape Communications Corporation. All - * Rights Reserved. + * The Original Code is XPCOM * - * Contributor(s): - * IBM Corp. - * Henry Sobotka - */ + * The Initial Developer of the Original Code is Doug Turner + * + * Portions created by the Initial Developer are Copyright (C) 2003 + * 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 MPL, 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 MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +#include "nsXPCOM.h" +#include "nsXPCOMPrivate.h" +#include "nsCOMPtr.h" +#include "nsIServiceManager.h" #include "nsDebug.h" -#include "prprf.h" -#include "prlog.h" -#include "prinit.h" -#include "plstr.h" -#include "nsError.h" -#include "prerror.h" -#include "prerr.h" +#include "nsDebugImpl.h" -#if defined(XP_BEOS) -/* For DEBUGGER macros */ -#include -#endif +static nsIDebug* gDebugObject = nsnull; -#if defined(XP_UNIX) || defined(_WIN32) || defined(XP_OS2) || defined(XP_BEOS) -/* for abort() and getenv() */ -#include -#endif - -#if defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) -#include -/* for nsTraceRefcnt::WalkTheStack() */ -#include "nsISupportsUtils.h" -#ifndef MOZILLA_STRICT_API -#include "nsTraceRefcnt.h" -#endif - -#if defined(__GNUC__) && defined(__i386) -# define DebugBreak() { asm("int $3"); } -#else -# define DebugBreak() -#endif -#endif - -#if defined(XP_OS2) - /* Added definitions for DebugBreak() for 2 different OS/2 compilers. Doing - * the int3 on purpose for Visual Age so that a developer can step over the - * instruction if so desired. Not always possible if trapping due to exception - * handling IBM-AKR - */ - #define INCL_WINDIALOGS // need for WinMessageBox - #include - #include - - #if defined(DEBUG) - #if defined(XP_OS2_VACPP) - #include - #define DebugBreak() { _interrupt(3); } - #else - #define DebugBreak() { asm("int $3"); } - #endif - #else - #define DebugBreak() - #endif /* DEBUG */ -#endif /* XP_OS2 */ - -#if defined(_WIN32) -#include -#include -#elif defined(XP_MAC) - #define TEMP_MAC_HACK - - //------------------------ - #ifdef TEMP_MAC_HACK - #include - #include - #include - - // TEMPORARY UNTIL WE HAVE MACINTOSH ENVIRONMENT VARIABLES THAT CAN TURN ON - // LOGGING ON MACINTOSH - // At this moment, NSPR's logging is a no-op on Macintosh. - - #include - #include - - #undef PR_LOG - #undef PR_LogFlush - #define PR_LOG(module,level,args) dprintf args - #define PR_LogFlush() - static void dprintf(const char *format, ...) - { - va_list ap; - Str255 buffer; - - va_start(ap, format); - buffer[0] = std::vsnprintf((char *)buffer + 1, sizeof(buffer) - 1, format, ap); - va_end(ap); - if (PL_strcasestr((char *)&buffer[1], "warning")) - printf("еее%s\n", (char*)buffer + 1); - else - DebugStr(buffer); - } - #endif // TEMP_MAC_HACK - //------------------------ -#elif defined(XP_UNIX) -#include -#endif - -/* - * Determine if debugger is present in windows. - */ -#if defined (_WIN32) - -typedef WINBASEAPI BOOL (WINAPI* LPFNISDEBUGGERPRESENT)(); -PRBool InDebugger() +static NS_METHOD FreeDebugObject(void) { - PRBool fReturn = PR_FALSE; - LPFNISDEBUGGERPRESENT lpfnIsDebuggerPresent = NULL; - HINSTANCE hKernel = LoadLibrary("Kernel32.dll"); - - if(hKernel) - { - lpfnIsDebuggerPresent = - (LPFNISDEBUGGERPRESENT)GetProcAddress(hKernel, "IsDebuggerPresent"); - if(lpfnIsDebuggerPresent) - { - fReturn = (*lpfnIsDebuggerPresent)(); - } - FreeLibrary(hKernel); - } - - return fReturn; + NS_IF_RELEASE(gDebugObject); + return NS_OK; } -#endif /* WIN32*/ +#define ENSURE_DEBUGOBJECT \ + (gDebugObject ? PR_TRUE : (PRBool)(SetupDebugObject() != nsnull)) - -/** - * Implementation of the nsDebug methods. Note that this code is - * always compiled in, in case some other module that uses it is - * compiled with debugging even if this library is not. - */ -static PRLogModuleInfo* gDebugLog; - -static void InitLog(void) +static nsIDebug* SetupDebugObject() { - if (0 == gDebugLog) { - gDebugLog = PR_NewLogModule("nsDebug"); - gDebugLog->level = PR_LOG_DEBUG; - } + NS_GetDebug(&gDebugObject); + if (gDebugObject) + NS_RegisterXPCOMExitRoutine(FreeDebugObject, 0); + return gDebugObject; +} + +#ifdef XPCOM_GLUE +nsresult GlueStartupDebug() +{ + NS_GetDebug(&gDebugObject); + if (!gDebugObject) + return NS_ERROR_FAILURE; + return NS_OK; +} + +void GlueShutdownDebug() +{ + NS_IF_RELEASE(gDebugObject); +} +#endif + +NS_COM void nsDebug::Abort(const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + + gDebugObject->Abort(aFile, aLine); +} + +NS_COM void nsDebug::Break(const char* aFile, PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + + gDebugObject->Break(aFile, aLine); +} + +NS_COM void nsDebug::Warning(const char* aStr, + const char* aFile, + PRIntn aLine) +{ + if (!ENSURE_DEBUGOBJECT) + return; + gDebugObject->Warning(aStr, aFile, aLine); } NS_COM void nsDebug::Assertion(const char* aStr, const char* aExpr, const char* aFile, PRIntn aLine) -{ - InitLog(); - - char buf[1000]; - PR_snprintf(buf, sizeof(buf), - "###!!! ASSERTION: %s: '%s', file %s, line %d", - aStr, aExpr, aFile, aLine); - - // Write out the assertion message to the debug log - PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); - PR_LogFlush(); - - // And write it out to the stderr - fprintf(stderr, "%s\n", buf); - fflush(stderr); - -#if defined(_WIN32) - char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); - if (assertBehavior && strcmp(assertBehavior, "warn") == 0) - return; - - if(!InDebugger()) - { - DWORD code = IDRETRY; - - /* Create the debug dialog out of process to avoid the crashes caused by - * Windows events leaking into our event loop from an in process dialog. - * We do this by launching windbgdlg.exe (built in xpcom/windbgdlg). - * See http://bugzilla.mozilla.org/show_bug.cgi?id=54792 - */ - PROCESS_INFORMATION pi; - STARTUPINFO si; - char executable[MAX_PATH]; - char* pName; - - memset(&pi, 0, sizeof(pi)); - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - si.wShowWindow = SW_SHOW; - - if(GetModuleFileName(GetModuleHandle("xpcom.dll"), executable, MAX_PATH) && - NULL != (pName = strrchr(executable, '\\')) && - NULL != strcpy(pName+1, "windbgdlg.exe") && -#ifdef DEBUG_jband - (printf("Launching %s\n", executable), PR_TRUE) && -#endif - CreateProcess(executable, buf, NULL, NULL, PR_FALSE, - DETACHED_PROCESS | NORMAL_PRIORITY_CLASS, - NULL, NULL, &si, &pi) && - WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, INFINITE) && - GetExitCodeProcess(pi.hProcess, &code)) - { - CloseHandle(pi.hProcess); - } - - switch(code) - { - case IDABORT: - //This should exit us - raise(SIGABRT); - //If we are ignored exit this way.. - _exit(3); - break; - - case IDIGNORE: - return; - // Fall Through - } - } -#endif - -#if defined(XP_OS2) - char* assertBehavior = getenv("XPCOM_DEBUG_BREAK"); - if (assertBehavior && strcmp(assertBehavior, "warn") == 0) - return; - - char msg[1200]; - PR_snprintf(msg, sizeof(msg), - "%s\n\nClick Cancel to Debug Application.\n" - "Click Enter to continue running the Application.", buf); - ULONG code = MBID_ERROR; - code = WinMessageBox(HWND_DESKTOP, HWND_DESKTOP, msg, - "nsDebug::Assertion", 0, - MB_ERROR | MB_ENTERCANCEL); - - /* It is possible that we are executing on a thread that doesn't have a - * message queue. In that case, the message won't appear, and code will - * be 0xFFFF. We'll give the user a chance to debug it by calling - * Break() - * Actually, that's a really bad idea since this happens a lot with threadsafe - * assertions and since it means that you can't actually run the debug build - * outside a debugger without it crashing constantly. - */ - if(( code == MBID_ENTER ) || (code == MBID_ERROR)) - { - return; - // If Retry, Fall Through - } -#endif - - Break(aFile, aLine); +{ + if (!ENSURE_DEBUGOBJECT) + return; + gDebugObject->Assertion(aStr, aExpr, aFile, aLine); } - -NS_COM void nsDebug::Break(const char* aFile, PRIntn aLine) -{ -#ifndef TEMP_MAC_HACK - // Write out the assertion message to the debug log - InitLog(); - - PR_LOG(gDebugLog, PR_LOG_ERROR, - ("###!!! Break: at file %s, line %d", aFile, aLine)); - PR_LogFlush(); - - fprintf(stderr, "Break: at file %s, line %d\n",aFile, aLine); fflush(stderr); - fflush(stderr); - -#if defined(_WIN32) -#ifdef _M_IX86 - ::DebugBreak(); -#endif -#elif defined(XP_UNIX) && !defined(UNIX_CRASH_ON_ASSERT) - fprintf(stderr, "\07"); - - char *assertBehavior = getenv("XPCOM_DEBUG_BREAK"); - - if (!assertBehavior) { - - // the default; nothing else to do - ; - - } else if ( strcmp(assertBehavior, "suspend")== 0 ) { - - // the suspend case is first because we wanna send the signal before - // other threads have had a chance to get too far from the state that - // caused this assertion (in case they happen to have been involved). - // - fprintf(stderr, "Suspending process; attach with the debugger.\n"); - kill(0, SIGSTOP); - - } else if ( strcmp(assertBehavior, "warn")==0 ) { - - // same as default; nothing else to do (see "suspend" case comment for - // why this compare isn't done as part of the default case) - // - ; - - } -#ifndef XPCOM_GLUE - else if ( strcmp(assertBehavior,"stack")==0 ) { - - // walk the stack - // - nsTraceRefcnt::WalkTheStack(stderr); - - } -#endif - else if ( strcmp(assertBehavior,"abort")==0 ) { - - // same as UNIX_CRASH_ON_ASSERT - // - Abort(aFile, aLine); - - } else if ( strcmp(assertBehavior,"trap")==0 ) { - - DebugBreak(); - - } else { - - fprintf(stderr, "unrecognized value of XPCOM_DEBUG_BREAK env var!\n"); - - } - fflush(stderr); // this shouldn't really be necessary, i don't think, - // but maybe there's some lame stdio that buffers stderr - -#elif defined(XP_BEOS) - { -#ifdef UNIX_CRASH_ON_ASSERT - char buf[2000]; - sprintf(buf, "Break: at file %s, line %d", aFile, aLine); - DEBUGGER(buf); -#endif - } -#else - Abort(aFile, aLine); -#endif -#endif // TEMP_MAC_HACK -} - -NS_COM void nsDebug::Warning(const char* aMessage, - const char* aFile, PRIntn aLine) -{ - InitLog(); - - char buf[1000]; - PR_snprintf(buf, sizeof(buf), - "WARNING: %s, file %s, line %d", - aMessage, aFile, aLine); - - // Write out the warning message to the debug log - PR_LOG(gDebugLog, PR_LOG_ERROR, ("%s", buf)); - - // And write it out to the stdout - fprintf(stderr, "%s\n", buf); - fflush(stderr); -} - -//**************** All Dead Code Below -// Don't use these! -NS_COM void nsDebug::AbortIfFalse(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine) -{ - Assertion(aStr, aExpr, aFile, aLine); -} - -NS_COM void nsDebug::WarnIfFalse(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine) -{ - Assertion(aStr, aExpr, aFile, aLine); -} - -NS_COM void nsDebug::Abort(const char* aFile, PRIntn aLine) -{ - InitLog(); - - PR_LOG(gDebugLog, PR_LOG_ERROR, - ("###!!! Abort: at file %s, line %d", aFile, aLine)); - PR_LogFlush(); - fprintf(stderr, "\07 Abort\n"); fflush(stderr); - fflush(stderr); - -#if defined(_WIN32) -#ifdef _M_IX86 - long* __p = (long*) 0x7; - *__p = 0x7; -#else /* _M_ALPHA */ - PR_Abort(); -#endif -#elif defined(XP_MAC) - ExitToShell(); -#elif defined(XP_UNIX) - PR_Abort(); -#elif defined(XP_OS2) - DebugBreak(); - return; -#elif defined(XP_BEOS) - { -#ifndef DEBUG_cls - char buf[2000]; - sprintf(buf, "Abort: at file %s, line %d", aFile, aLine); - DEBUGGER(buf); -#endif - } -#endif -} - - -NS_COM void nsDebug::PreCondition(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine) -{ - Assertion(aStr, aExpr, aFile, aLine); -} - -NS_COM void nsDebug::PostCondition(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine) -{ - Assertion(aStr, aExpr, aFile, aLine); -} - -NS_COM void nsDebug::NotYetImplemented(const char* aMessage, - const char* aFile, PRIntn aLine) -{ - Assertion(aMessage, "NotYetImplemented", aFile, aLine); -} - -NS_COM void nsDebug::NotReached(const char* aMessage, - const char* aFile, PRIntn aLine) -{ - Assertion(aMessage, "Not Reached", aFile, aLine); -} - -NS_COM void nsDebug::Error(const char* aMessage, - const char* aFile, PRIntn aLine) -{ - Assertion(aMessage, "Error", aFile, aLine); -} - -//////////////////////////////////////////////////////////////////////////////// - -NS_COM nsresult -NS_ErrorAccordingToNSPR() -{ - PRErrorCode err = PR_GetError(); - switch (err) { - case PR_OUT_OF_MEMORY_ERROR: return NS_ERROR_OUT_OF_MEMORY; - case PR_WOULD_BLOCK_ERROR: return NS_BASE_STREAM_WOULD_BLOCK; - case PR_FILE_NOT_FOUND_ERROR: return NS_ERROR_FILE_NOT_FOUND; - case PR_READ_ONLY_FILESYSTEM_ERROR: return NS_ERROR_FILE_READ_ONLY; - case PR_NOT_DIRECTORY_ERROR: return NS_ERROR_FILE_NOT_DIRECTORY; - case PR_IS_DIRECTORY_ERROR: return NS_ERROR_FILE_IS_DIRECTORY; - case PR_LOOP_ERROR: return NS_ERROR_FILE_UNRESOLVABLE_SYMLINK; - case PR_FILE_EXISTS_ERROR: return NS_ERROR_FILE_ALREADY_EXISTS; - case PR_FILE_IS_LOCKED_ERROR: return NS_ERROR_FILE_IS_LOCKED; - case PR_FILE_TOO_BIG_ERROR: return NS_ERROR_FILE_TOO_BIG; - case PR_NO_DEVICE_SPACE_ERROR: return NS_ERROR_FILE_NO_DEVICE_SPACE; - case PR_NAME_TOO_LONG_ERROR: return NS_ERROR_FILE_NAME_TOO_LONG; - case PR_DIRECTORY_NOT_EMPTY_ERROR: return NS_ERROR_FILE_DIR_NOT_EMPTY; - case PR_NO_ACCESS_RIGHTS_ERROR: return NS_ERROR_FILE_ACCESS_DENIED; - default: return NS_ERROR_FAILURE; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// This wrapper around PR_GetCurrentThread is simply here for debug builds so -// that clients linking with xpcom don't also have to link with nspr explicitly. - -#if defined(NS_DEBUG) - -#include "nsISupportsUtils.h" -#include "prthread.h" - -extern "C" NS_COM void* NS_CurrentThread(void); -extern "C" NS_COM void NS_CheckThreadSafe(void* owningThread, const char* msg); - -void* -NS_CurrentThread(void) -{ - void* th = PR_GetCurrentThread(); - return th; -} - -/* - * DON'T TOUCH THAT DIAL... - * For now, we're making the thread-safety checking be on by default which, yes, slows - * down linux a bit... but we're doing it so that everybody has a chance to exercise - * their code a good deal before the beta. After we branch, we'll turn this back off - * and then you can enable it explicitly by setting XPCOM_CHECK_THREADSAFE. This will - * let you verify the thread-safety of your classes without impacting everyone all the - * time. - */ -static PRBool gCheckThreadSafeDefault = PR_TRUE; // READ THE ABOVE COMMENT FIRST! - -void -NS_CheckThreadSafe(void* owningThread, const char* msg) -{ - static int check = -1; - if (check == -1) { - const char *eVar = getenv("XPCOM_CHECK_THREADSAFE"); - if (eVar && *eVar == '0') - check = 0; - else - check = gCheckThreadSafeDefault || eVar != 0; - } - if (check) { - NS_ASSERTION(owningThread == NS_CurrentThread(), msg); - } -} - -#endif // !(defined(NS_DEBUG) - -//////////////////////////////////////////////////////////////////////////////// diff --git a/xpcom/glue/nsDebug.h b/xpcom/glue/nsDebug.h index 91f19df4e2d..6c816e41cef 100644 --- a/xpcom/glue/nsDebug.h +++ b/xpcom/glue/nsDebug.h @@ -61,54 +61,12 @@ class nsDebug { public: - /** - * When called, this will log a fatal abort message (to stderr and - * to the NSPR log file) and then abort the program. This is - * used by the NS_ABORT_IF_FALSE macro below when debugging is - * enabled. - */ - static NS_COM void AbortIfFalse(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine); /** - * Log a warning message when an expression is not true. Used by - * the NS_WARN_IF_FALSE macro below when debugging is enabled. - * - * The default behavior of this method is print a message to stderr - * and to log an event in the NSPR log file. + * Log a warning message to the debug log. */ - static NS_COM void WarnIfFalse(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine); - - /** - * Enable flying a warning message box (if the platform supports - * such a thing) when WarnIfFalse is called in addition to - * the usual printing to stderr and the NSPR log file. - * - * If aOnOff is PR_TRUE then the message-box is enabled, otherwise - * the message-box is disabled. - * - * The default state for the message-box enable is "off". - * - * Note also that the implementation looks at an environment - * variable (for those platforms that have environment variables...) - * called MOZ_WARNING_MESSAGE_BOX that when set enables the - * warning message box by default. - */ - static NS_COM void SetWarningMessageBoxEnable(PRBool aOnOff); - - /** - * Get the current setting of the message-box enable. - */ - static NS_COM PRBool GetWarningMessageBoxEnable(void); - - // Note: Methods below this line are the old ones; please start using - // the new ones. The old ones will be removed eventually! - - ////////////////////////////////////////////////////////////////////// - - // XXX add in log controls here - // XXX probably want printf type arguments + static NS_COM void Warning(const char* aMessage, + const char* aFile, PRIntn aLine); /** * Abort the executing program. This works on all architectures. @@ -120,47 +78,11 @@ public: */ static NS_COM void Break(const char* aFile, PRIntn aLine); - /** - * Log a pre-condition message to the debug log - */ - static NS_COM void PreCondition(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine); - - /** - * Log a post-condition message to the debug log - */ - static NS_COM void PostCondition(const char* aStr, const char* aExpr, - const char* aFile, PRIntn aLine); - /** * Log an assertion message to the debug log */ static NS_COM void Assertion(const char* aStr, const char* aExpr, const char* aFile, PRIntn aLine); - - /** - * Log a not-yet-implemented message to the debug log - */ - static NS_COM void NotYetImplemented(const char* aMessage, - const char* aFile, PRIntn aLine); - - /** - * Log a not-reached message to the debug log - */ - static NS_COM void NotReached(const char* aMessage, - const char* aFile, PRIntn aLine); - - /** - * Log an error message to the debug log. This call returns. - */ - static NS_COM void Error(const char* aMessage, - const char* aFile, PRIntn aLine); - - /** - * Log a warning message to the debug log. - */ - static NS_COM void Warning(const char* aMessage, - const char* aFile, PRIntn aLine); }; #ifdef DEBUG @@ -184,7 +106,7 @@ public: #define NS_ABORT_IF_FALSE(_expr, _msg) \ PR_BEGIN_MACRO \ if (!(_expr)) { \ - nsDebug::AbortIfFalse(_msg, #_expr, __FILE__, __LINE__);\ + nsDebug::Assertion(_msg, #_expr, __FILE__, __LINE__); \ } \ PR_END_MACRO @@ -199,7 +121,7 @@ public: #define NS_WARN_IF_FALSE(_expr,_msg) \ PR_BEGIN_MACRO \ if (!(_expr)) { \ - nsDebug::WarnIfFalse(_msg, #_expr, __FILE__, __LINE__); \ + nsDebug::Assertion(_msg, #_expr, __FILE__, __LINE__); \ } \ PR_END_MACRO @@ -210,7 +132,7 @@ public: #define NS_PRECONDITION(expr, str) \ PR_BEGIN_MACRO \ if (!(expr)) { \ - nsDebug::PreCondition(str, #expr, __FILE__, __LINE__); \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ } \ PR_END_MACRO @@ -232,7 +154,7 @@ public: #define NS_POSTCONDITION(expr, str) \ PR_BEGIN_MACRO \ if (!(expr)) { \ - nsDebug::PostCondition(str, #expr, __FILE__, __LINE__); \ + nsDebug::Assertion(str, #expr, __FILE__, __LINE__); \ } \ PR_END_MACRO @@ -241,20 +163,20 @@ public: * an attempt was made to execute some unimplimented functionality. */ #define NS_NOTYETIMPLEMENTED(str) \ - nsDebug::NotYetImplemented(str, __FILE__, __LINE__) + nsDebug::Assertion(str, "NotYetImplemented", __FILE__, __LINE__) /** * This macros triggers a program failure if executed. It indicates that * an attempt was made to execute some unimplimented functionality. */ #define NS_NOTREACHED(str) \ - nsDebug::NotReached(str, __FILE__, __LINE__) + nsDebug::Assertion(str, "Not Reached", __FILE__, __LINE__) /** * Log an error message. */ #define NS_ERROR(str) \ - nsDebug::Error(str, __FILE__, __LINE__) + nsDebug::Assertion(str, "Error", __FILE__, __LINE__) /** * Log a warning message. @@ -348,4 +270,7 @@ public: /////////////////////////////////////////////////////////////////////////////// +#define NS_CheckThreadSafe(owningThread, msg) \ + NS_ASSERTION(owningThread == PR_GetCurrentThread(), msg) + #endif /* nsDebug_h___ */ diff --git a/xpcom/glue/nsISupportsImpl.h b/xpcom/glue/nsISupportsImpl.h index 793ca514109..5e5b9ba3944 100644 --- a/xpcom/glue/nsISupportsImpl.h +++ b/xpcom/glue/nsISupportsImpl.h @@ -45,7 +45,10 @@ #include "nsISupportsBase.h" #endif -#include "pratom.h" /* needed for PR_AtomicIncrement and PR_AtomicDecrement */ +#include "prthread.h" /* needed for thread-safety checks */ +#include "pratom.h" /* needed for PR_AtomicIncrement and PR_AtomicDecrement */ + +#include "nsDebug.h" #ifdef XPCOM_GLUE // nsTraceRefcnt needs a cleaning... @@ -65,15 +68,11 @@ //////////////////////////////////////////////////////////////////////////////// // Macros to help detect thread-safety: -#if defined(NS_DEBUG) && !defined(XPCOM_GLUE) - -extern "C" NS_COM void* NS_CurrentThread(void); -extern "C" NS_COM void NS_CheckThreadSafe(void* owningThread, - const char* msg); +#if defined(NS_DEBUG) class nsAutoOwningThread { public: - nsAutoOwningThread() { mThread = NS_CurrentThread(); } + nsAutoOwningThread() { mThread = PR_GetCurrentThread(); } void *GetThread() const { return mThread; } private: diff --git a/xpcom/glue/standalone/nsXPCOMGlue.cpp b/xpcom/glue/standalone/nsXPCOMGlue.cpp index d8101776eee..a372f731348 100644 --- a/xpcom/glue/standalone/nsXPCOMGlue.cpp +++ b/xpcom/glue/standalone/nsXPCOMGlue.cpp @@ -46,10 +46,10 @@ static PRLibrary *xpcomLib = nsnull; static XPCOMFunctions *xpcomFunctions = nsnull; static nsIMemory* xpcomMemory = nsnull; -//#define XPCOM_GLUE_NO_DYNAMIC_LOADING - extern nsresult GlueStartupMemory(); extern void GlueShutdownMemory(); +extern nsresult GlueStartupDebug(); +extern void GlueShutdownDebug(); extern "C" nsresult NS_COM XPCOMGlueStartup(const char* xpcomFile) @@ -98,8 +98,29 @@ nsresult NS_COM XPCOMGlueStartup(const char* xpcomFile) return NS_ERROR_FAILURE; } + rv = GlueStartupDebug(); + + if (NS_FAILED(rv)) { + free(xpcomFunctions); + xpcomFunctions = nsnull; + PR_UnloadLibrary(xpcomLib); + xpcomLib = nsnull; + return NS_ERROR_FAILURE; + } + // startup the nsMemory - return GlueStartupMemory(); + rv = GlueStartupMemory(); + + if (NS_FAILED(rv)) { + GlueShutdownDebug(); + + free(xpcomFunctions); + xpcomFunctions = nsnull; + PR_UnloadLibrary(xpcomLib); + xpcomLib = nsnull; + return NS_ERROR_FAILURE; + } + #endif } @@ -116,6 +137,8 @@ nsresult NS_COM XPCOMGlueShutdown() GlueShutdownMemory(); + GlueShutdownDebug(); + if (xpcomLib) { PR_UnloadLibrary(xpcomLib); xpcomLib = nsnull; @@ -207,6 +230,15 @@ NS_UnregisterXPCOMExitRoutine(XPCOMExitRoutine exitRoutine) return NS_ERROR_NOT_INITIALIZED; return xpcomFunctions->unregisterExitRoutine(exitRoutine); } + +extern "C" NS_COM nsresult +NS_GetDebug(nsIDebug* *result) +{ + if (!xpcomFunctions) + return NS_ERROR_NOT_INITIALIZED; + return xpcomFunctions->getDebug(result); +} + #endif // #ifndef XPCOM_GLUE_NO_DYNAMIC_LOADING