diff options
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/README | 34 | ||||
-rw-r--r-- | macosx/Tcl.xcodeproj/project.pbxproj | 22 | ||||
-rw-r--r-- | macosx/tclMacOSXFCmd.c | 30 | ||||
-rw-r--r-- | macosx/tclMacOSXNotify.c | 138 |
4 files changed, 168 insertions, 56 deletions
diff --git a/macosx/README b/macosx/README index 561c468..6c2c81a 100644 --- a/macosx/README +++ b/macosx/README @@ -1,7 +1,7 @@ Tcl Mac OS X README ----------------- -RCS: @(#) $Id: README,v 1.6 2005/11/27 02:33:49 das Exp $ +RCS: @(#) $Id: README,v 1.7 2006/07/20 06:18:37 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 GNUmakefile 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 projects in tcl/macosx, take care to only use the project matching your DevTools and OS version: @@ -116,12 +118,22 @@ Notes about the native targets of the Xcode projects: 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/GNUmakefile ---------------------------------------------------------- @@ -152,8 +164,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/Tcl.xcodeproj/project.pbxproj b/macosx/Tcl.xcodeproj/project.pbxproj index 89c24e1..9c72230 100644 --- a/macosx/Tcl.xcodeproj/project.pbxproj +++ b/macosx/Tcl.xcodeproj/project.pbxproj @@ -1871,7 +1871,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/bash; - shellScript = "## tcl configure shell script phase\n\ncd \"${TCL_SRCROOT}\"/macosx &&\nif [ configure.ac -nt configure -o ../unix/configure.in -nt configure -o ../unix/tcl.m4 -nt configure -o ../unix/aclocal.m4 -nt configure ]; then\n echo \"Running autoconf & autoheader in tcl/macosx\"\n rm -rf autom4te.cache\n ${AUTOCONF:-/usr/bin/autoconf} && ${AUTOHEADER:-/usr/bin/autoheader}\n rm -rf autom4te.cache\nfi\n\ncd \"${DERIVED_FILE_DIR}\" && mkdir -p tcl && cd tcl &&\nif [ \"${TCL_SRCROOT}\"/macosx/configure -nt config.status ]; then\n \"${TCL_SRCROOT}\"/macosx/configure --cache-file=../config.cache --prefix=${PREFIX} --bindir=${BINDIR} --libdir=${LIBDIR} --mandir=${MANDIR} --includedir=${INCLUDEDIR} --disable-shared ${CONFIGURE_ARGS}\nelse\n ./config.status\nfi\n"; + shellScript = "## tcl configure shell script phase\n\ncd \"${TCL_SRCROOT}\"/macosx &&\nif [ configure.ac -nt configure -o ../unix/configure.in -nt configure -o ../unix/tcl.m4 -nt configure -o ../unix/aclocal.m4 -nt configure ]; then\n echo \"Running autoconf & autoheader in tcl/macosx\"\n rm -rf autom4te.cache\n ${AUTOCONF:-/usr/bin/autoconf} && ${AUTOHEADER:-/usr/bin/autoheader}\n rm -rf autom4te.cache\nfi\n\ncd \"${DERIVED_FILE_DIR}\" && mkdir -p tcl && cd tcl &&\nif [ \"${TCL_SRCROOT}\"/macosx/configure -nt config.status ]; then\n echo \"Configuring tcl\"\n \"${TCL_SRCROOT}\"/macosx/configure --cache-file=../config.cache --prefix=${PREFIX} --bindir=${BINDIR} --libdir=${LIBDIR} --mandir=${MANDIR} --includedir=${INCLUDEDIR} --disable-shared ${CONFIGURE_ARGS}\nelse\n ./config.status\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -2084,7 +2084,6 @@ INCLUDEDIR = "${PREFIX}/include"; INSTALL_PATH = "${BINDIR}"; LIBDIR = "${PREFIX}/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.4; MANDIR = "${PREFIX}/man"; OTHER_LDFLAGS = "-headerpad_max_install_names"; PER_ARCH_CFLAGS_ppc = "-mcpu=G3 -mtune=G4"; @@ -2100,6 +2099,9 @@ WARNING_CFLAGS = ( "-Wall", "-Wno-implicit-int", + "-Wextra", + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", ); ZERO_LINK = NO; }; @@ -2111,6 +2113,7 @@ CFLAGS = "-arch ppc -arch ppc64 -arch i386 -isysroot ${SDKROOT} -mmacosx-version-min=10.4"; CONFIGURE_ARGS = "--disable-symbols"; GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; + MACOSX_DEPLOYMENT_TARGET = 10.4; SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk; }; name = ReleaseUniversal; @@ -2184,7 +2187,6 @@ INCLUDEDIR = "${PREFIX}/include"; INSTALL_PATH = "${BINDIR}"; LIBDIR = "${PREFIX}/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.4; MANDIR = "${PREFIX}/man"; OTHER_LDFLAGS = "-headerpad_max_install_names"; PER_ARCH_CFLAGS_ppc = "-mcpu=G3 -mtune=G4"; @@ -2200,6 +2202,9 @@ WARNING_CFLAGS = ( "-Wall", "-Wno-implicit-int", + "-Wextra", + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", ); ZERO_LINK = YES; }; @@ -2231,7 +2236,6 @@ INCLUDEDIR = "${PREFIX}/include"; INSTALL_PATH = "${BINDIR}"; LIBDIR = "${PREFIX}/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.4; MANDIR = "${PREFIX}/man"; OTHER_LDFLAGS = "-headerpad_max_install_names"; PER_ARCH_CFLAGS_ppc = "-mcpu=G3 -mtune=G4"; @@ -2247,6 +2251,9 @@ WARNING_CFLAGS = ( "-Wall", "-Wno-implicit-int", + "-Wextra", + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", ); ZERO_LINK = NO; }; @@ -2279,7 +2286,6 @@ INCLUDEDIR = "${PREFIX}/include"; INSTALL_PATH = "${BINDIR}"; LIBDIR = "${PREFIX}/lib"; - MACOSX_DEPLOYMENT_TARGET = 10.4; MANDIR = "${PREFIX}/man"; OTHER_LDFLAGS = "-headerpad_max_install_names"; PER_ARCH_CFLAGS_ppc = "-mcpu=G3 -mtune=G4"; @@ -2295,6 +2301,9 @@ WARNING_CFLAGS = ( "-Wall", "-Wno-implicit-int", + "-Wextra", + "-Wno-unused-parameter", + "-Wno-missing-field-initializers", ); ZERO_LINK = NO; }; @@ -2305,6 +2314,7 @@ buildSettings = { CONFIGURE_ARGS = "--enable-symbols"; GCC_PREPROCESSOR_DEFINITIONS = "__private_extern__=extern"; + MACOSX_DEPLOYMENT_TARGET = 10.2; }; name = Debug; }; @@ -2313,6 +2323,7 @@ buildSettings = { CONFIGURE_ARGS = "--disable-symbols"; GCC_PREPROCESSOR_DEFINITIONS = NDEBUG; + MACOSX_DEPLOYMENT_TARGET = 10.2; }; name = Release; }; @@ -2321,6 +2332,7 @@ buildSettings = { CONFIGURE_ARGS = "--enable-symbols"; GCC_PREPROCESSOR_DEFINITIONS = ""; + MACOSX_DEPLOYMENT_TARGET = 10.2; }; name = DebugNoFixZL; }; diff --git a/macosx/tclMacOSXFCmd.c b/macosx/tclMacOSXFCmd.c index 80e9785..51fe222 100644 --- a/macosx/tclMacOSXFCmd.c +++ b/macosx/tclMacOSXFCmd.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMacOSXFCmd.c,v 1.8 2006/03/21 11:06:23 das Exp $ + * RCS: @(#) $Id: tclMacOSXFCmd.c,v 1.9 2006/07/20 06:18:37 das Exp $ */ #include "tclInt.h" @@ -21,7 +21,7 @@ #include <libkern/OSByteOrder.h> #endif -/* Darwin 8 copyfile API */ +/* Darwin 8 copyfile API. */ #ifdef HAVE_COPYFILE #ifdef HAVE_COPYFILE_H #include <copyfile.h> @@ -30,8 +30,14 @@ int copyfile(const char *from, const char *to, void *state, uint32_t flags); #define COPYFILE_ACL (1<<0) #define COPYFILE_XATTR (1<<2) #define COPYFILE_NOFOLLOW_SRC (1<<18) -#endif -#endif +#endif /* HAVE_COPYFILE_H */ +#if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040 +/* Support for weakly importing copyfile. */ +#define WEAK_IMPORT_COPYFILE +extern int copyfile(const char *from, const char *to, void *state, + uint32_t flags) WEAK_IMPORT_ATTRIBUTE; +#endif /* HAVE_WEAK_IMPORT */ +#endif /* HAVE_COPYFILE */ #include <libkern/OSByteOrder.h> @@ -365,14 +371,22 @@ TclMacOSXCopyFileAttributes( CONST Tcl_StatBuf *statBufPtr) /* Stat info for source file */ { -#if defined(HAVE_COPYFILE) +#ifdef WEAK_IMPORT_COPYFILE + if (copyfile != NULL) { +#endif +#ifdef HAVE_COPYFILE if (copyfile(src, dst, NULL, COPYFILE_XATTR | (S_ISLNK(statBufPtr->st_mode) ? COPYFILE_NOFOLLOW_SRC : COPYFILE_ACL)) < 0) { return TCL_ERROR; } return TCL_OK; -#elif defined(HAVE_GETATTRLIST) +#endif /* HAVE_COPYFILE */ +#ifdef WEAK_IMPORT_COPYFILE + } else { +#endif +#if !defined(HAVE_COPYFILE) || defined(WEAK_IMPORT_COPYFILE) +#ifdef HAVE_GETATTRLIST struct attrlist alist; fileinfobuf finfo; off_t *rsrcForkSize = (off_t*)(&finfo.data); @@ -430,6 +444,10 @@ TclMacOSXCopyFileAttributes( return TCL_OK; #else return TCL_ERROR; +#endif /* HAVE_GETATTRLIST */ +#endif /* !defined(HAVE_COPYFILE) || defined(WEAK_IMPORT_COPYFILE) */ +#ifdef WEAK_IMPORT_COPYFILE + } #endif } diff --git a/macosx/tclMacOSXNotify.c b/macosx/tclMacOSXNotify.c index a99e11b..6d892ea 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.7 2006/05/27 05:22:58 das Exp $ + * RCS: @(#) $Id: tclMacOSXNotify.c,v 1.8 2006/07/20 06:18:37 das Exp $ */ #include "tclInt.h" @@ -163,6 +163,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. @@ -171,8 +197,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 */ @@ -187,10 +213,10 @@ static OSSpinLock notifierLock = 0; * Macros abstracting notifier locking/unlocking */ -#define LOCK_NOTIFIER_INIT OSSpinLockLock(¬ifierInitLock) -#define UNLOCK_NOTIFIER_INIT OSSpinLockUnlock(¬ifierInitLock) -#define LOCK_NOTIFIER OSSpinLockLock(¬ifierLock) -#define UNLOCK_NOTIFIER OSSpinLockUnlock(¬ifierLock) +#define LOCK_NOTIFIER_INIT SpinLockLock(¬ifierInitLock) +#define UNLOCK_NOTIFIER_INIT SpinLockUnlock(¬ifierInitLock) +#define LOCK_NOTIFIER SpinLockLock(¬ifierLock) +#define UNLOCK_NOTIFIER SpinLockUnlock(¬ifierLock) /* * The pollState bits @@ -222,7 +248,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 */ /* *---------------------------------------------------------------------- @@ -247,8 +279,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) { @@ -267,28 +308,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."); @@ -308,16 +352,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(¬ifierThread, &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; @@ -378,9 +419,12 @@ Tcl_FinalizeNotifier( 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); @@ -784,6 +828,28 @@ Tcl_WaitForEvent( } /* + * 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(¬ifierThread, &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. */ @@ -1158,9 +1224,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(); } |