Attachment "tcl-CFNotifier-HEAD.diff" to
ticket [1202052fff]
added by
das
2005-05-15 03:41:00.
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.2630
diff -u -p -u -p -r1.2630 ChangeLog
--- ChangeLog 13 May 2005 21:20:35 -0000 1.2630
+++ ChangeLog 14 May 2005 19:11:43 -0000
@@ -1,3 +1,55 @@
+2005-05-14 Daniel Steffen <[email protected]>
+
+ * generic/tclInt.decls:
+ * generic/tclTest.c:
+ * generic/tclUtil.c:
+ * win/tclWin32Dll.c: fixed link error due to direct access by
+ tclTest.c to the MODULE_SCOPE tclPlatform global: renamed existing
+ TclWinGetPlatform() accessor to TclGetPlatform() and moved it to
+ generic code so that it can be used by on all platforms where
+ MODULE_SCOPE is enforced.
+
+ * macosx/tclMacOSXBundle.c:
+ * unix/tclUnixInit.c:
+ * unix/tcl.m4 (Darwin): made use of CoreFoundation API configurable
+ and added test of CoreFoundation availablility to allow building on
+ ppc64, replaced HAVE_CFBUNDLE by HAVE_COREFOUNDATION; test for
+ availability of Tiger or later OSSpinLockLock API.
+
+ * unix/tclUnixNotfy.c:
+ * unix/Makefile.in:
+ * macosx/tclMacOSXNotify.c (new file): when CoreFoundation is
+ available, use new CFRunLoop based notifier: allows easy integration
+ with other event loops on Mac OS X, in particular the TkAqua Carbon
+ event loop is now integrated via a standard tcl event source (instead
+ of TkAqua upon loading having to finalize the exsting notifier and
+ replace it with its custom version). [Patch 1202052]
+
+ * tests/unixNotfy.test: don't run unthreaded tests on Darwin
+ since notifier may be using threads even in unthreaded core.
+
+ * unix/tclUnixPort.h:
+ * unix/tcl.m4 (Darwin): test for thread-unsafe realpath durning
+ configure, as Darwin 7 and later realpath is threadsafe.
+
+ * macosx/Makefile: enable configure caching.
+
+ * unix/configure.in: wrap tclConfig.h header in #ifndef _TCLCONFIG so
+ that it can be included more than once without warnings from gcc4.0
+ (as happens e.g. when including both tclInt.h and tclPort.h)
+
+ * macosx/tclMacOSXBundle.c:
+ * unix/tclUnixChan.c:
+ * unix/tclLoadDyld.c:
+ * unix/tclUnixInit.c: fixed gcc 4.0 warnings.
+
+ * unix/configure: autoconf-2.59
+ * unix/tclConfig.h.in: autoheader-2.59
+
+ * generic/tclIntDecls.h:
+ * generic/tclIntPlatDecls.h:
+ * generic/tclStubInit.c: make genstubs
+
2005-05-13 Kevin Kenny <[email protected]>
* win/tclWin32Dll.c: Further rework of the SEH logic. All
Index: generic/tclInt.decls
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.decls,v
retrieving revision 1.88
diff -u -p -u -p -r1.88 tclInt.decls
--- generic/tclInt.decls 10 May 2005 18:34:41 -0000 1.88
+++ generic/tclInt.decls 14 May 2005 19:11:44 -0000
@@ -891,6 +891,10 @@ declare 222 generic {
declare 223 generic {
int TclBN_mp_read_radix(mp_int *a, const char *str, int radix)
}
+# for use in tclTest.c
+declare 224 generic {
+ TclPlatformType *TclGetPlatform(void)
+}
##############################################################################
@@ -993,9 +997,10 @@ declare 23 win {
declare 24 win {
char *TclWinNoBackslash(char *path)
}
-declare 25 win {
- TclPlatformType *TclWinGetPlatform(void)
-}
+# replaced by generic TclGetPlatform
+#declare 25 win {
+# TclPlatformType *TclWinGetPlatform(void)
+#}
declare 26 win {
void TclWinSetInterfaces(int wide)
}
Index: generic/tclIntDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIntDecls.h,v
retrieving revision 1.79
diff -u -p -u -p -r1.79 tclIntDecls.h
--- generic/tclIntDecls.h 10 May 2005 18:34:42 -0000 1.79
+++ generic/tclIntDecls.h 14 May 2005 19:11:44 -0000
@@ -1156,6 +1156,11 @@ EXTERN int TclBN_mp_init _ANSI_ARGS_((m
EXTERN int TclBN_mp_read_radix _ANSI_ARGS_((mp_int * a,
const char * str, int radix));
#endif
+#ifndef TclGetPlatform_TCL_DECLARED
+#define TclGetPlatform_TCL_DECLARED
+/* 224 */
+EXTERN TclPlatformType * TclGetPlatform _ANSI_ARGS_((void));
+#endif
typedef struct TclIntStubs {
int magic;
@@ -1400,6 +1405,7 @@ typedef struct TclIntStubs {
void (*tclBN_mp_clear) _ANSI_ARGS_((mp_int * a)); /* 221 */
int (*tclBN_mp_init) _ANSI_ARGS_((mp_int * a)); /* 222 */
int (*tclBN_mp_read_radix) _ANSI_ARGS_((mp_int * a, const char * str, int radix)); /* 223 */
+ TclPlatformType * (*tclGetPlatform) _ANSI_ARGS_((void)); /* 224 */
} TclIntStubs;
#ifdef __cplusplus
@@ -2174,6 +2180,10 @@ extern TclIntStubs *tclIntStubsPtr;
#define TclBN_mp_read_radix \
(tclIntStubsPtr->tclBN_mp_read_radix) /* 223 */
#endif
+#ifndef TclGetPlatform
+#define TclGetPlatform \
+ (tclIntStubsPtr->tclGetPlatform) /* 224 */
+#endif
#endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */
Index: generic/tclIntPlatDecls.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIntPlatDecls.h,v
retrieving revision 1.26
diff -u -p -u -p -r1.26 tclIntPlatDecls.h
--- generic/tclIntPlatDecls.h 3 Nov 2004 19:13:40 -0000 1.26
+++ generic/tclIntPlatDecls.h 14 May 2005 19:11:44 -0000
@@ -249,11 +249,7 @@ EXTERN char * TclpGetTZName _ANSI_ARGS_
/* 24 */
EXTERN char * TclWinNoBackslash _ANSI_ARGS_((char * path));
#endif
-#ifndef TclWinGetPlatform_TCL_DECLARED
-#define TclWinGetPlatform_TCL_DECLARED
-/* 25 */
-EXTERN TclPlatformType * TclWinGetPlatform _ANSI_ARGS_((void));
-#endif
+/* Slot 25 is reserved */
#ifndef TclWinSetInterfaces_TCL_DECLARED
#define TclWinSetInterfaces_TCL_DECLARED
/* 26 */
@@ -348,7 +344,7 @@ typedef struct TclIntPlatStubs {
TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char * contents)); /* 22 */
char * (*tclpGetTZName) _ANSI_ARGS_((int isdst)); /* 23 */
char * (*tclWinNoBackslash) _ANSI_ARGS_((char * path)); /* 24 */
- TclPlatformType * (*tclWinGetPlatform) _ANSI_ARGS_((void)); /* 25 */
+ void *reserved25;
void (*tclWinSetInterfaces) _ANSI_ARGS_((int wide)); /* 26 */
void (*tclWinFlushDirtyChannels) _ANSI_ARGS_((void)); /* 27 */
void (*tclWinResetInterfaces) _ANSI_ARGS_((void)); /* 28 */
@@ -520,10 +516,7 @@ extern TclIntPlatStubs *tclIntPlatStubsP
#define TclWinNoBackslash \
(tclIntPlatStubsPtr->tclWinNoBackslash) /* 24 */
#endif
-#ifndef TclWinGetPlatform
-#define TclWinGetPlatform \
- (tclIntPlatStubsPtr->tclWinGetPlatform) /* 25 */
-#endif
+/* Slot 25 is reserved */
#ifndef TclWinSetInterfaces
#define TclWinSetInterfaces \
(tclIntPlatStubsPtr->tclWinSetInterfaces) /* 26 */
Index: generic/tclStubInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStubInit.c,v
retrieving revision 1.116
diff -u -p -u -p -r1.116 tclStubInit.c
--- generic/tclStubInit.c 10 May 2005 18:34:49 -0000 1.116
+++ generic/tclStubInit.c 14 May 2005 19:11:44 -0000
@@ -308,6 +308,7 @@ TclIntStubs tclIntStubs = {
TclBN_mp_clear, /* 221 */
TclBN_mp_init, /* 222 */
TclBN_mp_read_radix, /* 223 */
+ TclGetPlatform, /* 224 */
};
TclIntPlatStubs tclIntPlatStubs = {
@@ -356,7 +357,7 @@ TclIntPlatStubs tclIntPlatStubs = {
TclpCreateTempFile, /* 22 */
TclpGetTZName, /* 23 */
TclWinNoBackslash, /* 24 */
- TclWinGetPlatform, /* 25 */
+ NULL, /* 25 */
TclWinSetInterfaces, /* 26 */
TclWinFlushDirtyChannels, /* 27 */
TclWinResetInterfaces, /* 28 */
Index: generic/tclTest.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclTest.c,v
retrieving revision 1.89
diff -u -p -u -p -r1.89 tclTest.c
--- generic/tclTest.c 10 May 2005 18:34:50 -0000 1.89
+++ generic/tclTest.c 14 May 2005 19:11:46 -0000
@@ -2457,11 +2457,7 @@ TestgetplatformCmd(clientData, interp, a
static CONST char *platformStrings[] = { "unix", "mac", "windows" };
TclPlatformType *platform;
-#ifdef __WIN32__
- platform = TclWinGetPlatform();
-#else
- platform = &tclPlatform;
-#endif
+ platform = TclGetPlatform();
if (argc != 1) {
Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
@@ -3697,11 +3693,7 @@ TestsetplatformCmd(clientData, interp, a
size_t length;
TclPlatformType *platform;
-#ifdef __WIN32__
- platform = TclWinGetPlatform();
-#else
- platform = &tclPlatform;
-#endif
+ platform = TclGetPlatform();
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
Index: generic/tclUtil.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclUtil.c,v
retrieving revision 1.59
diff -u -p -u -p -r1.59 tclUtil.c
--- generic/tclUtil.c 10 May 2005 18:34:52 -0000 1.59
+++ generic/tclUtil.c 14 May 2005 19:11:46 -0000
@@ -2993,3 +2993,26 @@ TclpGetTime(timePtr)
{
Tcl_GetTime(timePtr);
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclGetPlatform --
+ *
+ * This is a kludge that allows the test library to get access
+ * the internal tclPlatform variable.
+ *
+ * Results:
+ * Returns a pointer to the tclPlatform variable.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TclPlatformType *
+TclGetPlatform()
+{
+ return &tclPlatform;
+}
Index: macosx/Makefile
===================================================================
RCS file: /cvsroot/tcl/tcl/macosx/Makefile,v
retrieving revision 1.18
diff -u -p -u -p -r1.18 Makefile
--- macosx/Makefile 19 Nov 2004 06:28:29 -0000 1.18
+++ macosx/Makefile 14 May 2005 19:11:46 -0000
@@ -124,7 +124,7 @@ export CPPROG := cp -p
${PROJECT}: install-${PROJECT}
${OBJ_DIR}/Makefile: ${UNIX_DIR}/Makefile.in ${UNIX_DIR}/configure
- mkdir -p ${OBJ_DIR} && cd ${OBJ_DIR} && ${UNIX_DIR}/configure \
+ mkdir -p ${OBJ_DIR} && cd ${OBJ_DIR} && ${UNIX_DIR}/configure -C \
--prefix=${PREFIX} --bindir=${BINDIR} --libdir=${LIBDIR} \
--includedir=${INCLUDEDIR} --mandir=${MANDIR} --enable-threads \
--enable-framework ${CONFIGURE_ARGS} ${EXTRA_CONFIGURE_ARGS}
Index: macosx/tclMacOSXBundle.c
===================================================================
RCS file: /cvsroot/tcl/tcl/macosx/tclMacOSXBundle.c,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 tclMacOSXBundle.c
--- macosx/tclMacOSXBundle.c 20 Jul 2004 05:40:57 -0000 1.6
+++ macosx/tclMacOSXBundle.c 14 May 2005 19:11:46 -0000
@@ -51,8 +51,11 @@
* license.
*/
+#ifdef HAVE_COREFOUNDATION
#include <CoreFoundation/CoreFoundation.h>
#include <mach-o/dyld.h>
+#endif /* HAVE_COREFOUNDATION */
+
#include "tcl.h"
/*
@@ -119,6 +122,7 @@ Tcl_MacOSXOpenVersionedBundleResources(
int maxPathLen,
char *libraryPath)
{
+#ifdef HAVE_COREFOUNDATION
CFBundleRef bundleRef;
CFStringRef bundleNameRef;
CFURLRef libURL;
@@ -199,7 +203,7 @@ Tcl_MacOSXOpenVersionedBundleResources(
*/
CFURLGetFileSystemRepresentation(libURL, TRUE,
- libraryPath, maxPathLen);
+ (unsigned char*) libraryPath, maxPathLen);
CFRelease(libURL);
}
}
@@ -209,4 +213,7 @@ Tcl_MacOSXOpenVersionedBundleResources(
} else {
return TCL_ERROR;
}
+#else /* HAVE_COREFOUNDATION */
+ return TCL_ERROR;
+#endif /* HAVE_COREFOUNDATION */
}
Index: macosx/tclMacOSXNotify.c
===================================================================
RCS file: macosx/tclMacOSXNotify.c
diff -N macosx/tclMacOSXNotify.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ macosx/tclMacOSXNotify.c 14 May 2005 19:11:46 -0000
@@ -0,0 +1,1048 @@
+/*
+ * tclMacOSXNotify.c --
+ *
+ * This file contains the implementation of a merged
+ * CFRunLoop/select-based notifier, which is the lowest-level part
+ * of the Tcl event loop. This file works together with
+ * generic/tclNotify.c.
+ *
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ * Copyright 2001, Apple Computer, Inc.
+ * Copyright 2005, Tcl Core Team.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id$
+ */
+
+#ifdef HAVE_COREFOUNDATION /* Traditional unix select-based notifier
+ * is in tclUnixNotfy.c */
+#include "tclInt.h"
+#include <CoreFoundation/CoreFoundation.h>
+#include <pthread.h>
+
+extern TclStubs tclStubs;
+extern Tcl_NotifierProcs tclOriginalNotifier;
+
+/*
+ * This structure is used to keep track of the notifier info for a
+ * a registered file.
+ */
+
+typedef struct FileHandler {
+ int fd;
+ int mask; /* Mask of desired events: TCL_READABLE,
+ * etc. */
+ int readyMask; /* Mask of events that have been seen since the
+ * last time file handlers were invoked for
+ * this file. */
+ Tcl_FileProc *proc; /* Procedure to call, in the style of
+ * Tcl_CreateFileHandler. */
+ ClientData clientData; /* Argument to pass to proc. */
+ struct FileHandler *nextPtr;/* Next in list of all files we care about. */
+} FileHandler;
+
+/*
+ * The following structure is what is added to the Tcl event queue when
+ * file handlers are ready to fire.
+ */
+
+typedef struct FileHandlerEvent {
+ Tcl_Event header; /* Information that is standard for
+ * all events. */
+ int fd; /* File descriptor that is ready. Used
+ * to find the FileHandler structure for
+ * the file (can't point directly to the
+ * FileHandler structure because it could
+ * go away while the event is queued). */
+} FileHandlerEvent;
+
+/*
+ *
+ * The following structure contains a set of select() masks to track
+ * readable, writable, and exceptional conditions.
+ */
+
+typedef struct SelectMasks {
+ fd_set readable;
+ fd_set writable;
+ fd_set exceptional;
+} SelectMasks;
+
+/*
+ * The following static structure contains the state information for the
+ * select based implementation of the Tcl notifier. One of these structures
+ * is created for each thread that is using the notifier.
+ */
+
+typedef struct ThreadSpecificData {
+ FileHandler *firstFileHandlerPtr;
+ /* Pointer to head of file handler list. */
+
+ SelectMasks checkMasks; /* This structure is used to build up the masks
+ * to be used in the next call to select.
+ * Bits are set in response to calls to
+ * Tcl_CreateFileHandler. */
+ SelectMasks readyMasks; /* This array reflects the readable/writable
+ * conditions that were found to exist by the
+ * last call to select. */
+ int numFdBits; /* Number of valid bits in checkMasks
+ * (one more than highest fd for which
+ * Tcl_WatchFile has been called). */
+ int onList; /* True if it is in this list */
+ unsigned int pollState; /* pollState is used to implement a polling
+ * handshake between each thread and the
+ * notifier thread. Bits defined below. */
+ struct ThreadSpecificData *nextPtr, *prevPtr;
+ /* All threads that are currently waiting on
+ * an event have their ThreadSpecificData
+ * structure on a doubly-linked listed formed
+ * from these pointers. You must hold the
+ * notifierLock before accessing these
+ * fields. */
+ CFRunLoopSourceRef runLoopSource;
+ /* Any other thread alerts a notifier
+ * that an event is ready to be processed
+ * by signaling this CFRunLoopSource. */
+ CFRunLoopRef runLoop; /* This thread's CFRunLoop, needs to be woken
+ * up whenever the runLoopSource is signaled. */
+ int eventReady; /* True if an event is ready to be processed. */
+} ThreadSpecificData;
+
+static Tcl_ThreadDataKey dataKey;
+
+/*
+ * The following static indicates the number of threads that have
+ * initialized notifiers.
+ *
+ * You must hold the notifierInitLock before accessing this variable.
+ */
+
+static int notifierCount = 0;
+
+/*
+ * The following variable points to the head of a doubly-linked list of
+ * of ThreadSpecificData structures for all threads that are currently
+ * waiting on an event.
+ *
+ * You must hold the notifierLock before accessing this list.
+ */
+
+static ThreadSpecificData *waitingListPtr = NULL;
+
+/*
+ * The notifier thread spends all its time in select() waiting for a
+ * file descriptor associated with one of the threads on the waitingListPtr
+ * list to do something interesting. But if the contents of the
+ * waitingListPtr list ever changes, we need to wake up and restart
+ * the select() system call. You can wake up the notifier thread by
+ * writing a single byte to the file descriptor defined below. This
+ * file descriptor is the input-end of a pipe and the notifier thread is
+ * listening for data on the output-end of the same pipe. Hence writing
+ * to this file descriptor will cause the select() system call to return
+ * and wake up the notifier thread.
+ *
+ * You must hold the notifierLock lock before writing to the pipe.
+ */
+
+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).
+ */
+
+#if defined(HAVE_LIBKERN_OSATOMIC_H) && defined(HAVE_OSSPINLOCKLOCK)
+/* Use OSSpinLock API where available (Tiger or later) */
+#include <libkern/OSAtomic.h>
+#else
+/* Otherwise, use commpage spinlock SPI directly */
+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)
+#endif
+
+/*
+ * These spinlocks lock access to the global notifier state.
+ */
+
+static OSSpinLock notifierInitLock = 0;
+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)
+
+/*
+ * The pollState bits
+ * POLL_WANT is set by each thread before it waits on its condition
+ * variable. It is checked by the notifier before it does
+ * select.
+ * POLL_DONE is set by the notifier if it goes into select after
+ * seeing POLL_WANT. The idea is to ensure it tries a select
+ * with the same bits the initial thread had set.
+ */
+#define POLL_WANT 0x1
+#define POLL_DONE 0x2
+
+/*
+ * This is the thread ID of the notifier thread that does select.
+ */
+static pthread_t notifierThread;
+
+/*
+ * Static routines defined in this file.
+ */
+
+static void NotifierThreadProc(ClientData clientData);
+static int FileHandlerEventProc(Tcl_Event *evPtr, int flags);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_InitNotifier --
+ *
+ * Initializes the platform specific notifier state.
+ *
+ * Results:
+ * Returns a handle to the notifier state for this thread..
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ClientData
+Tcl_InitNotifier()
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ tsdPtr->eventReady = 0;
+
+ /*
+ * Initialize CFRunLoopSource and add it to CFRunLoop of this thread
+ */
+
+ if (!tsdPtr->runLoop) {
+ CFRunLoopRef runLoop = CFRunLoopGetCurrent();
+ CFRunLoopSourceRef runLoopSource;
+ CFRunLoopSourceContext runLoopSourceContext;
+
+ bzero(&runLoopSourceContext, sizeof(CFRunLoopSourceContext));
+ runLoopSourceContext.info = tsdPtr;
+ runLoopSource = CFRunLoopSourceCreate(NULL, 0, &runLoopSourceContext);
+ if (!runLoopSource) {
+ Tcl_Panic("Tcl_InitNotifier: could not create CFRunLoopSource.");
+ }
+ CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopCommonModes);
+ CFRelease(runLoopSource);
+ tsdPtr->runLoopSource = runLoopSource;
+ tsdPtr->runLoop = runLoop;
+ }
+
+ /*
+ * Initialize trigger pipe and start the Notifier thread if necessary.
+ */
+
+ LOCK_NOTIFIER_INIT;
+ if (notifierCount == 0) {
+ int fds[2], status, result;
+ pthread_attr_t attr;
+
+ if (pipe(fds) != 0) {
+ Tcl_Panic("Tcl_InitNotifier: could not create trigger pipe.");
+ }
+
+ status = fcntl(fds[0], F_GETFL);
+ status |= O_NONBLOCK;
+ if (fcntl(fds[0], F_SETFL, status) < 0) {
+ Tcl_Panic("Tcl_InitNotifier: could not make receive pipe non blocking.");
+ }
+ status = fcntl(fds[1], F_GETFL);
+ status |= O_NONBLOCK;
+ if (fcntl(fds[1], F_SETFL, status) < 0) {
+ Tcl_Panic("Tcl_InitNotifier: could not make trigger pipe non blocking.");
+ }
+
+ 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.");
+ }
+ }
+ notifierCount++;
+ UNLOCK_NOTIFIER_INIT;
+
+ return (ClientData) tsdPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_FinalizeNotifier --
+ *
+ * This function is called to cleanup the notifier state before
+ * a thread is terminated.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * May terminate the background notifier thread if this is the
+ * last notifier instance.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_FinalizeNotifier(clientData)
+ ClientData clientData; /* Not used. */
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ LOCK_NOTIFIER_INIT;
+ notifierCount--;
+
+ /*
+ * If this is the last thread to use the notifier, close the notifier
+ * pipe and wait for the background thread to terminate.
+ */
+
+ if (notifierCount == 0) {
+ int result;
+
+ if (triggerPipe < 0) {
+ Tcl_Panic("Tcl_FinalizeNotifier: notifier pipe not initialized.");
+ }
+
+ /*
+ * Send "q" message to the notifier thread so that it will
+ * terminate. The notifier will return from its call to select()
+ * and notice that a "q" message has arrived, it will then close
+ * its side of the pipe and terminate its thread. Note the we can
+ * not just close the pipe and check for EOF in the notifier
+ * thread because if a background child process was created with
+ * exec, select() would not register the EOF on the pipe until the
+ * child processes had terminated. [Bug: 4139]
+ */
+ write(triggerPipe, "q", 1);
+ close(triggerPipe);
+
+ result = pthread_join(notifierThread, NULL);
+ if (result) {
+ Tcl_Panic("Tcl_FinalizeNotifier: unable to join notifier thread.");
+ }
+
+ close(receivePipe);
+ triggerPipe = -1;
+ }
+ UNLOCK_NOTIFIER_INIT;
+
+ LOCK_NOTIFIER; /* for concurrency with Tcl_AlertNotifier */
+ if (tsdPtr->runLoop) {
+ tsdPtr->runLoop = NULL;
+ /* Remove runLoopSource from all CFRunLoops and release it */
+ CFRunLoopSourceInvalidate(tsdPtr->runLoopSource);
+ tsdPtr->runLoopSource = NULL;
+ }
+ UNLOCK_NOTIFIER;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AlertNotifier --
+ *
+ * Wake up the specified notifier from any thread. This routine
+ * is called by the platform independent notifier code whenever
+ * the Tcl_ThreadAlert routine is called. This routine is
+ * guaranteed not to be called on a given notifier after
+ * Tcl_FinalizeNotifier is called for that notifier.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Signals the notifier condition variable for the specified
+ * notifier.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_AlertNotifier(clientData)
+ ClientData clientData;
+{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+ LOCK_NOTIFIER;
+ if (tsdPtr->runLoop) {
+ tsdPtr->eventReady = 1;
+ CFRunLoopSourceSignal(tsdPtr->runLoopSource);
+ CFRunLoopWakeUp(tsdPtr->runLoop);
+ }
+ UNLOCK_NOTIFIER;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_SetTimer --
+ *
+ * This procedure sets the current notifier timer value. This
+ * interface is not implemented in this notifier because we are
+ * always running inside of Tcl_DoOneEvent.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_SetTimer(timePtr)
+ Tcl_Time *timePtr; /* Timeout value, may be NULL. */
+{
+ /*
+ * The interval timer doesn't do anything in this implementation,
+ * because the only event loop is via Tcl_DoOneEvent, which passes
+ * timeout values to Tcl_WaitForEvent.
+ */
+
+ if (tclStubs.tcl_SetTimer != tclOriginalNotifier.setTimerProc) {
+ tclStubs.tcl_SetTimer(timePtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_ServiceModeHook --
+ *
+ * This function is invoked whenever the service mode changes.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_ServiceModeHook(mode)
+ int mode; /* Either TCL_SERVICE_ALL, or
+ * TCL_SERVICE_NONE. */
+{
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_CreateFileHandler --
+ *
+ * This procedure registers a file handler with the select notifier.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Creates a new file handler structure.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_CreateFileHandler(fd, mask, proc, clientData)
+ int fd; /* Handle of stream to watch. */
+ int mask; /* OR'ed combination of TCL_READABLE,
+ * TCL_WRITABLE, and TCL_EXCEPTION:
+ * indicates conditions under which
+ * proc should be called. */
+ Tcl_FileProc *proc; /* Procedure to call for each
+ * selected event. */
+ ClientData clientData; /* Arbitrary data to pass to proc. */
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr;
+
+ if (tclStubs.tcl_CreateFileHandler != tclOriginalNotifier.createFileHandlerProc) {
+ tclStubs.tcl_CreateFileHandler(fd, mask, proc, clientData);
+ return;
+ }
+
+ for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
+ filePtr = filePtr->nextPtr) {
+ if (filePtr->fd == fd) {
+ break;
+ }
+ }
+ if (filePtr == NULL) {
+ filePtr = (FileHandler*) ckalloc(sizeof(FileHandler));
+ filePtr->fd = fd;
+ filePtr->readyMask = 0;
+ filePtr->nextPtr = tsdPtr->firstFileHandlerPtr;
+ tsdPtr->firstFileHandlerPtr = filePtr;
+ }
+ filePtr->proc = proc;
+ filePtr->clientData = clientData;
+ filePtr->mask = mask;
+
+ /*
+ * Update the check masks for this file.
+ */
+
+ if (mask & TCL_READABLE) {
+ FD_SET(fd, &(tsdPtr->checkMasks.readable));
+ } else {
+ FD_CLR(fd, &(tsdPtr->checkMasks.readable));
+ }
+ if (mask & TCL_WRITABLE) {
+ FD_SET(fd, &(tsdPtr->checkMasks.writable));
+ } else {
+ FD_CLR(fd, &(tsdPtr->checkMasks.writable));
+ }
+ if (mask & TCL_EXCEPTION) {
+ FD_SET(fd, &(tsdPtr->checkMasks.exceptional));
+ } else {
+ FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
+ }
+ if (tsdPtr->numFdBits <= fd) {
+ tsdPtr->numFdBits = fd+1;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_DeleteFileHandler --
+ *
+ * Cancel a previously-arranged callback arrangement for
+ * a file.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * If a callback was previously registered on file, remove it.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+Tcl_DeleteFileHandler(fd)
+ int fd; /* Stream id for which to remove callback procedure. */
+{
+ FileHandler *filePtr, *prevPtr;
+ int i;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ if (tclStubs.tcl_DeleteFileHandler != tclOriginalNotifier.deleteFileHandlerProc) {
+ tclStubs.tcl_DeleteFileHandler(fd);
+ return;
+ }
+
+ /*
+ * Find the entry for the given file (and return if there isn't one).
+ */
+
+ for (prevPtr = NULL, filePtr = tsdPtr->firstFileHandlerPtr; ;
+ prevPtr = filePtr, filePtr = filePtr->nextPtr) {
+ if (filePtr == NULL) {
+ return;
+ }
+ if (filePtr->fd == fd) {
+ break;
+ }
+ }
+
+ /*
+ * Update the check masks for this file.
+ */
+
+ if (filePtr->mask & TCL_READABLE) {
+ FD_CLR(fd, &(tsdPtr->checkMasks.readable));
+ }
+ if (filePtr->mask & TCL_WRITABLE) {
+ FD_CLR(fd, &(tsdPtr->checkMasks.writable));
+ }
+ if (filePtr->mask & TCL_EXCEPTION) {
+ FD_CLR(fd, &(tsdPtr->checkMasks.exceptional));
+ }
+
+ /*
+ * Find current max fd.
+ */
+
+ if (fd+1 == tsdPtr->numFdBits) {
+ tsdPtr->numFdBits = 0;
+ for (i = fd-1; i >= 0; i--) {
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))
+ || FD_ISSET(i, &(tsdPtr->checkMasks.writable))
+ || FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) {
+ tsdPtr->numFdBits = i+1;
+ break;
+ }
+ }
+ }
+
+ /*
+ * Clean up information in the callback record.
+ */
+
+ if (prevPtr == NULL) {
+ tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = filePtr->nextPtr;
+ }
+ ckfree((char *) filePtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * FileHandlerEventProc --
+ *
+ * This procedure is called by Tcl_ServiceEvent when a file event
+ * reaches the front of the event queue. This procedure is
+ * responsible for actually handling the event by invoking the
+ * callback for the file handler.
+ *
+ * Results:
+ * Returns 1 if the event was handled, meaning it should be removed
+ * from the queue. Returns 0 if the event was not handled, meaning
+ * it should stay on the queue. The only time the event isn't
+ * handled is if the TCL_FILE_EVENTS flag bit isn't set.
+ *
+ * Side effects:
+ * Whatever the file handler's callback procedure does.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+FileHandlerEventProc(evPtr, flags)
+ Tcl_Event *evPtr; /* Event to service. */
+ int flags; /* Flags that indicate what events to
+ * handle, such as TCL_FILE_EVENTS. */
+{
+ int mask;
+ FileHandler *filePtr;
+ FileHandlerEvent *fileEvPtr = (FileHandlerEvent *) evPtr;
+ ThreadSpecificData *tsdPtr;
+
+ if (!(flags & TCL_FILE_EVENTS)) {
+ return 0;
+ }
+
+ /*
+ * Search through the file handlers to find the one whose handle matches
+ * the event. We do this rather than keeping a pointer to the file
+ * handler directly in the event, so that the handler can be deleted
+ * while the event is queued without leaving a dangling pointer.
+ */
+
+ tsdPtr = TCL_TSD_INIT(&dataKey);
+ for (filePtr = tsdPtr->firstFileHandlerPtr; filePtr != NULL;
+ filePtr = filePtr->nextPtr) {
+ if (filePtr->fd != fileEvPtr->fd) {
+ continue;
+ }
+
+ /*
+ * The code is tricky for two reasons:
+ * 1. The file handler's desired events could have changed
+ * since the time when the event was queued, so AND the
+ * ready mask with the desired mask.
+ * 2. The file could have been closed and re-opened since
+ * the time when the event was queued. This is why the
+ * ready mask is stored in the file handler rather than
+ * the queued event: it will be zeroed when a new
+ * file handler is created for the newly opened file.
+ */
+
+ mask = filePtr->readyMask & filePtr->mask;
+ filePtr->readyMask = 0;
+ if (mask != 0) {
+ (*filePtr->proc)(filePtr->clientData, mask);
+ }
+ break;
+ }
+ return 1;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_WaitForEvent --
+ *
+ * This function is called by Tcl_DoOneEvent to wait for new
+ * events on the message queue. If the block time is 0, then
+ * Tcl_WaitForEvent just polls without blocking.
+ *
+ * Results:
+ * Returns -1 if the select would block forever, otherwise
+ * returns 0.
+ *
+ * Side effects:
+ * Queues file events that are detected by the select.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_WaitForEvent(timePtr)
+ Tcl_Time *timePtr; /* Maximum block time, or NULL. */
+{
+ FileHandler *filePtr;
+ FileHandlerEvent *fileEvPtr;
+ int mask;
+ Tcl_Time myTime;
+ int waitForFiles;
+ Tcl_Time *myTimePtr;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ if (tclStubs.tcl_WaitForEvent != tclOriginalNotifier.waitForEventProc) {
+ return tclStubs.tcl_WaitForEvent(timePtr);
+ }
+
+ if (timePtr != NULL) {
+ /* TIP #233 (Virtualized Time). Is virtual time in effect ?
+ * And do we actually have something to scale ? If yes to both
+ * then we call the handler to do this scaling */
+
+ myTime.sec = timePtr->sec;
+ myTime.usec = timePtr->usec;
+
+ if (myTime.sec != 0 || myTime.usec != 0) {
+ (*tclScaleTimeProcPtr) (&myTime, tclTimeClientData);
+ }
+
+ myTimePtr = &myTime;
+ } else {
+ myTimePtr = NULL;
+ }
+
+ /*
+ * Place this thread on the list of interested threads, signal the
+ * notifier thread, and wait for a response or a timeout.
+ */
+
+ LOCK_NOTIFIER;
+
+ waitForFiles = (tsdPtr->numFdBits > 0);
+ if (myTimePtr != NULL && myTimePtr->sec == 0 && myTimePtr->usec == 0) {
+ /*
+ * Cannot emulate a polling select with a polling condition variable.
+ * Instead, pretend to wait for files and tell the notifier
+ * thread what we are doing. The notifier thread makes sure
+ * it goes through select with its select mask in the same state
+ * as ours currently is. We block until that happens.
+ */
+
+ waitForFiles = 1;
+ tsdPtr->pollState = POLL_WANT;
+ myTimePtr = NULL;
+ } else {
+ tsdPtr->pollState = 0;
+ }
+
+ if (waitForFiles) {
+ /*
+ * Add the ThreadSpecificData structure of this thread to the list
+ * of ThreadSpecificData structures of all threads that are waiting
+ * on file events.
+ */
+
+ tsdPtr->nextPtr = waitingListPtr;
+ if (waitingListPtr) {
+ waitingListPtr->prevPtr = tsdPtr;
+ }
+ tsdPtr->prevPtr = 0;
+ waitingListPtr = tsdPtr;
+ tsdPtr->onList = 1;
+
+ write(triggerPipe, "", 1);
+ }
+
+ FD_ZERO(&(tsdPtr->readyMasks.readable));
+ FD_ZERO(&(tsdPtr->readyMasks.writable));
+ FD_ZERO(&(tsdPtr->readyMasks.exceptional));
+
+ if (!tsdPtr->eventReady) {
+ CFTimeInterval waitTime;
+
+ if (myTimePtr == NULL) {
+ waitTime = 1.0e10; /* Wait forever, as per CFRunLoop.c */
+ } else {
+ waitTime = myTimePtr->sec + 1.0e-6 * myTimePtr->usec;
+ }
+ UNLOCK_NOTIFIER;
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, waitTime, TRUE);
+ LOCK_NOTIFIER;
+ }
+ tsdPtr->eventReady = 0;
+
+ if (waitForFiles && tsdPtr->onList) {
+ /*
+ * Remove the ThreadSpecificData structure of this thread from the
+ * waiting list. Alert the notifier thread to recompute its select
+ * masks - skipping this caused a hang when trying to close a pipe
+ * which the notifier thread was still doing a select on.
+ */
+
+ if (tsdPtr->prevPtr) {
+ tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
+ } else {
+ waitingListPtr = tsdPtr->nextPtr;
+ }
+ if (tsdPtr->nextPtr) {
+ tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+ }
+ tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
+ tsdPtr->onList = 0;
+ write(triggerPipe, "", 1);
+ }
+
+
+ /*
+ * Queue all detected file events before returning.
+ */
+
+ for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
+ filePtr = filePtr->nextPtr) {
+
+ mask = 0;
+ if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.readable))) {
+ mask |= TCL_READABLE;
+ }
+ if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.writable))) {
+ mask |= TCL_WRITABLE;
+ }
+ if (FD_ISSET(filePtr->fd, &(tsdPtr->readyMasks.exceptional))) {
+ mask |= TCL_EXCEPTION;
+ }
+
+ if (!mask) {
+ continue;
+ }
+
+ /*
+ * Don't bother to queue an event if the mask was previously
+ * non-zero since an event must still be on the queue.
+ */
+
+ if (filePtr->readyMask == 0) {
+ fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+ }
+ filePtr->readyMask = mask;
+ }
+ UNLOCK_NOTIFIER;
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * NotifierThreadProc --
+ *
+ * This routine is the initial (and only) function executed by the
+ * special notifier thread. Its job is to wait for file descriptors
+ * to become readable or writable or to have an exception condition
+ * and then to notify other threads who are interested in this
+ * information by signalling a condition variable. Other threads
+ * can signal this notifier thread of a change in their interests
+ * by writing a single byte to a special pipe that the notifier
+ * thread is monitoring.
+ *
+ * Result:
+ * None. Once started, this routine never exits. It dies with
+ * the overall process.
+ *
+ * Side effects:
+ * The trigger pipe used to signal the notifier thread is created
+ * when the notifier thread first starts.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+NotifierThreadProc(clientData)
+ ClientData clientData; /* Not used. */
+{
+ ThreadSpecificData *tsdPtr;
+ fd_set readableMask;
+ fd_set writableMask;
+ fd_set exceptionalMask;
+ int i, numFdBits = 0;
+ long found;
+ struct timeval poll = {0., 0.}, *timePtr;
+ char buf[2];
+
+ /*
+ * Look for file events and report them to interested threads.
+ */
+
+ while (1) {
+ FD_ZERO(&readableMask);
+ FD_ZERO(&writableMask);
+ FD_ZERO(&exceptionalMask);
+
+ /*
+ * Compute the logical OR of the select masks from all the
+ * waiting notifiers.
+ */
+
+ LOCK_NOTIFIER;
+ timePtr = NULL;
+ for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
+ for (i = tsdPtr->numFdBits-1; i >= 0; --i) {
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))) {
+ FD_SET(i, &readableMask);
+ }
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))) {
+ FD_SET(i, &writableMask);
+ }
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))) {
+ FD_SET(i, &exceptionalMask);
+ }
+ }
+ if (tsdPtr->numFdBits > numFdBits) {
+ numFdBits = tsdPtr->numFdBits;
+ }
+ if (tsdPtr->pollState & POLL_WANT) {
+ /*
+ * Here we make sure we go through select() with the same
+ * mask bits that were present when the thread tried to poll.
+ */
+
+ tsdPtr->pollState |= POLL_DONE;
+ timePtr = &poll;
+ }
+ }
+ UNLOCK_NOTIFIER;
+
+ /*
+ * Set up the select mask to include the receive pipe.
+ */
+
+ if (receivePipe >= numFdBits) {
+ numFdBits = receivePipe + 1;
+ }
+ FD_SET(receivePipe, &readableMask);
+
+ if (select(numFdBits, &readableMask, &writableMask, &exceptionalMask,
+ timePtr) == -1) {
+ /*
+ * Try again immediately on an error.
+ */
+
+ continue;
+ }
+
+ /*
+ * Alert any threads that are waiting on a ready file descriptor.
+ */
+
+ LOCK_NOTIFIER;
+ for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
+ found = 0;
+
+ for (i = tsdPtr->numFdBits-1; i >= 0; --i) {
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.readable))
+ && FD_ISSET(i, &readableMask)) {
+ FD_SET(i, &(tsdPtr->readyMasks.readable));
+ found = 1;
+ }
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.writable))
+ && FD_ISSET(i, &writableMask)) {
+ FD_SET(i, &(tsdPtr->readyMasks.writable));
+ found = 1;
+ }
+ if (FD_ISSET(i, &(tsdPtr->checkMasks.exceptional))
+ && FD_ISSET(i, &exceptionalMask)) {
+ FD_SET(i, &(tsdPtr->readyMasks.exceptional));
+ found = 1;
+ }
+ }
+
+ if (found || (tsdPtr->pollState & POLL_DONE)) {
+ tsdPtr->eventReady = 1;
+ if (tsdPtr->onList) {
+ /*
+ * Remove the ThreadSpecificData structure of this
+ * thread from the waiting list. This prevents us from
+ * continuously spining on select until the other
+ * threads runs and services the file event.
+ */
+
+ if (tsdPtr->prevPtr) {
+ tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
+ } else {
+ waitingListPtr = tsdPtr->nextPtr;
+ }
+ if (tsdPtr->nextPtr) {
+ tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
+ }
+ tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
+ tsdPtr->onList = 0;
+ tsdPtr->pollState = 0;
+ }
+ if (tsdPtr->runLoop) {
+ CFRunLoopSourceSignal(tsdPtr->runLoopSource);
+ CFRunLoopWakeUp(tsdPtr->runLoop);
+ }
+ }
+ }
+ UNLOCK_NOTIFIER;
+
+ /*
+ * Consume the next byte from the notifier pipe if the pipe was
+ * readable. Note that there may be multiple bytes pending, but
+ * to avoid a race condition we only read one at a time.
+ */
+
+ if (FD_ISSET(receivePipe, &readableMask)) {
+ i = read(receivePipe, buf, 1);
+
+ if ((i == 0) || ((i == 1) && (buf[0] == 'q'))) {
+ /*
+ * Someone closed the write end of the pipe or sent us a
+ * Quit message [Bug: 4139] and then closed the write end
+ * of the pipe so we need to shut down the notifier thread.
+ */
+
+ break;
+ }
+ }
+ }
+ pthread_exit (0);
+}
+
+#endif /* HAVE_COREFOUNDATION */
Index: tests/unixNotfy.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/unixNotfy.test,v
retrieving revision 1.17
diff -u -p -u -p -r1.17 unixNotfy.test
--- tests/unixNotfy.test 24 Jun 2004 10:34:12 -0000 1.17
+++ tests/unixNotfy.test 14 May 2005 19:11:46 -0000
@@ -24,8 +24,10 @@ if {[lsearch [namespace children] ::tclt
# When run in a Tk shell, these tests hang.
testConstraint noTk [expr {![info exists tk_version]}]
testConstraint testthread [expr {[info commands testthread] != {}}]
+# Darwin always uses a threaded notifier
testConstraint unthreaded [expr {
- ![info exist tcl_platform(threaded)] || !$tcl_platform(threaded)
+ (![info exist tcl_platform(threaded)] || !$tcl_platform(threaded))
+ && $tcl_platform(os) ne "Darwin"
}]
# The next two tests will hang if threads are enabled because the notifier
Index: unix/Makefile.in
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/Makefile.in,v
retrieving revision 1.166
diff -u -p -u -p -r1.166 Makefile.in
--- unix/Makefile.in 13 May 2005 17:12:19 -0000 1.166
+++ unix/Makefile.in 14 May 2005 19:11:46 -0000
@@ -323,7 +323,7 @@ TOMMATH_OBJS = bncore.o bn_reverse.o bn_
STUB_LIB_OBJS = tclStubLib.o ${COMPAT_OBJS}
-MAC_OSX_OBJS = tclMacOSXBundle.o tclMacOSXFCmd.o
+MAC_OSX_OBJS = tclMacOSXBundle.o tclMacOSXFCmd.o tclMacOSXNotify.o
OBJS = ${GENERIC_OBJS} ${TOMMATH_OBJS} ${UNIX_OBJS} ${NOTIFY_OBJS} \
${COMPAT_OBJS} @DL_OBJS@ @PLAT_OBJS@
@@ -504,7 +504,8 @@ DL_SRCS = \
MAC_OSX_SRCS = \
$(MAC_OSX_DIR)/tclMacOSXBundle.c \
- $(MAC_OSX_DIR)/tclMacOSXFCmd.c
+ $(MAC_OSX_DIR)/tclMacOSXFCmd.c \
+ $(MAC_OSX_DIR)/tclMacOSXNotify.c
# Note: don't include DL_SRCS or MAC_OSX_SRCS in SRCS: most of those
# files won't compile on the current machine, and they will cause
@@ -825,6 +826,9 @@ install-private-headers: libraries
do \
$(INSTALL_DATA) $$i $(PRIVATE_INCLUDE_INSTALL_DIR); \
done;
+ @if test -f tclConfig.h; then\
+ $(INSTALL_DATA) tclConfig.h $(PRIVATE_INCLUDE_INSTALL_DIR); \
+ fi;
Makefile: $(UNIX_DIR)/Makefile.in $(DLTEST_DIR)/Makefile.in
$(SHELL) config.status
@@ -1352,6 +1356,9 @@ tclMacOSXBundle.o: $(MAC_OSX_DIR)/tclMac
tclMacOSXFCmd.o: $(MAC_OSX_DIR)/tclMacOSXFCmd.c
$(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXFCmd.c
+tclMacOSXNotify.o: $(MAC_OSX_DIR)/tclMacOSXNotify.c
+ $(CC) -c $(CC_SWITCHES) $(MAC_OSX_DIR)/tclMacOSXNotify.c
+
# The following targets are not completely general. They are provide
# purely for documentation purposes so people who are interested in
# the Xt based notifier can modify them to suit their own installation.
Index: unix/configure
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/configure,v
retrieving revision 1.144
diff -u -p -u -p -r1.144 configure
--- unix/configure 7 May 2005 00:05:56 -0000 1.144
+++ unix/configure 14 May 2005 19:11:47 -0000
@@ -851,6 +851,7 @@ Optional Features:
--enable-shared build and link with shared libraries --enable-shared
--enable-64bit enable 64bit support (where applicable)
--enable-64bit-vis enable 64bit Sparc VIS support
+ --enable-corefoundation use CoreFoundation API --enable-corefoundation
--disable-load disallow dynamic loading and "load" command
--enable-symbols build with debugging symbols --disable-symbols
--enable-langinfo use nl_langinfo if possible to determine
@@ -1322,6 +1323,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
TCL_VERSION=8.5
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=5
@@ -7913,19 +7915,344 @@ echo "${ECHO_T}$tcl_cv_ld_search_paths_f
CC_SEARCH_FLAGS=""
LD_SEARCH_FLAGS=""
LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH"
- PLAT_OBJS="\${MAC_OSX_OBJS}"
- PLAT_SRCS="\${MAC_OSX_SRCS}"
+ PLAT_OBJS='${MAC_OSX_OBJS}'
+ PLAT_SRCS='${MAC_OSX_SRCS}'
TCL_SHLIB_LD_EXTRAS='-compatibility_version ${VERSION} -current_version ${VERSION} -install_name ${DYLIB_INSTALL_DIR}/${TCL_LIB_FILE} -seg1addr 0xa000000'
TK_SHLIB_LD_EXTRAS=' -compatibility_version ${VERSION} -current_version ${VERSION} -install_name ${DYLIB_INSTALL_DIR}/${TK_LIB_FILE} -seg1addr 0xb000000 -unexported_symbols_list $$(f=$(TCL_STUB_LIB_FILE).E && nm -gjp $(TCL_BIN_DIR)/$(TCL_STUB_LIB_FILE) | tail +3 > $$f && echo $$f)'
- LIBS="$LIBS -framework CoreFoundation"
+ echo "$as_me:$LINENO: checking whether to use CoreFoundation" >&5
+echo $ECHO_N "checking whether to use CoreFoundation... $ECHO_C" >&6
+ # Check whether --enable-corefoundation or --disable-corefoundation was given.
+if test "${enable_corefoundation+set}" = set; then
+ enableval="$enable_corefoundation"
+ tcl_corefoundation=$enableval
+else
+ tcl_corefoundation=yes
+fi;
+ echo "$as_me:$LINENO: result: $tcl_corefoundation" >&5
+echo "${ECHO_T}$tcl_corefoundation" >&6
+ if test $tcl_corefoundation = yes; then
+ echo "$as_me:$LINENO: checking for CoreFoundation.framework" >&5
+echo $ECHO_N "checking for CoreFoundation.framework... $ECHO_C" >&6
+if test "${tcl_cv_lib_corefoundation+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ hold_libs=$LIBS
+ LIBS="$LIBS -framework CoreFoundation"
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <CoreFoundation/CoreFoundation.h>
+int
+main ()
+{
+CFBundleRef b = CFBundleGetMainBundle();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ tcl_cv_lib_corefoundation=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+tcl_cv_lib_corefoundation=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS=$hold_libs
+fi
+echo "$as_me:$LINENO: result: $tcl_cv_lib_corefoundation" >&5
+echo "${ECHO_T}$tcl_cv_lib_corefoundation" >&6
+ if test $tcl_cv_lib_corefoundation = yes; then
+ LIBS="$LIBS -framework CoreFoundation"
cat >>confdefs.h <<\_ACEOF
-#define MAC_OSX_TCL 1
+#define HAVE_COREFOUNDATION 1
+_ACEOF
+
+ fi
+ fi
+
+for ac_header in libkern/OSAtomic.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------ ##
+## Report this to the tcl lists. ##
+## ------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ eval "$as_ac_Header=\$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+for ac_func in OSSpinLockLock
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+char (*f) () = $ac_func;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != $ac_func;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+eval "$as_ac_var=no"
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
cat >>confdefs.h <<\_ACEOF
-#define HAVE_CFBUNDLE 1
+#define MAC_OSX_TCL 1
_ACEOF
@@ -7943,6 +8270,103 @@ cat >>confdefs.h <<\_ACEOF
#define MODULE_SCOPE __private_extern__
_ACEOF
+ # prior to Darwin 7, realpath is not threadsafe, so don't
+ # use it when threads are enabled, c.f. bug # 711232:
+ echo "$as_me:$LINENO: checking for realpath" >&5
+echo $ECHO_N "checking for realpath... $ECHO_C" >&6
+if test "${ac_cv_func_realpath+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+/* Define realpath to an innocuous variant, in case <limits.h> declares realpath.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define realpath innocuous_realpath
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char realpath (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef realpath
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char realpath ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_realpath) || defined (__stub___realpath)
+choke me
+#else
+char (*f) () = realpath;
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+int
+main ()
+{
+return f != realpath;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag"
+ || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_realpath=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_func_realpath=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_realpath" >&5
+echo "${ECHO_T}$ac_cv_func_realpath" >&6
+
+ if test "$ac_cv_func_realpath" = yes -a "${TCL_THREADS}" = 1 \
+ -a `uname -r | awk -F. '{print $1}'` -lt 7 ; then
+ ac_cv_func_realpath=no
+ fi
;;
NEXTSTEP-*)
SHLIB_CFLAGS=""
@@ -14904,6 +15328,11 @@ echo "${ECHO_T}framework" >&6
echo "$as_me: WARNING: \"Frameworks can only be built if --enable-shared is yes\"" >&2;}
FRAMEWORK_BUILD=0
fi
+ if test $tcl_corefoundation = no; then
+ { echo "$as_me:$LINENO: WARNING: \"Frameworks can only be used when CoreFoundation is available\"" >&5
+echo "$as_me: WARNING: \"Frameworks can only be used when CoreFoundation is available\"" >&2;}
+ FRAMEWORK_BUILD=0
+ fi
else
echo "$as_me:$LINENO: result: standard shared library" >&5
echo "${ECHO_T}standard shared library" >&6
Index: unix/configure.in
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/configure.in,v
retrieving revision 1.128
diff -u -p -u -p -r1.128 configure.in
--- unix/configure.in 10 May 2005 18:35:26 -0000 1.128
+++ unix/configure.in 14 May 2005 19:11:47 -0000
@@ -7,8 +7,12 @@ dnl to configure the system for the loca
AC_INIT([tcl],[8.5])
AC_PREREQ(2.57)
+
dnl AC_CONFIG_HEADERS([tclConfig.h])
-dnl AC_CONFIG_COMMANDS_PRE([DEFS=-DHAVE_TCL_CONFIG_H])
+dnl AC_CONFIG_COMMANDS_PRE([DEFS="-DHAVE_TCL_CONFIG_H -imacros tclConfig.h"])
+dnl AH_TOP([#ifndef _TCLCONFIG
+dnl #define _TCLCONFIG])
+dnl AH_BOTTOM([#endif /* _TCLCONFIG */])
TCL_VERSION=8.5
TCL_MAJOR_VERSION=8
Index: unix/tcl.m4
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tcl.m4,v
retrieving revision 1.143
diff -u -p -u -p -r1.143 tcl.m4
--- unix/tcl.m4 7 May 2005 00:06:03 -0000 1.143
+++ unix/tcl.m4 14 May 2005 19:11:47 -0000
@@ -402,6 +402,10 @@ AC_DEFUN(SC_ENABLE_FRAMEWORK, [
AC_MSG_WARN("Frameworks can only be built if --enable-shared is yes")
FRAMEWORK_BUILD=0
fi
+ if test $tcl_corefoundation = no; then
+ AC_MSG_WARN("Frameworks can only be used when CoreFoundation is available")
+ FRAMEWORK_BUILD=0
+ fi
else
AC_MSG_RESULT([standard shared library])
FRAMEWORK_BUILD=0
@@ -1406,17 +1410,42 @@ dnl AC_CHECK_TOOL(AR, ar)
CC_SEARCH_FLAGS=""
LD_SEARCH_FLAGS=""
LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH"
- PLAT_OBJS="\${MAC_OSX_OBJS}"
- PLAT_SRCS="\${MAC_OSX_SRCS}"
+ PLAT_OBJS='${MAC_OSX_OBJS}'
+ PLAT_SRCS='${MAC_OSX_SRCS}'
TCL_SHLIB_LD_EXTRAS='-compatibility_version ${VERSION} -current_version ${VERSION} -install_name ${DYLIB_INSTALL_DIR}/${TCL_LIB_FILE} -seg1addr 0xa000000'
TK_SHLIB_LD_EXTRAS=' -compatibility_version ${VERSION} -current_version ${VERSION} -install_name ${DYLIB_INSTALL_DIR}/${TK_LIB_FILE} -seg1addr 0xb000000 -unexported_symbols_list $$(f=$(TCL_STUB_LIB_FILE).E && nm -gjp $(TCL_BIN_DIR)/$(TCL_STUB_LIB_FILE) | tail +3 > $$f && echo $$f)'
- LIBS="$LIBS -framework CoreFoundation"
- AC_DEFINE(MAC_OSX_TCL, 1, ["Is this a Mac I see before me?"])
- AC_DEFINE(HAVE_CFBUNDLE, 1, [Do we have access to Mac bundles?])
+ AC_MSG_CHECKING([whether to use CoreFoundation])
+ AC_ARG_ENABLE(corefoundation, [ --enable-corefoundation use CoreFoundation API [--enable-corefoundation]],
+ [tcl_corefoundation=$enableval], [tcl_corefoundation=yes])
+ AC_MSG_RESULT([$tcl_corefoundation])
+ if test $tcl_corefoundation = yes; then
+ AC_CACHE_CHECK([for CoreFoundation.framework], tcl_cv_lib_corefoundation, [
+ hold_libs=$LIBS
+ LIBS="$LIBS -framework CoreFoundation"
+ AC_TRY_LINK([#include <CoreFoundation/CoreFoundation.h>],
+ [CFBundleRef b = CFBundleGetMainBundle();],
+ tcl_cv_lib_corefoundation=yes, tcl_cv_lib_corefoundation=no)
+ LIBS=$hold_libs])
+ if test $tcl_cv_lib_corefoundation = yes; then
+ LIBS="$LIBS -framework CoreFoundation"
+ AC_DEFINE(HAVE_COREFOUNDATION, 1,
+ [Do we have access to Darwin CoreFoundation.framework ?])
+ fi
+ fi
+ AC_CHECK_HEADERS(libkern/OSAtomic.h)
+ AC_CHECK_FUNCS(OSSpinLockLock)
+ AC_DEFINE(MAC_OSX_TCL, 1, [Is this a Mac I see before me?])
AC_DEFINE(USE_VFORK, 1, [Should we use vfork() instead of fork()?])
AC_DEFINE(TCL_DEFAULT_ENCODING,"utf-8",
[Are we to override what our default encoding is?])
AC_DEFINE(MODULE_SCOPE, __private_extern__, [Linker support for module scope symbols])
+ # prior to Darwin 7, realpath is not threadsafe, so don't
+ # use it when threads are enabled, c.f. bug # 711232:
+ AC_CHECK_FUNC(realpath)
+ if test "$ac_cv_func_realpath" = yes -a "${TCL_THREADS}" = 1 \
+ -a `uname -r | awk -F. '{print [$]1}'` -lt 7 ; then
+ ac_cv_func_realpath=no
+ fi
;;
NEXTSTEP-*)
SHLIB_CFLAGS=""
Index: unix/tclConfig.h.in
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclConfig.h.in,v
retrieving revision 1.3
diff -u -p -u -p -r1.3 tclConfig.h.in
--- unix/tclConfig.h.in 9 Jan 2005 19:31:38 -0000 1.3
+++ unix/tclConfig.h.in 14 May 2005 19:11:47 -0000
@@ -1,5 +1,8 @@
/* tclConfig.h.in. Generated from configure.in by autoheader. */
+#ifndef _TCLCONFIG
+#define _TCLCONFIG
+
/* Is pthread_attr_get_np() declared in <pthread.h>? */
#undef ATTRGETNP_NOT_DECLARED
@@ -12,12 +15,12 @@
/* Do we have BSDgettimeofday()? */
#undef HAVE_BSDGETTIMEOFDAY
-/* Do we have access to Mac bundles? */
-#undef HAVE_CFBUNDLE
-
/* Define to 1 if you have the `chflags' function. */
#undef HAVE_CHFLAGS
+/* Do we have access to Darwin CoreFoundation.framework ? */
+#undef HAVE_COREFOUNDATION
+
/* Define to 1 if you have the `getattrlist' function. */
#undef HAVE_GETATTRLIST
@@ -33,12 +36,18 @@
/* Do we have nl_langinfo()? */
#undef HAVE_LANGINFO
+/* Define to 1 if you have the <libkern/OSAtomic.h> header file. */
+#undef HAVE_LIBKERN_OSATOMIC_H
+
/* Do we have <limits.h>? */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the `localtime_r' function. */
#undef HAVE_LOCALTIME_R
+/* Define to 1 if you have the `lseek64' function. */
+#undef HAVE_LSEEK64
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
@@ -48,9 +57,15 @@
/* Do we have <net/errno.h>? */
#undef HAVE_NET_ERRNO_H
+/* Define to 1 if you have the `open64' function. */
+#undef HAVE_OPEN64
+
/* Define to 1 if you have the `opendir' function. */
#undef HAVE_OPENDIR
+/* Define to 1 if you have the `OSSpinLockLock' function. */
+#undef HAVE_OSSPINLOCKLOCK
+
/* Do we want a BSD-like thread-attribute interface? */
#undef HAVE_PTHREAD_ATTR_GET_NP
@@ -78,9 +93,6 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
-/* Define to 1 if you have the `strstr' function. */
-#undef HAVE_STRSTR
-
/* Define to 1 if you have the `strtol' function. */
#undef HAVE_STRTOL
@@ -159,9 +171,12 @@
/* Define to 1 if you have the `waitpid' function. */
#undef HAVE_WAITPID
-/* "Is this a Mac I see before me?" */
+/* Is this a Mac I see before me? */
#undef MAC_OSX_TCL
+/* Linker support for module scope symbols */
+#undef MODULE_SCOPE
+
/* Do we have <dirent.h>? */
#undef NO_DIRENT_H
@@ -261,9 +276,6 @@
/* Are bytecode statistics enabled? */
#undef TCL_COMPILE_STATS
-/* What extra letters do we insert for debugging binary code? */
-#undef TCL_DBGX
-
/* Are we to override what our default encoding is? */
#undef TCL_DEFAULT_ENCODING
@@ -386,3 +398,5 @@
/* Define to `int' if <sys/types.h> doesn't define. */
#undef uid_t
+
+#endif /* _TCLCONFIG */
Index: unix/tclLoadDyld.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclLoadDyld.c,v
retrieving revision 1.15
diff -u -p -u -p -r1.15 tclLoadDyld.c
--- unix/tclLoadDyld.c 6 Apr 2004 22:25:56 -0000 1.15
+++ unix/tclLoadDyld.c 14 May 2005 19:11:47 -0000
@@ -23,7 +23,7 @@ typedef struct Tcl_DyldModuleHandle {
} Tcl_DyldModuleHandle;
typedef struct Tcl_DyldLoadHandle {
- const struct mach_header *dyld_lib;
+ CONST struct mach_header *dyld_lib;
Tcl_DyldModuleHandle *firstModuleHandle;
} Tcl_DyldLoadHandle;
@@ -59,7 +59,7 @@ TclpDlopen(interp, pathPtr, loadHandle,
* this file. */
{
Tcl_DyldLoadHandle *dyldLoadHandle;
- const struct mach_header *dyld_lib;
+ CONST struct mach_header *dyld_lib;
CONST char *native;
/*
@@ -89,7 +89,7 @@ TclpDlopen(interp, pathPtr, loadHandle,
if (!dyld_lib) {
NSLinkEditErrors editError;
- char *name, *msg;
+ CONST char *name, *msg;
NSLinkEditError(&editError, &errno, &name, &msg);
Tcl_AppendResult(interp, msg, (char *) NULL);
return TCL_ERROR;
@@ -152,7 +152,7 @@ TclpFindSymbol(interp, loadHandle, symbo
}
} else {
NSLinkEditErrors editError;
- char *name, *msg;
+ CONST char *name, *msg;
NSLinkEditError(&editError, &errno, &name, &msg);
Tcl_AppendResult(interp, msg, (char *) NULL);
}
@@ -198,7 +198,7 @@ TclpUnloadFile(loadHandle)
dyldModuleHandle = dyldModuleHandle->nextModuleHandle;
ckfree(ptr);
}
- ckfree(dyldLoadHandle);
+ ckfree((char*) dyldLoadHandle);
}
/*
Index: unix/tclUnixChan.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixChan.c,v
retrieving revision 1.56
diff -u -p -u -p -r1.56 tclUnixChan.c
--- unix/tclUnixChan.c 10 May 2005 18:35:27 -0000 1.56
+++ unix/tclUnixChan.c 14 May 2005 19:11:47 -0000
@@ -43,6 +43,13 @@
#define SUPPORTS_TTY
+#undef DIRECT_BAUD
+#ifdef B4800
+# if (B4800 == 4800)
+# define DIRECT_BAUD
+# endif /* B4800 == 4800 */
+#endif /* B4800 */
+
#ifdef USE_TERMIOS
# include <termios.h>
# ifdef HAVE_SYS_IOCTL_H
@@ -261,11 +268,15 @@ static int TtyCloseProc _ANSI_ARGS_((Cl
Tcl_Interp *interp));
static void TtyGetAttributes _ANSI_ARGS_((int fd,
TtyAttrs *ttyPtr));
+#ifndef DIRECT_BAUD
static int TtyGetBaud _ANSI_ARGS_((unsigned long speed));
+#endif
static int TtyGetOptionProc _ANSI_ARGS_((ClientData instanceData,
Tcl_Interp *interp, CONST char *optionName,
Tcl_DString *dsPtr));
+#ifndef DIRECT_BAUD
static unsigned long TtyGetSpeed _ANSI_ARGS_((int baud));
+#endif
static FileState * TtyInit _ANSI_ARGS_((int fd, int initialize));
static void TtyModemStatusStr _ANSI_ARGS_((int status,
Tcl_DString *dsPtr));
@@ -1190,13 +1201,6 @@ TtyGetOptionProc(instanceData, interp, o
}
}
-#undef DIRECT_BAUD
-#ifdef B4800
-# if (B4800 == 4800)
-# define DIRECT_BAUD
-# endif /* B4800 == 4800 */
-#endif /* B4800 */
-
#ifdef DIRECT_BAUD
# define TtyGetSpeed(baud) ((unsigned) (baud))
# define TtyGetBaud(speed) ((int) (speed))
Index: unix/tclUnixInit.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixInit.c,v
retrieving revision 1.56
diff -u -p -u -p -r1.56 tclUnixInit.c
--- unix/tclUnixInit.c 10 May 2005 18:35:27 -0000 1.56
+++ unix/tclUnixInit.c 14 May 2005 19:11:47 -0000
@@ -26,7 +26,7 @@
# include <dlfcn.h>
# endif
#endif
-#ifdef HAVE_CFBUNDLE
+#ifdef HAVE_COREFOUNDATION
#include <CoreFoundation/CoreFoundation.h>
#endif
@@ -328,11 +328,11 @@ static CONST LocaleTable localeTable[] =
#ifndef TCL_NO_STACK_CHECK
static int GetStackSize _ANSI_ARGS_((size_t *stackSizePtr));
#endif /* TCL_NO_STACK_CHECK */
-#ifdef HAVE_CFBUNDLE
+#ifdef HAVE_COREFOUNDATION
static int MacOSXGetLibraryPath _ANSI_ARGS_((
Tcl_Interp *interp, int maxPathLen,
char *tclLibPath));
-#endif /* HAVE_CFBUNDLE */
+#endif /* HAVE_COREFOUNDATION */
/*
@@ -511,13 +511,13 @@ TclpInitLibraryPath(valuePtr, lengthPtr,
*/
{
-#ifdef HAVE_CFBUNDLE
+#ifdef HAVE_COREFOUNDATION
char tclLibPath[MAXPATHLEN + 1];
if (MacOSXGetLibraryPath(NULL, MAXPATHLEN, tclLibPath) == TCL_OK) {
str = tclLibPath;
} else
-#endif /* HAVE_CFBUNDLE */
+#endif /* HAVE_COREFOUNDATION */
{
/* TODO: Pull this value from the TIP 59 table */
str = defaultLibraryDir;
@@ -724,7 +724,7 @@ TclpSetVariables(interp)
CONST char *user;
Tcl_DString ds;
-#ifdef HAVE_CFBUNDLE
+#ifdef HAVE_COREFOUNDATION
char tclLibPath[MAXPATHLEN + 1];
if (MacOSXGetLibraryPath(interp, MAXPATHLEN, tclLibPath) == TCL_OK) {
@@ -756,7 +756,7 @@ TclpSetVariables(interp)
Tcl_StatBuf statBuf;
if((frameworksURL = CFBundleCopyPrivateFrameworksURL(bundleRef))) {
if(CFURLGetFileSystemRepresentation(frameworksURL, TRUE,
- tclLibPath, MAXPATHLEN) &&
+ (unsigned char*) tclLibPath, MAXPATHLEN) &&
! TclOSstat(tclLibPath, &statBuf) &&
S_ISDIR(statBuf.st_mode)) {
Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath,
@@ -768,7 +768,7 @@ TclpSetVariables(interp)
}
if((frameworksURL = CFBundleCopySharedFrameworksURL(bundleRef))) {
if(CFURLGetFileSystemRepresentation(frameworksURL, TRUE,
- tclLibPath, MAXPATHLEN) &&
+ (unsigned char*) tclLibPath, MAXPATHLEN) &&
! TclOSstat(tclLibPath, &statBuf) &&
S_ISDIR(statBuf.st_mode)) {
Tcl_SetVar(interp, "tcl_pkgPath", tclLibPath,
@@ -782,7 +782,7 @@ TclpSetVariables(interp)
Tcl_SetVar(interp, "tcl_pkgPath", pkgPath,
TCL_GLOBAL_ONLY | TCL_APPEND_VALUE);
} else
-#endif /* HAVE_CFBUNDLE */
+#endif /* HAVE_COREFOUNDATION */
{
Tcl_SetVar(interp, "tcl_pkgPath", pkgPath, TCL_GLOBAL_ONLY);
}
@@ -1131,7 +1131,7 @@ GetStackSize(stackSizePtr)
*----------------------------------------------------------------------
*/
-#ifdef HAVE_CFBUNDLE
+#ifdef HAVE_COREFOUNDATION
static int
MacOSXGetLibraryPath(Tcl_Interp *interp, int maxPathLen, char *tclLibPath)
{
@@ -1142,4 +1142,4 @@ MacOSXGetLibraryPath(Tcl_Interp *interp,
#endif
return foundInFramework;
}
-#endif /* HAVE_CFBUNDLE */
+#endif /* HAVE_COREFOUNDATION */
Index: unix/tclUnixNotfy.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixNotfy.c,v
retrieving revision 1.23
diff -u -p -u -p -r1.23 tclUnixNotfy.c
--- unix/tclUnixNotfy.c 10 May 2005 18:35:28 -0000 1.23
+++ unix/tclUnixNotfy.c 14 May 2005 19:11:48 -0000
@@ -14,6 +14,8 @@
* RCS: @(#) $Id: tclUnixNotfy.c,v 1.23 2005/05/10 18:35:28 kennykb Exp $
*/
+#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier
+ * is in tclMacOSXNotify.c */
#include "tclInt.h"
#include <signal.h>
@@ -1080,3 +1082,5 @@ NotifierThreadProc(clientData)
TclpThreadExit (0);
}
#endif
+
+#endif /* HAVE_COREFOUNDATION */
Index: unix/tclUnixPort.h
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixPort.h,v
retrieving revision 1.41
diff -u -p -u -p -r1.41 tclUnixPort.h
--- unix/tclUnixPort.h 10 May 2005 18:35:28 -0000 1.41
+++ unix/tclUnixPort.h 14 May 2005 19:11:48 -0000
@@ -563,13 +563,6 @@ EXTERN char * TclpInetNtoa(str
* #define gmtime(x) TclpGmtime(x) */
# undef inet_ntoa
# define inet_ntoa(x) TclpInetNtoa(x)
-# ifdef MAC_OSX_TCL
-/*
- * On Mac OS X, realpath is currently not
- * thread safe, c.f. SF bug # 711232.
- */
-# define NO_REALPATH
-# endif
# ifdef HAVE_PTHREAD_ATTR_GET_NP
# define TclpPthreadGetAttrs pthread_attr_get_np
# ifdef ATTRGETNP_NOT_DECLARED
Index: win/tclWin32Dll.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWin32Dll.c,v
retrieving revision 1.42
diff -u -p -u -p -r1.42 tclWin32Dll.c
--- win/tclWin32Dll.c 13 May 2005 21:20:36 -0000 1.42
+++ win/tclWin32Dll.c 14 May 2005 19:11:48 -0000
@@ -627,29 +627,6 @@ TclpCheckStackSpace()
}
/*
- *----------------------------------------------------------------------
- *
- * TclWinGetPlatform --
- *
- * This is a kludge that allows the test library to get access
- * the internal tclPlatform variable.
- *
- * Results:
- * Returns a pointer to the tclPlatform variable.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-TclPlatformType *
-TclWinGetPlatform()
-{
- return &tclPlatform;
-}
-
-/*
*---------------------------------------------------------------------------
*
* TclWinSetInterfaces --