summaryrefslogtreecommitdiff
path: root/mozglue
diff options
context:
space:
mode:
authorBrian Smith <brian@dbsoft.org>2022-04-26 11:07:23 -0500
committerBrian Smith <brian@dbsoft.org>2022-04-26 11:07:23 -0500
commit9e2a89c71ddf67975da35eb100673f6b5546f292 (patch)
treeca7b972015f5ad2388d416fa0ec8f506cc9fb8d6 /mozglue
parent68d1c14bdf79d1c536ae05a4ce33fd9601c277eb (diff)
downloaduxp-9e2a89c71ddf67975da35eb100673f6b5546f292.tar.gz
Issue #1829 - Revert "Issue #1751 -- Remove XP_DARWIN"
This reverts commit 3d671e4275c73a1484c72713304c6e04ec4ffc7c.
Diffstat (limited to 'mozglue')
-rw-r--r--mozglue/misc/StackWalk.cpp116
-rw-r--r--mozglue/misc/TimeStamp.h9
2 files changed, 123 insertions, 2 deletions
diff --git a/mozglue/misc/StackWalk.cpp b/mozglue/misc/StackWalk.cpp
index 7d853b075d..8925ae9488 100644
--- a/mozglue/misc/StackWalk.cpp
+++ b/mozglue/misc/StackWalk.cpp
@@ -29,10 +29,17 @@ static CriticalAddress gCriticalAddress;
#define _GNU_SOURCE
#endif
-#if defined(HAVE_DLOPEN)
+#if defined(HAVE_DLOPEN) || defined(XP_DARWIN)
#include <dlfcn.h>
#endif
+#if (defined(XP_DARWIN) && \
+ (defined(__i386) || defined(__ppc__) || defined(HAVE__UNWIND_BACKTRACE)))
+#define MOZ_STACKWALK_SUPPORTS_MACOSX 1
+#else
+#define MOZ_STACKWALK_SUPPORTS_MACOSX 0
+#endif
+
#if (defined(linux) && \
((defined(__GNUC__) && (defined(__i386) || defined(PPC))) || \
defined(HAVE__UNWIND_BACKTRACE)))
@@ -51,18 +58,121 @@ static CriticalAddress gCriticalAddress;
extern MOZ_EXPORT void* __libc_stack_end; // from ld-linux.so
#endif
+#if MOZ_STACKWALK_SUPPORTS_MACOSX
+#include <pthread.h>
+#include <sys/errno.h>
+#ifdef MOZ_WIDGET_COCOA
+#include <CoreServices/CoreServices.h>
+#endif
+
+typedef void
+malloc_logger_t(uint32_t aType,
+ uintptr_t aArg1, uintptr_t aArg2, uintptr_t aArg3,
+ uintptr_t aResult, uint32_t aNumHotFramesToSkip);
+extern malloc_logger_t* malloc_logger;
+
+static void
+stack_callback(uint32_t aFrameNumber, void* aPc, void* aSp, void* aClosure)
+{
+ const char* name = static_cast<char*>(aClosure);
+ Dl_info info;
+
+ // On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
+ // stack shows up as having two pthread_cond_wait$UNIX2003 frames. The
+ // correct one is the first that we find on our way up, so the
+ // following check for gCriticalAddress.mAddr is critical.
+ if (gCriticalAddress.mAddr || dladdr(aPc, &info) == 0 ||
+ !info.dli_sname || strcmp(info.dli_sname, name) != 0) {
+ return;
+ }
+ gCriticalAddress.mAddr = aPc;
+}
+
+static void
+my_malloc_logger(uint32_t aType,
+ uintptr_t aArg1, uintptr_t aArg2, uintptr_t aArg3,
+ uintptr_t aResult, uint32_t aNumHotFramesToSkip)
+{
+ static bool once = false;
+ if (once) {
+ return;
+ }
+ once = true;
+
+ // On Leopard dladdr returns the wrong value for "new_sem_from_pool". The
+ // stack shows up as having two pthread_cond_wait$UNIX2003 frames.
+ const char* name = "new_sem_from_pool";
+ MozStackWalk(stack_callback, /* skipFrames */ 0, /* maxFrames */ 0,
+ const_cast<char*>(name), 0, nullptr);
+}
+
+// This is called from NS_LogInit() and from the stack walking functions, but
+// only the first call has any effect. We need to call this function from both
+// places because it must run before any mutexes are created, and also before
+// any objects whose refcounts we're logging are created. Running this
+// function during NS_LogInit() ensures that we meet the first criterion, and
+// running this function during the stack walking functions ensures we meet the
+// second criterion.
+MFBT_API void
+StackWalkInitCriticalAddress()
+{
+ if (gCriticalAddress.mInit) {
+ return;
+ }
+ gCriticalAddress.mInit = true;
+ // We must not do work when 'new_sem_from_pool' calls realloc, since
+ // it holds a non-reentrant spin-lock and we will quickly deadlock.
+ // new_sem_from_pool is not directly accessible using dlsym, so
+ // we force a situation where new_sem_from_pool is on the stack and
+ // use dladdr to check the addresses.
+
+ // malloc_logger can be set by external tools like 'Instruments' or 'leaks'
+ malloc_logger_t* old_malloc_logger = malloc_logger;
+ malloc_logger = my_malloc_logger;
+
+ pthread_cond_t cond;
+ int r = pthread_cond_init(&cond, 0);
+ MOZ_ASSERT(r == 0);
+ pthread_mutex_t mutex;
+ r = pthread_mutex_init(&mutex, 0);
+ MOZ_ASSERT(r == 0);
+ r = pthread_mutex_lock(&mutex);
+ MOZ_ASSERT(r == 0);
+ struct timespec abstime = { 0, 1 };
+ r = pthread_cond_timedwait_relative_np(&cond, &mutex, &abstime);
+
+ // restore the previous malloc logger
+ malloc_logger = old_malloc_logger;
+
+ MOZ_ASSERT(r == ETIMEDOUT);
+ r = pthread_mutex_unlock(&mutex);
+ MOZ_ASSERT(r == 0);
+ r = pthread_mutex_destroy(&mutex);
+ MOZ_ASSERT(r == 0);
+ r = pthread_cond_destroy(&cond);
+ MOZ_ASSERT(r == 0);
+}
+
+static bool
+IsCriticalAddress(void* aPC)
+{
+ return gCriticalAddress.mAddr == aPC;
+}
+#else
static bool
IsCriticalAddress(void* aPC)
{
return false;
}
// We still initialize gCriticalAddress.mInit so that this code behaves
-// the same on all platforms.
+// the same on all platforms. Otherwise a failure to init would be visible
+// only on OS X.
MFBT_API void
StackWalkInitCriticalAddress()
{
gCriticalAddress.mInit = true;
}
+#endif
#if defined(_WIN32) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_IA64)) // WIN32 x86 stack walking code
@@ -799,6 +909,8 @@ MozStackWalk(MozWalkStackCallback aCallback, uint32_t aSkipFrames,
void* stackEnd;
#if HAVE___LIBC_STACK_END
stackEnd = __libc_stack_end;
+#elif defined(XP_DARWIN)
+ stackEnd = pthread_get_stackaddr_np(pthread_self());
#else
# error Unsupported configuration
#endif
diff --git a/mozglue/misc/TimeStamp.h b/mozglue/misc/TimeStamp.h
index 20e70cbdc1..019393b284 100644
--- a/mozglue/misc/TimeStamp.h
+++ b/mozglue/misc/TimeStamp.h
@@ -399,9 +399,18 @@ public:
* retrieved by mozilla::TimeStamp. Since we need this for
* vsync timestamps, we enable the creation of mozilla::TimeStamps
* on platforms that support vsync aligned refresh drivers / compositors
+ * Verified true as of Jan 31, 2015: OS X
* False on Windows 7
* UNTESTED ON OTHER PLATFORMS
*/
+#if defined(XP_DARWIN)
+ static TimeStamp FromSystemTime(int64_t aSystemTime)
+ {
+ static_assert(sizeof(aSystemTime) == sizeof(TimeStampValue),
+ "System timestamp should be same units as TimeStampValue");
+ return TimeStamp(aSystemTime);
+ }
+#endif
/**
* Return true if this is the "null" moment