From 5e46f127214e62bad14a33d4d4be75a51589fa57 Mon Sep 17 00:00:00 2001
From: das <das>
Date: Wed, 7 Mar 2007 23:43:13 +0000
Subject: 	* macosx/tclMacOSXNotify.c: add spinlock debugging and sanity
 checks.

	* macosx/Tcl.xcodeproj/project.pbxproj: ensure gcc version used by
	* macosx/Tcl.xcodeproj/default.pbxuser: Xcode and configure/make are
	* macosx/Tcl-Common.xcconfig:		consistent and independent of
	gcc_select default and CC env var; fixes for Xcode 3.0.

	* unix/tcl.m4 (Darwin): s/CFLAGS/CPPFLAGS/ in macosx-version-min check.
	* unix/configure: autoconf-2.59
---
 ChangeLog                            | 14 ++++++-
 macosx/Tcl-Common.xcconfig           |  9 +++--
 macosx/Tcl.xcodeproj/default.pbxuser |  1 +
 macosx/Tcl.xcodeproj/project.pbxproj |  2 +-
 macosx/tclMacOSXNotify.c             | 78 +++++++++++++++++++++++++++++++-----
 unix/configure                       |  2 +-
 unix/tcl.m4                          |  2 +-
 7 files changed, 90 insertions(+), 18 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 780657e..20756da 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2007-03-07  Daniel Steffen  <das@users.sourceforge.net>
+
+	* macosx/tclMacOSXNotify.c: add spinlock debugging and sanity checks.
+
+	* macosx/Tcl.xcodeproj/project.pbxproj: ensure gcc version used by
+	* macosx/Tcl.xcodeproj/default.pbxuser: Xcode and configure/make are
+	* macosx/Tcl-Common.xcconfig:		consistent and independent of
+	gcc_select default and CC env var; fixes for Xcode 3.0.
+
+	* unix/tcl.m4 (Darwin): s/CFLAGS/CPPFLAGS/ in macosx-version-min check.
+	* unix/configure: autoconf-2.59
+
 2007-03-07  Don Porter  <dgp@users.sourceforge.net>
 
 	* generic/tclCmdIL.c (TclLindex*):	Rewrites to make efficient private
@@ -2863,7 +2875,7 @@
 	of a real windows service shell.
 
 	******************************************************************
-	*** CHANGELOG ENTRIES FOR 2004 IN "ChangeLog.2005"	       ***
+	*** CHANGELOG ENTRIES FOR 2005 IN "ChangeLog.2005"	       ***
 	*** CHANGELOG ENTRIES FOR 2004 IN "ChangeLog.2004"	       ***
 	*** CHANGELOG ENTRIES FOR 2003 IN "ChangeLog.2003"	       ***
 	*** CHANGELOG ENTRIES FOR 2002 IN "ChangeLog.2002"	       ***
diff --git a/macosx/Tcl-Common.xcconfig b/macosx/Tcl-Common.xcconfig
index 64c77e0..abc1792 100644
--- a/macosx/Tcl-Common.xcconfig
+++ b/macosx/Tcl-Common.xcconfig
@@ -9,7 +9,7 @@
 // See the file "license.terms" for information on usage and redistribution
 // of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 //
-// RCS: @(#) $Id: Tcl-Common.xcconfig,v 1.1 2007/01/28 01:42:05 das Exp $
+// RCS: @(#) $Id: Tcl-Common.xcconfig,v 1.2 2007/03/07 23:43:13 das Exp $
 //
 
 HEADER_SEARCH_PATHS = $(DERIVED_FILE_DIR)/tcl $(HEADER_SEARCH_PATHS)
@@ -19,8 +19,11 @@ GCC_PREFIX_HEADER = $(DERIVED_FILE_DIR)/tcl/tclConfig.h
 GCC_GENERATE_DEBUGGING_SYMBOLS = YES
 GCC_NO_COMMON_BLOCKS = YES
 GCC_DYNAMIC_NO_PIC = YES
