summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2021-09-24 13:23:18 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2021-09-24 13:23:18 (GMT)
commit00fc9b5939930c7993d830310e41b3fee2d930ca (patch)
treeb36b6dca7cda52369f1210596093f3764e1c8a0d /unix
parent9dd933ddbd77c005974356951f153c9f6de1236e (diff)
parent3d43898853cb0d4550889e72c6f6452cff60fa7d (diff)
downloadtcl-00fc9b5939930c7993d830310e41b3fee2d930ca.zip
tcl-00fc9b5939930c7993d830310e41b3fee2d930ca.tar.gz
tcl-00fc9b5939930c7993d830310e41b3fee2d930ca.tar.bz2
Merge 8.7
Diffstat (limited to 'unix')
-rw-r--r--unix/Makefile.in48
-rw-r--r--unix/README6
-rwxr-xr-xunix/configure311
-rw-r--r--unix/configure.ac9
-rw-r--r--unix/dltest/pkgooa.c7
-rw-r--r--unix/dltest/pkgua.c53
-rw-r--r--unix/tcl.m46
-rw-r--r--unix/tcl.pc.in2
-rw-r--r--unix/tcl.spec4
-rw-r--r--unix/tclAppInit.c15
-rw-r--r--unix/tclConfig.h.in3
-rw-r--r--unix/tclEpollNotfy.c565
-rw-r--r--unix/tclKqueueNotfy.c551
-rw-r--r--unix/tclLoadDyld.c6
-rw-r--r--unix/tclLoadNext.c2
-rw-r--r--unix/tclLoadOSF.c4
-rw-r--r--unix/tclLoadShl.c2
-rw-r--r--unix/tclSelectNotfy.c918
-rw-r--r--unix/tclUnixChan.c13
-rw-r--r--unix/tclUnixEvent.c4
-rw-r--r--unix/tclUnixFCmd.c8
-rw-r--r--unix/tclUnixFile.c27
-rw-r--r--unix/tclUnixNotfy.c221
-rw-r--r--unix/tclUnixPort.h3
-rw-r--r--unix/tclUnixThrd.c8
-rw-r--r--unix/tclUnixTime.c51
-rw-r--r--unix/tclXtNotify.c8
-rw-r--r--unix/tclXtTest.c3
28 files changed, 1576 insertions, 1282 deletions
diff --git a/unix/Makefile.in b/unix/Makefile.in
index 7b32815..f97573e 100644
--- a/unix/Makefile.in
+++ b/unix/Makefile.in
@@ -209,7 +209,7 @@ TCL_LIB_FLAG = @TCL_LIB_FLAG@
#TCL_LIB_FLAG = -ltcl
# support for embedded libraries on Darwin / Mac OS X
-DYLIB_INSTALL_DIR = ${LIB_RUNTIME_DIR}
+DYLIB_INSTALL_DIR = $(libdir)
#--------------------------------------------------------------------------
# The information below is modified by the configure script when Makefile is
@@ -268,6 +268,7 @@ TRACE_OPTS =
VALGRIND = valgrind
VALGRINDARGS = --tool=memcheck --num-callers=24 \
--leak-resolution=high --leak-check=yes --show-reachable=yes -v \
+ --keep-debuginfo=yes \
--suppressions=$(TOOL_DIR)/valgrind_suppress
#--------------------------------------------------------------------------
@@ -673,7 +674,8 @@ UNIX_SRCS = \
NOTIFY_SRCS = \
$(UNIX_DIR)/tclEpollNotfy.c \
$(UNIX_DIR)/tclKqueueNotfy.c \
- $(UNIX_DIR)/tclSelectNotfy.c
+ $(UNIX_DIR)/tclSelectNotfy.c \
+ $(UNIX_DIR)/tclUnixNotfy.c
DL_SRCS = \
$(UNIX_DIR)/tclLoadAix.c \
@@ -903,18 +905,13 @@ test-tcl: ${TCLTEST_EXE}
$(SHELL_ENV) ./${TCLTEST_EXE} $(TOP_DIR)/tests/all.tcl $(TESTFLAGS)
gdb-test: ${TCLTEST_EXE}
- @echo "set env @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > gdb.run
- @echo "set env TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> gdb.run
- @echo "set args $(TOP_DIR)/tests/all.tcl $(TESTFLAGS) -singleproc 1" >> gdb.run
- $(GDB) ./${TCLTEST_EXE} --command=gdb.run
- @rm gdb.run
+ $(SHELL_ENV) $(GDB) --args ./${TCLTEST_EXE} $(TOP_DIR)/tests/all.tcl \
+ $(TESTFLAGS) -singleproc 1
lldb-test: ${TCLTEST_EXE}
- @echo "settings set target.env-vars @LD_LIBRARY_PATH_VAR@=`pwd`:$${@LD_LIBRARY_PATH_VAR@}" > lldb.run
- @echo "settings set target.env-vars TCL_LIBRARY=${TCL_BUILDTIME_LIBRARY}" >> lldb.run
- $(LLDB) --source lldb.run ./${TCLTEST_EXE} -- $(TOP_DIR)/tests/all.tcl \
+ $(SHELL_ENV) $(LLDB) -- ./${TCLTEST_EXE} $(TOP_DIR)/tests/all.tcl \
$(TESTFLAGS) -singleproc 1
- @rm lldb.run
+
# Useful target to launch a built tcltest with the proper path,...
runtest: ${TCLTEST_EXE}
@@ -947,6 +944,9 @@ shell: ${TCL_EXE}
gdb: ${TCL_EXE}
$(SHELL_ENV) $(GDB) ./${TCL_EXE}
+lldb: ${TCL_EXE}
+ $(SHELL_ENV) $(LLDB) ./${TCL_EXE}
+
valgrind: ${TCL_EXE} ${TCLTEST_EXE}
$(SHELL_ENV) $(VALGRIND) $(VALGRINDARGS) ./${TCLTEST_EXE} \
$(TOP_DIR)/tests/all.tcl -singleproc 1 -constraints valgrind \
@@ -1041,9 +1041,9 @@ install-libraries: libraries
@for i in $(TOP_DIR)/library/cookiejar/*.gz; do \
$(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/cookiejar0.2"; \
done
- @echo "Installing package http 2.10.0a1 as a Tcl Module"
+ @echo "Installing package http 2.10a1 as a Tcl Module"
@$(INSTALL_DATA) $(TOP_DIR)/library/http/http.tcl \
- "$(MODULE_INSTALL_DIR)/8.6/http-2.10.0a1.tm"
+ "$(MODULE_INSTALL_DIR)/8.6/http-2.10a1.tm"
@echo "Installing package opt 0.4.7"
@for i in $(TOP_DIR)/library/opt/*.tcl; do \
$(INSTALL_DATA) $$i "$(SCRIPT_INSTALL_DIR)/opt0.4"; \
@@ -1529,7 +1529,7 @@ tclZlib.o: $(GENERIC_DIR)/tclZlib.c
$(CC) -c $(CC_SWITCHES) $(ZLIB_INCLUDE) $(GENERIC_DIR)/tclZlib.c
tclZipfs.o: $(GENERIC_DIR)/tclZipfs.c
- $(CC) -c $(CC_SWITCHES) \
+ $(CC) -c $(CC_SWITCHES) -D_GNU_SOURCE \
-DCFG_RUNTIME_DLLFILE="\"$(TCL_LIB_FILE)\"" \
-DCFG_RUNTIME_LIBDIR="\"$(libdir)\"" \
-I$(ZLIB_DIR) -I$(ZLIB_DIR)/contrib/minizip \
@@ -1778,13 +1778,13 @@ tclUnixFCmd.o: $(UNIX_DIR)/tclUnixFCmd.c
tclUnixFile.o: $(UNIX_DIR)/tclUnixFile.c $(FSHDR)
$(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclUnixFile.c
-tclEpollNotfy.o: $(UNIX_DIR)/tclEpollNotfy.c
+tclEpollNotfy.o: $(UNIX_DIR)/tclEpollNotfy.c $(UNIX_DIR)/tclUnixNotfy.c
$(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclEpollNotfy.c
-tclKqueueNotfy.o: $(UNIX_DIR)/tclKqueueNotfy.c
+tclKqueueNotfy.o: $(UNIX_DIR)/tclKqueueNotfy.c $(UNIX_DIR)/tclUnixNotfy.c
$(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclKqueueNotfy.c
-tclSelectNotfy.o: $(UNIX_DIR)/tclSelectNotfy.c
+tclSelectNotfy.o: $(UNIX_DIR)/tclSelectNotfy.c $(UNIX_DIR)/tclUnixNotfy.c
$(CC) -c $(CC_SWITCHES) $(UNIX_DIR)/tclSelectNotfy.c
tclUnixPipe.o: $(UNIX_DIR)/tclUnixPipe.c
@@ -2273,7 +2273,7 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in gen
mkdir $(DISTDIR)/library/$$i;\
cp -p $(TOP_DIR)/library/$$i/*.tcl $(DISTDIR)/library/$$i; \
done
- cp -p $(TOP_DIR)/library/cookiejar/*.txt.gz $(DISTDIR)/library/cookiejar
+ cp -p $(TOP_DIR)/library/cookiejar/*.dat.gz $(DISTDIR)/library/cookiejar
@mkdir $(DISTDIR)/library/encoding
cp -p $(TOP_DIR)/library/encoding/*.enc $(DISTDIR)/library/encoding
@mkdir $(DISTDIR)/library/msgs
@@ -2293,11 +2293,16 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in gen
@( cd $(COMPAT_DIR)/zlib; find . -type f -print ) \
| ( cd $(COMPAT_DIR)/zlib ; xargs tar cf - ) \
| ( cd $(DISTDIR)/compat/zlib ; tar xfp - )
+ @mkdir $(DISTDIR)/libtommath
+ @echo cp -r $(TOP_DIR)/libtommath $(DISTDIR)/libtommath
+ @( cd $(TOP_DIR)/libtommath; find . -type f -print ) \
+ | ( cd $(TOP_DIR)/libtommath ; xargs tar cf - ) \
+ | ( cd $(DISTDIR)/libtommath ; tar xfp - )
@mkdir $(DISTDIR)/tests
cp -p $(TOP_DIR)/license.terms $(DISTDIR)/tests
cp -p $(TOP_DIR)/tests/*.test $(TOP_DIR)/tests/README \
$(TOP_DIR)/tests/httpd $(TOP_DIR)/tests/*.tcl \
- $(DISTDIR)/tests
+ $(TOP_DIR)/tests/auto-files.zip $(DISTDIR)/tests
@mkdir $(DISTDIR)/tests/auto0
for i in auto1 auto2 ; \
do \
@@ -2346,8 +2351,6 @@ dist: $(UNIX_DIR)/configure $(UNIX_DIR)/tclConfig.h.in $(UNIX_DIR)/tcl.pc.in gen
cp -p $(TOOL_DIR)/README $(TOOL_DIR)/*.c $(TOOL_DIR)/*.svg \
$(TOOL_DIR)/*.tcl $(TOOL_DIR)/*.bmp \
$(TOOL_DIR)/valgrind_suppress $(DISTDIR)/tools
- @mkdir $(DISTDIR)/libtommath
- cp -p $(TOMMATH_SRCS) $(TOMMATH_DIR)/*.h $(DISTDIR)/libtommath
@mkdir $(DISTDIR)/pkgs
cp -p $(TOP_DIR)/pkgs/README $(DISTDIR)/pkgs
cp -p $(TOP_DIR)/pkgs/package.list.txt $(DISTDIR)/pkgs
@@ -2394,7 +2397,8 @@ html-tk: ${NATIVE_TCLSH}
BUILD_HTML = \
@${NATIVE_TCLSH} $(TOOL_DIR)/tcltk-man2html.tcl \
- --tcl --useversion=$(MAJOR_VERSION).$(MINOR_VERSION) --htmldir="$(HTML_INSTALL_DIR)" \
+ --useversion=$(MAJOR_VERSION).$(MINOR_VERSION) \
+ --htmldir="$(HTML_INSTALL_DIR)" \
--srcdir=$(TOP_DIR) $(BUILD_HTML_FLAGS)
#--------------------------------------------------------------------------
diff --git a/unix/README b/unix/README
index 3c1a207..b8adc71 100644
--- a/unix/README
+++ b/unix/README
@@ -8,11 +8,11 @@ MacOSX platform too, but they all depend on UNIX (POSIX/ANSI C) interfaces and
some of them only make sense under UNIX.
Updated forms of the information found in this file is available at:
- http://www.tcl.tk/doc/howto/compile.html#unix
+ https://www.tcl-tk.org/doc/howto/compile.html#unix
For information on platforms where Tcl is known to compile, along with any
porting notes for getting it to work on those platforms, see:
- http://www.tcl.tk/software/tcltk/platforms.html
+ https://www.tcl-tk.org/software/tcltk/platforms.html
The rest of this file contains instructions on how to do this. The release
should compile and run either "out of the box" or with trivial changes on any
@@ -89,7 +89,7 @@ How To Compile And Install Tcl:
--enable-dtrace Enable tcl DTrace provider (if DTrace is
available on the platform), c.f. tclDTrace.d
for descriptions of the probes made available,
- see http://wiki.tcl.tk/DTrace for more details
+ see https://wiki.tcl-lang.org/page/DTrace for more details
--with-encoding=ENCODING Specifies the encoding for compile-time
configuration values. Defaults to utf-8,
which is also sufficient for ASCII.
diff --git a/unix/configure b/unix/configure
index 53e41fa..86c93f4 100755
--- a/unix/configure
+++ b/unix/configure
@@ -1,9 +1,10 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.70 for tcl 8.7.
+# Generated by GNU Autoconf 2.71 for tcl 8.7.
#
#
-# Copyright (C) 1992-1996, 1998-2017, 2020 Free Software Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation,
+# Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -1551,9 +1552,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
tcl configure 8.7
-generated by GNU Autoconf 2.70
+generated by GNU Autoconf 2.71
-Copyright (C) 2020 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1783,24 +1784,23 @@ printf "%s\n" "$ac_res" >&6; }
} # ac_fn_c_check_func
-# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
-# ---------------------------------------------
+# ac_fn_check_decl LINENO SYMBOL VAR INCLUDES EXTRA-OPTIONS FLAG-VAR
+# ------------------------------------------------------------------
# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
-# accordingly.
-ac_fn_c_check_decl ()
+# accordingly. Pass EXTRA-OPTIONS to the compiler, using FLAG-VAR.
+ac_fn_check_decl ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- # Initialize each $ac_[]_AC_LANG_ABBREV[]_decl_warn_flag once.
- as_decl_name=`echo $2|sed 's/ *(.*//'`
- as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ as_decl_name=`echo $2|sed 's/ *(.*//'`
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
printf %s "checking whether $as_decl_name is declared... " >&6; }
if eval test \${$3+y}
then :
printf %s "(cached) " >&6
else $as_nop
- ac_save_werror_flag=$ac_c_werror_flag
- ac_c_werror_flag="$ac_c_decl_warn_flag$ac_c_werror_flag"
+ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ eval ac_save_FLAGS=\$$6
+ as_fn_append $6 " $5"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
@@ -1826,14 +1826,15 @@ else $as_nop
eval "$3=no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
- ac_c_werror_flag=$ac_save_werror_flag
+ eval $6=\$ac_save_FLAGS
+
fi
eval ac_res=\$$3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-} # ac_fn_c_check_decl
+} # ac_fn_check_decl
# ac_fn_c_check_type LINENO TYPE VAR INCLUDES
# -------------------------------------------
@@ -2019,7 +2020,7 @@ This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by tcl $as_me 8.7, which was
-generated by GNU Autoconf 2.70. Invocation command line was
+generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -2683,7 +2684,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
TCL_VERSION=8.7
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=7
-TCL_PATCH_LEVEL="a4"
+TCL_PATCH_LEVEL="a6"
VERSION=${TCL_VERSION}
EXTRA_INSTALL_BINARIES=${EXTRA_INSTALL_BINARIES:-"@:"}
@@ -3650,7 +3651,10 @@ else
CFLAGS=
fi
fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
+ac_prog_cc_stdc=no
+if test x$ac_prog_cc_stdc = xno
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
printf %s "checking for $CC option to enable C11 features... " >&6; }
if test ${ac_cv_prog_cc_c11+y}
then :
@@ -3674,28 +3678,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
-
fi
-# AC_CACHE_VAL
-ac_prog_cc_stdc_options=
-case "x$ac_cv_prog_cc_c11" in #(
- x) :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;; #(
- xno) :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; } ;; #(
- *) :
- ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c11"
- CC="$CC$ac_prog_cc_stdc_options"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
-printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c11" != xno
+
+if test "x$ac_cv_prog_cc_c11" = xno
then :
- ac_prog_cc_stdc=c11
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c11" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
+printf "%s\n" "$ac_cv_prog_cc_c11" >&6; }
+ CC="$CC $ac_cv_prog_cc_c11"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
+ ac_prog_cc_stdc=c11
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
printf %s "checking for $CC option to enable C99 features... " >&6; }
if test ${ac_cv_prog_cc_c99+y}
@@ -3706,9 +3710,9 @@ else $as_nop
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-$ac_c_conftest_c89_program
+$ac_c_conftest_c99_program
_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc1x -qlanglvl=extc99
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99=
do
CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"
@@ -3720,28 +3724,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
-
fi
-# AC_CACHE_VAL
-ac_prog_cc_stdc_options=
-case "x$ac_cv_prog_cc_c99" in #(
- x) :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;; #(
- xno) :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; } ;; #(
- *) :
- ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c99"
- CC="$CC$ac_prog_cc_stdc_options"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c99" != xno
+
+if test "x$ac_cv_prog_cc_c99" = xno
then :
- ac_prog_cc_stdc=c99
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
else $as_nop
+ if test "x$ac_cv_prog_cc_c99" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+printf "%s\n" "$ac_cv_prog_cc_c99" >&6; }
+ CC="$CC $ac_cv_prog_cc_c99"
+fi
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+ ac_prog_cc_stdc=c99
+fi
+fi
+if test x$ac_prog_cc_stdc = xno
+then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
printf %s "checking for $CC option to enable C89 features... " >&6; }
if test ${ac_cv_prog_cc_c89+y}
@@ -3754,8 +3758,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_c_conftest_c89_program
_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
CC="$ac_save_CC $ac_arg"
if ac_fn_c_try_compile "$LINENO"
@@ -3767,34 +3770,25 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
-
fi
-# AC_CACHE_VAL
-ac_prog_cc_stdc_options=
-case "x$ac_cv_prog_cc_c89" in #(
- x) :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-printf "%s\n" "none needed" >&6; } ;; #(
- xno) :
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-printf "%s\n" "unsupported" >&6; } ;; #(
- *) :
- ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c89"
- CC="$CC$ac_prog_cc_stdc_options"
- { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno
+
+if test "x$ac_cv_prog_cc_c89" = xno
then :
- ac_prog_cc_stdc=c89
- ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; }
+else $as_nop
+ if test "x$ac_cv_prog_cc_c89" = x
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; }
else $as_nop
- ac_prog_cc_stdc=no
- ac_cv_prog_cc_stdc=no
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+printf "%s\n" "$ac_cv_prog_cc_c89" >&6; }
+ CC="$CC $ac_cv_prog_cc_c89"
fi
-
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+ ac_prog_cc_stdc=c89
fi
-
fi
ac_ext=c
@@ -4412,22 +4406,18 @@ printf "%s\n" "#define TCL_CFGVAL_ENCODING \"utf-8\"" >>confdefs.h
# Look for libraries that we will need when compiling the Tcl shell
#--------------------------------------------------------------------
-# The Clang compiler raises a warning for an undeclared identifier that matches
-# a compiler builtin function. All extant Clang versions are affected, as of
-# Clang 3.6.0. Test a builtin known to every version. This problem affects the
-# C and Objective C languages, but Clang does report an error under C++ and
-# Objective C++.
-#
-# Passing -fno-builtin to the compiler would suppress this problem. That
-# strategy would have the advantage of being insensitive to stray warnings, but
-# it would make tests less realistic.
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how $CC reports undeclared, standard C functions" >&5
-printf %s "checking how $CC reports undeclared, standard C functions... " >&6; }
-if test ${ac_cv_c_decl_report+y}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5
+printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; }
+if test ${ac_cv_c_undeclared_builtin_options+y}
then :
printf %s "(cached) " >&6
else $as_nop
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+ ac_save_CFLAGS=$CFLAGS
+ ac_cv_c_undeclared_builtin_options='cannot detect'
+ for ac_arg in '' -fno-builtin; do
+ CFLAGS="$ac_save_CFLAGS $ac_arg"
+ # This test program should *not* compile successfully.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
@@ -4440,29 +4430,26 @@ main (void)
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
- if test -s conftest.err
-then :
- # For AC_CHECK_DECL to react to warnings, the compiler must be silent on
- # valid AC_CHECK_DECL input. No library function is consistently available
- # on freestanding implementations, so test against a dummy declaration.
- # Include always-available headers on the off chance that they somehow
- # elicit warnings.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+
+else $as_nop
+ # This test program should compile successfully.
+ # No library function is consistently available on
+ # freestanding implementations, so test against a dummy
+ # declaration. Include always-available headers on the
+ # off chance that they somehow elicit warnings.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <float.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
extern void ac_decl (int, char *);
+
int
main (void)
{
-#ifdef __cplusplus
- (void) ac_decl ((int) 0, (char *) 0);
- (void) ac_decl;
-#else
+(void) ac_decl (0, (char *) 0);
(void) ac_decl;
-#endif
;
return 0;
@@ -4470,39 +4457,33 @@ main (void)
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
- if test -s conftest.err
+ if test x"$ac_arg" = x
then :
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot detect from compiler exit status or warnings
-See \`config.log' for more details" "$LINENO" 5; }
+ ac_cv_c_undeclared_builtin_options='none needed'
else $as_nop
- ac_cv_c_decl_report=warning
+ ac_cv_c_undeclared_builtin_options=$ac_arg
fi
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot compile a simple declaration test
-See \`config.log' for more details" "$LINENO" 5; }
+ break
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-else $as_nop
- { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "compiler does not report undeclared identifiers
-See \`config.log' for more details" "$LINENO" 5; }
-fi
-else $as_nop
- ac_cv_c_decl_report=error
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_decl_report" >&5
-printf "%s\n" "$ac_cv_c_decl_report" >&6; }
+ done
+ CFLAGS=$ac_save_CFLAGS
-case $ac_cv_c_decl_report in
- warning) ac_c_decl_warn_flag=yes ;;
- *) ac_c_decl_warn_flag= ;;
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5
+printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; }
+ case $ac_cv_c_undeclared_builtin_options in #(
+ 'cannot detect') :
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot make $CC report undeclared builtins
+See \`config.log' for more details" "$LINENO" 5; } ;; #(
+ 'none needed') :
+ ac_c_undeclared_builtin_options='' ;; #(
+ *) :
+ ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;;
esac
@@ -4975,15 +4956,14 @@ fi
LIBS=$ac_saved_libs
# TIP #509
- ac_fn_c_check_decl "$LINENO" "PTHREAD_MUTEX_RECURSIVE" "ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" "#include <pthread.h>
-"
+ ac_fn_check_decl "$LINENO" "PTHREAD_MUTEX_RECURSIVE" "ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" "#include <pthread.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_PTHREAD_MUTEX_RECURSIVE" = xyes
then :
ac_have_decl=1
else $as_nop
ac_have_decl=0
fi
-
printf "%s\n" "#define HAVE_DECL_PTHREAD_MUTEX_RECURSIVE $ac_have_decl" >>confdefs.h
if test $ac_have_decl = 1
then :
@@ -7204,12 +7184,12 @@ then :
AIX-*) ;;
BSD/OS*) ;;
CYGWIN_*|MINGW32_*|MSYS_*) ;;
- HP_UX*) ;;
+ HP-UX*) ;;
Darwin-*) ;;
IRIX*) ;;
Linux*|GNU*) ;;
- NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
- OSF1-V*) ;;
+ NetBSD-*|OpenBSD-*) ;;
+ OSF1-*) ;;
SCO_SV-3.2*) ;;
*) SHLIB_CFLAGS="-fPIC" ;;
esac
@@ -8796,15 +8776,14 @@ printf "%s\n" "#define HAVE_MTSAFE_GETHOSTBYADDR 1" >>confdefs.h
else
# Avoids picking hidden internal symbol from libc
- ac_fn_c_check_decl "$LINENO" "gethostbyname_r" "ac_cv_have_decl_gethostbyname_r" "#include <netdb.h>
-"
+ ac_fn_check_decl "$LINENO" "gethostbyname_r" "ac_cv_have_decl_gethostbyname_r" "#include <netdb.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_gethostbyname_r" = xyes
then :
ac_have_decl=1
else $as_nop
ac_have_decl=0
fi
-
printf "%s\n" "#define HAVE_DECL_GETHOSTBYNAME_R $ac_have_decl" >>confdefs.h
if test $ac_have_decl = 1
then :
@@ -8965,15 +8944,14 @@ fi
# Avoids picking hidden internal symbol from libc
- ac_fn_c_check_decl "$LINENO" "gethostbyaddr_r" "ac_cv_have_decl_gethostbyaddr_r" "#include <netdb.h>
-"
+ ac_fn_check_decl "$LINENO" "gethostbyaddr_r" "ac_cv_have_decl_gethostbyaddr_r" "#include <netdb.h>
+" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_gethostbyaddr_r" = xyes
then :
ac_have_decl=1
else $as_nop
ac_have_decl=0
fi
-
printf "%s\n" "#define HAVE_DECL_GETHOSTBYADDR_R $ac_have_decl" >>confdefs.h
if test $ac_have_decl = 1
then :
@@ -9205,6 +9183,41 @@ printf "%s\n" "#define NO_FD_SET 1" >>confdefs.h
fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pselect" >&5
+printf %s "checking for pselect... " >&6; }
+if test ${tcl_cv_func_pselect+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+int
+main (void)
+{
+void *func = pselect;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ tcl_cv_func_pselect=yes
+else $as_nop
+ tcl_cv_func_pselect=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_func_pselect" >&5
+printf "%s\n" "$tcl_cv_func_pselect" >&6; }
+tcl_ok=$tcl_cv_func_pselect
+if test $tcl_ok = yes; then
+
+printf "%s\n" "#define HAVE_PSELECT 1" >>confdefs.h
+
+fi
+
#------------------------------------------------------------------------
# Options for the notifier. Checks for epoll(7) on Linux, and
# kqueue(2) on {DragonFly,Free,Net,Open}BSD
@@ -11849,7 +11862,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by tcl $as_me 8.7, which was
-generated by GNU Autoconf 2.70. Invocation command line was
+generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -11908,10 +11921,10 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
tcl config.status 8.7
-configured by $0, generated by GNU Autoconf 2.70,
+configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2020 Free Software Foundation, Inc.
+Copyright (C) 2021 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
diff --git a/unix/configure.ac b/unix/configure.ac
index 067fc70..b824ede 100644
--- a/unix/configure.ac
+++ b/unix/configure.ac
@@ -26,7 +26,7 @@ m4_ifdef([SC_USE_CONFIG_HEADERS], [
TCL_VERSION=8.7
TCL_MAJOR_VERSION=8
TCL_MINOR_VERSION=7
-TCL_PATCH_LEVEL="a4"
+TCL_PATCH_LEVEL="a6"
VERSION=${TCL_VERSION}
EXTRA_INSTALL_BINARIES=${EXTRA_INSTALL_BINARIES:-"@:"}
@@ -318,6 +318,13 @@ if test $tcl_ok = no; then
AC_DEFINE(NO_FD_SET, 1, [Do we have fd_set?])
fi
+AC_CACHE_CHECK([for pselect], tcl_cv_func_pselect, [
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>]], [[void *func = pselect;]])],[tcl_cv_func_pselect=yes],[tcl_cv_func_pselect=no])])
+tcl_ok=$tcl_cv_func_pselect
+if test $tcl_ok = yes; then
+ AC_DEFINE(HAVE_PSELECT, 1, [Should we use pselect()?])
+fi
+
#------------------------------------------------------------------------
# Options for the notifier. Checks for epoll(7) on Linux, and
# kqueue(2) on {DragonFly,Free,Net,Open}BSD
diff --git a/unix/dltest/pkgooa.c b/unix/dltest/pkgooa.c
index ff1cf1f..5aa48a5 100644
--- a/unix/dltest/pkgooa.c
+++ b/unix/dltest/pkgooa.c
@@ -84,10 +84,13 @@ static TclOOStubs stubsCopy = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL
+#ifdef Tcl_MethodIsPrivate
+ ,NULL
+#endif
};
-extern DLLEXPORT int
+DLLEXPORT int
Pkgooa_Init(
Tcl_Interp *interp) /* Interpreter in which the package is to be
* made available. */
diff --git a/unix/dltest/pkgua.c b/unix/dltest/pkgua.c
index 0ab3e23..a822541 100644
--- a/unix/dltest/pkgua.c
+++ b/unix/dltest/pkgua.c
@@ -21,6 +21,7 @@ static int PkguaEqObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
static int PkguaQuoteObjCmd(ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]);
+static void CommandDeleted(ClientData clientData);
/*
* In the following hash table we are going to store a struct that holds all
@@ -30,23 +31,32 @@ static int PkguaQuoteObjCmd(ClientData clientData,
* need to keep the various command tokens we have registered, as they are the
* only safe way to unregister our registered commands, even if they have been
* renamed.
- *
- * Note that this code is utterly single-threaded.
*/
-static Tcl_HashTable interpTokenMap;
-static int interpTokenMapInitialised = 0;
+typedef struct ThreadSpecificData {
+ int interpTokenMapInitialised;
+ Tcl_HashTable interpTokenMap;
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
#define MAX_REGISTERED_COMMANDS 2
+static void
+CommandDeleted(ClientData clientData)
+{
+ Tcl_Command *cmdToken = (Tcl_Command *)clientData;
+ *cmdToken = NULL;
+}
static void
PkguaInitTokensHashTable(void)
{
- if (interpTokenMapInitialised) {
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
+
+ if (tsdPtr->interpTokenMapInitialised) {
return;
}
- Tcl_InitHashTable(&interpTokenMap, TCL_ONE_WORD_KEYS);
- interpTokenMapInitialised = 1;
+ Tcl_InitHashTable(&tsdPtr->interpTokenMap, TCL_ONE_WORD_KEYS);
+ tsdPtr->interpTokenMapInitialised = 1;
}
static void
@@ -54,12 +64,13 @@ PkguaFreeTokensHashTable(void)
{
Tcl_HashSearch search;
Tcl_HashEntry *entryPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
- for (entryPtr = Tcl_FirstHashEntry(&interpTokenMap, &search);
+ for (entryPtr = Tcl_FirstHashEntry(&tsdPtr->interpTokenMap, &search);
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
}
- interpTokenMapInitialised = 0;
+ tsdPtr->interpTokenMapInitialised = 0;
}
static Tcl_Command *
@@ -68,13 +79,14 @@ PkguaInterpToTokens(
{
int newEntry;
Tcl_Command *cmdTokens;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
Tcl_HashEntry *entryPtr =
- Tcl_CreateHashEntry(&interpTokenMap, interp, &newEntry);
+ Tcl_CreateHashEntry(&tsdPtr->interpTokenMap, (char *) interp, &newEntry);
if (newEntry) {
cmdTokens = (Tcl_Command *)
- Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS+1));
- for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS+1 ; ++newEntry) {
+ Tcl_Alloc(sizeof(Tcl_Command) * (MAX_REGISTERED_COMMANDS));
+ for (newEntry=0 ; newEntry<MAX_REGISTERED_COMMANDS ; ++newEntry) {
cmdTokens[newEntry] = NULL;
}
Tcl_SetHashValue(entryPtr, cmdTokens);
@@ -88,8 +100,9 @@ static void
PkguaDeleteTokens(
Tcl_Interp *interp)
{
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)Tcl_GetThreadData((&dataKey), sizeof(ThreadSpecificData));
Tcl_HashEntry *entryPtr =
- Tcl_FindHashEntry(&interpTokenMap, interp);
+ Tcl_FindHashEntry(&tsdPtr->interpTokenMap, (char *) interp);
if (entryPtr) {
Tcl_Free((char *) Tcl_GetHashValue(entryPtr));
@@ -199,7 +212,7 @@ Pkgua_Init(
Tcl_Interp *interp) /* Interpreter in which the package is to be
* made available. */
{
- int code, cmdIndex = 0;
+ int code;
Tcl_Command *cmdTokens;
if (Tcl_InitStubs(interp, "8.5-", 0) == NULL) {
@@ -207,7 +220,7 @@ Pkgua_Init(
}
/*
- * Initialise our Hash table, where we store the registered command tokens
+ * Initialize our Hash table, where we store the registered command tokens
* for each interpreter.
*/
@@ -221,12 +234,12 @@ Pkgua_Init(
Tcl_SetVar2(interp, "::pkgua_loaded", NULL, ".", TCL_APPEND_VALUE);
cmdTokens = PkguaInterpToTokens(interp);
- cmdTokens[cmdIndex++] =
- Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, NULL,
- NULL);
- cmdTokens[cmdIndex++] =
+ cmdTokens[0] =
+ Tcl_CreateObjCommand(interp, "pkgua_eq", PkguaEqObjCmd, &cmdTokens[0],
+ CommandDeleted);
+ cmdTokens[1] =
Tcl_CreateObjCommand(interp, "pkgua_quote", PkguaQuoteObjCmd,
- NULL, NULL);
+ &cmdTokens[1], CommandDeleted);
return TCL_OK;
}
diff --git a/unix/tcl.m4 b/unix/tcl.m4
index 7fc696e..9cfec6b 100644
--- a/unix/tcl.m4
+++ b/unix/tcl.m4
@@ -1782,12 +1782,12 @@ dnl # preprocessing tests use only CPPFLAGS.
AIX-*) ;;
BSD/OS*) ;;
CYGWIN_*|MINGW32_*|MSYS_*) ;;
- HP_UX*) ;;
+ HP-UX*) ;;
Darwin-*) ;;
IRIX*) ;;
Linux*|GNU*) ;;
- NetBSD-*|DragonFly-*|FreeBSD-*|OpenBSD-*) ;;
- OSF1-V*) ;;
+ NetBSD-*|OpenBSD-*) ;;
+ OSF1-*) ;;
SCO_SV-3.2*) ;;
*) SHLIB_CFLAGS="-fPIC" ;;
esac])
diff --git a/unix/tcl.pc.in b/unix/tcl.pc.in
index 2693cd8..21ea0ce 100644
--- a/unix/tcl.pc.in
+++ b/unix/tcl.pc.in
@@ -8,7 +8,7 @@ libfile=@TCL_LIB_FILE@
Name: Tool Command Language
Description: Tcl is a powerful, easy-to-learn dynamic programming language, suitable for a wide range of uses.
-URL: http://www.tcl.tk/
+URL: https://www.tcl-tk.org/
Version: @TCL_VERSION@@TCL_PATCH_LEVEL@
Requires.private: zlib >= 1.2.3, libtommath >= 1.2.0
Libs: -L${libdir} @TCL_LIB_FLAG@ @TCL_STUB_LIB_FLAG@
diff --git a/unix/tcl.spec b/unix/tcl.spec
index b62fa2b..3956126 100644
--- a/unix/tcl.spec
+++ b/unix/tcl.spec
@@ -4,12 +4,12 @@
Name: tcl
Summary: Tcl scripting language development environment
-Version: 8.7a4
+Version: 8.7a6
Release: 2
License: BSD
Group: Development/Languages
Source: http://prdownloads.sourceforge.net/tcl/tcl%{version}-src.tar.gz
-URL: http://www.tcl.tk/
+URL: https://www.tcl-lang.org/
Buildroot: /var/tmp/%{name}%{version}
%description
diff --git a/unix/tclAppInit.c b/unix/tclAppInit.c
index 3587f35..f3caae7 100644
--- a/unix/tclAppInit.c
+++ b/unix/tclAppInit.c
@@ -15,15 +15,19 @@
#undef BUILD_tcl
#undef STATIC_BUILD
#include "tcl.h"
+#if TCL_MAJOR_VERSION < 9 && TCL_MINOR_VERSION < 7
+# define Tcl_LibraryInitProc Tcl_PackageInitProc
+# define Tcl_StaticLibrary Tcl_StaticPackage
+#endif
#ifdef TCL_TEST
-extern Tcl_PackageInitProc Tcltest_Init;
-extern Tcl_PackageInitProc Tcltest_SafeInit;
+extern Tcl_LibraryInitProc Tcltest_Init;
+extern Tcl_LibraryInitProc Tcltest_SafeInit;
#endif /* TCL_TEST */
#ifdef TCL_XT_TEST
extern void XtToolkitInitialize(void);
-extern Tcl_PackageInitProc Tclxttest_Init;
+extern Tcl_LibraryInitProc Tclxttest_Init;
#endif /* TCL_XT_TEST */
/*
@@ -79,7 +83,8 @@ main(
#ifdef TCL_LOCAL_MAIN_HOOK
TCL_LOCAL_MAIN_HOOK(&argc, &argv);
-#else
+#elif !defined(_WIN32) || defined(UNICODE)
+ /* This doesn't work on Windows without UNICODE */
TclZipfs_AppHook(&argc, &argv);
#endif
@@ -124,7 +129,7 @@ Tcl_AppInit(
if (Tcltest_Init(interp) == TCL_ERROR) {
return TCL_ERROR;
}
- Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, Tcltest_SafeInit);
+ Tcl_StaticLibrary(interp, "Tcltest", Tcltest_Init, Tcltest_SafeInit);
#endif /* TCL_TEST */
/*
diff --git a/unix/tclConfig.h.in b/unix/tclConfig.h.in
index 0bf3c3d..d7f51bf 100644
--- a/unix/tclConfig.h.in
+++ b/unix/tclConfig.h.in
@@ -190,6 +190,9 @@
/* Define to 1 if you have the `pthread_attr_setstacksize' function. */
#undef HAVE_PTHREAD_ATTR_SETSTACKSIZE
+/* Define to 1 if you have the `pselect' function */
+#undef HAVE_PSELECT
+
/* Does putenv() copy strings or incorporate them by reference? */
#undef HAVE_PUTENV_THAT_COPIES
diff --git a/unix/tclEpollNotfy.c b/unix/tclEpollNotfy.c
index 3a99e6d..649c21b 100644
--- a/unix/tclEpollNotfy.c
+++ b/unix/tclEpollNotfy.c
@@ -97,7 +97,7 @@ typedef struct ThreadSpecificData {
* that are ready for I/O. */
pthread_mutex_t notifierMutex;
/* Mutex protecting notifier termination in
- * PlatformEventsFinalize. */
+ * TclpFinalizeNotifier. */
#ifdef HAVE_EVENTFD
int triggerEventFd; /* eventfd(2) used by other threads to wake
* up this thread for inter-thread IPC. */
@@ -111,6 +111,7 @@ typedef struct ThreadSpecificData {
/* Pointer to at most maxReadyEvents events
* returned by epoll_wait(2). */
size_t maxReadyEvents; /* Count of epoll_events in readyEvents. */
+ int asyncPending; /* True when signal triggered thread. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -121,14 +122,13 @@ static Tcl_ThreadDataKey dataKey;
static void PlatformEventsControl(FileHandler *filePtr,
ThreadSpecificData *tsdPtr, int op, int isNew);
-static void PlatformEventsFinalize(void);
static void PlatformEventsInit(void);
static int PlatformEventsTranslate(struct epoll_event *event);
static int PlatformEventsWait(struct epoll_event *events,
size_t numEvents, struct timeval *timePtr);
-
+
/*
- * Incorporate the base notifier API.
+ * Incorporate the base notifier implementation.
*/
#include "tclUnixNotfy.c"
@@ -136,7 +136,7 @@ static int PlatformEventsWait(struct epoll_event *events,
/*
*----------------------------------------------------------------------
*
- * Tcl_InitNotifier --
+ * TclpInitNotifier --
*
* Initializes the platform specific notifier state.
*
@@ -144,54 +144,21 @@ static int PlatformEventsWait(struct epoll_event *events,
* Returns a handle to the notifier state for this thread.
*
* Side effects:
- * If no initNotifierProc notifier hook exists, PlatformEventsInit
- * is called.
+ * If no initNotifierProc notifier hook exists, PlatformEventsInit is
+ * called.
*
*----------------------------------------------------------------------
*/
ClientData
-Tcl_InitNotifier(void)
+TclpInitNotifier(void)
{
- if (tclNotifierHooks.initNotifierProc) {
- return tclNotifierHooks.initNotifierProc();
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- PlatformEventsInit();
- return tsdPtr;
- }
+ PlatformEventsInit();
+ return tsdPtr;
}
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_FinalizeNotifier --
- *
- * This function is called to cleanup the notifier state before a thread
- * is terminated.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If no finalizeNotifierProc notifier hook exists, PlatformEvents-
- * Finalize is called.
- *
- *----------------------------------------------------------------------
- */
-
-void
-Tcl_FinalizeNotifier(
- ClientData clientData)
-{
- if (tclNotifierHooks.finalizeNotifierProc) {
- tclNotifierHooks.finalizeNotifierProc(clientData);
- return;
- } else {
- PlatformEventsFinalize();
- }
-}
/*
*----------------------------------------------------------------------
@@ -221,7 +188,7 @@ Tcl_FinalizeNotifier(
*----------------------------------------------------------------------
*/
-void
+static void
PlatformEventsControl(
FileHandler *filePtr,
ThreadSpecificData *tsdPtr,
@@ -230,7 +197,7 @@ PlatformEventsControl(
{
struct epoll_event newEvent;
struct PlatformEventData *newPedPtr;
- struct stat fdStat;
+ Tcl_StatBuf fdStat;
newEvent.events = 0;
if (filePtr->mask & (TCL_READABLE | TCL_EXCEPTION)) {
@@ -240,7 +207,8 @@ PlatformEventsControl(
newEvent.events |= EPOLLOUT;
}
if (isNew) {
- newPedPtr = (struct PlatformEventData *)ckalloc(sizeof(struct PlatformEventData));
+ newPedPtr = (struct PlatformEventData *)
+ ckalloc(sizeof(struct PlatformEventData));
newPedPtr->filePtr = filePtr;
newPedPtr->tsdPtr = tsdPtr;
filePtr->pedPtr = newPedPtr;
@@ -249,35 +217,42 @@ PlatformEventsControl(
/*
* N.B. As discussed in Tcl_WaitForEvent(), epoll(7) does not support
- * regular files (S_IFREG.) Therefore, filePtr is in these cases simply
+ * regular files (S_IFREG). Therefore, filePtr is in these cases simply
* added or deleted from the list of FileHandlers associated with regular
* files belonging to tsdPtr.
*/
- if (fstat(filePtr->fd, &fdStat) == -1) {
+ if (TclOSfstat(filePtr->fd, &fdStat) == -1) {
Tcl_Panic("fstat: %s", strerror(errno));
- } else if ((fdStat.st_mode & S_IFMT) == S_IFREG) {
- switch (op) {
- case EPOLL_CTL_ADD:
- if (isNew) {
- LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr,
- readyNode);
- }
- break;
- case EPOLL_CTL_DEL:
- LIST_REMOVE(filePtr, readyNode);
- break;
+ }
+
+ if (epoll_ctl(tsdPtr->eventsFd, op, filePtr->fd, &newEvent) == -1) {
+ switch (errno) {
+ case EPERM:
+ switch (op) {
+ case EPOLL_CTL_ADD:
+ if (isNew) {
+ LIST_INSERT_HEAD(&tsdPtr->firstReadyFileHandlerPtr, filePtr,
+ readyNode);
+ }
+ break;
+ case EPOLL_CTL_DEL:
+ LIST_REMOVE(filePtr, readyNode);
+ break;
+
+ }
+ break;
+ default:
+ Tcl_Panic("epoll_ctl: %s", strerror(errno));
}
- return;
- } else if (epoll_ctl(tsdPtr->eventsFd, op, filePtr->fd, &newEvent) == -1) {
- Tcl_Panic("epoll_ctl: %s", strerror(errno));
- }
+ }
+ return;
}
/*
*----------------------------------------------------------------------
*
- * PlatformEventsFinalize --
+ * TclpFinalizeNotifier --
*
* This function closes the eventfd and the epoll file descriptor and
* frees the epoll_event structs owned by the thread of the caller. The
@@ -299,8 +274,8 @@ PlatformEventsControl(
*/
void
-PlatformEventsFinalize(
- void)
+TclpFinalizeNotifier(
+ TCL_UNUSED(ClientData))
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -362,7 +337,7 @@ PlatformEventsFinalize(
*----------------------------------------------------------------------
*/
-void
+static void
PlatformEventsInit(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -372,7 +347,7 @@ PlatformEventsInit(void)
if (errno) {
Tcl_Panic("Tcl_InitNotifier: %s", "could not create mutex");
}
- filePtr = (FileHandler *)ckalloc(sizeof(FileHandler));
+ filePtr = (FileHandler *) ckalloc(sizeof(FileHandler));
#ifdef HAVE_EVENTFD
tsdPtr->triggerEventFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (tsdPtr->triggerEventFd <= 0) {
@@ -393,7 +368,7 @@ PlatformEventsInit(void)
PlatformEventsControl(filePtr, tsdPtr, EPOLL_CTL_ADD, 1);
if (!tsdPtr->readyEvents) {
tsdPtr->maxReadyEvents = 512;
- tsdPtr->readyEvents = (struct epoll_event *)ckalloc(
+ tsdPtr->readyEvents = (struct epoll_event *) ckalloc(
tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0]));
}
LIST_INIT(&tsdPtr->firstReadyFileHandlerPtr);
@@ -416,7 +391,7 @@ PlatformEventsInit(void)
*----------------------------------------------------------------------
*/
-int
+static int
PlatformEventsTranslate(
struct epoll_event *eventPtr)
{
@@ -457,7 +432,7 @@ PlatformEventsTranslate(
*----------------------------------------------------------------------
*/
-int
+static int
PlatformEventsWait(
struct epoll_event *events,
size_t numEvents,
@@ -480,9 +455,9 @@ PlatformEventsWait(
} else if (!timePtr->tv_sec && !timePtr->tv_usec) {
timeout = 0;
} else {
- timeout = (int)timePtr->tv_sec * 1000;
+ timeout = (int) timePtr->tv_sec * 1000;
if (timePtr->tv_usec) {
- timeout += (int)timePtr->tv_usec / 1000;
+ timeout += (int) timePtr->tv_usec / 1000;
}
}
@@ -493,7 +468,7 @@ PlatformEventsWait(
*/
gettimeofday(&tv0, NULL);
- numFound = epoll_wait(tsdPtr->eventsFd, events, (int)numEvents, timeout);
+ numFound = epoll_wait(tsdPtr->eventsFd, events, (int) numEvents, timeout);
gettimeofday(&tv1, NULL);
if (timePtr && (timePtr->tv_sec && timePtr->tv_usec)) {
timersub(&tv1, &tv0, &tv_delta);
@@ -504,13 +479,17 @@ PlatformEventsWait(
timePtr->tv_usec = 0;
}
}
+ if (tsdPtr->asyncPending) {
+ tsdPtr->asyncPending = 0;
+ TclAsyncMarkFromNotifier();
+ }
return numFound;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_CreateFileHandler --
+ * TclpCreateFileHandler --
*
* This function registers a file handler with the epoll notifier of the
* thread of the caller.
@@ -526,7 +505,7 @@ PlatformEventsWait(
*/
void
-Tcl_CreateFileHandler(
+TclpCreateFileHandler(
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
@@ -536,44 +515,29 @@ Tcl_CreateFileHandler(
* event. */
ClientData clientData) /* Arbitrary data to pass to proc. */
{
- int isNew;
-
- if (tclNotifierHooks.createFileHandlerProc) {
- tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
- return;
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileHandler *filePtr;
-
- 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;
- isNew = 1;
- } else {
- isNew = 0;
- }
- filePtr->proc = proc;
- filePtr->clientData = clientData;
- filePtr->mask = mask;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL);
+ int isNew = (filePtr == NULL);
- PlatformEventsControl(filePtr, tsdPtr,
- isNew ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, isNew);
+ if (isNew) {
+ 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;
+
+ PlatformEventsControl(filePtr, tsdPtr,
+ isNew ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, isNew);
}
/*
*----------------------------------------------------------------------
*
- * Tcl_DeleteFileHandler --
+ * TclpDeleteFileHandler --
*
* Cancel a previously-arranged callback arrangement for a file on the
* epoll file descriptor of the thread of the caller.
@@ -591,60 +555,50 @@ Tcl_CreateFileHandler(
*/
void
-Tcl_DeleteFileHandler(
+TclpDeleteFileHandler(
int fd) /* Stream id for which to remove callback
* function. */
{
- if (tclNotifierHooks.deleteFileHandlerProc) {
- tclNotifierHooks.deleteFileHandlerProc(fd);
- return;
- } else {
- FileHandler *filePtr, *prevPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr, *prevPtr;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- /*
- * Find the entry for the given file (and return if there isn't one).
- */
+ /*
+ * 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;
- }
- }
+ filePtr = LookUpFileHandler(tsdPtr, fd, &prevPtr);
+ if (filePtr == NULL) {
+ return;
+ }
- /*
- * Update the check masks for this file.
- */
+ /*
+ * Update the check masks for this file.
+ */
- PlatformEventsControl(filePtr, tsdPtr, EPOLL_CTL_DEL, 0);
- if (filePtr->pedPtr) {
- ckfree(filePtr->pedPtr);
- }
+ PlatformEventsControl(filePtr, tsdPtr, EPOLL_CTL_DEL, 0);
+ if (filePtr->pedPtr) {
+ ckfree(filePtr->pedPtr);
+ }
- /*
- * Clean up information in the callback record.
- */
+ /*
+ * Clean up information in the callback record.
+ */
- if (prevPtr == NULL) {
- tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
- } else {
- prevPtr->nextPtr = filePtr->nextPtr;
- }
- ckfree(filePtr);
+ if (prevPtr == NULL) {
+ tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = filePtr->nextPtr;
}
+ ckfree(filePtr);
}
/*
*----------------------------------------------------------------------
*
- * Tcl_WaitForEvent --
+ * TclpWaitForEvent --
*
* 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
+ * the message queue. If the block time is 0, then TclpWaitForEvent just
* polls without blocking.
*
* The waiting logic is implemented in PlatformEventsWait.
@@ -660,172 +614,225 @@ Tcl_DeleteFileHandler(
*/
int
-Tcl_WaitForEvent(
+TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
- if (tclNotifierHooks.waitForEventProc) {
- return tclNotifierHooks.waitForEventProc(timePtr);
- } else {
- FileHandler *filePtr;
- int mask;
- Tcl_Time vTime;
- /*
- * Impl. notes: timeout & timeoutPtr are used if, and only if threads
- * are not enabled. They are the arguments for the regular epoll_wait()
- * used when the core is not thread-enabled.
- */
+ FileHandler *filePtr;
+ Tcl_Time vTime;
+ struct timeval timeout, *timeoutPtr;
+ /* Impl. notes: timeout & timeoutPtr are used
+ * if, and only if threads are not enabled.
+ * They are the arguments for the regular
+ * epoll_wait() used when the core is not
+ * thread-enabled. */
+ int mask, numFound, numEvent;
+ struct PlatformEventData *pedPtr;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ int numQueued;
+ ssize_t i;
- struct timeval timeout, *timeoutPtr;
- int numFound, numEvent;
- struct PlatformEventData *pedPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- int numQueued;
- ssize_t i;
+ /*
+ * Set up the timeout structure. Note that if there are no events to check
+ * for, we return with a negative result rather than blocking forever.
+ */
+ if (timePtr != NULL) {
/*
- * Set up the timeout structure. Note that if there are no events to
- * check for, we return with a negative result rather than blocking
- * forever.
+ * 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.
*/
- 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.
- */
-
- if (timePtr->sec != 0 || timePtr->usec != 0) {
- vTime = *timePtr;
- tclScaleTimeProcPtr(&vTime, tclTimeClientData);
- timePtr = &vTime;
- }
- timeout.tv_sec = timePtr->sec;
- timeout.tv_usec = timePtr->usec;
- timeoutPtr = &timeout;
- } else {
- timeoutPtr = NULL;
+ if (timePtr->sec != 0 || timePtr->usec != 0) {
+ vTime = *timePtr;
+ TclScaleTime(&vTime);
+ timePtr = &vTime;
}
+ timeout.tv_sec = timePtr->sec;
+ timeout.tv_usec = timePtr->usec;
+ timeoutPtr = &timeout;
+ } else {
+ timeoutPtr = NULL;
+ }
- /*
- * Walk the list of FileHandlers associated with regular files
- * (S_IFREG) belonging to tsdPtr, queue Tcl events for them, and
- * update their mask of events of interest.
- *
- * As epoll(7) does not support regular files, the behaviour of
- * {select,poll}(2) is simply simulated here: fds associated with
- * regular files are added to this list by PlatformEventsControl() and
- * processed here before calling (and possibly blocking) on
- * PlatformEventsWait().
- */
-
- numQueued = 0;
- LIST_FOREACH(filePtr, &tsdPtr->firstReadyFileHandlerPtr, readyNode) {
- mask = 0;
- if (filePtr->mask & TCL_READABLE) {
- mask |= TCL_READABLE;
- }
- if (filePtr->mask & TCL_WRITABLE) {
- mask |= TCL_WRITABLE;
- }
-
- /*
- * 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) {
- FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
- ckalloc(sizeof(FileHandlerEvent));
+ /*
+ * Walk the list of FileHandlers associated with regular files (S_IFREG)
+ * belonging to tsdPtr, queue Tcl events for them, and update their mask
+ * of events of interest.
+ *
+ * As epoll(7) does not support regular files, the behaviour of
+ * {select,poll}(2) is simply simulated here: fds associated with regular
+ * files are added to this list by PlatformEventsControl() and processed
+ * here before calling (and possibly blocking) on PlatformEventsWait().
+ */
- fileEvPtr->header.proc = FileHandlerEventProc;
- fileEvPtr->fd = filePtr->fd;
- Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
- numQueued++;
- }
- filePtr->readyMask = mask;
+ numQueued = 0;
+ LIST_FOREACH(filePtr, &tsdPtr->firstReadyFileHandlerPtr, readyNode) {
+ mask = 0;
+ if (filePtr->mask & TCL_READABLE) {
+ mask |= TCL_READABLE;
+ }
+ if (filePtr->mask & TCL_WRITABLE) {
+ mask |= TCL_WRITABLE;
}
/*
- * If any events were queued in the above loop, force
- * PlatformEventsWait() to poll as there already are events that need
- * to be processed at this point.
+ * Don't bother to queue an event if the mask was previously non-zero
+ * since an event must still be on the queue.
*/
- if (numQueued) {
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- timeoutPtr = &timeout;
+ if (filePtr->readyMask == 0) {
+ FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
+ ckalloc(sizeof(FileHandlerEvent));
+
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+ numQueued++;
}
+ filePtr->readyMask = mask;
+ }
- /*
- * Wait or poll for new events, queue Tcl events for the FileHandlers
- * corresponding to them, and update the FileHandlers' mask of events
- * of interest registered by the last call to Tcl_CreateFileHandler().
- *
- * Events for the eventfd(2)/trigger pipe are processed here in order
- * to facilitate inter-thread IPC. If another thread intends to wake
- * up this thread whilst it's blocking on PlatformEventsWait(), it
- * write(2)s to the eventfd(2)/trigger pipe (see Tcl_AlertNotifier(),)
- * which in turn will cause PlatformEventsWait() to return
- * immediately.
- */
+ /*
+ * If any events were queued in the above loop, force PlatformEventsWait()
+ * to poll as there already are events that need to be processed at this
+ * point.
+ */
- numFound = PlatformEventsWait(tsdPtr->readyEvents,
- tsdPtr->maxReadyEvents, timeoutPtr);
- for (numEvent = 0; numEvent < numFound; numEvent++) {
- pedPtr = (struct PlatformEventData*)tsdPtr->readyEvents[numEvent].data.ptr;
- filePtr = pedPtr->filePtr;
- mask = PlatformEventsTranslate(&tsdPtr->readyEvents[numEvent]);
+ if (numQueued) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ timeoutPtr = &timeout;
+ }
+
+ /*
+ * Wait or poll for new events, queue Tcl events for the FileHandlers
+ * corresponding to them, and update the FileHandlers' mask of events of
+ * interest registered by the last call to Tcl_CreateFileHandler().
+ *
+ * Events for the eventfd(2)/trigger pipe are processed here in order to
+ * facilitate inter-thread IPC. If another thread intends to wake up this
+ * thread whilst it's blocking on PlatformEventsWait(), it write(2)s to
+ * the eventfd(2)/trigger pipe (see Tcl_AlertNotifier(),) which in turn
+ * will cause PlatformEventsWait() to return immediately.
+ */
+
+ numFound = PlatformEventsWait(tsdPtr->readyEvents,
+ tsdPtr->maxReadyEvents, timeoutPtr);
+ for (numEvent = 0; numEvent < numFound; numEvent++) {
+ pedPtr = (struct PlatformEventData *)
+ tsdPtr->readyEvents[numEvent].data.ptr;
+ filePtr = pedPtr->filePtr;
+ mask = PlatformEventsTranslate(&tsdPtr->readyEvents[numEvent]);
#ifdef HAVE_EVENTFD
- if (filePtr->fd == tsdPtr->triggerEventFd) {
- uint64_t eventFdVal;
- i = read(tsdPtr->triggerEventFd, &eventFdVal,
- sizeof(eventFdVal));
- if ((i != sizeof(eventFdVal)) && (errno != EAGAIN)) {
- Tcl_Panic(
- "Tcl_WaitForEvent: read from %p->triggerEventFd: %s",
- (void *) tsdPtr, strerror(errno));
- }
- continue;
+ if (filePtr->fd == tsdPtr->triggerEventFd) {
+ uint64_t eventFdVal;
+
+ i = read(tsdPtr->triggerEventFd, &eventFdVal, sizeof(eventFdVal));
+ if ((i != sizeof(eventFdVal)) && (errno != EAGAIN)) {
+ Tcl_Panic("%s: read from %p->triggerEventFd: %s",
+ "Tcl_WaitForEvent", (void *) tsdPtr, strerror(errno));
}
+ continue;
+ }
#else /* !HAVE_EVENTFD */
- if (filePtr->fd == tsdPtr->triggerPipe[0]) {
- char triggerPipeVal;
- i = read(tsdPtr->triggerPipe[0], &triggerPipeVal,
- sizeof(triggerPipeVal));
- if ((i != sizeof(triggerPipeVal)) && (errno != EAGAIN)) {
- Tcl_Panic(
- "Tcl_WaitForEvent: read from %p->triggerPipe[0]: %s",
- (void *) tsdPtr, strerror(errno));
- }
- continue;
+ if (filePtr->fd == tsdPtr->triggerPipe[0]) {
+ char triggerPipeVal;
+
+ i = read(tsdPtr->triggerPipe[0], &triggerPipeVal,
+ sizeof(triggerPipeVal));
+ if ((i != sizeof(triggerPipeVal)) && (errno != EAGAIN)) {
+ Tcl_Panic("%s: read from %p->triggerPipe[0]: %s",
+ "Tcl_WaitForEvent", (void *) tsdPtr, strerror(errno));
}
+ continue;
+ }
#endif /* HAVE_EVENTFD */
- if (!mask) {
- continue;
- }
+ 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.
- */
+ /*
+ * 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) {
- FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
- ckalloc(sizeof(FileHandlerEvent));
+ if (filePtr->readyMask == 0) {
+ FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
+ ckalloc(sizeof(FileHandlerEvent));
- fileEvPtr->header.proc = FileHandlerEventProc;
- fileEvPtr->fd = filePtr->fd;
- Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
- }
- filePtr->readyMask = mask;
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+ }
+ filePtr->readyMask = mask;
+ }
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclAsyncNotifier --
+ *
+ * This procedure sets the async mark of an async handler to a
+ * given value, if it is called from the target thread.
+ *
+ * Result:
+ * True, when the handler will be marked, false otherwise.
+ *
+ * Side effects:
+ * The signal may be resent to the target thread.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclAsyncNotifier(
+ int sigNumber, /* Signal number. */
+ Tcl_ThreadId threadId, /* Target thread. */
+ ClientData clientData, /* Notifier data. */
+ int *flagPtr, /* Flag to mark. */
+ int value) /* Value of mark. */
+{
+#if TCL_THREADS
+ /*
+ * WARNING:
+ * This code most likely runs in a signal handler. Thus,
+ * only few async-signal-safe system calls are allowed,
+ * e.g. pthread_self(), sem_post(), write().
+ */
+
+ if (pthread_equal(pthread_self(), (pthread_t) threadId)) {
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+
+ *flagPtr = value;
+ if (tsdPtr != NULL && !tsdPtr->asyncPending) {
+ tsdPtr->asyncPending = 1;
+ TclpAlertNotifier(tsdPtr);
+ return 1;
}
return 0;
}
+
+ /*
+ * Re-send the signal to the proper target thread.
+ */
+
+ pthread_kill((pthread_t) threadId, sigNumber);
+#else
+ (void)sigNumber;
+ (void)threadId;
+ (void)clientData;
+ (void)flagPtr;
+ (void)value;
+#endif
+ return 0;
}
#endif /* NOTIFIER_EPOLL && TCL_THREADS */
+#else
+TCL_MAC_EMPTY_FILE(unix_tclEpollNotfy_c)
#endif /* !HAVE_COREFOUNDATION */
/*
diff --git a/unix/tclKqueueNotfy.c b/unix/tclKqueueNotfy.c
index 2f1d8e6..2f495bd 100644
--- a/unix/tclKqueueNotfy.c
+++ b/unix/tclKqueueNotfy.c
@@ -31,7 +31,8 @@
struct PlatformEventData;
typedef struct FileHandler {
- int fd;
+ int fd; /* File descriptor that this is describing a
+ * handler for. */
int mask; /* Mask of desired events: TCL_READABLE,
* etc. */
int readyMask; /* Mask of events that have been seen since
@@ -93,7 +94,7 @@ typedef struct ThreadSpecificData {
* that are ready for I/O. */
pthread_mutex_t notifierMutex;
/* Mutex protecting notifier termination in
- * PlatformEventsFinalize. */
+ * TclpFinalizeNotifier. */
int triggerPipe[2]; /* pipe(2) used by other threads to wake
* up this thread for inter-thread IPC. */
int eventsFd; /* kqueue(2) file descriptor used to wait for
@@ -101,6 +102,7 @@ typedef struct ThreadSpecificData {
struct kevent *readyEvents; /* Pointer to at most maxReadyEvents events
* returned by kevent(2). */
size_t maxReadyEvents; /* Count of kevents in readyEvents. */
+ int asyncPending; /* True when signal triggered thread. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -111,73 +113,15 @@ static Tcl_ThreadDataKey dataKey;
static void PlatformEventsControl(FileHandler *filePtr,
ThreadSpecificData *tsdPtr, int op, int isNew);
-static void PlatformEventsFinalize(void);
-static void PlatformEventsInit(void);
static int PlatformEventsTranslate(struct kevent *eventPtr);
static int PlatformEventsWait(struct kevent *events,
size_t numEvents, struct timeval *timePtr);
-
-#include "tclUnixNotfy.c"
-
-/*
- *----------------------------------------------------------------------
- *
- * Tcl_InitNotifier --
- *
- * Initializes the platform specific notifier state.
- *
- * Results:
- * Returns a handle to the notifier state for this thread.
- *
- * Side effects:
- * If no initNotifierProc notifier hook exists, PlatformEventsInit
- * is called.
- *
- *----------------------------------------------------------------------
- */
-
-ClientData
-Tcl_InitNotifier(void)
-{
- if (tclNotifierHooks.initNotifierProc) {
- return tclNotifierHooks.initNotifierProc();
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
-
- PlatformEventsInit();
- return tsdPtr;
- }
-}
/*
- *----------------------------------------------------------------------
- *
- * Tcl_FinalizeNotifier --
- *
- * This function is called to cleanup the notifier state before a thread
- * is terminated.
- *
- * Results:
- * None.
- *
- * Side effects:
- * If no finalizeNotifierProc notifier hook exists, PlatformEvents-
- * Finalize is called.
- *
- *----------------------------------------------------------------------
+ * Incorporate the base notifier implementation.
*/
-void
-Tcl_FinalizeNotifier(
- ClientData clientData)
-{
- if (tclNotifierHooks.finalizeNotifierProc) {
- tclNotifierHooks.finalizeNotifierProc(clientData);
- return;
- } else {
- PlatformEventsFinalize();
- }
-}
+#include "tclUnixNotfy.c"
/*
*----------------------------------------------------------------------
@@ -209,7 +153,7 @@ Tcl_FinalizeNotifier(
*----------------------------------------------------------------------
*/
-void
+static void
PlatformEventsControl(
FileHandler *filePtr,
ThreadSpecificData *tsdPtr,
@@ -219,13 +163,14 @@ PlatformEventsControl(
int numChanges;
struct kevent changeList[2];
struct PlatformEventData *newPedPtr;
- struct stat fdStat;
+ Tcl_StatBuf fdStat;
if (isNew) {
- newPedPtr = (struct PlatformEventData *)ckalloc(sizeof(struct PlatformEventData));
- newPedPtr->filePtr = filePtr;
- newPedPtr->tsdPtr = tsdPtr;
- filePtr->pedPtr = newPedPtr;
+ newPedPtr = (struct PlatformEventData *)
+ ckalloc(sizeof(struct PlatformEventData));
+ newPedPtr->filePtr = filePtr;
+ newPedPtr->tsdPtr = tsdPtr;
+ filePtr->pedPtr = newPedPtr;
}
/*
@@ -236,9 +181,12 @@ PlatformEventsControl(
* with regular files belonging to tsdPtr.
*/
- if (fstat(filePtr->fd, &fdStat) == -1) {
+ if (TclOSfstat(filePtr->fd, &fdStat) == -1) {
Tcl_Panic("fstat: %s", strerror(errno));
- } else if ((fdStat.st_mode & S_IFMT) == S_IFREG) {
+ } else if ((fdStat.st_mode & S_IFMT) == S_IFREG
+ || (fdStat.st_mode & S_IFMT) == S_IFDIR
+ || (fdStat.st_mode & S_IFMT) == S_IFLNK
+ ) {
switch (op) {
case EV_ADD:
if (isNew) {
@@ -257,16 +205,16 @@ PlatformEventsControl(
switch (op) {
case EV_ADD:
if (filePtr->mask & (TCL_READABLE | TCL_EXCEPTION)) {
- EV_SET(&changeList[numChanges], (uintptr_t)filePtr->fd,
+ EV_SET(&changeList[numChanges], (uintptr_t) filePtr->fd,
EVFILT_READ, op, 0, 0, filePtr->pedPtr);
numChanges++;
}
if (filePtr->mask & TCL_WRITABLE) {
- EV_SET(&changeList[numChanges], (uintptr_t)filePtr->fd,
+ EV_SET(&changeList[numChanges], (uintptr_t) filePtr->fd,
EVFILT_WRITE, op, 0, 0, filePtr->pedPtr);
numChanges++;
}
- if (numChanges) {
+ if (numChanges) {
if (kevent(tsdPtr->eventsFd, changeList, numChanges, NULL, 0,
NULL) == -1) {
Tcl_Panic("kevent: %s", strerror(errno));
@@ -284,13 +232,13 @@ PlatformEventsControl(
* As one of these calls can fail, two separate kevent(2) calls are
* made for EVFILT_{READ,WRITE}.
*/
- EV_SET(&changeList[0], (uintptr_t)filePtr->fd, EVFILT_READ, op, 0, 0,
+ EV_SET(&changeList[0], (uintptr_t) filePtr->fd, EVFILT_READ, op, 0, 0,
NULL);
if ((kevent(tsdPtr->eventsFd, changeList, 1, NULL, 0, NULL) == -1)
&& (errno != ENOENT)) {
Tcl_Panic("kevent: %s", strerror(errno));
}
- EV_SET(&changeList[0], (uintptr_t)filePtr->fd, EVFILT_WRITE, op, 0, 0,
+ EV_SET(&changeList[0], (uintptr_t) filePtr->fd, EVFILT_WRITE, op, 0, 0,
NULL);
if ((kevent(tsdPtr->eventsFd, changeList, 1, NULL, 0, NULL) == -1)
&& (errno != ENOENT)) {
@@ -303,7 +251,7 @@ PlatformEventsControl(
/*
*----------------------------------------------------------------------
*
- * PlatformEventsFinalize --
+ * TclpFinalizeNotifier --
*
* This function closes the pipe and the kqueue file descriptors and
* frees the kevent structs owned by the thread of the caller. The above
@@ -325,8 +273,8 @@ PlatformEventsControl(
*/
void
-PlatformEventsFinalize(
- void)
+TclpFinalizeNotifier(
+ TCL_UNUSED(ClientData))
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -356,14 +304,16 @@ PlatformEventsFinalize(
/*
*----------------------------------------------------------------------
*
- * PlatformEventsInit --
+ * TclpInitNotifier --
+ *
+ * Initializes the platform specific notifier state.
*
* This function abstracts creating a kqueue fd via the kqueue system
* call and allocating memory for the kevents structs in tsdPtr for the
* thread of the caller.
*
* Results:
- * None.
+ * Returns a handle to the notifier state for this thread.
*
* Side effects:
* The following per-thread entities are initialised:
@@ -380,8 +330,8 @@ PlatformEventsFinalize(
*----------------------------------------------------------------------
*/
-void
-PlatformEventsInit(void)
+ClientData
+TclpInitNotifier(void)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int i, fdFl;
@@ -409,16 +359,18 @@ PlatformEventsInit(void)
} else if (fcntl(tsdPtr->eventsFd, F_SETFD, FD_CLOEXEC) == -1) {
Tcl_Panic("fcntl: %s", strerror(errno));
}
- filePtr = (FileHandler *)ckalloc(sizeof(FileHandler));
+ filePtr = (FileHandler *) ckalloc(sizeof(FileHandler));
filePtr->fd = tsdPtr->triggerPipe[0];
filePtr->mask = TCL_READABLE;
PlatformEventsControl(filePtr, tsdPtr, EV_ADD, 1);
if (!tsdPtr->readyEvents) {
- tsdPtr->maxReadyEvents = 512;
- tsdPtr->readyEvents = (struct kevent *)ckalloc(
+ tsdPtr->maxReadyEvents = 512;
+ tsdPtr->readyEvents = (struct kevent *) ckalloc(
tsdPtr->maxReadyEvents * sizeof(tsdPtr->readyEvents[0]));
}
LIST_INIT(&tsdPtr->firstReadyFileHandlerPtr);
+
+ return tsdPtr;
}
/*
@@ -438,7 +390,7 @@ PlatformEventsInit(void)
*----------------------------------------------------------------------
*/
-int
+static int
PlatformEventsTranslate(
struct kevent *eventPtr)
{
@@ -459,7 +411,7 @@ PlatformEventsTranslate(
}
return mask;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -483,7 +435,7 @@ PlatformEventsTranslate(
*----------------------------------------------------------------------
*/
-int
+static int
PlatformEventsWait(
struct kevent *events,
size_t numEvents,
@@ -532,13 +484,17 @@ PlatformEventsWait(
timePtr->tv_usec = 0;
}
}
+ if (tsdPtr->asyncPending) {
+ tsdPtr->asyncPending = 0;
+ TclAsyncMarkFromNotifier();
+ }
return numFound;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_CreateFileHandler --
+ * TclpCreateFileHandler --
*
* This function registers a file handler with the kqueue notifier
* of the thread of the caller.
@@ -554,7 +510,7 @@ PlatformEventsWait(
*/
void
-Tcl_CreateFileHandler(
+TclpCreateFileHandler(
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
@@ -564,43 +520,28 @@ Tcl_CreateFileHandler(
* event. */
ClientData clientData) /* Arbitrary data to pass to proc. */
{
- int isNew;
-
- if (tclNotifierHooks.createFileHandlerProc) {
- tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
- return;
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileHandler *filePtr;
-
- 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;
- isNew = 1;
- } else {
- isNew = 0;
- }
- filePtr->proc = proc;
- filePtr->clientData = clientData;
- filePtr->mask = mask;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL);
+ int isNew = (filePtr == NULL);
- PlatformEventsControl(filePtr, tsdPtr, EV_ADD, isNew);
+ if (isNew) {
+ 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;
+
+ PlatformEventsControl(filePtr, tsdPtr, EV_ADD, isNew);
}
/*
*----------------------------------------------------------------------
*
- * Tcl_DeleteFileHandler --
+ * TclpDeleteFileHandler --
*
* Cancel a previously-arranged callback arrangement for a file on the
* kqueue of the thread of the caller.
@@ -618,60 +559,50 @@ Tcl_CreateFileHandler(
*/
void
-Tcl_DeleteFileHandler(
+TclpDeleteFileHandler(
int fd) /* Stream id for which to remove callback
* function. */
{
- if (tclNotifierHooks.deleteFileHandlerProc) {
- tclNotifierHooks.deleteFileHandlerProc(fd);
- return;
- } else {
- FileHandler *filePtr, *prevPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr, *prevPtr;
- /*
- * Find the entry for the given file (and return if there isn't one).
- */
+ /*
+ * 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;
- }
- }
+ filePtr = LookUpFileHandler(tsdPtr, fd, &prevPtr);
+ if (filePtr == NULL) {
+ return;
+ }
- /*
- * Update the check masks for this file.
- */
+ /*
+ * Update the check masks for this file.
+ */
- PlatformEventsControl(filePtr, tsdPtr, EV_DELETE, 0);
- if (filePtr->pedPtr) {
- ckfree(filePtr->pedPtr);
- }
+ PlatformEventsControl(filePtr, tsdPtr, EV_DELETE, 0);
+ if (filePtr->pedPtr) {
+ ckfree(filePtr->pedPtr);
+ }
- /*
- * Clean up information in the callback record.
- */
+ /*
+ * Clean up information in the callback record.
+ */
- if (prevPtr == NULL) {
- tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
- } else {
- prevPtr->nextPtr = filePtr->nextPtr;
- }
- ckfree(filePtr);
+ if (prevPtr == NULL) {
+ tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = filePtr->nextPtr;
}
+ ckfree(filePtr);
}
/*
*----------------------------------------------------------------------
*
- * Tcl_WaitForEvent --
+ * TclpWaitForEvent --
*
* 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
+ * the message queue. If the block time is 0, then TclpWaitForEvent just
* polls without blocking.
*
* The waiting logic is implemented in PlatformEventsWait.
@@ -687,161 +618,217 @@ Tcl_DeleteFileHandler(
*/
int
-Tcl_WaitForEvent(
- const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
+TclpWaitForEvent(
+ const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
- if (tclNotifierHooks.waitForEventProc) {
- return tclNotifierHooks.waitForEventProc(timePtr);
- } else {
- FileHandler *filePtr;
- int mask;
- Tcl_Time vTime;
- /*
- * Impl. notes: timeout & timeoutPtr are used if, and only if threads
- * are not enabled. They are the arguments for the regular epoll_wait()
- * used when the core is not thread-enabled.
- */
+ FileHandler *filePtr;
+ int mask;
+ Tcl_Time vTime;
+ struct timeval timeout, *timeoutPtr;
+ /* Impl. notes: timeout & timeoutPtr are used
+ * if, and only if threads are not enabled.
+ * They are the arguments for the regular
+ * epoll_wait() used when the core is not
+ * thread-enabled. */
+ int numFound, numEvent;
+ struct PlatformEventData *pedPtr;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ int numQueued;
+ ssize_t i;
+ char buf[1];
- struct timeval timeout, *timeoutPtr;
- int numFound, numEvent;
- struct PlatformEventData *pedPtr;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- int numQueued;
- ssize_t i;
- char buf[1];
+ /*
+ * Set up the timeout structure. Note that if there are no events to check
+ * for, we return with a negative result rather than blocking forever.
+ */
+ if (timePtr != NULL) {
/*
- * Set up the timeout structure. Note that if there are no events to
- * check for, we return with a negative result rather than blocking
- * forever.
+ * 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.
*/
- 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.
- */
-
- if (timePtr->sec != 0 || timePtr->usec != 0) {
- vTime = *timePtr;
- tclScaleTimeProcPtr(&vTime, tclTimeClientData);
- timePtr = &vTime;
- }
- timeout.tv_sec = timePtr->sec;
- timeout.tv_usec = timePtr->usec;
- timeoutPtr = &timeout;
- } else {
- timeoutPtr = NULL;
+ if (timePtr->sec != 0 || timePtr->usec != 0) {
+ vTime = *timePtr;
+ TclScaleTime(&vTime);
+ timePtr = &vTime;
+ }
+ timeout.tv_sec = timePtr->sec;
+ timeout.tv_usec = timePtr->usec;
+ timeoutPtr = &timeout;
+ } else {
+ timeoutPtr = NULL;
+ }
+
+ /*
+ * Walk the list of FileHandlers associated with regular files (S_IFREG)
+ * belonging to tsdPtr, queue Tcl events for them, and update their mask
+ * of events of interest.
+ *
+ * kqueue(2), unlike epoll(7), does support regular files, but EVFILT_READ
+ * only `[r]eturns when the file pointer is not at the end of file' as
+ * opposed to unconditionally. While FreeBSD 11.0-RELEASE adds support for
+ * this mode (NOTE_FILE_POLL,) this is not used for reasons of
+ * compatibility.
+ *
+ * Therefore, the behaviour of {select,poll}(2) is simply simulated here:
+ * fds associated with regular files are added to this list by
+ * PlatformEventsControl() and processed here before calling (and possibly
+ * blocking) on PlatformEventsWait().
+ */
+
+ numQueued = 0;
+ LIST_FOREACH(filePtr, &tsdPtr->firstReadyFileHandlerPtr, readyNode) {
+ mask = 0;
+ if (filePtr->mask & TCL_READABLE) {
+ mask |= TCL_READABLE;
+ }
+ if (filePtr->mask & TCL_WRITABLE) {
+ mask |= TCL_WRITABLE;
}
/*
- * Walk the list of FileHandlers associated with regular files
- * (S_IFREG) belonging to tsdPtr, queue Tcl events for them, and
- * update their mask of events of interest.
- *
- * kqueue(2), unlike epoll(7), does support regular files, but
- * EVFILT_READ only `[r]eturns when the file pointer is not at the end
- * of file' as opposed to unconditionally. While FreeBSD 11.0-RELEASE
- * adds support for this mode (NOTE_FILE_POLL,) this is not used for
- * reasons of compatibility.
- *
- * Therefore, the behaviour of {select,poll}(2) is simply simulated
- * here: fds associated with regular files are added to this list by
- * PlatformEventsControl() and processed here before calling (and
- * possibly blocking) on PlatformEventsWait().
+ * Don't bother to queue an event if the mask was previously non-zero
+ * since an event must still be on the queue.
*/
- numQueued = 0;
- LIST_FOREACH(filePtr, &tsdPtr->firstReadyFileHandlerPtr, readyNode) {
- mask = 0;
- if (filePtr->mask & TCL_READABLE) {
- mask |= TCL_READABLE;
- }
- if (filePtr->mask & TCL_WRITABLE) {
- mask |= TCL_WRITABLE;
- }
+ if (filePtr->readyMask == 0) {
+ FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
+ ckalloc(sizeof(FileHandlerEvent));
+
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+ numQueued++;
+ }
+ filePtr->readyMask = mask;
+ }
- /*
- * Don't bother to queue an event if the mask was previously
- * non-zero since an event must still be on the queue.
- */
+ /*
+ * If any events were queued in the above loop, force PlatformEventsWait()
+ * to poll as there already are events that need to be processed at this
+ * point.
+ */
+
+ if (numQueued) {
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ timeoutPtr = &timeout;
+ }
- if (filePtr->readyMask == 0) {
- FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
- ckalloc(sizeof(FileHandlerEvent));
+ /*
+ * Wait or poll for new events, queue Tcl events for the FileHandlers
+ * corresponding to them, and update the FileHandlers' mask of events of
+ * interest registered by the last call to Tcl_CreateFileHandler().
+ *
+ * Events for the trigger pipe are processed here in order to facilitate
+ * inter-thread IPC. If another thread intends to wake up this thread
+ * whilst it's blocking on PlatformEventsWait(), it write(2)s to the other
+ * end of the pipe (see Tcl_AlertNotifier(),) which in turn will cause
+ * PlatformEventsWait() to return immediately.
+ */
- fileEvPtr->header.proc = FileHandlerEventProc;
- fileEvPtr->fd = filePtr->fd;
- Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
- numQueued++;
+ numFound = PlatformEventsWait(tsdPtr->readyEvents,
+ tsdPtr->maxReadyEvents, timeoutPtr);
+ for (numEvent = 0; numEvent < numFound; numEvent++) {
+ pedPtr = (struct PlatformEventData *)
+ tsdPtr->readyEvents[numEvent].udata;
+ filePtr = pedPtr->filePtr;
+ mask = PlatformEventsTranslate(&tsdPtr->readyEvents[numEvent]);
+ if (filePtr->fd == tsdPtr->triggerPipe[0]) {
+ i = read(tsdPtr->triggerPipe[0], buf, 1);
+ if ((i == -1) && (errno != EAGAIN)) {
+ Tcl_Panic("Tcl_WaitForEvent: read from %p->triggerPipe: %s",
+ (void *) tsdPtr, strerror(errno));
}
- filePtr->readyMask = mask;
+ continue;
}
-
- /*
- * If any events were queued in the above loop, force PlatformEvents-
- * Wait() to poll as there already are events that need to be processed
- * at this point.
- */
-
- if (numQueued) {
- timeout.tv_sec = 0;
- timeout.tv_usec = 0;
- timeoutPtr = &timeout;
+ if (!mask) {
+ continue;
}
/*
- * Wait or poll for new events, queue Tcl events for the FileHandlers
- * corresponding to them, and update the FileHandlers' mask of events
- * of interest registered by the last call to Tcl_CreateFileHandler().
- *
- * Events for the trigger pipe are processed here in order to facilitate
- * inter-thread IPC. If another thread intends to wake up this thread
- * whilst it's blocking on PlatformEventsWait(), it write(2)s to the
- * other end of the pipe (see Tcl_AlertNotifier(),) which in turn will
- * cause PlatformEventsWait() to return immediately.
+ * Don't bother to queue an event if the mask was previously non-zero
+ * since an event must still be on the queue.
*/
- numFound = PlatformEventsWait(tsdPtr->readyEvents,
- tsdPtr->maxReadyEvents, timeoutPtr);
- for (numEvent = 0; numEvent < numFound; numEvent++) {
- pedPtr = (struct PlatformEventData *)
- tsdPtr->readyEvents[numEvent].udata;
- filePtr = pedPtr->filePtr;
- mask = PlatformEventsTranslate(&tsdPtr->readyEvents[numEvent]);
- if (filePtr->fd == tsdPtr->triggerPipe[0]) {
- i = read(tsdPtr->triggerPipe[0], buf, 1);
- if ((i == -1) && (errno != EAGAIN)) {
- Tcl_Panic("Tcl_WaitForEvent: read from %p->triggerPipe: %s",
- (void *) tsdPtr, strerror(errno));
- }
- continue;
- }
- if (!mask) {
- continue;
- }
+ if (filePtr->readyMask == 0) {
+ FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
+ ckalloc(sizeof(FileHandlerEvent));
- /*
- * Don't bother to queue an event if the mask was previously
- * non-zero since an event must still be on the queue.
- */
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
+ }
+ filePtr->readyMask |= mask;
+ }
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclAsyncNotifier --
+ *
+ * This procedure sets the async mark of an async handler to a
+ * given value, if it is called from the target thread.
+ *
+ * Result:
+ * True, when the handler will be marked, false otherwise.
+ *
+ * Side effects:
+ * The signal may be resent to the target thread.
+ *
+ *----------------------------------------------------------------------
+ */
- if (filePtr->readyMask == 0) {
- FileHandlerEvent *fileEvPtr = (FileHandlerEvent *)
- ckalloc(sizeof(FileHandlerEvent));
+int
+TclAsyncNotifier(
+ int sigNumber, /* Signal number. */
+ Tcl_ThreadId threadId, /* Target thread. */
+ ClientData clientData, /* Notifier data. */
+ int *flagPtr, /* Flag to mark. */
+ int value) /* Value of mark. */
+{
+#if TCL_THREADS
+ /*
+ * WARNING:
+ * This code most likely runs in a signal handler. Thus,
+ * only few async-signal-safe system calls are allowed,
+ * e.g. pthread_self(), sem_post(), write().
+ */
- fileEvPtr->header.proc = FileHandlerEventProc;
- fileEvPtr->fd = filePtr->fd;
- Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
- }
- filePtr->readyMask |= mask;
+ if (pthread_equal(pthread_self(), (pthread_t) threadId)) {
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
+
+ *flagPtr = value;
+ if (tsdPtr != NULL && !tsdPtr->asyncPending) {
+ tsdPtr->asyncPending = 1;
+ TclpAlertNotifier(tsdPtr);
+ return 1;
}
return 0;
}
+
+ /*
+ * Re-send the signal to the proper target thread.
+ */
+
+ pthread_kill((pthread_t) threadId, sigNumber);
+#else
+ (void)sigNumber;
+ (void)threadId;
+ (void)clientData;
+ (void)flagPtr;
+ (void)value;
+#endif
+ return 0;
}
#endif /* NOTIFIER_KQUEUE && TCL_THREADS */
+#else
+TCL_MAC_EMPTY_FILE(unix_tclKqueueNotfy_c)
#endif /* !HAVE_COREFOUNDATION */
/*
diff --git a/unix/tclLoadDyld.c b/unix/tclLoadDyld.c
index 017793d..7cd48f2 100644
--- a/unix/tclLoadDyld.c
+++ b/unix/tclLoadDyld.c
@@ -336,7 +336,7 @@ FindSymbol(
const char *symbol) /* Symbol name to look up. */
{
Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *)loadHandle->clientData;
- Tcl_PackageInitProc *proc = NULL;
+ Tcl_LibraryInitProc *proc = NULL;
const char *errMsg = NULL;
Tcl_DString ds;
const char *native;
@@ -344,7 +344,7 @@ FindSymbol(
native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
if (dyldLoadHandle->dlHandle) {
#if TCL_DYLD_USE_DLFCN
- proc = (Tcl_PackageInitProc *)dlsym(dyldLoadHandle->dlHandle, native);
+ proc = (Tcl_LibraryInitProc *)dlsym(dyldLoadHandle->dlHandle, native);
if (!proc) {
errMsg = dlerror();
}
@@ -400,7 +400,7 @@ FindSymbol(
dyldLoadHandle->modulePtr->module, native);
}
if (nsSymbol) {
- proc = (Tcl_PackageInitProc *)NSAddressOfSymbol(nsSymbol);
+ proc = (Tcl_LibraryInitProc *)NSAddressOfSymbol(nsSymbol);
}
Tcl_DStringFree(&newName);
#endif /* TCL_DYLD_USE_NSMODULE */
diff --git a/unix/tclLoadNext.c b/unix/tclLoadNext.c
index ee39326..2055210 100644
--- a/unix/tclLoadNext.c
+++ b/unix/tclLoadNext.c
@@ -133,7 +133,7 @@ FindSymbol(
Tcl_LoadHandle loadHandle,
const char *symbol)
{
- Tcl_PackageInitProc *proc = NULL;
+ Tcl_LibraryInitProc *proc = NULL;
if (symbol) {
char sym[strlen(symbol) + 2];
diff --git a/unix/tclLoadOSF.c b/unix/tclLoadOSF.c
index 7fd0cf3..bb58871 100644
--- a/unix/tclLoadOSF.c
+++ b/unix/tclLoadOSF.c
@@ -89,7 +89,7 @@ TclpDlopen(
*/
native = Tcl_FSGetNativePath(pathPtr);
- lm = (Tcl_PackageInitProc *) load(native, LDR_NOFLAGS);
+ lm = (Tcl_LibraryInitProc *) load(native, LDR_NOFLAGS);
if (lm == LDR_NULL_MODULE) {
/*
@@ -101,7 +101,7 @@ TclpDlopen(
Tcl_DString ds;
native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
- lm = (Tcl_PackageInitProc *) load(native, LDR_NOFLAGS);
+ lm = (Tcl_LibraryInitProc *) load(native, LDR_NOFLAGS);
Tcl_DStringFree(&ds);
}
diff --git a/unix/tclLoadShl.c b/unix/tclLoadShl.c
index 11eaa83..5bf97eb 100644
--- a/unix/tclLoadShl.c
+++ b/unix/tclLoadShl.c
@@ -128,7 +128,7 @@ FindSymbol(
const char *symbol)
{
Tcl_DString newName;
- Tcl_PackageInitProc *proc = NULL;
+ Tcl_LibraryInitProc *proc = NULL;
shl_t handle = (shl_t) loadHandle->clientData;
/*
diff --git a/unix/tclSelectNotfy.c b/unix/tclSelectNotfy.c
index 1d16114..732e4c9 100644
--- a/unix/tclSelectNotfy.c
+++ b/unix/tclSelectNotfy.c
@@ -148,6 +148,7 @@ static ThreadSpecificData *waitingListPtr = NULL;
*/
static int triggerPipe = -1;
+static int otherPipe = -1;
/*
* The notifierMutex locks access to all of the global notifier state.
@@ -164,9 +165,15 @@ static pthread_mutex_t notifierMutex = PTHREAD_MUTEX_INITIALIZER;
static int notifierThreadRunning = 0;
/*
+ * The following static flag indicates that async handlers are pending.
+ */
+
+static int asyncPending = 0;
+
+/*
* The notifier thread signals the notifierCV when it has finished
* initializing the triggerPipe and right before the notifier thread
- * terminates.
+ * terminates. This condition is used to deal with the signal mask, too.
*/
static pthread_cond_t notifierCV = PTHREAD_COND_INITIALIZER;
@@ -190,6 +197,16 @@ static pthread_cond_t notifierCV = PTHREAD_COND_INITIALIZER;
*/
static Tcl_ThreadId notifierThread;
+
+/*
+ * Signal mask information for notifier thread.
+ */
+
+static sigset_t notifierSigMask;
+#ifndef HAVE_PSELECT
+static sigset_t allSigMask;
+#endif /* HAVE_PSELECT */
+
#endif /* TCL_THREADS */
/*
@@ -216,8 +233,8 @@ extern "C" {
typedef struct {
void *hwnd; /* Messaging window. */
unsigned int *message; /* Message payload. */
- size_t wParam; /* Event-specific "word" parameter. */
- size_t lParam; /* Event-specific "long" parameter. */
+ size_t wParam; /* Event-specific "word" parameter. */
+ size_t lParam; /* Event-specific "long" parameter. */
int time; /* Event timestamp. */
int x; /* Event location (where meaningful). */
int y;
@@ -244,8 +261,8 @@ extern void __stdcall CloseHandle(void *);
extern void *__stdcall CreateEventW(void *, unsigned char, unsigned char,
void *);
extern void *__stdcall CreateWindowExW(void *, const void *, const void *,
- unsigned int, int, int, int, int, void *, void *, void *,
- void *);
+ unsigned int, int, int, int, int, void *, void *,
+ void *, void *);
extern unsigned int __stdcall DefWindowProcW(void *, int, void *, void *);
extern unsigned char __stdcall DestroyWindow(void *);
extern int __stdcall DispatchMessageW(const MSG *);
@@ -264,21 +281,26 @@ extern unsigned char __stdcall TranslateMessage(const MSG *);
* Threaded-cygwin specific constants and functions in this file:
*/
+#if TCL_THREADS && defined(__CYGWIN__)
static const wchar_t className[] = L"TclNotifier";
static unsigned int __stdcall NotifierProc(void *hwnd, unsigned int message,
void *wParam, void *lParam);
+#endif /* TCL_THREADS && defined(__CYGWIN__) */
#ifdef __cplusplus
}
#endif
#endif /* TCL_THREADS && __CYGWIN__ */
-
+/*
+ * Incorporate the base notifier implementation.
+ */
+
#include "tclUnixNotfy.c"
/*
*----------------------------------------------------------------------
*
- * Tcl_InitNotifier --
+ * TclpInitNotifier --
*
* Initializes the platform specific notifier state.
*
@@ -292,75 +314,72 @@ static unsigned int __stdcall NotifierProc(void *hwnd, unsigned int message,
*/
ClientData
-Tcl_InitNotifier(void)
+TclpInitNotifier(void)
{
- if (tclNotifierHooks.initNotifierProc) {
- return tclNotifierHooks.initNotifierProc();
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#if TCL_THREADS
- tsdPtr->eventReady = 0;
+ tsdPtr->eventReady = 0;
- /*
- * Initialize thread specific condition variable for this thread.
- */
- if (tsdPtr->waitCVinitialized == 0) {
+ /*
+ * Initialize thread specific condition variable for this thread.
+ */
+
+ if (tsdPtr->waitCVinitialized == 0) {
#ifdef __CYGWIN__
- WNDCLASSW clazz;
-
- clazz.style = 0;
- clazz.cbClsExtra = 0;
- clazz.cbWndExtra = 0;
- clazz.hInstance = TclWinGetTclInstance();
- clazz.hbrBackground = NULL;
- clazz.lpszMenuName = NULL;
- clazz.lpszClassName = className;
- clazz.lpfnWndProc = (void *)NotifierProc;
- clazz.hIcon = NULL;
- clazz.hCursor = NULL;
-
- RegisterClassW(&clazz);
- tsdPtr->hwnd = CreateWindowExW(NULL, clazz.lpszClassName,
- clazz.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
- clazz.hInstance, NULL);
- tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
- 0 /* !signaled */, NULL);
-#else
- pthread_cond_init(&tsdPtr->waitCV, NULL);
+ WNDCLASSW clazz;
+
+ clazz.style = 0;
+ clazz.cbClsExtra = 0;
+ clazz.cbWndExtra = 0;
+ clazz.hInstance = TclWinGetTclInstance();
+ clazz.hbrBackground = NULL;
+ clazz.lpszMenuName = NULL;
+ clazz.lpszClassName = className;
+ clazz.lpfnWndProc = (void *) NotifierProc;
+ clazz.hIcon = NULL;
+ clazz.hCursor = NULL;
+
+ RegisterClassW(&clazz);
+ tsdPtr->hwnd = CreateWindowExW(NULL, clazz.lpszClassName,
+ clazz.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
+ clazz.hInstance, NULL);
+ tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
+ 0 /* !signaled */, NULL);
+#else /* !__CYGWIN__ */
+ pthread_cond_init(&tsdPtr->waitCV, NULL);
#endif /* __CYGWIN__ */
- tsdPtr->waitCVinitialized = 1;
- }
+ tsdPtr->waitCVinitialized = 1;
+ }
- pthread_mutex_lock(&notifierInitMutex);
+ pthread_mutex_lock(&notifierInitMutex);
#if defined(HAVE_PTHREAD_ATFORK)
- /*
- * Install pthread_atfork handlers to clean up the notifier in the
- * child of a fork.
- */
+ /*
+ * Install pthread_atfork handlers to clean up the notifier in the child
+ * of a fork.
+ */
- if (!atForkInit) {
- int result = pthread_atfork(NULL, NULL, AtForkChild);
+ if (!atForkInit) {
+ int result = pthread_atfork(NULL, NULL, AtForkChild);
- if (result) {
- Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
- }
- atForkInit = 1;
+ if (result) {
+ Tcl_Panic("Tcl_InitNotifier: %s", "pthread_atfork failed");
}
+ atForkInit = 1;
+ }
#endif /* HAVE_PTHREAD_ATFORK */
- notifierCount++;
- pthread_mutex_unlock(&notifierInitMutex);
-
+ notifierCount++;
+ pthread_mutex_unlock(&notifierInitMutex);
#endif /* TCL_THREADS */
- return tsdPtr;
- }
+
+ return tsdPtr;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_FinalizeNotifier --
+ * TclpFinalizeNotifier --
*
* This function is called to cleanup the notifier state before a thread
* is terminated.
@@ -376,67 +395,70 @@ Tcl_InitNotifier(void)
*/
void
-Tcl_FinalizeNotifier(
- ClientData clientData)
+TclpFinalizeNotifier(
+ TCL_UNUSED(void *))
{
- if (tclNotifierHooks.finalizeNotifierProc) {
- tclNotifierHooks.finalizeNotifierProc(clientData);
- return;
- } else {
#if TCL_THREADS
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- pthread_mutex_lock(&notifierInitMutex);
- notifierCount--;
+ pthread_mutex_lock(&notifierInitMutex);
+ notifierCount--;
- /*
- * If this is the last thread to use the notifier, close the notifier
- * pipe and wait for the background thread to terminate.
- */
+ /*
+ * 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 && triggerPipe != -1) {
+ if (write(triggerPipe, "q", 1) != 1) {
+ Tcl_Panic("Tcl_FinalizeNotifier: %s",
+ "unable to write 'q' to triggerPipe");
+ }
+ close(triggerPipe);
+ pthread_mutex_lock(&notifierMutex);
+ while(triggerPipe != -1) {
+ pthread_cond_wait(&notifierCV, &notifierMutex);
+ }
+ pthread_mutex_unlock(&notifierMutex);
+ if (notifierThreadRunning) {
+ int result = pthread_join((pthread_t) notifierThread, NULL);
- if (notifierCount == 0 && triggerPipe != -1) {
- if (write(triggerPipe, "q", 1) != 1) {
+ if (result) {
Tcl_Panic("Tcl_FinalizeNotifier: %s",
- "unable to write 'q' to triggerPipe");
+ "unable to join notifier thread");
}
- close(triggerPipe);
- pthread_mutex_lock(&notifierMutex);
- while(triggerPipe != -1) {
- pthread_cond_wait(&notifierCV, &notifierMutex);
- }
- pthread_mutex_unlock(&notifierMutex);
- if (notifierThreadRunning) {
- int result = pthread_join((pthread_t) notifierThread, NULL);
+ notifierThreadRunning = 0;
- if (result) {
- Tcl_Panic("Tcl_FinalizeNotifier: %s",
- "unable to join notifier thread");
- }
- notifierThreadRunning = 0;
+ /*
+ * If async marks are outstanding, perform actions now.
+ */
+ if (asyncPending) {
+ asyncPending = 0;
+ TclAsyncMarkFromNotifier();
}
}
+ }
- /*
- * Clean up any synchronization objects in the thread local storage.
- */
+ /*
+ * Clean up any synchronization objects in the thread local storage.
+ */
#ifdef __CYGWIN__
- DestroyWindow(tsdPtr->hwnd);
- CloseHandle(tsdPtr->event);
-#else /* __CYGWIN__ */
- pthread_cond_destroy(&tsdPtr->waitCV);
+ DestroyWindow(tsdPtr->hwnd);
+ CloseHandle(tsdPtr->event);
+#else /* !__CYGWIN__ */
+ pthread_cond_destroy(&tsdPtr->waitCV);
#endif /* __CYGWIN__ */
- tsdPtr->waitCVinitialized = 0;
+ tsdPtr->waitCVinitialized = 0;
- pthread_mutex_unlock(&notifierInitMutex);
+ pthread_mutex_unlock(&notifierInitMutex);
#endif /* TCL_THREADS */
- }
}
/*
*----------------------------------------------------------------------
*
- * Tcl_CreateFileHandler --
+ * TclpCreateFileHandler --
*
* This function registers a file handler with the select notifier.
*
@@ -450,7 +472,7 @@ Tcl_FinalizeNotifier(
*/
void
-Tcl_CreateFileHandler(
+TclpCreateFileHandler(
int fd, /* Handle of stream to watch. */
int mask, /* OR'ed combination of TCL_READABLE,
* TCL_WRITABLE, and TCL_EXCEPTION: indicates
@@ -460,59 +482,48 @@ Tcl_CreateFileHandler(
* event. */
ClientData clientData) /* Arbitrary data to pass to proc. */
{
- if (tclNotifierHooks.createFileHandlerProc) {
- tclNotifierHooks.createFileHandlerProc(fd, mask, proc, clientData);
- return;
- } else {
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
- FileHandler *filePtr;
-
- 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;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr = LookUpFileHandler(tsdPtr, fd, NULL);
+
+ 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.
- */
+ /*
+ * 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.exception);
- } else {
- FD_CLR(fd, &tsdPtr->checkMasks.exception);
- }
- if (tsdPtr->numFdBits <= fd) {
- tsdPtr->numFdBits = fd+1;
- }
+ 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.exception);
+ } else {
+ FD_CLR(fd, &tsdPtr->checkMasks.exception);
+ }
+ if (tsdPtr->numFdBits <= fd) {
+ tsdPtr->numFdBits = fd + 1;
}
}
/*
*----------------------------------------------------------------------
*
- * Tcl_DeleteFileHandler --
+ * TclpDeleteFileHandler --
*
* Cancel a previously-arranged callback arrangement for a file.
*
@@ -526,78 +537,68 @@ Tcl_CreateFileHandler(
*/
void
-Tcl_DeleteFileHandler(
+TclpDeleteFileHandler(
int fd) /* Stream id for which to remove callback
* function. */
{
- if (tclNotifierHooks.deleteFileHandlerProc) {
- tclNotifierHooks.deleteFileHandlerProc(fd);
- return;
- } else {
- FileHandler *filePtr, *prevPtr;
- int i;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr, *prevPtr;
+ int i;
- /*
- * Find the entry for the given file (and return if there isn't one).
- */
+ /*
+ * 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;
- }
- }
+ filePtr = LookUpFileHandler(tsdPtr, fd, &prevPtr);
+ if (filePtr == NULL) {
+ return;
+ }
- /*
- * Update the check masks for this file.
- */
+ /*
+ * 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.exception);
- }
+ 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.exception);
+ }
- /*
- * Find current max fd.
- */
+ /*
+ * Find current max fd.
+ */
- if (fd+1 == tsdPtr->numFdBits) {
- int numFdBits = 0;
+ if (fd + 1 == tsdPtr->numFdBits) {
+ int 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.exception)) {
- numFdBits = i+1;
- break;
- }
+ 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.exception)) {
+ numFdBits = i + 1;
+ break;
}
- tsdPtr->numFdBits = numFdBits;
}
+ tsdPtr->numFdBits = numFdBits;
+ }
- /*
- * Clean up information in the callback record.
- */
+ /*
+ * Clean up information in the callback record.
+ */
- if (prevPtr == NULL) {
- tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
- } else {
- prevPtr->nextPtr = filePtr->nextPtr;
- }
- ckfree(filePtr);
+ if (prevPtr == NULL) {
+ tsdPtr->firstFileHandlerPtr = filePtr->nextPtr;
+ } else {
+ prevPtr->nextPtr = filePtr->nextPtr;
}
+ ckfree(filePtr);
}
-#if defined(__CYGWIN__)
+#if TCL_THREADS && defined(__CYGWIN__)
static unsigned int __stdcall
NotifierProc(
@@ -625,7 +626,7 @@ NotifierProc(
/*
*----------------------------------------------------------------------
*
- * Tcl_WaitForEvent --
+ * TclpWaitForEvent --
*
* 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
@@ -641,265 +642,320 @@ NotifierProc(
*/
int
-Tcl_WaitForEvent(
+TclpWaitForEvent(
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
{
- if (tclNotifierHooks.waitForEventProc) {
- return tclNotifierHooks.waitForEventProc(timePtr);
- } else {
- FileHandler *filePtr;
- int mask;
- Tcl_Time vTime;
- ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ FileHandler *filePtr;
+ int mask;
+ Tcl_Time vTime;
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
#if TCL_THREADS
- int waitForFiles;
+ int waitForFiles;
# ifdef __CYGWIN__
- MSG msg;
+ MSG msg;
# endif /* __CYGWIN__ */
#else /* !TCL_THREADS */
- /*
- * Impl. notes: timeout & timeoutPtr are used if, and only if threads
- * are not enabled. They are the arguments for the regular select()
- * used when the core is not thread-enabled.
- */
+ /*
+ * Impl. notes: timeout & timeoutPtr are used if, and only if threads are
+ * not enabled. They are the arguments for the regular select() used when
+ * the core is not thread-enabled.
+ */
- struct timeval timeout, *timeoutPtr;
- int numFound;
+ struct timeval timeout, *timeoutPtr;
+ int numFound;
#endif /* TCL_THREADS */
+ /*
+ * Set up the timeout structure. Note that if there are no events to check
+ * for, we return with a negative result rather than blocking forever.
+ */
+
+ if (timePtr != NULL) {
/*
- * Set up the timeout structure. Note that if there are no events to
- * check for, we return with a negative result rather than blocking
- * forever.
+ * 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.
*/
- 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.
- */
-
- if (timePtr->sec != 0 || timePtr->usec != 0) {
- vTime = *timePtr;
- tclScaleTimeProcPtr(&vTime, tclTimeClientData);
- timePtr = &vTime;
- }
+ if (timePtr->sec != 0 || timePtr->usec != 0) {
+ vTime = *timePtr;
+ TclScaleTime(&vTime);
+ timePtr = &vTime;
+ }
#if !TCL_THREADS
- timeout.tv_sec = timePtr->sec;
- timeout.tv_usec = timePtr->usec;
- timeoutPtr = &timeout;
- } else if (tsdPtr->numFdBits == 0) {
- /*
- * If there are no threads, no timeout, and no fds registered,
- * then there are no events possible and we must avoid deadlock.
- * Note that this is not entirely correct because there might be a
- * signal that could interrupt the select call, but we don't
- * handle that case if we aren't using threads.
- */
+ timeout.tv_sec = timePtr->sec;
+ timeout.tv_usec = timePtr->usec;
+ timeoutPtr = &timeout;
+ } else if (tsdPtr->numFdBits == 0) {
+ /*
+ * If there are no threads, no timeout, and no fds registered, then
+ * there are no events possible and we must avoid deadlock. Note that
+ * this is not entirely correct because there might be a signal that
+ * could interrupt the select call, but we don't handle that case if
+ * we aren't using threads.
+ */
- return -1;
- } else {
- timeoutPtr = NULL;
+ return -1;
+ } else {
+ timeoutPtr = NULL;
#endif /* !TCL_THREADS */
- }
+ }
#if TCL_THREADS
- /*
- * Start notifier thread and place this thread on the list of
- * interested threads, signal the notifier thread, and wait for a
- * response or a timeout.
- */
- StartNotifierThread("Tcl_WaitForEvent");
+ /*
+ * Start notifier thread and place this thread on the list of interested
+ * threads, signal the notifier thread, and wait for a response or a
+ * timeout.
+ */
- pthread_mutex_lock(&notifierMutex);
+ StartNotifierThread("Tcl_WaitForEvent");
- if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0
+ pthread_mutex_lock(&notifierMutex);
+
+ if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0
#if defined(__APPLE__) && defined(__LP64__)
- /*
- * On 64-bit Darwin, pthread_cond_timedwait() appears to have
- * a bug that causes it to wait forever when passed an
- * absolute time which has already been exceeded by the system
- * time; as a workaround, when given a very brief timeout,
- * just do a poll. [Bug 1457797]
- */
- || timePtr->usec < 10
-#endif /* __APPLE__ && __LP64__ */
- )) {
/*
- * 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.
+ * On 64-bit Darwin, pthread_cond_timedwait() appears to have a
+ * bug that causes it to wait forever when passed an absolute time
+ * which has already been exceeded by the system time; as a
+ * workaround, when given a very brief timeout, just do a poll.
+ * [Bug 1457797]
*/
+ || timePtr->usec < 10
+#endif /* __APPLE__ && __LP64__ */
+ )) {
+ /*
+ * 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;
- timePtr = NULL;
- } else {
- waitForFiles = (tsdPtr->numFdBits > 0);
- tsdPtr->pollState = 0;
- }
+ waitForFiles = 1;
+ tsdPtr->pollState = POLL_WANT;
+ timePtr = NULL;
+ } else {
+ waitForFiles = (tsdPtr->numFdBits > 0);
+ 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.
- */
+ 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;
+ tsdPtr->nextPtr = waitingListPtr;
+ if (waitingListPtr) {
+ waitingListPtr->prevPtr = tsdPtr;
+ }
+ tsdPtr->prevPtr = 0;
+ waitingListPtr = tsdPtr;
+ tsdPtr->onList = 1;
- if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
- Tcl_Panic("Tcl_WaitForEvent: %s",
- "unable to write to triggerPipe");
- }
+ if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
+ Tcl_Panic("Tcl_WaitForEvent: %s",
+ "unable to write to triggerPipe");
}
+ }
- FD_ZERO(&tsdPtr->readyMasks.readable);
- FD_ZERO(&tsdPtr->readyMasks.writable);
- FD_ZERO(&tsdPtr->readyMasks.exception);
+ FD_ZERO(&tsdPtr->readyMasks.readable);
+ FD_ZERO(&tsdPtr->readyMasks.writable);
+ FD_ZERO(&tsdPtr->readyMasks.exception);
- if (!tsdPtr->eventReady) {
+ if (!tsdPtr->eventReady) {
#ifdef __CYGWIN__
- if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
- unsigned int timeout;
+ if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
+ unsigned int timeout;
- if (timePtr) {
- timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
- } else {
- timeout = 0xFFFFFFFF;
- }
- pthread_mutex_unlock(&notifierMutex);
- MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
- pthread_mutex_lock(&notifierMutex);
+ if (timePtr) {
+ timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
+ } else {
+ timeout = 0xFFFFFFFF;
}
+ pthread_mutex_unlock(&notifierMutex);
+ MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
+ pthread_mutex_lock(&notifierMutex);
+ }
#else /* !__CYGWIN__ */
- if (timePtr != NULL) {
- Tcl_Time now;
- struct timespec ptime;
+ if (timePtr != NULL) {
+ Tcl_Time now;
+ struct timespec ptime;
- Tcl_GetTime(&now);
- ptime.tv_sec = timePtr->sec + now.sec +
- (timePtr->usec + now.usec) / 1000000;
- ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
+ Tcl_GetTime(&now);
+ ptime.tv_sec = timePtr->sec + now.sec +
+ (timePtr->usec + now.usec) / 1000000;
+ ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
- pthread_cond_timedwait(&tsdPtr->waitCV, &notifierMutex, &ptime);
- } else {
- pthread_cond_wait(&tsdPtr->waitCV, &notifierMutex);
- }
-#endif /* __CYGWIN__ */
+ pthread_cond_timedwait(&tsdPtr->waitCV, &notifierMutex, &ptime);
+ } else {
+ pthread_cond_wait(&tsdPtr->waitCV, &notifierMutex);
}
- tsdPtr->eventReady = 0;
+#endif /* __CYGWIN__ */
+ }
+ tsdPtr->eventReady = 0;
#ifdef __CYGWIN__
- while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
- /*
- * Retrieve and dispatch the message.
- */
+ while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
+ /*
+ * Retrieve and dispatch the message.
+ */
- unsigned int result = GetMessageW(&msg, NULL, 0, 0);
+ unsigned int result = GetMessageW(&msg, NULL, 0, 0);
- if (result == 0) {
- PostQuitMessage(msg.wParam);
- /* What to do here? */
- } else if (result != (unsigned int) -1) {
- TranslateMessage(&msg);
- DispatchMessageW(&msg);
- }
+ if (result == 0) {
+ PostQuitMessage(msg.wParam);
+ /* What to do here? */
+ } else if (result != (unsigned int) -1) {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
}
- ResetEvent(tsdPtr->event);
+ }
+ ResetEvent(tsdPtr->event);
#endif /* __CYGWIN__ */
- 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 (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;
- if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
- Tcl_Panic("Tcl_WaitForEvent: %s",
- "unable to write to triggerPipe");
- }
+ 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;
+ if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
+ Tcl_Panic("Tcl_WaitForEvent: %s",
+ "unable to write to triggerPipe");
+ }
+ }
#else /* !TCL_THREADS */
- tsdPtr->readyMasks = tsdPtr->checkMasks;
- numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
- &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
- timeoutPtr);
+ tsdPtr->readyMasks = tsdPtr->checkMasks;
+ numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
+ &tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
+ timeoutPtr);
- /*
- * Some systems don't clear the masks after an error, so we have to do
- * it here.
- */
+ /*
+ * Some systems don't clear the masks after an error, so we have to do it
+ * here.
+ */
- if (numFound == -1) {
- FD_ZERO(&tsdPtr->readyMasks.readable);
- FD_ZERO(&tsdPtr->readyMasks.writable);
- FD_ZERO(&tsdPtr->readyMasks.exception);
- }
+ if (numFound == -1) {
+ FD_ZERO(&tsdPtr->readyMasks.readable);
+ FD_ZERO(&tsdPtr->readyMasks.writable);
+ FD_ZERO(&tsdPtr->readyMasks.exception);
+ }
#endif /* TCL_THREADS */
- /*
- * Queue all detected file events before returning.
- */
+ /*
+ * 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.exception)) {
- mask |= TCL_EXCEPTION;
- }
+ 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.exception)) {
+ mask |= TCL_EXCEPTION;
+ }
- if (!mask) {
- continue;
- }
+ 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.
- */
+ /*
+ * 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) {
- FileHandlerEvent *fileEvPtr =
- (FileHandlerEvent *)ckalloc(sizeof(FileHandlerEvent));
+ if (filePtr->readyMask == 0) {
+ FileHandlerEvent *fileEvPtr =
+ (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
- fileEvPtr->header.proc = FileHandlerEventProc;
- fileEvPtr->fd = filePtr->fd;
- Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
- }
- filePtr->readyMask = mask;
+ fileEvPtr->header.proc = FileHandlerEventProc;
+ fileEvPtr->fd = filePtr->fd;
+ Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
}
+ filePtr->readyMask = mask;
+ }
#if TCL_THREADS
- pthread_mutex_unlock(&notifierMutex);
+ pthread_mutex_unlock(&notifierMutex);
#endif /* TCL_THREADS */
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclAsyncNotifier --
+ *
+ * This procedure sets the async mark of an async handler to a
+ * given value, if it is called from the notifier thread.
+ *
+ * Result:
+ * True, when the handler will be marked, false otherwise.
+ *
+ * Side effetcs:
+ * The trigger pipe is written when called from the notifier
+ * thread.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TclAsyncNotifier(
+ int sigNumber, /* Signal number. */
+ TCL_UNUSED(Tcl_ThreadId), /* Target thread. */
+ TCL_UNUSED(ClientData), /* Notifier data. */
+ int *flagPtr, /* Flag to mark. */
+ int value) /* Value of mark. */
+{
+#if TCL_THREADS
+ /*
+ * WARNING:
+ * This code most likely runs in a signal handler. Thus,
+ * only few async-signal-safe system calls are allowed,
+ * e.g. pthread_self(), sem_post(), write().
+ */
+
+ if (pthread_equal(pthread_self(), (pthread_t) notifierThread)) {
+ if (notifierThreadRunning) {
+ *flagPtr = value;
+ if (!asyncPending) {
+ asyncPending = 1;
+ write(triggerPipe, "S", 1);
+ }
+ return 1;
+ }
return 0;
}
+
+ /*
+ * Re-send the signal to the notifier thread.
+ */
+
+ pthread_kill((pthread_t) notifierThread, sigNumber);
+#else
+ (void)sigNumber;
+ (void)flagPtr;
+ (void)value;
+#endif
+ return 0;
}
/*
@@ -916,8 +972,9 @@ Tcl_WaitForEvent(
* 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.
+ * None. Once started, this routine normally never exits and usually dies
+ * with the overall process, but it can be shut down if the Tcl library
+ * is finalized.
*
* Side effects:
* The trigger pipe used to signal the notifier thread is created when
@@ -935,8 +992,7 @@ NotifierThreadProc(
fd_set readableMask;
fd_set writableMask;
fd_set exceptionMask;
- int i;
- int fds[2], receivePipe;
+ int i, fds[2], receivePipe, ret;
long found;
struct timeval poll = {0, 0}, *timePtr;
char buf[2];
@@ -946,6 +1002,14 @@ NotifierThreadProc(
Tcl_Panic("NotifierThreadProc: %s", "could not create trigger pipe");
}
+ /*
+ * Ticket [c6897e6e6a].
+ */
+
+ if (fds[0] >= FD_SETSIZE || fds[1] >= FD_SETSIZE) {
+ Tcl_Panic("NotifierThreadProc: %s", "too many open files");
+ }
+
receivePipe = fds[0];
if (TclUnixSetBlockingMode(receivePipe, TCL_MODE_NONBLOCKING) < 0) {
@@ -971,6 +1035,7 @@ NotifierThreadProc(
pthread_mutex_lock(&notifierMutex);
triggerPipe = fds[1];
+ otherPipe = fds[0];
/*
* Signal any threads that are waiting.
@@ -1031,12 +1096,44 @@ NotifierThreadProc(
}
FD_SET(receivePipe, &readableMask);
- if (select(numFdBits, &readableMask, &writableMask, &exceptionMask,
- timePtr) == -1) {
+ /*
+ * Signals are unblocked only during select().
+ */
+
+#ifdef HAVE_PSELECT
+ {
+ struct timespec tspec, *tspecPtr;
+
+ if (timePtr == NULL) {
+ tspecPtr = NULL;
+ } else {
+ tspecPtr = &tspec;
+ tspecPtr->tv_sec = timePtr->tv_sec;
+ tspecPtr->tv_nsec = timePtr->tv_usec * 1000;
+ }
+ ret = pselect(numFdBits, &readableMask, &writableMask,
+ &exceptionMask, tspecPtr, &notifierSigMask);
+ }
+#else
+ pthread_sigmask(SIG_SETMASK, &notifierSigMask, NULL);
+ ret = select(numFdBits, &readableMask, &writableMask, &exceptionMask,
+ timePtr);
+ pthread_sigmask(SIG_BLOCK, &allSigMask, NULL);
+#endif
+
+ if (ret == -1) {
/*
- * Try again immediately on an error.
+ * In case a signal was caught during select(),
+ * perform work on async handlers now.
*/
+ if (errno == EINTR && asyncPending) {
+ asyncPending = 0;
+ TclAsyncMarkFromNotifier();
+ }
+ /*
+ * Try again immediately on select() error.
+ */
continue;
}
@@ -1048,7 +1145,7 @@ NotifierThreadProc(
for (tsdPtr = waitingListPtr; tsdPtr; tsdPtr = tsdPtr->nextPtr) {
found = 0;
- for (i = tsdPtr->numFdBits-1; i >= 0; --i) {
+ 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);
@@ -1092,6 +1189,12 @@ NotifierThreadProc(
break;
}
} while (1);
+
+ if (asyncPending) {
+ asyncPending = 0;
+ TclAsyncMarkFromNotifier();
+ }
+
if ((i == 0) || (buf[0] == 'q')) {
break;
}
@@ -1105,6 +1208,7 @@ NotifierThreadProc(
close(receivePipe);
pthread_mutex_lock(&notifierMutex);
triggerPipe = -1;
+ otherPipe = -1;
pthread_cond_broadcast(&notifierCV);
pthread_mutex_unlock(&notifierMutex);
@@ -1113,6 +1217,8 @@ NotifierThreadProc(
#endif /* TCL_THREADS */
#endif /* (!NOTIFIER_EPOLL && !NOTIFIER_KQUEUE) || !TCL_THREADS */
+#else
+TCL_MAC_EMPTY_FILE(unix_tclSelectNotfy_c)
#endif /* !HAVE_COREFOUNDATION */
/*
diff --git a/unix/tclUnixChan.c b/unix/tclUnixChan.c
index 837aa59..4cb9af0 100644
--- a/unix/tclUnixChan.c
+++ b/unix/tclUnixChan.c
@@ -282,12 +282,15 @@ FileInputProc(
* nonblocking, the read will never block.
*/
- bytesRead = read(fsPtr->fd, buf, (size_t) toRead);
- if (bytesRead >= 0) {
- return bytesRead;
+ do {
+ bytesRead = read(fsPtr->fd, buf, (size_t) toRead);
+ } while ((bytesRead < 0) && (errno == EINTR));
+
+ if (bytesRead < 0) {
+ *errorCodePtr = errno;
+ return -1;
}
- *errorCodePtr = errno;
- return -1;
+ return bytesRead;
}
/*
diff --git a/unix/tclUnixEvent.c b/unix/tclUnixEvent.c
index aff7797..0047dd9 100644
--- a/unix/tclUnixEvent.c
+++ b/unix/tclUnixEvent.c
@@ -64,7 +64,7 @@ Tcl_Sleep(
}
if ((vdelay.sec != 0) || (vdelay.usec != 0)) {
- tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
+ TclScaleTime(&vdelay);
}
delay.tv_sec = vdelay.sec;
@@ -85,6 +85,8 @@ Tcl_Sleep(
}
}
+#else
+TCL_MAC_EMPTY_FILE(unix_tclUnixEvent_c)
#endif /* HAVE_COREFOUNDATION */
/*
* Local Variables:
diff --git a/unix/tclUnixFCmd.c b/unix/tclUnixFCmd.c
index 4d08c1d..9f7a2ba 100644
--- a/unix/tclUnixFCmd.c
+++ b/unix/tclUnixFCmd.c
@@ -2239,17 +2239,17 @@ static const char *
DefaultTempDir(void)
{
const char *dir;
- struct stat buf;
+ Tcl_StatBuf buf;
dir = getenv("TMPDIR");
- if (dir && dir[0] && stat(dir, &buf) == 0 && S_ISDIR(buf.st_mode)
+ if (dir && dir[0] && TclOSstat(dir, &buf) == 0 && S_ISDIR(buf.st_mode)
&& access(dir, W_OK) == 0) {
return dir;
}
#ifdef P_tmpdir
dir = P_tmpdir;
- if (stat(dir, &buf)==0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)==0) {
+ if (TclOSstat(dir, &buf)==0 && S_ISDIR(buf.st_mode) && access(dir, W_OK)==0) {
return dir;
}
#endif
@@ -2350,7 +2350,7 @@ StatError(
Tcl_Obj *fileName) /* The name of the file which caused the
* error. */
{
- TclWinConvertError(GetLastError());
+ Tcl_WinConvertError(GetLastError());
Tcl_SetObjResult(interp, Tcl_ObjPrintf("could not read \"%s\": %s",
TclGetString(fileName), Tcl_PosixError(interp)));
}
diff --git a/unix/tclUnixFile.c b/unix/tclUnixFile.c
index 1ab5d14..998614d 100644
--- a/unix/tclUnixFile.c
+++ b/unix/tclUnixFile.c
@@ -41,10 +41,10 @@ TclpFindExecutable(
{
Tcl_Encoding encoding;
int length;
- wchar_t buf[PATH_MAX];
+ wchar_t buf[PATH_MAX] = L"";
char name[PATH_MAX * 3 + 1];
- GetModuleFileNameW(NULL, buf, sizeof(buf)/sizeof(wchar_t));
+ GetModuleFileNameW(NULL, buf, PATH_MAX);
cygwin_conv_path(3, buf, name, sizeof(name));
length = strlen(name);
if ((length > 4) && !strcasecmp(name + length - 4, ".exe")) {
@@ -1198,6 +1198,29 @@ TclpUtime(
#ifdef __CYGWIN__
int
+TclOSfstat(
+ int fd,
+ void *cygstat)
+{
+ struct stat buf;
+ Tcl_StatBuf *statBuf = (Tcl_StatBuf *)cygstat;
+ int result = fstat(fd, &buf);
+
+ statBuf->st_mode = buf.st_mode;
+ statBuf->st_ino = buf.st_ino;
+ statBuf->st_dev = buf.st_dev;
+ statBuf->st_rdev = buf.st_rdev;
+ statBuf->st_nlink = buf.st_nlink;
+ statBuf->st_uid = buf.st_uid;
+ statBuf->st_gid = buf.st_gid;
+ statBuf->st_size = buf.st_size;
+ statBuf->st_atime = buf.st_atime;
+ statBuf->st_mtime = buf.st_mtime;
+ statBuf->st_ctime = buf.st_ctime;
+ return result;
+}
+
+int
TclOSstat(
const char *name,
void *cygstat)
diff --git a/unix/tclUnixNotfy.c b/unix/tclUnixNotfy.c
index d992d65..943e7d7 100644
--- a/unix/tclUnixNotfy.c
+++ b/unix/tclUnixNotfy.c
@@ -2,10 +2,12 @@
* tclUnixNotfy.c --
*
* This file contains subroutines shared by all notifier backend
- * implementations on *nix platforms.
+ * implementations on *nix platforms. It is *included* by the epoll,
+ * kqueue and select notifier implementation files.
*
* Copyright © 1995-1997 Sun Microsystems, Inc.
* Copyright © 2016 Lucio Andrés Illanes Albornoz <l.illanes@gmx.de>
+ * Copyright © 2021 Donal K. Fellows
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -45,8 +47,10 @@ static void AtForkChild(void);
*
*----------------------------------------------------------------------
*/
+
static void
-StartNotifierThread(const char *proc)
+StartNotifierThread(
+ const char *proc)
{
if (!notifierThreadRunning) {
pthread_mutex_lock(&notifierInitMutex);
@@ -57,6 +61,7 @@ StartNotifierThread(const char *proc)
}
pthread_mutex_lock(&notifierMutex);
+
/*
* Wait for the notifier pipe to be created.
*/
@@ -76,7 +81,7 @@ StartNotifierThread(const char *proc)
/*
*----------------------------------------------------------------------
*
- * Tcl_AlertNotifier --
+ * TclpAlertNotifier --
*
* Wake up the specified notifier from any thread. This routine is called
* by the platform independent notifier code whenever the Tcl_ThreadAlert
@@ -99,50 +104,99 @@ StartNotifierThread(const char *proc)
*/
void
-Tcl_AlertNotifier(
- ClientData clientData)
+TclpAlertNotifier(
+ void *clientData)
{
- if (tclNotifierHooks.alertNotifierProc) {
- tclNotifierHooks.alertNotifierProc(clientData);
- return;
- } else {
#ifdef NOTIFIER_SELECT
#if TCL_THREADS
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)clientData;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
- pthread_mutex_lock(&notifierMutex);
- tsdPtr->eventReady = 1;
+ pthread_mutex_lock(&notifierMutex);
+ tsdPtr->eventReady = 1;
# ifdef __CYGWIN__
- PostMessageW(tsdPtr->hwnd, 1024, 0, 0);
+ PostMessageW(tsdPtr->hwnd, 1024, 0, 0);
# else
- pthread_cond_broadcast(&tsdPtr->waitCV);
+ pthread_cond_broadcast(&tsdPtr->waitCV);
# endif /* __CYGWIN__ */
- pthread_mutex_unlock(&notifierMutex);
+ pthread_mutex_unlock(&notifierMutex);
+#else
+ (void)clientData;
#endif /* TCL_THREADS */
#else /* !NOTIFIER_SELECT */
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)clientData;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *) clientData;
#if defined(NOTIFIER_EPOLL) && defined(HAVE_EVENTFD)
- uint64_t eventFdVal = 1;
- if (write(tsdPtr->triggerEventFd, &eventFdVal,
- sizeof(eventFdVal)) != sizeof(eventFdVal)) {
- Tcl_Panic("Tcl_AlertNotifier: unable to write to %p->triggerEventFd",
- (void *)tsdPtr);
- }
+ uint64_t eventFdVal = 1;
+
+ if (write(tsdPtr->triggerEventFd, &eventFdVal,
+ sizeof(eventFdVal)) != sizeof(eventFdVal)) {
+ Tcl_Panic("Tcl_AlertNotifier: unable to write to %p->triggerEventFd",
+ (void *) tsdPtr);
+ }
#else
- if (write(tsdPtr->triggerPipe[1], "", 1) != 1) {
- Tcl_Panic("Tcl_AlertNotifier: unable to write to %p->triggerPipe",
- (void *)tsdPtr);
- }
+ if (write(tsdPtr->triggerPipe[1], "", 1) != 1) {
+ Tcl_Panic("Tcl_AlertNotifier: unable to write to %p->triggerPipe",
+ (void *) tsdPtr);
+ }
#endif /* NOTIFIER_EPOLL && HAVE_EVENTFD */
#endif /* NOTIFIER_SELECT */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * LookUpFileHandler --
+ *
+ * Look up the file handler structure (and optionally the previous one in
+ * the chain) associated with a file descriptor.
+ *
+ * Returns:
+ * A pointer to the file handler, or NULL if it can't be found.
+ *
+ * Side effects:
+ * If prevPtrPtr is non-NULL, it will be written to if the file handler
+ * is found.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static inline FileHandler *
+LookUpFileHandler(
+ ThreadSpecificData *tsdPtr, /* Where to look things up. */
+ int fd, /* What we are looking for. */
+ FileHandler **prevPtrPtr) /* If non-NULL, where to report the previous
+ * pointer. */
+{
+ FileHandler *filePtr, *prevPtr;
+
+ /*
+ * 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 NULL;
+ }
+ if (filePtr->fd == fd) {
+ break;
+ }
}
+
+ /*
+ * Report what we've found to our caller.
+ */
+
+ if (prevPtrPtr) {
+ *prevPtrPtr = prevPtr;
+ }
+ return filePtr;
}
/*
*----------------------------------------------------------------------
*
- * Tcl_SetTimer --
+ * TclpSetTimer --
*
* This function sets the current notifier timer value. This interface is
* not implemented in this notifier because we are always running inside
@@ -158,19 +212,14 @@ Tcl_AlertNotifier(
*/
void
-Tcl_SetTimer(
- const Tcl_Time *timePtr) /* Timeout value, may be NULL. */
+TclpSetTimer(
+ TCL_UNUSED(const Tcl_Time *)) /* Timeout value, may be NULL. */
{
- if (tclNotifierHooks.setTimerProc) {
- tclNotifierHooks.setTimerProc(timePtr);
- return;
- } else {
- /*
- * 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.
- */
- }
+ /*
+ * 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.
+ */
}
/*
@@ -190,14 +239,11 @@ Tcl_SetTimer(
*/
void
-Tcl_ServiceModeHook(
+TclpServiceModeHook(
int mode) /* Either TCL_SERVICE_ALL, or
* TCL_SERVICE_NONE. */
{
- if (tclNotifierHooks.serviceModeHookProc) {
- tclNotifierHooks.serviceModeHookProc(mode);
- return;
- } else if (mode == TCL_SERVICE_ALL) {
+ if (mode == TCL_SERVICE_ALL) {
#ifdef NOTIFIER_SELECT
#if TCL_THREADS
StartNotifierThread("Tcl_ServiceModeHook");
@@ -306,24 +352,24 @@ AlertSingleThread(
{
tsdPtr->eventReady = 1;
if (tsdPtr->onList) {
- /*
- * Remove the ThreadSpecificData structure of this thread from the
- * waiting list. This prevents us from continuously spinning on
- * epoll_wait until the other threads runs and services the file
- * event.
- */
-
- if (tsdPtr->prevPtr) {
+ /*
+ * Remove the ThreadSpecificData structure of this thread from the
+ * waiting list. This prevents us from continuously spinning on
+ * epoll_wait until the other threads runs and services the file
+ * event.
+ */
+
+ if (tsdPtr->prevPtr) {
tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
- } else {
+ } else {
waitingListPtr = tsdPtr->nextPtr;
- }
- if (tsdPtr->nextPtr) {
+ }
+ if (tsdPtr->nextPtr) {
tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
- }
- tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
- tsdPtr->onList = 0;
- tsdPtr->pollState = 0;
+ }
+ tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
+ tsdPtr->onList = 0;
+ tsdPtr->pollState = 0;
}
#ifdef __CYGWIN__
PostMessageW(tsdPtr->hwnd, 1024, 0, 0);
@@ -359,6 +405,10 @@ AtForkChild(void)
pthread_mutex_init(&notifierMutex, NULL);
pthread_cond_init(&notifierCV, NULL);
+#ifdef NOTIFIER_SELECT
+ asyncPending = 0;
+#endif
+
/*
* notifierThreadRunning == 1: thread is running, (there might be data in
* notifier lists)
@@ -376,6 +426,10 @@ AtForkChild(void)
close(triggerPipe);
triggerPipe = -1;
+#ifdef NOTIFIER_SELECT
+ close(otherPipe);
+ otherPipe = -1;
+#endif
/*
* The waitingListPtr might contain event info from multiple
* threads, which are invalid here, so setting it to NULL is not
@@ -412,14 +466,49 @@ AtForkChild(void)
}
Tcl_InitNotifier();
+
+#ifdef NOTIFIER_SELECT
+ /*
+ * Restart the notifier thread for signal handling.
+ */
+
+ StartNotifierThread("AtForkChild");
+#endif
}
#endif /* HAVE_PTHREAD_ATFORK */
-
#endif /* TCL_THREADS */
-
#endif /* NOTIFIER_SELECT */
-#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
- * in tclMacOSXNotify.c */
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpNotifierData --
+ *
+ * This function returns a ClientData pointer to be associated
+ * with a Tcl_AsyncHandler.
+ *
+ * Results:
+ * For the epoll and kqueue notifiers, this function returns the
+ * thread specific data. Otherwise NULL.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+ClientData
+TclpNotifierData(void)
+{
+#if defined(NOTIFIER_EPOLL) || defined(NOTIFIER_KQUEUE)
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+
+ return (ClientData) tsdPtr;
+#else
+ return NULL;
+#endif
+}
+
/*
*----------------------------------------------------------------------
*
@@ -443,6 +532,9 @@ AtForkChild(void)
*----------------------------------------------------------------------
*/
+#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
+ * in tclMacOSXNotify.c */
+
int
TclUnixWaitForFile(
int fd, /* Handle for file on which to wait. */
@@ -563,9 +655,8 @@ TclUnixWaitForFile(
|| (abortTime.sec == now.sec && abortTime.usec > now.usec));
return result;
}
-
#endif /* !HAVE_COREFOUNDATION */
-
+
/*
* Local Variables:
* mode: c
diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h
index ece0202..791c2a3 100644
--- a/unix/tclUnixPort.h
+++ b/unix/tclUnixPort.h
@@ -120,15 +120,18 @@ extern "C" {
#pragma clang diagnostic pop
#endif
# define timezone _timezone
+ extern int TclOSfstat(int fd, void *statBuf);
extern int TclOSstat(const char *name, void *statBuf);
extern int TclOSlstat(const char *name, void *statBuf);
#ifdef __cplusplus
}
#endif
#elif defined(HAVE_STRUCT_STAT64) && !defined(__APPLE__)
+# define TclOSfstat(fd, buf) fstat64(fd, (struct stat64 *)buf)
# define TclOSstat(name, buf) stat64(name, (struct stat64 *)buf)
# define TclOSlstat(name,buf) lstat64(name, (struct stat64 *)buf)
#else
+# define TclOSfstat(fd, buf) fstat(fd, (struct stat *)buf)
# define TclOSstat(name, buf) stat(name, (struct stat *)buf)
# define TclOSlstat(name, buf) lstat(name, (struct stat *)buf)
#endif
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index 8a16d0b..aa5926e 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -277,6 +277,11 @@ TclpThreadCreate(
pthread_attr_destroy(&attr);
return result;
#else
+ (void)idPtr;
+ (void)proc;
+ (void)clientData;
+ (void)stackSize;
+ (void)flags;
return TCL_ERROR;
#endif /* TCL_THREADS */
}
@@ -314,6 +319,9 @@ Tcl_JoinThread(
}
return (result == 0) ? TCL_OK : TCL_ERROR;
#else
+ (void)threadId;
+ (void)state;
+
return TCL_ERROR;
#endif
}
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c
index adeacb6..e0c7ac8 100644
--- a/unix/tclUnixTime.c
+++ b/unix/tclUnixTime.c
@@ -61,6 +61,23 @@ Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
void *tclTimeClientData = NULL;
/*
+ * Inlined version of Tcl_GetTime.
+ */
+
+static inline void
+GetTime(
+ Tcl_Time *timePtr)
+{
+ tclGetTimeProcPtr(timePtr, tclTimeClientData);
+}
+
+static inline int
+IsTimeNative(void)
+{
+ return tclGetTimeProcPtr == NativeGetTime;
+}
+
+/*
*----------------------------------------------------------------------
*
* TclpGetSeconds --
@@ -105,8 +122,8 @@ TclpGetMicroseconds(void)
{
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
- return ((long long)time.sec)*1000000 + time.usec;
+ GetTime(&time);
+ return ((long long) time.sec)*1000000 + time.usec;
}
/*
@@ -134,10 +151,10 @@ TclpGetClicks(void)
unsigned long now;
#ifdef NO_GETTOD
- if (tclGetTimeProcPtr != NativeGetTime) {
+ if (!IsTimeNative()) {
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
+ GetTime(&time);
now = time.sec*1000000 + time.usec;
} else {
/*
@@ -147,12 +164,12 @@ TclpGetClicks(void)
now = (unsigned long) times(&dummy);
}
-#else
+#else /* !NO_GETTOD */
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
+ GetTime(&time);
now = time.sec*1000000 + time.usec;
-#endif
+#endif /* NO_GETTOD */
return now;
}
@@ -182,17 +199,17 @@ TclpGetWideClicks(void)
{
long long now;
- if (tclGetTimeProcPtr != NativeGetTime) {
+ if (!IsTimeNative()) {
Tcl_Time time;
- tclGetTimeProcPtr(&time, tclTimeClientData);
- now = ((long long)time.sec)*1000000 + time.usec;
+ GetTime(&time);
+ now = ((long long) time.sec)*1000000 + time.usec;
} else {
#ifdef MAC_OSX_TCL
now = (long long) (mach_absolute_time() & INT64_MAX);
#else
#error Wide high-resolution clicks not implemented on this platform
-#endif
+#endif /* MAC_OSX_TCL */
}
return now;
@@ -221,7 +238,7 @@ TclpWideClicksToNanoseconds(
{
double nsec;
- if (tclGetTimeProcPtr != NativeGetTime) {
+ if (!IsTimeNative()) {
nsec = clicks * 1000;
} else {
#ifdef MAC_OSX_TCL
@@ -239,7 +256,7 @@ TclpWideClicksToNanoseconds(
}
#else
#error Wide high-resolution clicks not implemented on this platform
-#endif
+#endif /* MAC_OSX_TCL */
}
return nsec;
@@ -266,7 +283,7 @@ TclpWideClicksToNanoseconds(
double
TclpWideClickInMicrosec(void)
{
- if (tclGetTimeProcPtr != NativeGetTime) {
+ if (!IsTimeNative()) {
return 1.0;
} else {
#ifdef MAC_OSX_TCL
@@ -286,7 +303,7 @@ TclpWideClickInMicrosec(void)
}
#else
#error Wide high-resolution clicks not implemented on this platform
-#endif
+#endif /* MAC_OSX_TCL */
}
}
#endif /* TCL_WIDE_CLICKS */
@@ -315,7 +332,7 @@ void
Tcl_GetTime(
Tcl_Time *timePtr) /* Location to store time information. */
{
- tclGetTimeProcPtr(timePtr, tclTimeClientData);
+ GetTime(timePtr);
}
/*
@@ -578,7 +595,7 @@ SetTZIfNecessary(void)
} else {
ckfree(lastTZ);
}
- lastTZ = (char *)ckalloc(strlen(newTZ) + 1);
+ lastTZ = (char *) ckalloc(strlen(newTZ) + 1);
strcpy(lastTZ, newTZ);
}
Tcl_MutexUnlock(&tmMutex);
diff --git a/unix/tclXtNotify.c b/unix/tclXtNotify.c
index 68ee578..3d90135 100644
--- a/unix/tclXtNotify.c
+++ b/unix/tclXtNotify.c
@@ -132,7 +132,7 @@ TclSetAppContext(
* after initialization, so we panic.
*/
- Tcl_Panic("TclSetAppContext: multiple application contexts");
+ Tcl_Panic("TclSetAppContext: multiple application contexts");
}
} else {
/*
@@ -359,7 +359,7 @@ CreateFileHandler(
}
}
if (filePtr == NULL) {
- filePtr = (FileHandler *)ckalloc(sizeof(FileHandler));
+ filePtr = (FileHandler *) ckalloc(sizeof(FileHandler));
filePtr->fd = fd;
filePtr->read = 0;
filePtr->write = 0;
@@ -496,7 +496,7 @@ FileProc(
int *fd,
XtInputId *id)
{
- FileHandler *filePtr = (FileHandler *)clientData;
+ FileHandler *filePtr = (FileHandler *) clientData;
FileHandlerEvent *fileEvPtr;
int mask = 0;
@@ -525,7 +525,7 @@ FileProc(
*/
filePtr->readyMask |= mask;
- fileEvPtr = (FileHandlerEvent *)ckalloc(sizeof(FileHandlerEvent));
+ fileEvPtr = (FileHandlerEvent *) ckalloc(sizeof(FileHandlerEvent));
fileEvPtr->header.proc = FileHandlerEventProc;
fileEvPtr->fd = filePtr->fd;
Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
diff --git a/unix/tclXtTest.c b/unix/tclXtTest.c
index afac493..882f497 100644
--- a/unix/tclXtTest.c
+++ b/unix/tclXtTest.c
@@ -16,7 +16,6 @@
#include "tcl.h"
static Tcl_ObjCmdProc TesteventloopCmd;
-extern DLLEXPORT Tcl_PackageInitProc Tclxttest_Init;
/*
* Functions defined in tclXtNotify.c for use by users of the Xt Notifier:
@@ -44,7 +43,7 @@ extern XtAppContext TclSetAppContext(XtAppContext ctx);
*----------------------------------------------------------------------
*/
-int
+DLLEXPORT int
Tclxttest_Init(
Tcl_Interp *interp) /* Interpreter for application. */
{