summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
Diffstat (limited to 'macosx')
-rw-r--r--macosx/README34
-rw-r--r--macosx/tclMacOSXNotify.c138
2 files changed, 127 insertions, 45 deletions
diff --git a/macosx/README b/macosx/README
index 46469cb..2475ea2 100644
--- a/macosx/README
+++ b/macosx/README
@@ -1,7 +1,7 @@
Tcl Mac OS X README
-----------------
-RCS: @(#) $Id: README,v 1.1.2.4 2005/11/27 02:34:41 das Exp $
+RCS: @(#) $Id: README,v 1.1.2.5 2006/07/20 06:21:41 das Exp $
This is the README file for the Mac OS X/Darwin version of Tcl.
@@ -36,9 +36,12 @@ Mac OS X specific bugs should usually be assigned to 'das' or 'wolfsuit'.
- At a minimum, Mac OS X 10.1 is required to run Tcl, but OS X 10.3 or higher is
recommended (certain [file] operations behave incorrectly on earlier releases).
-- Tcl built on Mac OS X 10.x will not run on 10.y for y < x, on the other hand
-Tcl built on 10.y will run on 10.x for y < x (but without any of the fixes and
-optimizations that would be available in a binary built on 10.x).
+- Unless weak-linking is used, Tcl built on Mac OS X 10.x will not run on 10.y
+with y < x; on the other hand Tcl built on 10.y will always run on 10.x with
+y <= x (but without any of the fixes and optimizations that would be available
+in a binary built on 10.x).
+Weak-linking is available on OS X 10.2 or later, it additionally allows Tcl
+built on 10.x to run on any 10.y with x > y >= z (for a chosen z >= 2).
- Tcl extensions can be installed in any of:
$HOME/Library/Tcl /Library/Tcl /Network/Library/Tcl /System/Library/Tcl
@@ -79,10 +82,9 @@ http://connect.apple.com (after you register for free ADC membership).
(see below for details), but can also be built with the standard unix configure
and make buildsystem in tcl/unix as on any other unix platform (indeed, the
Makefile is just a wrapper around the unix buildsystem).
-The Mac OS X specifc configure flags are --enable-framework and
+The Mac OS X specific configure flags are --enable-framework and
--disable-corefoundation (which disables CF and notably reverts to the standard
-select based notifier, you will only need this if your require use of naked fork
-(i.e. not followed by execve) in an unthreaded core).
+select based notifier).
- It is also possible to build with Apple's IDE via the tcl/macosx/Tcl.pbproj
project, this simply calls through to the tcl/macosx/GNUMakefile.
@@ -91,12 +93,22 @@ project, this simply calls through to the tcl/macosx/GNUMakefile.
export CFLAGS="-arch ppc -arch ppc64 -arch i386 \
-isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4"
This requires Mac OS X 10.4 and Xcode 2.2 (_not_ Xcode 2.1) and will work on any
-of the architectures (on i386 DTKs, the -isysroot is not required). Note that it
-is not possible to configure correctly if the current architecture is not
+of the architectures (on intel Macs, the -isysroot is not required). Note that
+it is not possible to configure correctly if the current architecture is not
present in CFLAGS (i.e. -arch `arch` must always be there). Universal builds of
Tcl TEA extensions are also possible with CFLAGS set as above, they will be
[load]able by universal as well as thin binaries of Tcl.
+- To enable weak-linking, set the MACOSX_DEPLOYMENT_TARGET environment variable
+to the minimal OS version (>= 10.2) the binaries should be able to run on, e.g:
+ export MACOSX_DEPLOYMENT_TARGET=10.2
+This requires Mac OS X 10.2 and gcc 3.1; if you have gcc 4 or later you can set
+CFLAGS instead:
+ export CFLAGS="-mmacosx-version-min=10.2"
+The Tcl.xcodeproj is setup to produce binaires that can run on 10.2 or later,
+except for the 'ReleaseUniversal'configuration, where they require 10.4.
+Support for weak-linking was added to the code for 8.4.14/8.5a5.
+
Detailed Instructions for building with macosx/Makefile
-------------------------------------------------------
@@ -127,8 +139,8 @@ instead by passing an INSTALL_ROOT argument to make:
- The default Makefile targets will build _both_ debug and optimized versions of
the Tcl framework with the standard convention of naming the debug library
Tcl.framework/Tcl_debug.
-This allows you to dynamically link to the debug libraries at runtime by setting
- setenv DYLD_IMAGE_SUFFIX _debug
+This allows switching to the debug libraries at runtime by setting
+ export DYLD_IMAGE_SUFFIX=_debug
(c.f. man dyld for more details)
If you only want to build and install the debug or optimized build, use the
diff --git a/macosx/tclMacOSXNotify.c b/macosx/tclMacOSXNotify.c
index bdda1ce..f9cd046 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.1.2.6 2006/05/27 05:23:04 das Exp $
+ * RCS: @(#) $Id: tclMacOSXNotify.c,v 1.1.2.7 2006/07/20 06:21:42 das Exp $
*/
#include "tclInt.h"
@@ -164,6 +164,32 @@ static int receivePipe = -1; /* Output end of triggerPipe */
#include <libkern/OSAtomic.h>
+#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040
+/*
+ * Support for weakly importing spinlock API.
+ */
+#define WEAK_IMPORT_SPINLOCKLOCK
+extern void OSSpinLockLock(OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
+extern void OSSpinLockUnlock(OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
+extern void _spin_lock(OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
+extern void _spin_unlock(OSSpinLock *lock) WEAK_IMPORT_ATTRIBUTE;
+static void (* lockLock)(OSSpinLock *lock) = NULL;
+static void (* lockUnlock)(OSSpinLock *lock) = NULL;
+static pthread_once_t spinLockLockInitControl = PTHREAD_ONCE_INIT;
+static void SpinLockLockInit(void) {
+ lockLock = OSSpinLockLock != NULL ? OSSpinLockLock : _spin_lock;
+ lockUnlock = OSSpinLockUnlock != NULL ? OSSpinLockUnlock : _spin_unlock;
+ if (lockLock == NULL || lockUnlock == NULL) {
+ Tcl_Panic("SpinLockLockInit: no spinlock API available.");
+ }
+}
+#define SpinLockLock(p) lockLock(p)
+#define SpinLockUnlock(p) lockUnlock(p)
+#else
+#define SpinLockLock(p) OSSpinLockLock(p)
+#define SpinLockUnlock(p) OSSpinLockUnlock(p)
+#endif /* HAVE_WEAK_IMPORT */
+
#else
/*
* Otherwise, use commpage spinlock SPI directly.
@@ -172,8 +198,8 @@ static int receivePipe = -1; /* Output end of triggerPipe */
typedef uint32_t OSSpinLock;
extern void _spin_lock(OSSpinLock *lock);
extern void _spin_unlock(OSSpinLock *lock);
-#define OSSpinLockLock(p) _spin_lock(p)
-#define OSSpinLockUnlock(p) _spin_unlock(p)
+#define SpinLockLock(p) _spin_lock(p)
+#define SpinLockUnlock(p) _spin_unlock(p)
#endif /* HAVE_LIBKERN_OSATOMIC_H && HAVE_OSSPINLOCKLOCK */
@@ -188,10 +214,10 @@ static OSSpinLock notifierLock = 0;
* Macros abstracting notifier locking/unlocking
*/
-#define LOCK_NOTIFIER_INIT OSSpinLockLock(&notifierInitLock)
-#define UNLOCK_NOTIFIER_INIT OSSpinLockUnlock(&notifierInitLock)
-#define LOCK_NOTIFIER OSSpinLockLock(&notifierLock)
-#define UNLOCK_NOTIFIER OSSpinLockUnlock(&notifierLock)
+#define LOCK_NOTIFIER_INIT SpinLockLock(&notifierInitLock)
+#define UNLOCK_NOTIFIER_INIT SpinLockUnlock(&notifierInitLock)
+#define LOCK_NOTIFIER SpinLockLock(&notifierLock)
+#define UNLOCK_NOTIFIER SpinLockUnlock(&notifierLock)
/*
* The pollState bits
@@ -223,7 +249,13 @@ static int atForkInit = 0;
static void AtForkPrepare(void);
static void AtForkParent(void);
static void AtForkChild(void);
-#endif
+#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040
+/* Support for weakly importing pthread_atfork. */
+#define WEAK_IMPORT_PTHREAD_ATFORK
+extern int pthread_atfork(void (*prepare)(void), void (*parent)(void),
+ void (*child)(void)) WEAK_IMPORT_ATTRIBUTE;
+#endif /* HAVE_WEAK_IMPORT */
+#endif /* HAVE_PTHREAD_ATFORK */
/*
*----------------------------------------------------------------------
@@ -248,8 +280,17 @@ Tcl_InitNotifier(void)
tsdPtr->eventReady = 0;
+#ifdef WEAK_IMPORT_SPINLOCKLOCK
+ /*
+ * Initialize support for weakly imported spinlock API.
+ */
+ if (pthread_once(&spinLockLockInitControl, SpinLockLockInit)) {
+ Tcl_Panic("Tcl_InitNotifier: pthread_once failed.");
+ }
+#endif
+
/*
- * Initialize CFRunLoopSource and add it to CFRunLoop of this thread
+ * Initialize CFRunLoopSource and add it to CFRunLoop of this thread.
*/
if (!tsdPtr->runLoop) {
@@ -268,28 +309,31 @@ Tcl_InitNotifier(void)
tsdPtr->runLoop = runLoop;
}
- /*
- * Initialize trigger pipe and start the Notifier thread if necessary.
- */
-
LOCK_NOTIFIER_INIT;
#ifdef HAVE_PTHREAD_ATFORK
/*
- * Install pthread_atfork handlers to reinstall the notifier thread in the
+ * Install pthread_atfork handlers to reinitialize the notifier in the
* child of a fork.
*/
- if (!atForkInit) {
+ if (
+#ifdef WEAK_IMPORT_PTHREAD_ATFORK
+ pthread_atfork != NULL &&
+#endif
+ !atForkInit) {
int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild);
if (result) {
- Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
+ Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed.");
}
atForkInit = 1;
}
#endif
if (notifierCount == 0) {
- int fds[2], status, result;
- pthread_attr_t attr;
+ int fds[2], status;
+
+ /*
+ * Initialize trigger pipe.
+ */
if (pipe(fds) != 0) {
Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe.");
@@ -309,16 +353,13 @@ Tcl_InitNotifier(void)
receivePipe = fds[0];
triggerPipe = fds[1];
- pthread_attr_init(&attr);
- pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
- pthread_attr_setstacksize(&attr, 60 * 1024);
- result = pthread_create(&notifierThread, &attr,
- (void * (*)(void *))NotifierThreadProc, NULL);
- pthread_attr_destroy(&attr);
- if (result) {
- Tcl_Panic("Tcl_InitNotifier: unable to start notifier thread.");
- }
+ /*
+ * Create notifier thread lazily in Tcl_WaitForEvent() to avoid
+ * interfering with fork() followed immediately by execve()
+ * (cannot execve() when more than one thread is present).
+ */
+
+ notifierThread = 0;
}
notifierCount++;
UNLOCK_NOTIFIER_INIT;
@@ -379,9 +420,12 @@ Tcl_FinalizeNotifier(clientData)
write(triggerPipe, "q", 1);
close(triggerPipe);
- result = pthread_join(notifierThread, NULL);
- if (result) {
- Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread.");
+ if (notifierThread) {
+ result = pthread_join(notifierThread, NULL);
+ if (result) {
+ Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread.");
+ }
+ notifierThread = 0;
}
close(receivePipe);
@@ -764,6 +808,28 @@ Tcl_WaitForEvent(timePtr)
}
/*
+ * Start notifier thread if necessary.
+ */
+
+ LOCK_NOTIFIER_INIT;
+ if (!notifierThread) {
+ int result;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pthread_attr_setstacksize(&attr, 60 * 1024);
+ result = pthread_create(&notifierThread, &attr,
+ (void * (*)(void *))NotifierThreadProc, NULL);
+ pthread_attr_destroy(&attr);
+ if (result || !notifierThread) {
+ Tcl_Panic("Tcl_WaitForEvent: unable to start notifier thread.");
+ }
+ }
+ UNLOCK_NOTIFIER_INIT;
+
+ /*
* Place this thread on the list of interested threads, signal the
* notifier thread, and wait for a response or a timeout.
*/
@@ -1138,9 +1204,13 @@ AtForkChild(void)
}
if (notifierCount > 0) {
notifierCount = 0;
- /* Note that Tcl_FinalizeNotifier does not use its clientData
- * parameter, so discard return value of Tcl_InitNotifier here and
- * leave stale clientData in tclNotify.c's ThreadSpecificData.
+ /*
+ * Assume that the return value of Tcl_InitNotifier() in the child
+ * will be identical to the one stored as clientData in tclNotify.c's
+ * ThreadSpecificData by the parent's TclInitNotifier(), so discard
+ * the return value here. This assumption may require the fork() to
+ * be executed in the main thread of the parent, otherwise
+ * Tcl_AlertNotifier() may break in the child.
*/
Tcl_InitNotifier();
}