-WARNING_CFLAGS_GCC3 = -Wall -Wno-implicit-int -Wno-unused-parameter -Wno-deprecated-declarations $(WARNING_CFLAGS)
-WARNING_CFLAGS = -Wextra -Wno-missing-field-initializers $(WARNING_CFLAGS_GCC3)
+GCC = /usr/bin/gcc
+GCC_VERSION = 4.0
+CC = $(GCC)-$(GCC_VERSION)
+WARNING_CFLAGS_GCC3 = -Wall -Wno-implicit-int -Wno-unused-parameter -Wno-deprecated-declarations
+WARNING_CFLAGS = -Wextra -Wno-missing-field-initializers $(WARNING_CFLAGS_GCC3) $(WARNING_CFLAGS)
 BINDIR = $(PREFIX)/bin
 CFLAGS = $(CFLAGS)
 CPPFLAGS = -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) $(CPPFLAGS)
diff --git a/macosx/Tcl.xcodeproj/default.pbxuser b/macosx/Tcl.xcodeproj/default.pbxuser
index 2f2b53a..960d3d6 100644
--- a/macosx/Tcl.xcodeproj/default.pbxuser
+++ b/macosx/Tcl.xcodeproj/default.pbxuser
@@ -16,6 +16,7 @@
 		};
 		sourceControlManager = F944EB9C08F798180049FDD4 /* Source Control */;
 		userBuildSettings = {
+			GCC = /usr/bin/gcc;
 			SYMROOT = "${SRCROOT}/../../build/tcl";
 		};
 	};
diff --git a/macosx/Tcl.xcodeproj/project.pbxproj b/macosx/Tcl.xcodeproj/project.pbxproj
index b578176..37e921e 100644
--- a/macosx/Tcl.xcodeproj/project.pbxproj
+++ b/macosx/Tcl.xcodeproj/project.pbxproj
@@ -2409,6 +2409,7 @@
 		F9DB621F0B65AFDE00A370FB /* ReleasePPC10.3.9SDK */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				LDFLAGS = "-force_cpusubtype_ALL $(LDFLAGS)";
 				PRODUCT_NAME = tclsh;
 			};
 			name = ReleasePPC10.3.9SDK;
@@ -2452,7 +2453,6 @@
 			baseConfigurationReference = F97AE82B0B65C69B00310EA2 /* Tcl-Release.xcconfig */;
 			buildSettings = {
 				ARCHS = ppc;
-				CC = "$(CC)-$(GCC_VERSION)";
 				CFLAGS = "$(PER_ARCH_CFLAGS_ppc) -fconstant-cfstrings $(CFLAGS)";
 				CPPFLAGS = "-arch ppc -D__CONSTANT_CFSTRINGS__ -DMAC_OS_X_VERSION_MIN_REQUIRED=1020 -nostdinc -isystem $(SDKROOT)/usr/include/gcc/darwin/$(GCC_VERSION) -isystem $(SDKROOT)/usr/include -F$(SDKROOT)/System/Library/Frameworks";
 				DEBUG_INFORMATION_FORMAT = stabs;
diff --git a/macosx/tclMacOSXNotify.c b/macosx/tclMacOSXNotify.c
index af2fa65..ecd78ae 100644
--- a/macosx/tclMacOSXNotify.c
+++ b/macosx/tclMacOSXNotify.c
@@ -13,7 +13,7 @@
  * See the file "license.terms" for information on usage and redistribution of
  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
  *
- * RCS: @(#) $Id: tclMacOSXNotify.c,v 1.12 2007/01/19 01:03:59 das Exp $
+ * RCS: @(#) $Id: tclMacOSXNotify.c,v 1.13 2007/03/07 23:43:13 das Exp $
  */
 
 #include "tclInt.h"
@@ -149,11 +149,12 @@ static int triggerPipe = -1;
 static int receivePipe = -1; /* Output end of triggerPipe */
 
 /*
- * We use Darwin-native spinlocks instead of pthread mutexes for notifier
- * locking: this radically simplifies the implementation and lowers overhead.
- * Note that these are not pure spinlocks, they employ various strategies to
- * back off, making them immune to most priority-inversion livelocks (c.f. man
- * 3 OSSpinLockLock).
+ * We use the Darwin-native spinlock API rather than pthread mutexes for
+ * notifier locking: this radically simplifies the implementation and lowers
+ * overhead. Note that these are not pure spinlocks, they employ various
+ * strategies to back off and relinquish the processor, making them immune to
+ * most priority-inversion livelocks (c.f. 'man 3 OSSpinLockLock' and Darwin
+ * sources: xnu/osfmk/{ppc,i386}/commpage/spinlocks.s).
  */
 
 #if defined(HAVE_LIBKERN_OSATOMIC_H) && defined(HAVE_OSSPINLOCKLOCK)
@@ -173,27 +174,37 @@ static int receivePipe = -1; /* Output end of triggerPipe */
 #else
 #define VOLATILE
 #endif
+#ifndef bool
+#define bool int
+#endif
 extern void OSSpinLockLock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
 extern void OSSpinLockUnlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
+extern bool OSSpinLockTry(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
 extern void _spin_lock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
 extern void _spin_unlock(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
+extern bool _spin_lock_try(VOLATILE OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
 static void (* lockLock)(VOLATILE OSSpinLock *lock) = NULL;
 static void (* lockUnlock)(VOLATILE OSSpinLock *lock) = NULL;
+static bool (* lockTry)(VOLATILE OSSpinLock *lock) = NULL;
 #undef VOLATILE
 static pthread_once_t spinLockLockInitControl = PTHREAD_ONCE_INIT;
 static void SpinLockLockInit(void) {
     lockLock   = OSSpinLockLock   != NULL ? OSSpinLockLock   : _spin_lock;
     lockUnlock = OSSpinLockUnlock != NULL ? OSSpinLockUnlock : _spin_unlock;
+    lockTry    = OSSpinLockTry    != NULL ? OSSpinLockTry    : _spin_lock_try;
     if (lockLock == NULL || lockUnlock == NULL) {
 	Tcl_Panic("SpinLockLockInit: no spinlock API available");
     }
 }
 #define SpinLockLock(p) 	lockLock(p)
 #define SpinLockUnlock(p)	lockUnlock(p)
+#define SpinLockTry(p)  	lockTry(p)
 #else
 #define SpinLockLock(p) 	OSSpinLockLock(p)
 #define SpinLockUnlock(p)	OSSpinLockUnlock(p)
+#define SpinLockTry(p)  	OSSpinLockTry(p)
 #endif /* HAVE_WEAK_IMPORT */
+#define SPINLOCK_INIT   	OS_SPINLOCK_INIT
 
 #else
 /*
@@ -201,10 +212,13 @@ static void SpinLockLockInit(void) {
  */
 
 typedef uint32_t OSSpinLock;
-extern void	_spin_lock(OSSpinLock *lock);
-extern void	_spin_unlock(OSSpinLock *lock);
+extern void _spin_lock(OSSpinLock *lock);
+extern void _spin_unlock(OSSpinLock *lock);
+extern int  _spin_lock_try(OSSpinLock *lock);
 #define SpinLockLock(p) 	_spin_lock(p)
 #define SpinLockUnlock(p)	_spin_unlock(p)
+#define SpinLockTry(p)  	_spin_lock_try(p)
+#define SPINLOCK_INIT   	0
 
 #endif /* HAVE_LIBKERN_OSATOMIC_H && HAVE_OSSPINLOCKLOCK */
 
@@ -212,8 +226,8 @@ extern void	_spin_unlock(OSSpinLock *lock);
  * These spinlocks lock access to the global notifier state.
  */
 
-static OSSpinLock notifierInitLock = 0;
-static OSSpinLock notifierLock = 0;
+static OSSpinLock notifierInitLock = SPINLOCK_INIT;
+static OSSpinLock notifierLock     = SPINLOCK_INIT;
 
 /*
  * Macros abstracting notifier locking/unlocking
@@ -224,6 +238,37 @@ static OSSpinLock notifierLock = 0;
 #define LOCK_NOTIFIER		SpinLockLock(&notifierLock)
 #define UNLOCK_NOTIFIER		SpinLockUnlock(&notifierLock)
 
+#ifdef TCL_MAC_DEBUG_NOTIFIER
+/*
+ * Debug version of SpinLockLock that logs the time spent waiting for the lock
+ */
+
+#define SpinLockLockDbg(p)	if(!SpinLockTry(p)) { \
+				    Tcl_WideInt s = TclpGetWideClicks(), e; \
+				    SpinLockLock(p); e = TclpGetWideClicks(); \
+				    fprintf(notifierLog, "tclMacOSXNotify.c:" \
+				    "%4d: thread %10p waited on %s for " \
+				    "%8llu ns\n", __LINE__, pthread_self(), \
+				    #p, TclpWideClicksToNanoseconds(e-s)); \
+				    fflush(notifierLog); \
+				}
+#undef LOCK_NOTIFIER_INIT
+#define LOCK_NOTIFIER_INIT	SpinLockLockDbg(&notifierInitLock)
+#undef LOCK_NOTIFIER
+#define LOCK_NOTIFIER		SpinLockLockDbg(&notifierLock)
+static FILE *notifierLog = stderr;
+#ifndef NOTIFIER_LOG
+#define NOTIFIER_LOG "/tmp/tclMacOSXNotify.log"
+#endif
+#define OPEN_NOTIFIER_LOG	if (notifierLog == stderr) { \
+				    notifierLog = fopen(NOTIFIER_LOG, "a"); \
+				}
+#define CLOSE_NOTIFIER_LOG	if (notifierLog != stderr) { \
+				    fclose(notifierLog); \
+				    notifierLog = stderr; \
+				}
+#endif /* TCL_MAC_DEBUG_NOTIFIER */
+
 /*
  * The pollState bits
  *	POLL_WANT is set by each thread before it waits on its condition
@@ -386,6 +431,9 @@ Tcl_InitNotifier(void)
 	 */
 
 	notifierThread = 0;
+#ifdef TCL_MAC_DEBUG_NOTIFIER
+	OPEN_NOTIFIER_LOG;
+#endif
     }
     notifierCount++;
     UNLOCK_NOTIFIER_INIT;
@@ -456,6 +504,9 @@ Tcl_FinalizeNotifier(
 
 	close(receivePipe);
 	triggerPipe = -1;
+#ifdef TCL_MAC_DEBUG_NOTIFIER
+	CLOSE_NOTIFIER_LOG;
+#endif
     }
     UNLOCK_NOTIFIER_INIT;
 
@@ -859,6 +910,9 @@ Tcl_WaitForEvent(
      */
 
     LOCK_NOTIFIER_INIT;
+    if (!notifierCount) {
+        Tcl_Panic("Tcl_WaitForEvent: notifier not initialized");
+    }
     if (!notifierThread) {
 	int result;
 	pthread_attr_t attr;
@@ -882,7 +936,9 @@ Tcl_WaitForEvent(
      */
 
     LOCK_NOTIFIER;
-
+    if (!tsdPtr->runLoop) {
+        Tcl_Panic("Tcl_WaitForEvent: CFRunLoop not initialized");
+    }
     waitForFiles = (tsdPtr->numFdBits > 0);
     if (myTimePtr != NULL && myTimePtr->sec == 0 && myTimePtr->usec == 0) {
 	/*
diff --git a/unix/configure b/unix/configure
index 5cc036e..de0c514 100755
--- a/unix/configure
+++ b/unix/configure
@@ -7662,7 +7662,7 @@ echo "${ECHO_T}$tcl_cv_ld_single_module" >&6
 	    DL_LIBS=""
 	    # Don't use -prebind when building for Mac OS X 10.4 or later only:
 	    test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int($2)}'`" -lt 4 -a \
-		"`echo "${CFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4 && \
+		"`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int($2)}'`" -lt 4 && \
 		LDFLAGS="$LDFLAGS -prebind"
 	    LDFLAGS="$LDFLAGS -headerpad_max_install_names"
 	    echo "$as_me:$LINENO: checking if ld accepts -search_paths_first flag" >&5
diff --git a/unix/tcl.m4 b/unix/tcl.m4
index 1ca5af3..d2e82c6 100644
--- a/unix/tcl.m4
+++ b/unix/tcl.m4
@@ -1656,7 +1656,7 @@ dnl AC_CHECK_TOOL(AR, ar)
 	    DL_LIBS=""
 	    # Don't use -prebind when building for Mac OS X 10.4 or later only:
 	    test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F '10\\.' '{print int([$]2)}'`" -lt 4 -a \
-		"`echo "${CFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4 && \
+		"`echo "${CPPFLAGS}" | awk -F '-mmacosx-version-min=10\\.' '{print int([$]2)}'`" -lt 4 && \
 		LDFLAGS="$LDFLAGS -prebind"
 	    LDFLAGS="$LDFLAGS -headerpad_max_install_names"
 	    AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [
-- 
cgit v0.12