Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Comment: | Pulling changes from trunk |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | practcl |
Files: | files | file ages | folders |
SHA3-256: |
03912025a6495064d38cddcdbe9a2c50 |
User & Date: | seandeelywoods 2018-03-19 17:24:00 |
2018-10-01
| ||
20:54 | Pulling changes from trunk Leaf check-in: d3a0e02691 user: seandeelywoods tags: practcl | |
2018-03-19
| ||
17:24 | Pulling changes from trunk check-in: 03912025a6 user: seandeelywoods tags: practcl | |
2018-02-26
| ||
22:17 | Merge thread-2-8-branch check-in: 23a8390cd1 user: jan.nijtmans tags: trunk | |
2016-06-29
| ||
22:21 | Type removal check-in: 2a36d0a6c3 user: tne tags: practcl | |
Added .fossil-settings/crlf-glob.
> > > > > > > | 1 2 3 4 5 6 7 | win/thread-win.dsp win/thread-win.dsw win/makefile.vc win/pkg.vc win/rules.vc win/rules-ext.vc win/targets.vc |
Changes to .fossil-settings/crnl-glob.
1 2 3 4 5 | win/thread-win.dsp win/thread-win.dsw win/makefile.vc win/pkg.vc win/rules.vc | > > | 1 2 3 4 5 6 7 | win/thread-win.dsp win/thread-win.dsw win/makefile.vc win/pkg.vc win/rules.vc win/rules-ext.vc win/targets.vc |
Changes to Makefile.in.
︙ | ︙ | |||
82 83 84 85 86 87 88 | pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL_OPTIONS = | | | 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | pkgdatadir = $(datadir)/$(PKG_DIR) pkglibdir = $(libdir)/$(PKG_DIR) pkgincludedir = $(includedir)/$(PKG_DIR) top_builddir = . INSTALL_OPTIONS = INSTALL = @INSTALL@ $(INSTALL_OPTIONS) INSTALL_DATA_DIR = @INSTALL_DATA_DIR@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_LIBRARY = @INSTALL_LIBRARY@ PACKAGE_NAME = @PACKAGE_NAME@ |
︙ | ︙ | |||
152 153 154 155 156 157 158 | # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.ac checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) | | | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | # TCL_DEFS is not strictly need here, but if you remove it, then you # must make sure that configure.ac checks for the necessary components # that your library may use. TCL_DEFS can actually be a problem if # you do not compile with a similar machine setup as the Tcl core was # compiled with. #DEFS = $(TCL_DEFS) @DEFS@ $(PKG_CFLAGS) DEFS = @DEFS@ $(PKG_CFLAGS) -DTCL_NO_DEPRECATED=1 # Move pkgIndex.tcl to 'BINARIES' var if it is generated in the Makefile CONFIG_CLEAN_FILES = Makefile pkgIndex.tcl CLEANFILES = @CLEANFILES@ CPPFLAGS = @CPPFLAGS@ LIBS = @PKG_LIBS@ @LIBS@ |
︙ | ︙ | |||
226 227 228 229 230 231 232 | #======================================================================== install-doc: doc @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/mann @echo "Installing documentation in $(DESTDIR)$(mandir)" @list='$(srcdir)/doc/man/*.n'; for i in $$list; do \ echo "Installing $$i"; \ | < | | 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | #======================================================================== install-doc: doc @$(INSTALL_DATA_DIR) $(DESTDIR)$(mandir)/mann @echo "Installing documentation in $(DESTDIR)$(mandir)" @list='$(srcdir)/doc/man/*.n'; for i in $$list; do \ echo "Installing $$i"; \ $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ done test: binaries libraries $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) \ -load "package ifneeded $(PACKAGE_NAME) $(PACKAGE_VERSION) \ [list load `@CYGPATH@ $(PKG_LIB_FILE)` $(PACKAGE_NAME)]" shell: binaries libraries @$(TCLSH) $(SCRIPT) gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) |
︙ | ︙ | |||
303 304 305 306 307 308 309 310 311 312 313 314 | #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean $(INSTALL_DATA_DIR) $(DIST_DIR) | > > > > | | | > | | > | < < | | > > | > | | > | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | #======================================================================== #COMPRESS = tar cvf $(PKG_DIR).tar $(PKG_DIR); compress $(PKG_DIR).tar COMPRESS = tar zcvf $(PKG_DIR).tar.gz $(PKG_DIR) DIST_ROOT = /tmp/dist DIST_DIR = $(DIST_ROOT)/$(PKG_DIR) DIST_INSTALL_DATA = CPPROG='cp -p' $(INSTALL) -m 644 DIST_INSTALL_SCRIPT = CPPROG='cp -p' $(INSTALL) -m 755 dist-clean: rm -rf $(DIST_DIR) $(DIST_ROOT)/$(PKG_DIR).tar.* dist: dist-clean $(INSTALL_DATA_DIR) $(DIST_DIR) $(DIST_INSTALL_DATA) $(srcdir)/license.terms \ $(srcdir)/ChangeLog $(srcdir)/README \ $(srcdir)/aclocal.m4 $(srcdir)/configure.ac \ $(srcdir)/Makefile.in $(srcdir)/pkgIndex.tcl.in \ $(srcdir)/naviserver.m4 \ $(DIST_DIR)/ $(DIST_INSTALL_SCRIPT) $(srcdir)/configure $(DIST_DIR)/ $(INSTALL_DATA_DIR) $(DIST_DIR)/tclconfig $(DIST_INSTALL_DATA) $(srcdir)/tclconfig/README.txt \ $(srcdir)/tclconfig/tcl.m4 $(srcdir)/tclconfig/install-sh \ $(DIST_DIR)/tclconfig/ $(INSTALL_DATA_DIR) $(DIST_DIR)/unix $(DIST_INSTALL_DATA) $(srcdir)/unix/README $(srcdir)/unix/CONFIG \ $(srcdir)/unix/threadUnix.c \ $(DIST_DIR)/unix/ $(INSTALL_DATA_DIR) $(DIST_DIR)/win $(DIST_INSTALL_DATA) \ $(srcdir)/win/README.txt $(srcdir)/win/CONFIG $(srcdir)/win/thread.rc \ $(srcdir)/win/threadWin.c $(srcdir)/win/makefile.vc \ $(srcdir)/win/nmakehlp.c $(srcdir)/win/pkg.vc \ $(srcdir)/win/targets.vc $(srcdir)/win/rules-ext.vc \ $(srcdir)/win/rules.vc $(srcdir)/win/thread_win.dsw \ $(srcdir)/win/thread_win.dsp \ $(DIST_DIR)/win/ $(INSTALL_DATA_DIR) $(DIST_DIR)/tcl $(DIST_INSTALL_DATA) $(srcdir)/tcl/README $(DIST_DIR)/tcl/ list='tests doc doc/man doc/html generic lib tcl/cmdsrv tcl/phttpd tcl/tpool';\ for p in $$list; do \ if test -d $(srcdir)/$$p ; then \ $(INSTALL_DATA_DIR) $(DIST_DIR)/$$p; \ $(DIST_INSTALL_DATA) $(srcdir)/$$p/*.* $(DIST_DIR)/$$p/; \ fi; \ done (cd $(DIST_ROOT); $(COMPRESS);) #======================================================================== # End of user-definable section |
︙ | ︙ |
Changes to README.
1 2 3 4 | WHAT IS THIS ? ============== | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | WHAT IS THIS ? ============== This is the source distribution of the Tcl Thread extension. You can use this extension to gain script-level access to Tcl threading capabilities. The extension can be used with Tcl cores starting from Tcl8.4 and later. Also, this extension supports, i.e. can be used as a loadable module of, AOLserver 4.x series of the highly-scalable web server from America Online. You need to have your Tcl core compiled with "--enable-threads" in order to turn on internal directives supporting thread-specific details of the Tcl API. The extension will not load in an Tcl shell built w/o thread support. This extension is a freely available open source package. You can do virtually anything you like with it, such as modifying it, redistributing it, and selling it either in whole or in part. See the "license.terms" file in the top-level distribution directory for complete information. HOW TO COMPILE ? ================ Only Unix-like and Windows platforms are supported at the moment. Depending on your platform (Unix-like or Windows) go to the appropriate directory (unix or win) and start with the README file. Macintosh platform is supported with the Mac OS X only. The Mac OS 9 (and previous) are not supported. WHERE IS THE DOCUMENTATION ? ============================ Documentation in Unix man and standard HTML format is available in the doc/man and doc/html directories respectively. Currently, documentation is in reference-style only. The tutorial-style documentation will be provided with future releases of the extension. That is, if I ever get time to do that. Everybody is more than welcome to jump in and help with the docs. HOW TO GET SUPPORT ? |
︙ | ︙ |
Changes to configure.
1 2 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. | | < < | | 1 2 3 4 5 6 7 8 9 10 11 12 13 | #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for thread 2.9a1. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## |
︙ | ︙ | |||
130 131 132 133 134 135 136 137 138 139 140 141 142 143 | export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' | > > > > > > > > > > > > > > > > > > > > > > > > > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' |
︙ | ︙ | |||
163 164 165 166 167 168 169 | as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi | | > | 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes |
︙ | ︙ | |||
208 209 210 211 212 213 214 | { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : | > | | | | | | | < | | | | | | | > > > > | 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" |
︙ | ︙ | |||
324 325 326 327 328 329 330 331 332 333 334 335 336 337 | test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : | > > > > > > > > | 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : |
︙ | ︙ | |||
445 446 447 448 449 450 451 452 453 454 455 456 457 458 | s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } | > > > > | 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 | s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } |
︙ | ︙ | |||
479 480 481 482 483 484 485 | fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. | | | | | < | < < < < < < < < < < < < < < < < < < < | | 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 | fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" |
︙ | ︙ | |||
553 554 555 556 557 558 559 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='thread' PACKAGE_TARNAME='thread' | | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='thread' PACKAGE_TARNAME='thread' PACKAGE_VERSION='2.9a1' PACKAGE_STRING='thread 2.9a1' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H |
︙ | ︙ | |||
633 634 635 636 637 638 639 | AR STUBS_BUILD SHARED_BUILD TCL_THREADS TCL_INCLUDES PKG_OBJECTS PKG_SOURCES | < < < < < < < | 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | AR STUBS_BUILD SHARED_BUILD TCL_THREADS TCL_INCLUDES PKG_OBJECTS PKG_SOURCES EGREP GREP RANLIB SET_MAKE CPP TCL_SHLIB_LD_LIBS TCL_LD_FLAGS TCL_EXTRA_CFLAGS TCL_DEFS TCL_LIBS CLEANFILES |
︙ | ︙ | |||
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 | TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION CONFIG_CLEAN_FILES LN_S PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE EXEEXT CYGPATH target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C | > > > > > > > | 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 | TCL_LIB_FILE TCL_SRC_DIR TCL_BIN_DIR TCL_PATCH_LEVEL TCL_VERSION CONFIG_CLEAN_FILES LN_S INSTALL_LIBRARY INSTALL_SCRIPT INSTALL_PROGRAM INSTALL_DATA INSTALL_DATA_DIR INSTALL PKG_CFLAGS PKG_LIBS PKG_INCLUDES PKG_HEADERS PKG_TCL_SOURCES PKG_STUB_OBJECTS PKG_STUB_SOURCES PKG_STUB_LIB_FILE PKG_LIB_FILE EXEEXT CYGPATH TEA_TK_EXTENSION target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C |
︙ | ︙ | |||
1201 1202 1203 1204 1205 1206 1207 | host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe | < < | 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 | host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- |
︙ | ︙ | |||
1288 1289 1290 1291 1292 1293 1294 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF | | | 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 | # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures thread 2.9a1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. |
︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 | cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in | | | | 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 | cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of thread 2.9a1:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-threads build with threads (default: on) --enable-shared build and link with shared libraries (default: on) --enable-stubs build and link with stub libraries. Always true for shared builds (default: on) --enable-64bit enable 64bit support (default: off) --enable-64bit-vis enable 64bit Sparc VIS support (default: off) --disable-rpath disable rpath support (default: on) --enable-wince enable Win/CE support (where applicable) |
︙ | ︙ | |||
1455 1456 1457 1458 1459 1460 1461 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF | | | | | 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 | cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF thread configure 2.9a1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## |
︙ | ︙ | |||
1644 1645 1646 1647 1648 1649 1650 | fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || | | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 | fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { |
︙ | ︙ | |||
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 | eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 | eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case <limits.h> declares $2. For example, HP-UX 11i <limits.h> declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer <limits.h> to <assert.h> if __STDC__ is defined, since <limits.h> exists even on freestanding compilers. */ #ifdef __STDC__ # include <limits.h> #else # include <assert.h> #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by thread $as_me 2.9a1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME |
︙ | ︙ | |||
2079 2080 2081 2082 2083 2084 2085 | { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file | | | 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 | { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then |
︙ | ︙ | |||
2176 2177 2178 2179 2180 2181 2182 | #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- | < < | | | < < < < < < < | < > | | 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 | #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- TEA_VERSION="4.0" { $as_echo "$as_me:${as_lineno-$LINENO}: checking TEA configuration" >&5 $as_echo_n "checking TEA configuration... " >&6; } if test x"${PACKAGE_NAME}" = x ; then as_fn_error $? " The PACKAGE_NAME variable must be defined by your TEA configure.ac" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok (TEA ${TEA_VERSION})" >&5 $as_echo "ok (TEA ${TEA_VERSION})" >&6; } # If the user did not set CFLAGS, set it now to keep macros # like AC_PROG_CC and AC_TRY_COMPILE from adding "-g -O2". if test "${CFLAGS+set}" != "set" ; then CFLAGS="" fi TEA_TK_EXTENSION=0 case "`uname -s`" in *win32*|*WIN32*|*MINGW32_*) # Extract the first word of "cygpath", so it can be a program name with args. set dummy cygpath; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CYGPATH+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CYGPATH"; then ac_cv_prog_CYGPATH="$CYGPATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 | { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi CONFIG_CLEAN_FILES= if test ! -d $srcdir/tclconfig ; then if test -d $srcdir/../tclconfig ; then $LN_S $srcdir/../tclconfig tclconfig CONFIG_CLEAN_FILES=tclconfig fi fi ac_aux_dir= for ac_dir in tclconfig "$srcdir"/tclconfig; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 | # Configure the installer. INSTALL='$(SHELL) $(srcdir)/tclconfig/install-sh -c' INSTALL_DATA_DIR='${INSTALL} -d -m 755' INSTALL_DATA='${INSTALL} -m 644' INSTALL_PROGRAM='${INSTALL} -m 755' INSTALL_SCRIPT='${INSTALL} -m 755' { $as_echo "$as_me:${as_lineno-$LINENO}: checking system version" >&5 $as_echo_n "checking system version... " >&6; } if ${tcl_cv_sys_version+:} false; then : $as_echo_n "(cached) " >&6 else # TEA specific: if test "${TEA_PLATFORM}" = "windows" ; then tcl_cv_sys_version=windows else tcl_cv_sys_version=`uname -s`-`uname -r` if test "$?" -ne 0 ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: can't find uname command" >&5 $as_echo "$as_me: WARNING: can't find uname command" >&2;} tcl_cv_sys_version=unknown else if test "`uname -s`" = "AIX" ; then tcl_cv_sys_version=AIX-`uname -v`.`uname -r` fi fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tcl_cv_sys_version" >&5 $as_echo "$tcl_cv_sys_version" >&6; } system=$tcl_cv_sys_version case $system in HP-UX-*) INSTALL_LIBRARY='${INSTALL} -m 755' ;; *) INSTALL_LIBRARY='${INSTALL} -m 644' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi CONFIG_CLEAN_FILES= if test ! -d $srcdir/tclconfig ; then if test -d $srcdir/../tclconfig ; then $LN_S $srcdir/../tclconfig tclconfig CONFIG_CLEAN_FILES=tclconfig fi fi ac_aux_dir= for ac_dir in tclconfig "$srcdir"/tclconfig; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break |
︙ | ︙ | |||
2448 2449 2450 2451 2452 2453 2454 2455 | fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ | > | | 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 | fi # check in a few common install locations if test x"${ac_cv_c_tclconfig}" = x ; then for i in `ls -d ${libdir} 2>/dev/null` \ `ls -d ${exec_prefix}/lib 2>/dev/null` \ `ls -d ${prefix}/lib 2>/dev/null` \ `ls -d /usr/contrib/lib 2>/dev/null` \ `ls -d /usr/local/lib 2>/dev/null` \ `ls -d /usr/pkg/lib 2>/dev/null` \ `ls -d /usr/lib 2>/dev/null` \ `ls -d /usr/lib64 2>/dev/null` \ `ls -d /usr/lib/tcl8.6 2>/dev/null` \ `ls -d /usr/lib/tcl8.5 2>/dev/null` \ ; do if test -f "$i/tclConfig.sh" ; then ac_cv_c_tclconfig="`(cd $i; pwd)`" |
︙ | ︙ | |||
2517 2518 2519 2520 2521 2522 2523 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
2557 2558 2559 2560 2561 2562 2563 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
2610 2611 2612 2613 2614 2615 2616 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
2651 2652 2653 2654 2655 2656 2657 | ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 | ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 |
︙ | ︙ | |||
2709 2710 2711 2712 2713 2714 2715 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
2753 2754 2755 2756 2757 2758 2759 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
2796 2797 2798 2799 2800 2801 2802 | fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH | | | 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 | fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" |
︙ | ︙ | |||
2911 2912 2913 2914 2915 2916 2917 | $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables | | | 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 | $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 |
︙ | ︙ | |||
2954 2955 2956 2957 2958 2959 2960 | * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link | | | 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 | * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext |
︙ | ︙ | |||
3013 3014 3015 3016 3017 3018 3019 | if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. | | | 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 | if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out |
︙ | ︙ | |||
3065 3066 3067 3068 3069 3070 3071 | else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile | | | 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 | else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT |
︙ | ︙ | |||
3199 3200 3201 3202 3203 3204 3205 | else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> | < | | 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 | else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { |
︙ | ︙ | |||
3397 3398 3399 3400 3401 3402 3403 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -m" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
3529 3530 3531 3532 3533 3534 3535 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
3569 3570 3571 3572 3573 3574 3575 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
3622 3623 3624 3625 3626 3627 3628 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
3663 3664 3665 3666 3667 3668 3669 | ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 | ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 |
︙ | ︙ | |||
3721 3722 3723 3724 3725 3726 3727 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
3765 3766 3767 3768 3769 3770 3771 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
3808 3809 3810 3811 3812 3813 3814 | fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH | | | 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 | fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" |
︙ | ︙ | |||
3961 3962 3963 3964 3965 3966 3967 | else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> | < | | 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 | else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { |
︙ | ︙ | |||
4175 4176 4177 4178 4179 4180 4181 | rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check | | < < < < < < < < < < < < < < | 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 | rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu #-------------------------------------------------------------------- # Checks to see if the make program sets the $MAKE variable. #-------------------------------------------------------------------- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 |
︙ | ︙ | |||
4256 4257 4258 4259 4260 4261 4262 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
4296 4297 4298 4299 4300 4301 4302 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
4356 4357 4358 4359 4360 4361 4362 | for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" | | | 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 | for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 |
︙ | ︙ | |||
4422 4423 4424 4425 4426 4427 4428 | for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" | | | 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 | for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 |
︙ | ︙ | |||
4867 4868 4869 4870 4871 4872 4873 | universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness | | < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 | universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac if test "${TEA_PLATFORM}" = "unix" ; then TEA_TCL_LINK_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: checking dirent.h" >&5 $as_echo_n "checking dirent.h... " >&6; } if ${tcl_cv_dirent_h+:} false; then : $as_echo_n "(cached) " >&6 else |
︙ | ︙ | |||
5173 5174 5175 5176 5177 5178 5179 | ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = xyes; then : else $as_echo "#define NO_ERRNO_H 1" >>confdefs.h | < < < < < < < < < < | 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 | ac_fn_c_check_header_mongrel "$LINENO" "errno.h" "ac_cv_header_errno_h" "$ac_includes_default" if test "x$ac_cv_header_errno_h" = xyes; then : else $as_echo "#define NO_ERRNO_H 1" >>confdefs.h fi ac_fn_c_check_header_mongrel "$LINENO" "values.h" "ac_cv_header_values_h" "$ac_includes_default" if test "x$ac_cv_header_values_h" = xyes; then : else |
︙ | ︙ | |||
5612 5613 5614 5615 5616 5617 5618 | done vars="${GDBM_LIBS} ${LMDB_LIBS} ${NS_LIBS}" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then | > > | | > > | 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 | done vars="${GDBM_LIBS} ${LMDB_LIBS} ${NS_LIBS}" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then case $i in *.lib) # Convert foo.lib to -lfoo for GCC i=-l`echo "$i" | sed -e 's/\.[^.]*$//' -e 's/\.lib.*//'` ;; esac fi PKG_LIBS="$PKG_LIBS $i" done PKG_CFLAGS="$PKG_CFLAGS ${GDBM_CFLAGS} ${LMDB_CFLAGS}" |
︙ | ︙ | |||
6278 6279 6280 6281 6282 6283 6284 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
6318 6319 6320 6321 6322 6323 6324 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
6546 6547 6548 6549 6550 6551 6552 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
6586 6587 6588 6589 6590 6591 6592 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
6797 6798 6799 6800 6801 6802 6803 | case "x`echo \${VisualStudioVersion}`" in x1[4-9]*) lflags="${lflags} -nodefaultlib:libucrt.lib" vars="ucrt.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then | > > | | > > | 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 | case "x`echo \${VisualStudioVersion}`" in x1[4-9]*) lflags="${lflags} -nodefaultlib:libucrt.lib" vars="ucrt.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then case $i in *.lib) # Convert foo.lib to -lfoo for GCC i=-l`echo "$i" | sed -e 's/\.[^.]*$//' -e 's/\.lib.*//'` ;; esac fi PKG_LIBS="$PKG_LIBS $i" done ;; *) |
︙ | ︙ | |||
6824 6825 6826 6827 6828 6829 6830 | CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then | > > | | > > | 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 | CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" # Avoid 'unresolved external symbol __security_cookie' # errors, c.f. http://support.microsoft.com/?id=894573 vars="bufferoverflowU.lib" for i in $vars; do if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then case $i in *.lib) # Convert foo.lib to -lfoo for GCC i=-l`echo "$i" | sed -e 's/\.[^.]*$//' -e 's/\.lib.*//'` ;; esac fi PKG_LIBS="$PKG_LIBS $i" done elif test "$doWince" != "no" ; then CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" |
︙ | ︙ | |||
6897 6898 6899 6900 6901 6902 6903 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RC="${ac_tool_prefix}windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
6937 6938 6939 6940 6941 6942 6943 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do | | | 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 | else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RC="windres" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS |
︙ | ︙ | |||
6976 6977 6978 6979 6980 6981 6982 | RC="$ac_cv_prog_RC" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' | | | 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 | RC="$ac_cv_prog_RC" fi CFLAGS_DEBUG="-g" CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" SHLIB_LD='${CC} -shared' UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' PRACTCL_UNSHARED_LIB_SUFFIX='.a' LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cross-compile version of gcc" >&5 $as_echo_n "checking for cross-compile version of gcc... " >&6; } if ${ac_cv_cross+:} false; then : |
︙ | ︙ | |||
7207 7208 7209 7210 7211 7212 7213 | CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" | | | 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 | CC_SEARCH_FLAGS="" LD_SEARCH_FLAGS="" ;; Haiku*) LDFLAGS="$LDFLAGS -Wl,--export-dynamic" SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS} -shared' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inet_ntoa in -lnetwork" >&5 $as_echo_n "checking for inet_ntoa in -lnetwork... " >&6; } if ${ac_cv_lib_network_inet_ntoa+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetwork $LIBS" |
︙ | ︙ | |||
7434 7435 7436 7437 7438 7439 7440 | SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS | | | 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 | SHLIB_CFLAGS="-fPIC" SHLIB_SUFFIX=".so" # TEA specific: CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" # TEA specific: use LDFLAGS_DEFAULT instead of LDFLAGS SHLIB_LD='${CC} ${CFLAGS} ${LDFLAGS_DEFAULT} -shared' LDFLAGS="$LDFLAGS -Wl,--export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} if test "`uname -m`" = "alpha"; then : |
︙ | ︙ | |||
7510 7511 7512 7513 7514 7515 7516 | CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; OpenBSD-*) arch=`arch -s` case "$arch" in | < < < < < < < | | | | | | | | | | | | | | < < < < < < < | < < | | 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 | CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi ;; OpenBSD-*) arch=`arch -s` case "$arch" in alpha|sparc64) SHLIB_CFLAGS="-fPIC" ;; *) SHLIB_CFLAGS="-fpic" ;; esac SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so${SHLIB_VERSION}' LDFLAGS="-Wl,-export-dynamic" CFLAGS_OPTIMIZE="-O2" if test "${TCL_THREADS}" = "1"; then : # On OpenBSD: Compile with -pthread # Don't link with -lpthread LIBS=`echo $LIBS | sed s/-lpthread//` CFLAGS="$CFLAGS -pthread" fi # OpenBSD doesn't do version numbers with dots. UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' TCL_LIB_VERSIONS_OK=nodots ;; NetBSD-*) # NetBSD has ELF and can use 'cc -shared' to build shared libs SHLIB_CFLAGS="-fPIC" SHLIB_LD='${CC} ${SHLIB_CFLAGS} -shared' SHLIB_SUFFIX=".so" LDFLAGS="$LDFLAGS -export-dynamic" if test $doRpath = yes; then : CC_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' fi LD_SEARCH_FLAGS=${CC_SEARCH_FLAGS} |
︙ | ︙ | |||
9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 | fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi | > > | 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 | fi else if test -f "${TCL_BIN_DIR}/Makefile" ; then # tclConfig.sh is in Tcl build directory if test "${TEA_PLATFORM}" = "windows"; then if test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}sg${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}sg${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}s${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}t${EXEEXT}" elif test -f "${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" ; then TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}st${EXEEXT}" fi |
︙ | ︙ | |||
9502 9503 9504 9505 9506 9507 9508 | fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. | | | | | | 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 | fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- |
︙ | ︙ | |||
9571 9572 9573 9574 9575 9576 9577 | if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi | | | < > | | < > > | < | < < < < < < < < < < < < | | | | 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 | if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by thread $as_me 2.9a1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ |
︙ | ︙ | |||
9666 9667 9668 9669 9670 9671 9672 | Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ | | | | | 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 | Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ thread config.status 2.9a1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF |
︙ | ︙ | |||
9747 9748 9749 9750 9751 9752 9753 | exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then | | | 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 | exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi |
︙ | ︙ | |||
9780 9781 9782 9783 9784 9785 9786 | for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;; "config.tcl") CONFIG_FILES="$CONFIG_FILES config.tcl:tclconfig/config.tcl.in" ;; | | | 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 | for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "pkgIndex.tcl") CONFIG_FILES="$CONFIG_FILES pkgIndex.tcl" ;; "config.tcl") CONFIG_FILES="$CONFIG_FILES config.tcl:tclconfig/config.tcl.in" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely |
︙ | ︙ | |||
9988 9989 9990 9991 9992 9993 9994 | for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; | | | 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 | for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS |
︙ | ︙ | |||
10016 10017 10018 10019 10020 10021 10022 | # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || | | | 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 | # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: |
︙ | ︙ | |||
10043 10044 10045 10046 10047 10048 10049 | ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ | | | 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 | ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ |
︙ | ︙ | |||
10227 10228 10229 10230 10231 10232 10233 | # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi | > | 10008 10009 10010 10011 10012 10013 10014 10015 | # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi |
Changes to configure.ac.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- | | > | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | # Set your package name and version numbers here. # # This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION # set as provided. These will also be added as -D defs in your Makefile # so you can encode the package version directly into the source files. #----------------------------------------------------------------------- AC_INIT([thread], [2.9a1]) #-------------------------------------------------------------------- # Call TEA_INIT as the first TEA_ macro to set up initial vars. # This will define a ${TEA_PLATFORM} variable == "unix" or "windows" # as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. #-------------------------------------------------------------------- TEA_INIT([3.10]) AC_PROG_LN_S CONFIG_CLEAN_FILES= if test ! -d $srcdir/tclconfig ; then if test -d $srcdir/../tclconfig ; then $LN_S $srcdir/../tclconfig tclconfig CONFIG_CLEAN_FILES=tclconfig fi fi AC_SUBST(CONFIG_CLEAN_FILES) AC_CONFIG_AUX_DIR(tclconfig) #-------------------------------------------------------------------- # Load the tclConfig.sh file #-------------------------------------------------------------------- TEA_PATH_TCLCONFIG |
︙ | ︙ |
Changes to doc/html/thread.html.
︙ | ︙ | |||
154 155 156 157 158 159 160 | <li><a href="#33"><b class="cmd">thread::cond</b> <b class="method">destroy</b> <i class="arg">cond</i></a></li> <li><a href="#34"><b class="cmd">thread::cond</b> <b class="method">notify</b> <i class="arg">cond</i></a></li> <li><a href="#35"><b class="cmd">thread::cond</b> <b class="method">wait</b> <i class="arg">cond</i> <i class="arg">mutex</i> <span class="opt">?ms?</span></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 | <li><a href="#33"><b class="cmd">thread::cond</b> <b class="method">destroy</b> <i class="arg">cond</i></a></li> <li><a href="#34"><b class="cmd">thread::cond</b> <b class="method">notify</b> <i class="arg">cond</i></a></li> <li><a href="#35"><b class="cmd">thread::cond</b> <b class="method">wait</b> <i class="arg">cond</i> <i class="arg">mutex</i> <span class="opt">?ms?</span></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>The <b class="package">thread</b> extension creates threads that contain Tcl interpreters, and it lets you send scripts to those threads for evaluation. Additionaly, it provides script-level access to basic thread synchronization primitives, like mutexes and condition variables.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <p>This section describes commands for creating and destroying threads and sending scripts to threads for evaluation.</p> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">thread::create</b> <span class="opt">?-joinable?</span> <span class="opt">?-preserved?</span> <span class="opt">?script?</span></a></dt> <dd><p>This command creates a thread that contains a Tcl interpreter. The Tcl interpreter either evaluates the optional <b class="option">script</b>, if specified, or it waits in the event loop for scripts that arrive via the <b class="cmd">thread::send</b> command. The result, if any, of the optional <b class="option">script</b> is never returned to the caller. The result of <b class="cmd">thread::create</b> is the ID of the thread. This is the opaque handle which identifies the newly created thread for all other package commands. The handle of the thread goes out of scope automatically when thread is marked for exit (see the <b class="cmd">thread::release</b> command below).</p> <p>If the optional <b class="option">script</b> argument contains the <b class="cmd">thread::wait</b> command the thread will enter into the event loop. If such command is not found in the <b class="option">script</b> the thread will run the <b class="option">script</b> to the end and exit. In that case, the handle may be safely ignored since it refers to a thread which does not exists any more at the time when the command returns.</p> <p>Using flag <b class="option">-joinable</b> it is possible to create a joinable thread, i.e. one upon whose exit can be waited upon by using <b class="cmd">thread::join</b> command. Note that failure to join a thread created with <b class="option">-joinable</b> flag results in resource and memory leaks.</p> <p>Threads created by the <b class="cmd">thread::create</b> cannot be destroyed forcefully. Consequently, there is no corresponding thread destroy command. A thread may only be released using the <b class="cmd">thread::release</b> and if its internal reference count drops to zero, the thread is marked for exit. This kicks the thread out of the event loop servicing and the thread continues to execute commands passed in the <b class="option">script</b> argument, following the <b class="cmd">thread::wait</b> command. If this was the last command in the script, as usualy the case, the thread will exit.</p> <p>It is possible to create a situation in which it may be impossible to terminate the thread, for example by putting some endless loop after the <b class="cmd">thread::wait</b> or entering the event loop again by doing an vwait-type of command. In such cases, the thread may never exit. This is considered to be a bad practice and should be avoided if possible. This is best illustrated by the example below:</p> <pre class="doctools_example"> # You should never do ... set tid [thread::create { package require Http thread::wait vwait forever ; # <-- this! }] </pre> <p>The thread created in the above example will never be able to exit. After it has been released with the last matching <b class="cmd">thread::release</b> call, the thread will jump out of the <b class="cmd">thread::wait</b> and continue to execute commands following. It will enter <b class="cmd">vwait</b> command and wait endlessly for events. There is no way one can terminate such thread, so you wouldn't want to do this!</p> <p>Each newly created has its internal reference counter set to 0 (zero), i.e. it is unreserved. This counter gets incremented by a call to <b class="cmd">thread::preserve</b> and decremented by a call to <b class="cmd">thread::release</b> command. These two commands implement simple but effective thread reservation system and offer predictable and controllable thread termination capabilities. It is however possible to create initialy preserved threads by using flag <b class="option">-preserved</b> of the <b class="cmd">thread::create</b> command. Threads created with this flag have the initial value of the reference counter of 1 (one), and are thus initially marked reserved.</p></dd> <dt><a name="2"><b class="cmd">thread::preserve</b> <span class="opt">?id?</span></a></dt> <dd><p>This command increments the thread reference counter. Each call to this command increments the reference counter by one (1). Command returns the value of the reference counter after the increment. If called with the optional thread <b class="option">id</b>, the command preserves the given thread. Otherwise the current thread is preserved.</p> <p>With reference counting, one can implement controlled access to a shared Tcl thread. By incrementing the reference counter, the caller signalizes that he/she wishes to use the thread for a longer period of time. By decrementing the counter, caller signalizes that he/she has finished using the thread.</p></dd> <dt><a name="3"><b class="cmd">thread::release</b> <span class="opt">?-wait?</span> <span class="opt">?id?</span></a></dt> <dd><p>This command decrements the thread reference counter. Each call to this command decrements the reference counter by one (1). If called with the optional thread <b class="option">id</b>, the command releases the given thread. Otherwise, the current thread is released. Command returns the value of the reference counter after the decrement. When the reference counter reaches zero (0), the target thread is marked for termination. You should not reference the thread after the <b class="cmd">thread::release</b> command returns zero or negative integer. The handle of the thread goes out of scope and should not be used any more. Any following reference to the same thread handle will result in Tcl error.</p> <p>Optional flag <b class="option">-wait</b> instructs the caller thread to wait for the target thread to exit, if the effect of the command would result in termination of the target thread, i.e. if the return result would be zero (0). Without the flag, the caller thread does not wait for the target thread to exit. Care must be taken when using the <b class="option">-wait</b>, since this may block the caller thread indefinitely. This option has been implemented for some special uses of the extension and is deprecated for regular use. Regular users should create joinable threads by using the <b class="option">-joinable</b> option of the <b class="cmd">thread::create</b> command and the <b class="cmd">thread::join</b> to wait for thread to exit.</p></dd> <dt><a name="4"><b class="cmd">thread::id</b></a></dt> <dd><p>This command returns the ID of the current thread.</p></dd> <dt><a name="5"><b class="cmd">thread::errorproc</b> <span class="opt">?procname?</span></a></dt> <dd><p>This command sets a handler for errors that occur in scripts sent asynchronously, using the <b class="option">-async</b> flag of the <b class="cmd">thread::send</b> command, to other threads. If no handler is specified, the current handler is returned. The empty string resets the handler to default (unspecified) value. An uncaught error in a thread causes an error message to be sent to the standard error channel. This default reporting scheme can be changed by registering a procedure which is called to report the error. The <i class="arg">procname</i> is called in the interpreter that invoked the <b class="cmd">thread::errorproc</b> command. The <i class="arg">procname</i> |
︙ | ︙ | |||
289 290 291 292 293 294 295 | stack. With the <b class="option">-unwind</b> switch the evaluation stack for the interpreter is unwound without regard to any intervening catch command until there are no further invocations of the interpreter left on the call stack. If <i class="arg">result</i> is present, it will be used as the error message string; otherwise, a default error message string will be used.</p></dd> <dt><a name="7"><b class="cmd">thread::unwind</b></a></dt> <dd><p>Use of this command is deprecated in favour of more advanced thread | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 | stack. With the <b class="option">-unwind</b> switch the evaluation stack for the interpreter is unwound without regard to any intervening catch command until there are no further invocations of the interpreter left on the call stack. If <i class="arg">result</i> is present, it will be used as the error message string; otherwise, a default error message string will be used.</p></dd> <dt><a name="7"><b class="cmd">thread::unwind</b></a></dt> <dd><p>Use of this command is deprecated in favour of more advanced thread reservation system implemented with <b class="cmd">thread::preserve</b> and <b class="cmd">thread::release</b> commands. Support for <b class="cmd">thread::unwind</b> command will dissapear in some future major release of the extension.</p> <p>This command stops a prior <b class="cmd">thread::wait</b> command. Execution of the script passed to newly created thread will continue from the <b class="cmd">thread::wait</b> command. If <b class="cmd">thread::wait</b> was the last command in the script, the thread will exit. The command returns empty result but may trigger Tcl error with the message "target thread died" in some situations.</p></dd> <dt><a name="8"><b class="cmd">thread::exit</b> <span class="opt">?status?</span></a></dt> <dd><p>Use of this command is deprecated in favour of more advanced thread reservation system implemented with <b class="cmd">thread::preserve</b> and <b class="cmd">thread::release</b> commands. Support for <b class="cmd">thread::exit</b> command will dissapear in some future major release of the extension.</p> <p>This command forces a thread stuck in the <b class="cmd">thread::wait</b> command to unconditionaly exit. The thread's exit status defaults to 666 and can be specified using the optional <i class="arg">status</i> argument. The execution of <b class="cmd">thread::exit</b> command is guaranteed to leave the program memory in the unconsistent state, produce memory leaks and otherwise affect other subsytem(s) of the Tcl application in an unpredictable manner. The command returns empty result but may trigger Tcl error with the message "target thread died" in some situations.</p></dd> <dt><a name="9"><b class="cmd">thread::names</b></a></dt> <dd><p>This command returns a list of thread IDs. These are only for threads that have been created via <b class="cmd">thread::create</b> command. If your application creates other threads at the C level, they are not reported by this command.</p></dd> <dt><a name="10"><b class="cmd">thread::exists</b> <i class="arg">id</i></a></dt> <dd><p>Returns true (1) if thread given by the <i class="arg">id</i> parameter exists, false (0) otherwise. This applies only for threads that have been created via <b class="cmd">thread::create</b> command.</p></dd> <dt><a name="11"><b class="cmd">thread::send</b> <span class="opt">?-async?</span> <span class="opt">?-head?</span> <i class="arg">id</i> <i class="arg">script</i> <span class="opt">?varname?</span></a></dt> <dd><p>This command passes a <i class="arg">script</i> to another thread and, optionally, waits for the result. If the <b class="option">-async</b> flag is specified, the command does not wait for the result and it returns empty string. The target thread must enter it's event loop in order to receive scripts sent via this command. This is done by default for threads created without a startup script. Threads can enter the event loop explicitly by calling <b class="cmd">thread::wait</b> or any other relevant Tcl/Tk command, like <b class="cmd">update</b>, <b class="cmd">vwait</b>, etc.</p> <p>Optional <b class="option">varname</b> specifies name of the variable to store the result of the <i class="arg">script</i>. Without the <b class="option">-async</b> flag, the command returns the evaluation code, similarily to the standard Tcl <b class="cmd">catch</b> command. If, however, the <b class="option">-async</b> flag is specified, the command returns immediately and caller can later <b class="cmd">vwait</b> on <span class="opt">?varname?</span> to get the result of the passed <i class="arg">script</i></p> <pre class="doctools_example"> set t1 [thread::create] set t2 [thread::create] thread::send -async $t1 "set a 1" result thread::send -async $t2 "set b 2" result for {set i 0} {$i < 2} {incr i} { vwait result } </pre> <p>In the above example, two threads were fed work and both of them were instructed to signalize the same variable "result" in the calling thread. The caller entered the event loop twice to get both results. Note, however, that the order of the received results may vary, depending on the current system load, type of work done, etc, etc.</p> <p>Many threads can simultaneously send scripts to the target thread for execution. All of them are entered into the event queue of the target thread and executed on the FIFO basis, intermingled with optional other events pending in the event queue of the target thread. Using the optional <span class="opt">?-head?</span> switch, scripts posted to the thread's event queue can be placed on the head, instead on the tail of the queue, thus being executed in the LIFO fashion.</p></dd> <dt><a name="12"><b class="cmd">thread::broadcast</b> <i class="arg">script</i></a></dt> <dd><p>This command passes a <i class="arg">script</i> to all threads created by the package for execution. It does not wait for response from any of the threads.</p></dd> <dt><a name="13"><b class="cmd">thread::wait</b></a></dt> <dd><p>This enters the event loop so a thread can receive messages from the <b class="cmd">thread::send</b> command. This command should only be used within the script passed to the <b class="cmd">thread::create</b>. It should be the very last command in the script. If this is not the case, the exiting thread will continue executing the script lines past the <b class="cmd">thread::wait</b> which is usually not what you want and/or expect.</p> <pre class="doctools_example"> set t1 [thread::create { # # Do some initialization work here # thread::wait ; # Enter the event loop }] </pre> </dd> <dt><a name="14"><b class="cmd">thread::eval</b> <span class="opt">?-lock mutex?</span> <i class="arg">arg</i> <span class="opt">?arg ...?</span></a></dt> <dd><p>This command concatenates passed arguments and evaluates the resulting script under the mutex protection. If no mutex is specified by using the <span class="opt">?-lock mutex?</span> optional argument, the internal static mutex is used.</p></dd> <dt><a name="15"><b class="cmd">thread::join</b> <i class="arg">id</i></a></dt> <dd><p>This command waits for the thread with ID <i class="arg">id</i> to exit and then returns it's exit code. Errors will be returned for threads which are not joinable or already waited upon by another thread. Upon the join the handle of the thread has gone out of scope and should not be used any more.</p></dd> <dt><a name="16"><b class="cmd">thread::configure</b> <i class="arg">id</i> <span class="opt">?option?</span> <span class="opt">?value?</span> <span class="opt">?...?</span></a></dt> <dd><p>This command configures various low-level aspects of the thread with ID <i class="arg">id</i> in the similar way as the standard Tcl command <b class="cmd">fconfigure</b> configures some Tcl channel options. Options currently supported are: <b class="option">-eventmark</b> and <b class="option">-unwindonerror</b>.</p> <p>The <b class="option">-eventmark</b> option, when set, limits the number of asynchronously posted scripts to the thread event loop. The <b class="cmd">thread::send -async</b> command will block until the number of pending scripts in the event loop does not drop below the value configured with <b class="option">-eventmark</b>. Default value for the <b class="option">-eventmark</b> is 0 (zero) which effectively disables the checking, i.e. allows for unlimited number of posted scripts.</p> <p>The <b class="option">-unwindonerror</b> option, when set, causes the target thread to unwind if the result of the script processing resulted in error. Default value for the <b class="option">-unwindonerror</b> is 0 (false), i.e. thread continues to process scripts after one of the posted scripts fails.</p></dd> <dt><a name="17"><b class="cmd">thread::transfer</b> <i class="arg">id</i> <i class="arg">channel</i></a></dt> <dd><p>This moves the specified <i class="arg">channel</i> from the current thread and interpreter to the main interpreter of the thread with the given <i class="arg">id</i>. After the move the current interpreter has no access to the channel any more, but the main interpreter of the target thread will be able to use it from now on. The command waits until the other thread has incorporated the channel. Because of this it is possible to deadlock the participating threads by commanding the other through a synchronous <b class="cmd">thread::send</b> to transfer a channel to us. This easily extends into longer loops of threads waiting for each other. Other restrictions: the channel in question must not be shared among multiple interpreters running in the sending thread. This automatically excludes the special channels for standard input, output and error.</p> <p>Due to the internal Tcl core implementation and the restriction on transferring shared channels, one has to take extra measures when transferring socket channels created by accepting the connection out of the <b class="cmd">socket</b> commands callback procedures:</p> <pre class="doctools_example"> socket -server _Accept 2200 proc _Accept {s ipaddr port} { after idle [list Accept $s $ipaddr $port] } proc Accept {s ipaddr port} { set tid [thread::create] thread::transfer $tid $s } </pre> </dd> <dt><a name="18"><b class="cmd">thread::detach</b> <i class="arg">channel</i></a></dt> <dd><p>This detaches the specified <i class="arg">channel</i> from the current thread and interpreter. After that, the current interpreter has no access to the channel any more. The channel is in the parked state until some other (or the same) thread attaches the channel again with <b class="cmd">thread::attach</b>. Restrictions: same as for transferring shared channels with the <b class="cmd">thread::transfer</b> command.</p></dd> <dt><a name="19"><b class="cmd">thread::attach</b> <i class="arg">channel</i></a></dt> <dd><p>This attaches the previously detached <i class="arg">channel</i> in the current thread/interpreter. For already existing channels, the command does nothing, i.e. it is not an error to attach the same channel more than once. The first operation will actualy perform the operation, while all subsequent operation will just do nothing. Command throws error if the <i class="arg">channel</i> cannot be found in the list of detached channels and/or in the current interpreter.</p></dd> <dt><a name="20"><b class="cmd">thread::mutex</b></a></dt> <dd><p>Mutexes are most common thread synchronization primitives. They are used to synchronize access from two or more threads to one or more shared resources. This command provides script-level access to exclusive and/or recursive mutexes. Exclusive mutexes can be locked only once by one thread, while recursive mutexes can be locked many times by the same thread. For recursive mutexes, number of lock and unlock operations must match, otherwise, the mutex will never be released, which would lead to various deadlock situations.</p> <p>Care has to be taken when using mutexes in an multithreading program. Improper use of mutexes may lead to various deadlock situations, especially when using exclusive mutexes.</p> <p>The <b class="cmd">thread::mutex</b> command supports following subcommands and options:</p> <dl class="doctools_definitions"> <dt><a name="21"><b class="cmd">thread::mutex</b> <b class="method">create</b> <span class="opt">?-recursive?</span></a></dt> <dd><p>Creates the mutex and returns it's opaque handle. This handle should be used for any future reference to the newly created mutex. If no optional <span class="opt">?-recursive?</span> argument was specified, the command creates the exclusive mutex. With the <span class="opt">?-recursive?</span> argument, the command creates a recursive mutex.</p></dd> <dt><a name="22"><b class="cmd">thread::mutex</b> <b class="method">destroy</b> <i class="arg">mutex</i></a></dt> <dd><p>Destroys the <i class="arg">mutex</i>. Mutex should be in unlocked state before the destroy attempt. If the mutex is locked, the command will throw Tcl error.</p></dd> <dt><a name="23"><b class="cmd">thread::mutex</b> <b class="method">lock</b> <i class="arg">mutex</i></a></dt> <dd><p>Locks the <i class="arg">mutex</i>. Locking the exclusive mutex may throw Tcl error if on attempt to lock the same mutex twice from the same thread. If your program logic forces you to lock the same mutex twice or more from the same thread (this may happen in recursive procedure invocations) you should consider using the recursive mutexes.</p></dd> <dt><a name="24"><b class="cmd">thread::mutex</b> <b class="method">unlock</b> <i class="arg">mutex</i></a></dt> <dd><p>Unlocks the <i class="arg">mutex</i> so some other thread may lock it again. Attempt to unlock the already unlocked mutex will throw Tcl error.</p></dd> </dl></dd> <dt><a name="25"><b class="cmd">thread::rwmutex</b></a></dt> <dd><p>This command creates many-readers/single-writer mutexes. Reader/writer mutexes allow you to serialize access to a shared resource more optimally. In situations where a shared resource gets mostly read and seldom modified, you might gain some performace by using reader/writer mutexes instead of exclusive or recursive mutexes.</p> <p>For reading the resource, thread should obtain a read lock on the resource. Read lock is non-exclusive, meaning that more than one thread can obtain a read lock to the same resource, without waiting on other readers. For changing the resource, however, a thread must obtain a exclusive write lock. This lock effectively blocks all threads from gaining the read-lock while the resource is been modified by the writer thread. Only after the write lock has been released, the resource may be read-locked again.</p> <p>The <b class="cmd">thread::rwmutex</b> command supports following subcommands and options:</p> <dl class="doctools_definitions"> <dt><a name="26"><b class="cmd">thread::rwmutex</b> <b class="method">create</b></a></dt> <dd><p>Creates the reader/writer mutex and returns it's opaque handle. This handle should be used for any future reference to the newly created mutex.</p></dd> <dt><a name="27"><b class="cmd">thread::rwmutex</b> <b class="method">destroy</b> <i class="arg">mutex</i></a></dt> <dd><p>Destroys the reader/writer <i class="arg">mutex</i>. If the mutex is already locked, attempt to destroy it will throw Tcl error.</p></dd> <dt><a name="28"><b class="cmd">thread::rwmutex</b> <b class="method">rlock</b> <i class="arg">mutex</i></a></dt> <dd><p>Locks the <i class="arg">mutex</i> for reading. More than one thread may read-lock the same <i class="arg">mutex</i> at the same time.</p></dd> <dt><a name="29"><b class="cmd">thread::rwmutex</b> <b class="method">wlock</b> <i class="arg">mutex</i></a></dt> <dd><p>Locks the <i class="arg">mutex</i> for writing. Only one thread may write-lock the same <i class="arg">mutex</i> at the same time. Attempt to write-lock same <i class="arg">mutex</i> twice from the same thread will throw Tcl error.</p></dd> <dt><a name="30"><b class="cmd">thread::rwmutex</b> <b class="method">unlock</b> <i class="arg">mutex</i></a></dt> <dd><p>Unlocks the <i class="arg">mutex</i> so some other thread may lock it again. Attempt to unlock already unlocked <i class="arg">mutex</i> will throw Tcl error.</p></dd> </dl></dd> <dt><a name="31"><b class="cmd">thread::cond</b></a></dt> <dd><p>This command provides script-level access to condition variables. A condition variable creates a safe environment for the program to test some condition, sleep on it when false and be awakened when it might have become true. A condition variable is always used in the conjuction with an exclusive mutex. If you attempt to use other type of mutex in conjuction with the condition variable, a Tcl error will be thrown.</p> <p>The command supports following subcommands and options:</p> <dl class="doctools_definitions"> <dt><a name="32"><b class="cmd">thread::cond</b> <b class="method">create</b></a></dt> <dd><p>Creates the condition variable and returns it's opaque handle. This handle should be used for any future reference to newly created condition variable.</p></dd> <dt><a name="33"><b class="cmd">thread::cond</b> <b class="method">destroy</b> <i class="arg">cond</i></a></dt> <dd><p>Destroys condition variable <i class="arg">cond</i>. Extreme care has to be taken that nobody is using (i.e. waiting on) the condition variable, otherwise unexpected errors may happen.</p></dd> <dt><a name="34"><b class="cmd">thread::cond</b> <b class="method">notify</b> <i class="arg">cond</i></a></dt> <dd><p>Wakes up all threads waiting on the condition variable <i class="arg">cond</i>.</p></dd> <dt><a name="35"><b class="cmd">thread::cond</b> <b class="method">wait</b> <i class="arg">cond</i> <i class="arg">mutex</i> <span class="opt">?ms?</span></a></dt> <dd><p>This command is used to suspend program execution until the condition variable <i class="arg">cond</i> has been signalled or the optional timer has expired. The exclusive <i class="arg">mutex</i> must be locked by the calling thread on entrance to this command. If the mutex is not locked, Tcl error is thrown. While waiting on the <i class="arg">cond</i>, the command releases <i class="arg">mutex</i>. Before returning to the calling thread, the command re-acquires the <i class="arg">mutex</i> again. Unlocking the <i class="arg">mutex</i> and waiting on the condition variable <i class="arg">cond</i> is done atomically.</p> <p>The <b class="option">ms</b> command option, if given, must be an integer specifying time interval in milliseconds the command waits to be signalled. Otherwise the command waits on condition notify forever.</p> <p>In multithreading programs, there are many situations where a thread has to wait for some event to happen until it is allowed to proceed. This is usually accomplished by repeatedly testing a condition under the mutex protection and waiting on the condition variable until the condition evaluates to true:</p> <pre class="doctools_example"> set mutex [thread::mutex create] set cond [thread::cond create] thread::mutex lock $mutex while {<some_condition_is_true>} { thread::cond wait $cond $mutex } # Do some work under mutex protection thread::mutex unlock $mutex </pre> <p>Repeated testing of the condition is needed since the condition variable may get signalled without the condition being actually changed (spurious thread wake-ups, for example).</p></dd> </dl></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">DISCUSSION</a></h2> <p>The fundamental threading model in Tcl is that there can be one or more Tcl interpreters per thread, but each Tcl interpreter should only be used by a single thread which created it. A "shared memory" abstraction is awkward to provide in Tcl because Tcl makes assumptions about variable and data ownership. Therefore this extension supports a simple form of threading where the main thread can manage several background, or "worker" threads. For example, an event-driven server can pass requests to worker threads, and then await responses from worker threads or new client requests. Everything goes through the common Tcl event loop, so message passing between threads works naturally with event-driven I/O, <b class="cmd">vwait</b> on variables, and so forth. For the transfer of bulk information it is possible to move channels between the threads.</p> <p>For advanced multithreading scripts, script-level access to two basic synchronization primitives, mutex and condition variables, is also supported.</p> </div> <div id="see-also" class="doctools_section"><h2><a name="see-also">See Also</a></h2> |
︙ | ︙ |
Changes to doc/html/tpool.html.
︙ | ︙ | |||
130 131 132 133 134 135 136 | <li><a href="#9"><b class="cmd">tpool::suspend</b> <i class="arg">tpool</i></a></li> <li><a href="#10"><b class="cmd">tpool::resume</b> <i class="arg">tpool</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package creates and manages pools of worker threads. It allows you | | | | 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | <li><a href="#9"><b class="cmd">tpool::suspend</b> <i class="arg">tpool</i></a></li> <li><a href="#10"><b class="cmd">tpool::resume</b> <i class="arg">tpool</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package creates and manages pools of worker threads. It allows you to post jobs to worker threads and wait for their completion. The threadpool implementation is Tcl event-loop aware. That means that any time a caller is forced to wait for an event (job being completed or a worker thread becoming idle or initialized), the implementation will enter the event loop and allow for servicing of other pending file or timer (or any other supported) events.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">tpool::create</b> <span class="opt">?options?</span></a></dt> |
︙ | ︙ | |||
161 162 163 164 165 166 167 | <dt><b class="option">-maxworkers</b> <i class="arg">number</i></dt> <dd><p>Maximum number of worker threads allowed for this threadpool instance. If a new job is pending and there are no idle worker threads available, the implementation will try to create new worker thread. If the number of available worker threads is lower than the given number, new worker thread will start. The caller will automatically enter the event loop and wait until the worker thread has initialized. If. however, | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | <dt><b class="option">-maxworkers</b> <i class="arg">number</i></dt> <dd><p>Maximum number of worker threads allowed for this threadpool instance. If a new job is pending and there are no idle worker threads available, the implementation will try to create new worker thread. If the number of available worker threads is lower than the given number, new worker thread will start. The caller will automatically enter the event loop and wait until the worker thread has initialized. If. however, the number of available worker threads is equal to the given number, the caller will enter the event loop and wait for the first worker thread to get idle, thus ready to run the job. Default value of this parameter is 4 (four), which means that the threadpool instance will allow maximum of 4 worker threads running jobs or being idle waiting for new jobs to get posted to the job queue.</p></dd> <dt><b class="option">-idletime</b> <i class="arg">seconds</i></dt> <dd><p>Time in seconds an idle worker thread waits for the job to get posted to the job queue. If no job arrives during this interval and the time expires, the worker thread will check the number of currently available worker threads and if the number is higher than the number set by the <b class="option">minthreads</b> option, it will exit. If an <b class="option">exitscript</b> has been defined, the exiting worker thread will first run the script and then exit. Errors from the exit script, if any, are ignored.</p> <p>The idle worker thread is not servicing the event loop. If you, however, put the worker thread into the event loop, by evaluating the <b class="cmd">vwait</b> or other related Tcl commands, the worker thread will not be in the idle state, hence the idle timer will not be taken into account. Default value for this option is unspecified.</p></dd> <dt><b class="option">-initcmd</b> <i class="arg">script</i></dt> <dd><p>Sets a Tcl script used to initialize new worker thread. This is usually used to load packages and commands in the worker, set default variables, create namespaces, and such. If the passed script runs into a Tcl error, the worker will not be created and the initiating command (either the <b class="cmd">tpool::create</b> or <b class="cmd">tpool::post</b>) will throw error. Default value for this option is unspecified, hence, the Tcl interpreter of the worker thread will contain just the initial set of Tcl commands.</p></dd> <dt><b class="option">-exitcmd</b> <i class="arg">script</i></dt> <dd><p>Sets a Tcl script run when the idle worker thread exits. This is normaly used to cleanup the state of the worker thread, release reserved resources, cleanup memory and such. Default value for this option is unspecified, thus no Tcl script will run on the worker thread exit.</p></dd> </dl></dd> <dt><a name="2"><b class="cmd">tpool::names</b></a></dt> <dd><p>This command returns a list of IDs of threadpools created with the <b class="cmd">tpool::create</b> command. If no threadpools were found, the command will return empty list.</p></dd> <dt><a name="3"><b class="cmd">tpool::post</b> <span class="opt">?-detached?</span> <span class="opt">?-nowait?</span> <i class="arg">tpool</i> <i class="arg">script</i></a></dt> <dd><p>This command sends a <i class="arg">script</i> to the target <i class="arg">tpool</i> threadpool for execution. The script will be executed in the first available idle worker thread. If there are no idle worker threads available, the command will create new one, enter the event loop and service events until the newly created thread is initialized. If the current number of worker threads is equal to the maximum number of worker threads, as defined during the threadpool creation, the command will enter the event loop and service events while waiting for one of the worker threads to become idle. If the optional <span class="opt">?-nowait?</span> argument is given, the command will not wait for one idle worker. It will just place the job in the pool's job queue and return immediately.</p> <p>The command returns the ID of the posted job. This ID is used for subsequent <b class="cmd">tpool::wait</b>, <b class="cmd">tpool::get</b> and <b class="cmd">tpool::cancel</b> commands to wait for and retrieve result of the posted script, or cancel the posted job respectively. If the optional <span class="opt">?-detached?</span> argument is specified, the command will post a detached job. A detached job can not be cancelled or waited upon and is not identified by the job ID.</p> <p>If the threadpool <i class="arg">tpool</i> is not found in the list of active thread pools, the command will throw error. The error will also be triggered if the newly created worker thread fails to initialize.</p></dd> <dt><a name="4"><b class="cmd">tpool::wait</b> <i class="arg">tpool</i> <i class="arg">joblist</i> <span class="opt">?varname?</span></a></dt> <dd><p>This command waits for one or many jobs, whose job IDs are given in the <i class="arg">joblist</i> to get processed by the worker thread(s). If none of the specified jobs are ready, the command will enter the event loop, service events and wait for the first job to get ready.</p> <p>The command returns the list of completed job IDs. If the optional variable <span class="opt">?varname?</span> is given, it will be set to the list of jobs in the <i class="arg">joblist</i> which are still pending. If the threadpool <i class="arg">tpool</i> is not found in the list of active thread pools, the command will throw error.</p></dd> <dt><a name="5"><b class="cmd">tpool::cancel</b> <i class="arg">tpool</i> <i class="arg">joblist</i> <span class="opt">?varname?</span></a></dt> <dd><p>This command cancels the previously posted jobs given by the <i class="arg">joblist</i> to the pool <i class="arg">tpool</i>. Job cancellation succeeds only for job still waiting to be processed. If the job is already being executed by one of the worker threads, the job will not be cancelled. The command returns the list of cancelled job IDs. If the optional variable <span class="opt">?varname?</span> is given, it will be set to the list of jobs in the <i class="arg">joblist</i> which were not cancelled. If the threadpool <i class="arg">tpool</i> is not found in the list of active thread pools, the command will throw error.</p></dd> <dt><a name="6"><b class="cmd">tpool::get</b> <i class="arg">tpool</i> <i class="arg">job</i></a></dt> <dd><p>This command retrieves the result of the previously posted <i class="arg">job</i>. Only results of jobs waited upon with the <b class="cmd">tpool::wait</b> command can be retrieved. If the execution of the script resulted in error, the command will throw the error and update the <b class="variable">errorInfo</b> and <b class="variable">errorCode</b> variables correspondingly. If the pool <i class="arg">tpool</i> is not found in the list of threadpools, the command will throw error. If the job <i class="arg">job</i> is not ready for retrieval, because it is currently being executed by the worker thread, the command will throw error.</p></dd> <dt><a name="7"><b class="cmd">tpool::preserve</b> <i class="arg">tpool</i></a></dt> <dd><p>Each call to this command increments the reference counter of the threadpool <i class="arg">tpool</i> by one (1). Command returns the value of the reference counter after the increment. By incrementing the reference counter, the caller signalizes that he/she wishes to use the resource for a longer period of time.</p></dd> <dt><a name="8"><b class="cmd">tpool::release</b> <i class="arg">tpool</i></a></dt> <dd><p>Each call to this command decrements the reference counter of the threadpool <i class="arg">tpool</i> by one (1).Command returns the value of the reference counter after the decrement. When the reference counter reaches zero (0), the threadpool <i class="arg">tpool</i> is marked for termination. You should not reference the threadpool after the <b class="cmd">tpool::release</b> command returns zero. The <i class="arg">tpool</i> handle goes out of scope and should not be used any more. Any following reference to the same threadpool handle will result in Tcl error.</p></dd> <dt><a name="9"><b class="cmd">tpool::suspend</b> <i class="arg">tpool</i></a></dt> <dd><p>Suspends processing work on this queue. All pool workers are paused but additional work can be added to the pool. Note that adding the additional work will not increase the number of workers dynamically as the pool processing is suspended. Number of workers is maintained to the count that was found prior suspending worker activity. If you need to assure certain number of worker threads, use the <b class="option">minworkers</b> option of the <b class="cmd">tpool::create</b> command.</p></dd> <dt><a name="10"><b class="cmd">tpool::resume</b> <i class="arg">tpool</i></a></dt> <dd><p>Resume processing work on this queue. All paused (suspended) workers are free to get work from the pool. Note that resuming pool operation will just let already created workers to proceed. It will not create additional worker threads to handle the work posted to the pool's work queue.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">DISCUSSION</a></h2> <p>Threadpool is one of the most common threading paradigm when it comes to server applications handling a large number of relatively small tasks. A very simplistic model for building a server application would be to create a new thread each time a request arrives and service the request in the new thread. One of the disadvantages of this approach is that the overhead of creating a new thread for each request is significant; a server that created a new thread for each request would spend more time and consume more system resources in creating and destroying threads than in processing actual user requests. In addition to the overhead of creating and destroying threads, active threads consume system resources. Creating too many threads can cause the system to run out of memory or trash due to excessive memory consumption.</p> <p>A thread pool offers a solution to both the problem of thread life-cycle overhead and the problem of resource trashing. By reusing threads for multiple tasks, the thread-creation overhead is spread over many tasks. As a bonus, because the thread already exists when a request arrives, the delay introduced by thread creation is eliminated. Thus, the request can be serviced immediately. Furthermore, by properly tuning the number of threads in the thread pool, resource thrashing may also be eliminated by forcing any request to wait until a thread is available to process it.</p> </div> <div id="see-also" class="doctools_section"><h2><a name="see-also">See Also</a></h2> <p>thread, tsv, ttrace</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>thread, threadpool</p> </div> </div></body></html> |
Changes to doc/html/tsv.html.
︙ | ︙ | |||
158 159 160 161 162 163 164 | <li><a href="#33"><b class="cmd">tsv::keylkeys</b> <i class="arg">varname</i> <i class="arg">keylist</i> <span class="opt">?key?</span></a></li> <li><a href="#34"><b class="cmd">tsv::keylset</b> <i class="arg">varname</i> <i class="arg">keylist</i> <i class="arg">key</i> <i class="arg">value</i> <span class="opt">?key value..?</span></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This section describes commands implementing thread shared variables. | | | | | | | | | | | | | | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | <li><a href="#33"><b class="cmd">tsv::keylkeys</b> <i class="arg">varname</i> <i class="arg">keylist</i> <span class="opt">?key?</span></a></li> <li><a href="#34"><b class="cmd">tsv::keylset</b> <i class="arg">varname</i> <i class="arg">keylist</i> <i class="arg">key</i> <i class="arg">value</i> <span class="opt">?key value..?</span></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This section describes commands implementing thread shared variables. A thread shared variable is very similar to a Tcl array but in contrast to a Tcl array it is created in shared memory and can be accessed from many threads at the same time. Important feature of thread shared variable is that each access to the variable is internaly protected by a mutex so script programmer does not have to take care about locking the variable himself.</p> <p>Thread shared variables are not bound to any thread explicitly. That means that when a thread which created any of thread shared variables exits, the variable and associated memory is not unset/reclaimed. User has to explicitly unset the variable to reclaim the memory consumed by the variable.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">ELEMENT COMMANDS</a></h2> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">tsv::names</b> <span class="opt">?pattern?</span></a></dt> <dd><p>Returns names of shared variables matching optional <span class="opt">?pattern?</span> or all known variables if pattern is ommited.</p></dd> <dt><a name="2"><b class="cmd">tsv::object</b> <i class="arg">varname</i> <i class="arg">element</i></a></dt> <dd><p>Creates object accessor command for the <i class="arg">element</i> in the shared variable <i class="arg">varname</i>. Using this command, one can apply most of the other shared variable commands as method functions of the element object command. The object command is automatically deleted when the element which this command is pointing to is unset.</p> <pre class="doctools_example"> % tsv::set foo bar "A shared string" % set string [tsv::object foo bar] % $string append " appended" => A shared string appended </pre> </dd> <dt><a name="3"><b class="cmd">tsv::set</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?value?</span></a></dt> <dd><p>Sets the value of the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> to <i class="arg">value</i> and returns the value to caller. The <i class="arg">value</i> may be ommited, in which case the command will return the current value of the element. If the element cannot be found, error is triggered.</p></dd> <dt><a name="4"><b class="cmd">tsv::get</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?namedvar?</span></a></dt> <dd><p>Retrieves the value of the <i class="arg">element</i> from the shared variable <i class="arg">varname</i>. If the optional argument <i class="arg">namedvar</i> is given, the value is stored in the named variable. Return value of the command depends of the existence of the optional argument <i class="arg">namedvar</i>. If the argument is ommited and the requested element cannot be found in the shared array, the command triggers error. If, however, the optional argument is given on the command line, the command returns true (1) if the element is found or false (0) if the element is not found.</p></dd> <dt><a name="5"><b class="cmd">tsv::unset</b> <i class="arg">varname</i> <span class="opt">?element?</span></a></dt> <dd><p>Unsets the <i class="arg">element</i> from the shared variable <i class="arg">varname</i>. If the optional element is not given, it deletes the variable.</p></dd> <dt><a name="6"><b class="cmd">tsv::exists</b> <i class="arg">varname</i> <i class="arg">element</i></a></dt> <dd><p>Checks wether the <i class="arg">element</i> exists in the shared variable <i class="arg">varname</i> and returns true (1) if it does or false (0) if it doesn't.</p></dd> <dt><a name="7"><b class="cmd">tsv::pop</b> <i class="arg">varname</i> <i class="arg">element</i></a></dt> <dd><p>Returns value of the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> and unsets the element, all in one atomic operation.</p></dd> <dt><a name="8"><b class="cmd">tsv::move</b> <i class="arg">varname</i> <i class="arg">oldname</i> <i class="arg">newname</i></a></dt> <dd><p>Renames the element <i class="arg">oldname</i> to the <i class="arg">newname</i> in the shared variable <i class="arg">varname</i>. This effectively performs an get/unset/set sequence of operations but all in one atomic step.</p></dd> <dt><a name="9"><b class="cmd">tsv::incr</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?count?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">incr</b> command but increments the value of the <i class="arg">element</i> in shared variaboe <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="10"><b class="cmd">tsv::append</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">value</i> <span class="opt">?value ...?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">append</b> command but appends one or more values to the <i class="arg">element</i> in shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="11"><b class="cmd">tsv::lock</b> <i class="arg">varname</i> <i class="arg">arg</i> <span class="opt">?arg ...?</span></a></dt> <dd><p>This command concatenates passed arguments and evaluates the resulting script under the internal mutex protection. During the script evaluation, the entire shared variable is locked. For shared variable commands within the script, internal locking is disabled so no deadlock can occur. It is also allowed to unset the shared |
︙ | ︙ | |||
251 252 253 254 255 256 257 | </div> <div id="section3" class="doctools_section"><h2><a name="section3">LIST COMMANDS</a></h2> <p>Those command are similar to the equivalently named Tcl command. The difference is that they operate on elements of shared arrays.</p> <dl class="doctools_definitions"> <dt><a name="13"><b class="cmd">tsv::lappend</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">value</i> <span class="opt">?value ...?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lappend</b> command but appends one | | | | | | | | | 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 | </div> <div id="section3" class="doctools_section"><h2><a name="section3">LIST COMMANDS</a></h2> <p>Those command are similar to the equivalently named Tcl command. The difference is that they operate on elements of shared arrays.</p> <dl class="doctools_definitions"> <dt><a name="13"><b class="cmd">tsv::lappend</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">value</i> <span class="opt">?value ...?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lappend</b> command but appends one or more values to the <i class="arg">element</i> in shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="14"><b class="cmd">tsv::linsert</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">index</i> <i class="arg">value</i> <span class="opt">?value ...?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">linsert</b> command but inserts one or more values at the <i class="arg">index</i> list position in the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="15"><b class="cmd">tsv::lreplace</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">first</i> <i class="arg">last</i> <span class="opt">?value ...?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lreplace</b> command but replaces one or more values between the <i class="arg">first</i> and <i class="arg">last</i> position in the <i class="arg">element</i> of the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="16"><b class="cmd">tsv::llength</b> <i class="arg">varname</i> <i class="arg">element</i></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">llength</b> command but returns length of the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="17"><b class="cmd">tsv::lindex</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?index?</span></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lindex</b> command but returns the value at the <i class="arg">index</i> list position of the <i class="arg">element</i> from the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="18"><b class="cmd">tsv::lrange</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">from</i> <i class="arg">to</i></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lrange</b> command but returns values between <i class="arg">from</i> and <i class="arg">to</i> list positions from the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="19"><b class="cmd">tsv::lsearch</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?options?</span> <i class="arg">pattern</i></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lsearch</b> command but searches the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="20"><b class="cmd">tsv::lset</b> <i class="arg">varname</i> <i class="arg">element</i> <i class="arg">index</i> <span class="opt">?index ...?</span> <i class="arg">value</i></a></dt> <dd><p>Similar to standard Tcl <b class="cmd">lset</b> command but sets the <i class="arg">element</i> in the shared variable <i class="arg">varname</i> instead of the Tcl variable.</p></dd> <dt><a name="21"><b class="cmd">tsv::lpop</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?index?</span></a></dt> <dd><p>Similar to the standard Tcl <b class="cmd">lindex</b> command but in addition to returning, it also splices the value out of the <i class="arg">element</i> from the shared variable <i class="arg">varname</i> in one atomic operation. In contrast to the Tcl <b class="cmd">lindex</b> command, this command returns no value to the caller.</p></dd> <dt><a name="22"><b class="cmd">tsv::lpush</b> <i class="arg">varname</i> <i class="arg">element</i> <span class="opt">?index?</span></a></dt> <dd><p>This command performes the opposite of the <b class="cmd">tsv::lpop</b> command. As its counterpart, it returns no value to the caller.</p></dd> </dl> </div> <div id="section4" class="doctools_section"><h2><a name="section4">ARRAY COMMANDS</a></h2> |
︙ | ︙ | |||
319 320 321 322 323 324 325 | <dd><p>Binds the <i class="arg">varname</i> to the persistent storage <i class="arg">handle</i>. The format of the <i class="arg">handle</i> is <handler>:<address>, where <handler> is "gdbm" for GNU Gdbm and "lmdb" for LMDB and <address> is the path to the database file.</p></dd> <dt><a name="29"><b class="cmd">tsv::array unbind</b> <i class="arg">varname</i></a></dt> <dd><p>Unbinds the shared <i class="arg">array</i> from its bound persistent storage.</p></dd> <dt><a name="30"><b class="cmd">tsv::array isbound</b> <i class="arg">varname</i></a></dt> | | | | | | | | | | | | | | | | | | | | | | 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | <dd><p>Binds the <i class="arg">varname</i> to the persistent storage <i class="arg">handle</i>. The format of the <i class="arg">handle</i> is <handler>:<address>, where <handler> is "gdbm" for GNU Gdbm and "lmdb" for LMDB and <address> is the path to the database file.</p></dd> <dt><a name="29"><b class="cmd">tsv::array unbind</b> <i class="arg">varname</i></a></dt> <dd><p>Unbinds the shared <i class="arg">array</i> from its bound persistent storage.</p></dd> <dt><a name="30"><b class="cmd">tsv::array isbound</b> <i class="arg">varname</i></a></dt> <dd><p>Returns true (1) if the shared <i class="arg">varname</i> is bound to some persistent storage or zero (0) if not.</p></dd> </dl> </div> <div id="section5" class="doctools_section"><h2><a name="section5">KEYED LIST COMMANDS</a></h2> <p>Keyed list commands are borrowed from the TclX package. Keyed lists provide a structured data type built upon standard Tcl lists. This is a functionality similar to structs in the C programming language.</p> <p>A keyed list is a list in which each element contains a key and value pair. These element pairs are stored as lists themselves, where the key is the first element of the list, and the value is the second. The key-value pairs are referred to as fields. This is an example of a keyed list:</p> <pre class="doctools_example"> {{NAME {Frank Zappa}} {JOB {musician and composer}}} </pre> <p>Fields may contain subfields; `.' is the separator character. Subfields are actually fields where the value is another keyed list. Thus the following list has the top level fields ID and NAME, and subfields NAME.FIRST and NAME.LAST:</p> <pre class="doctools_example"> {ID 106} {NAME {{FIRST Frank} {LAST Zappa}}} </pre> <p>There is no limit to the recursive depth of subfields, allowing one to build complex data structures. Keyed lists are constructed and accessed via a number of commands. All keyed list management commands take the name of the variable containing the keyed list as an argument (i.e. passed by reference), rather than passing the list directly.</p> <dl class="doctools_definitions"> <dt><a name="31"><b class="cmd">tsv::keyldel</b> <i class="arg">varname</i> <i class="arg">keylist</i> <i class="arg">key</i></a></dt> <dd><p>Delete the field specified by <i class="arg">key</i> from the keyed list <i class="arg">keylist</i> in the shared variable <i class="arg">varname</i>. This removes both the key and the value from the keyed list.</p></dd> <dt><a name="32"><b class="cmd">tsv::keylget</b> <i class="arg">varname</i> <i class="arg">keylist</i> <i class="arg">key</i> <span class="opt">?retvar?</span></a></dt> <dd><p>Return the value associated with <i class="arg">key</i> from the keyed list <i class="arg">keylist</i> in the shared variable <i class="arg">varname</i>. If the optional <i class="arg">retvar</i> is not specified, then the value will be returned as the result of the command. In this case, if key is not found in the list, an error will result.</p> <p>If <i class="arg">retvar</i> is specified and <i class="arg">key</i> is in the list, then the value is returned in the variable <i class="arg">retvar</i> and the command returns 1 if the key was present within the list. If <i class="arg">key</i> isn't in the list, the command will return 0, and <i class="arg">retvar</i> will be left unchanged. If {} is specified for <i class="arg">retvar</i>, the value is not returned, allowing the Tcl programmer to determine if a <i class="arg">key</i> is present in a keyed list without setting a variable as a side-effect.</p></dd> <dt><a name="33"><b class="cmd">tsv::keylkeys</b> <i class="arg">varname</i> <i class="arg">keylist</i> <span class="opt">?key?</span></a></dt> <dd><p>Return the a list of the keys in the keyed list <i class="arg">keylist</i> in the shared variable <i class="arg">varname</i>. If <i class="arg">key</i> is specified, then it is the name of a key field who's subfield keys are to be retrieved.</p></dd> <dt><a name="34"><b class="cmd">tsv::keylset</b> <i class="arg">varname</i> <i class="arg">keylist</i> <i class="arg">key</i> <i class="arg">value</i> <span class="opt">?key value..?</span></a></dt> <dd><p>Set the value associated with <i class="arg">key</i>, in the keyed list <i class="arg">keylist</i> to <i class="arg">value</i>. If the <i class="arg">keylist</i> does not exists, it is created. If <i class="arg">key</i> is not currently in the list, it will be added. If it already exists, <i class="arg">value</i> replaces the existing value. Multiple keywords and values may be specified, if desired.</p></dd> </dl> </div> <div id="section6" class="doctools_section"><h2><a name="section6">DISCUSSION</a></h2> <p>The current implementation of thread shared variables allows for easy and convenient access to data shared between different threads. Internally, the data is stored in Tcl objects and all package commands operate on internal data representation, thus minimizing shimmering and improving performance. Special care has been taken to assure that all object data is properly locked and deep-copied when moving objects between threads.</p> <p>Due to the internal design of the Tcl core, there is no provision of full integration of shared variables within the Tcl syntax, unfortunately. All access to shared data must be performed with the supplied package commands. Also, variable traces are not supported. But even so, benefits of easy, simple and safe shared data manipulation outweights imposed limitations.</p> </div> <div id="section7" class="doctools_section"><h2><a name="section7">CREDITS</a></h2> <p>Thread shared variables are inspired by the nsv interface found in AOLserver, a highly scalable Web server from America Online.</p> </div> <div id="see-also" class="doctools_section"><h2><a name="see-also">See Also</a></h2> <p>thread, tpool, ttrace</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>locking, synchronization, thread shared data, threads</p> </div> </div></body></html> |
Changes to doc/html/ttrace.html.
︙ | ︙ | |||
139 140 141 142 143 144 145 | <li><a href="#17"><b class="cmd">ttrace::preload</b> <i class="arg">cmd</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package creates a framework for on-demand replication of the interpreter state accross threads in an multithreading application. | | | | | | | | | | | | | | | 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | <li><a href="#17"><b class="cmd">ttrace::preload</b> <i class="arg">cmd</i></a></li> </ul> </div> </div> <div id="section1" class="doctools_section"><h2><a name="section1">Description</a></h2> <p>This package creates a framework for on-demand replication of the interpreter state accross threads in an multithreading application. It relies on the mechanics of Tcl command tracing and the Tcl <b class="cmd">unknown</b> command and mechanism.</p> <p>The package requires Tcl threading extension but can be alternatively used stand-alone within the AOLserver, a scalable webserver from America Online.</p> <p>In a nutshell, a short sample illustrating the usage of the ttrace with the Tcl threading extension:</p> <pre class="doctools_example"> % package require Ttrace 2.8.2 % set t1 [thread::create {package require Ttrace; thread::wait}] tid0x1802800 % ttrace::eval {proc test args {return test-[thread::id]}} % thread::send $t1 test test-tid0x1802800 % set t2 [thread::create {package require Ttrace; thread::wait}] tid0x1804000 % thread::send $t2 test test-tid0x1804000 </pre> <p>As seen from above, the <b class="cmd">ttrace::eval</b> and <b class="cmd">ttrace::update</b> commands are used to create a thread-wide definition of a simple Tcl procedure and replicate that definition to all, already existing or later created, threads.</p> </div> <div id="section2" class="doctools_section"><h2><a name="section2">USER COMMANDS</a></h2> <p>This section describes user-level commands. Those commands can be used by script writers to control the execution of the tracing framework.</p> <dl class="doctools_definitions"> <dt><a name="1"><b class="cmd">ttrace::eval</b> <i class="arg">arg</i> <span class="opt">?arg ...?</span></a></dt> <dd><p>This command concatenates given arguments and evaluates the resulting Tcl command with trace framework enabled. If the command execution was ok, it takes necessary steps to automatically propagate the trace epoch change to all threads in the application. For AOLserver, only newly created threads actually receive the epoch change. For the Tcl threading extension, all threads created by the extension are automatically updated. If the command execution resulted in Tcl error, no state propagation takes place.</p> <p>This is the most important user-level command of the package as it wraps most of the commands described below. This greatly simplifies things, because user need to learn just this (one) command in order to effectively use the package. Other commands, as desribed below, are included mostly for the sake of completeness.</p></dd> <dt><a name="2"><b class="cmd">ttrace::enable</b></a></dt> <dd><p>Activates all registered callbacks in the framework and starts a new trace epoch. The trace epoch encapsulates all changes done to the interpreter during the time traces are activated.</p></dd> <dt><a name="3"><b class="cmd">ttrace::disable</b></a></dt> <dd><p>Deactivates all registered callbacks in the framework and closes the current trace epoch.</p></dd> <dt><a name="4"><b class="cmd">ttrace::cleanup</b></a></dt> <dd><p>Used to clean-up all on-demand loaded resources in the interpreter. It effectively brings Tcl interpreter to its pristine state.</p></dd> <dt><a name="5"><b class="cmd">ttrace::update</b> <span class="opt">?epoch?</span></a></dt> <dd><p>Used to refresh the state of the interpreter to match the optional trace <span class="opt">?epoch?</span>. If the optional <span class="opt">?epoch?</span> is not given, it takes the most recent trace epoch.</p></dd> <dt><a name="6"><b class="cmd">ttrace::getscript</b></a></dt> <dd><p>Returns a synthetized Tcl script which may be sourced in any interpreter. This script sets the stage for the Tcl <b class="cmd">unknown</b> command so it can load traced resources from the in-memory database. Normally, this command is automatically invoked by other higher-level commands like <b class="cmd">ttrace::eval</b> and <b class="cmd">ttrace::update</b>.</p></dd> </dl> </div> <div id="section3" class="doctools_section"><h2><a name="section3">CALLBACK COMMANDS</a></h2> <p>A word upfront: the package already includes callbacks for tracing following Tcl commands: <b class="cmd">proc</b>, <b class="cmd">namespace</b>, <b class="cmd">variable</b>, <b class="cmd">load</b>, and <b class="cmd">rename</b>. Additionaly, a set of callbacks for tracing resources (object, clasess) for the XOTcl v1.3.8+, an OO-extension to Tcl, is also provided. This gives a solid base for solving most of the real-life needs and serves as an example for people wanting to customize the package to cover their specific needs.</p> <p>Below, you can find commands for registering callbacks in the framework and for writing callback scripts. These callbacks are invoked by the framework in order to gather interpreter state changes, build in-memory database, perform custom-cleanups and various other tasks.</p> <dl class="doctools_definitions"> |
︙ | ︙ | |||
235 236 237 238 239 240 241 | <dd><p>Registers Tcl callback to be activated at <b class="cmd">ttrace::disable</b>. Registered callbacks are activated on FIFO basis. The callback definition includes the name of the callback, <i class="arg">cmd</i>, a list of callback arguments, <i class="arg">arglist</i> and the <i class="arg">body</i> of the callback. Effectively, this actually resembles the call interface of the standard Tcl <b class="cmd">proc</b> command.</p></dd> <dt><a name="9"><b class="cmd">ttrace::addtrace</b> <i class="arg">cmd</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> | | | | | | | | | | | | | | | | | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 | <dd><p>Registers Tcl callback to be activated at <b class="cmd">ttrace::disable</b>. Registered callbacks are activated on FIFO basis. The callback definition includes the name of the callback, <i class="arg">cmd</i>, a list of callback arguments, <i class="arg">arglist</i> and the <i class="arg">body</i> of the callback. Effectively, this actually resembles the call interface of the standard Tcl <b class="cmd">proc</b> command.</p></dd> <dt><a name="9"><b class="cmd">ttrace::addtrace</b> <i class="arg">cmd</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd><p>Registers Tcl callback to be activated for tracing the Tcl <b class="cmd">cmd</b> command. The callback definition includes the name of the Tcl command to trace, <i class="arg">cmd</i>, a list of callback arguments, <i class="arg">arglist</i> and the <i class="arg">body</i> of the callback. Effectively, this actually resembles the call interface of the standard Tcl <b class="cmd">proc</b> command.</p></dd> <dt><a name="10"><b class="cmd">ttrace::addscript</b> <i class="arg">name</i> <i class="arg">body</i></a></dt> <dd><p>Registers Tcl callback to be activated for building a Tcl script to be passed to other interpreters. This script is used to set the stage for the Tcl <b class="cmd">unknown</b> command. Registered callbacks are activated on FIFO basis. The callback definition includes the name of the callback, <i class="arg">name</i> and the <i class="arg">body</i> of the callback.</p></dd> <dt><a name="11"><b class="cmd">ttrace::addresolver</b> <i class="arg">cmd</i> <i class="arg">arglist</i> <i class="arg">body</i></a></dt> <dd><p>Registers Tcl callback to be activated by the overloaded Tcl <b class="cmd">unknown</b> command. Registered callbacks are activated on FIFO basis. This callback is used to resolve the resource and load the resource in the current interpreter.</p></dd> <dt><a name="12"><b class="cmd">ttrace::addcleanup</b> <i class="arg">body</i></a></dt> <dd><p>Registers Tcl callback to be activated by the <b class="cmd">trace::cleanup</b>. Registered callbacks are activated on FIFO basis.</p></dd> <dt><a name="13"><b class="cmd">ttrace::addentry</b> <i class="arg">cmd</i> <i class="arg">var</i> <i class="arg">val</i></a></dt> <dd><p>Adds one entry to the named in-memory database.</p></dd> <dt><a name="14"><b class="cmd">ttrace::getentry</b> <i class="arg">cmd</i> <i class="arg">var</i></a></dt> <dd><p>Returns the value of the entry from the named in-memory database.</p></dd> <dt><a name="15"><b class="cmd">ttrace::getentries</b> <i class="arg">cmd</i> <span class="opt">?pattern?</span></a></dt> <dd><p>Returns names of all entries from the named in-memory database.</p></dd> <dt><a name="16"><b class="cmd">ttrace::delentry</b> <i class="arg">cmd</i></a></dt> <dd><p>Deletes an entry from the named in-memory database.</p></dd> <dt><a name="17"><b class="cmd">ttrace::preload</b> <i class="arg">cmd</i></a></dt> <dd><p>Registers the Tcl command to be loaded in the interpreter. Commands registered this way will always be the part of the interpreter and not be on-demand loaded by the Tcl <b class="cmd">unknown</b> command.</p></dd> </dl> </div> <div id="section4" class="doctools_section"><h2><a name="section4">DISCUSSION</a></h2> <p>Common introspective state-replication approaches use a custom Tcl script to introspect the running interpreter and synthesize another Tcl script to replicate this state in some other interpreter. This package, on the contrary, uses Tcl command traces. Command traces are registered on selected Tcl commands, like <b class="cmd">proc</b>, <b class="cmd">namespace</b>, <b class="cmd">load</b> and other standard (and/or user-defined) Tcl commands. When activated, those traces build an in-memory database of created resources. This database is used as a resource repository for the (overloaded) Tcl <b class="cmd">unknown</b> command which creates the requested resource in the interpreter on demand. This way, users can update just one interpreter (master) in one thread and replicate that interpreter state (or part of it) to other threads/interpreters in the process.</p> <p>Immediate benefit of such approach is the much smaller memory footprint of the application and much faster thread creation. By not actually loading all necessary procedures (and other resources) in every thread at the thread initialization time, but by deffering this to the time the resource is actually referenced, significant improvements in both memory consumption and thread initialization time can be achieved. Some tests have shown that memory footprint of an multithreading Tcl application went down more than three times and thread startup time was reduced for about 50 times. Note that your mileage may vary. Other benefits include much finer control about what (and when) gets replicated from the master to other Tcl thread/interpreters.</p> </div> <div id="see-also" class="doctools_section"><h2><a name="see-also">See Also</a></h2> <p>thread, tpool, tsv</p> </div> <div id="keywords" class="doctools_section"><h2><a name="keywords">Keywords</a></h2> <p>command tracing, introspection</p> </div> </div></body></html> |
Changes to doc/thread.man.
1 2 3 4 5 6 7 8 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin thread n 2.8] [moddesc {Tcl Threading}] [titledesc {Extension for script access to Tcl threading}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin thread n 2.8] [moddesc {Tcl Threading}] [titledesc {Extension for script access to Tcl threading}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] The [package thread] extension creates threads that contain Tcl interpreters, and it lets you send scripts to those threads for evaluation. Additionally, it provides script-level access to basic thread synchronization primitives, like mutexes and condition variables. [section COMMANDS] This section describes commands for creating and destroying threads and sending scripts to threads for evaluation. [list_begin definitions] [call [cmd thread::create] [opt -joinable] [opt -preserved] [opt script]] This command creates a thread that contains a Tcl interpreter. The Tcl interpreter either evaluates the optional [option script], if specified, or it waits in the event loop for scripts that arrive via the [cmd thread::send] command. The result, if any, of the optional [option script] is never returned to the caller. The result of [cmd thread::create] is the ID of the thread. This is the opaque handle which identifies the newly created thread for all other package commands. The handle of the thread goes out of scope automatically when thread is marked for exit (see the [cmd thread::release] command below). [para] If the optional [option script] argument contains the [cmd thread::wait] command the thread will enter into the event loop. If such command is not found in the [option script] the thread will run the [option script] to the end and exit. In that case, the handle may be safely ignored since it refers to a thread which does not exists any more at the time when the command returns. [para] Using flag [option -joinable] it is possible to create a joinable thread, i.e. one upon whose exit can be waited upon by using [cmd thread::join] command. Note that failure to join a thread created with [option -joinable] flag results in resource and memory leaks. [para] Threads created by the [cmd thread::create] cannot be destroyed forcefully. Consequently, there is no corresponding thread destroy command. A thread may only be released using the [cmd thread::release] and if its internal reference count drops to zero, the thread is marked for exit. This kicks the thread out of the event loop servicing and the thread continues to execute commands passed in the [option script] argument, following the [cmd thread::wait] command. If this was the last command in the script, as usually the case, the thread will exit. [para] It is possible to create a situation in which it may be impossible to terminate the thread, for example by putting some endless loop after the [cmd thread::wait] or entering the event loop again by doing an vwait-type of command. In such cases, the thread may never exit. This is considered to be a bad practice and should be avoided if possible. This is best illustrated by the example below: [example { # You should never do ... set tid [thread::create { package require Http thread::wait vwait forever ; # <-- this! }] }] The thread created in the above example will never be able to exit. After it has been released with the last matching [cmd thread::release] call, the thread will jump out of the [cmd thread::wait] and continue to execute commands following. It will enter [cmd vwait] command and wait endlessly for events. There is no way one can terminate such thread, so you wouldn't want to do this! [para] Each newly created has its internal reference counter set to 0 (zero), i.e. it is unreserved. This counter gets incremented by a call to [cmd thread::preserve] and decremented by a call to [cmd thread::release] command. These two commands implement simple but effective thread reservation system and offer predictable and controllable thread termination capabilities. It is however possible to create initially preserved threads by using flag [option -preserved] of the [cmd thread::create] command. Threads created with this flag have the initial value of the reference counter of 1 (one), and are thus initially marked reserved. [call [cmd thread::preserve] [opt id]] This command increments the thread reference counter. Each call to this command increments the reference counter by one (1). Command returns the value of the reference counter after the increment. If called with the optional thread [option id], the command preserves the given thread. Otherwise the current thread is preserved. [para] With reference counting, one can implement controlled access to a shared Tcl thread. By incrementing the reference counter, the caller signalizes that he/she wishes to use the thread for a longer period of time. By decrementing the counter, caller signalizes that he/she has finished using the thread. [call [cmd thread::release] [opt -wait] [opt id]] This command decrements the thread reference counter. Each call to this command decrements the reference counter by one (1). If called with the optional thread [option id], the command releases the given thread. Otherwise, the current thread is released. Command returns the value of the reference counter after the decrement. When the reference counter reaches zero (0), the target thread is marked for termination. You should not reference the thread after the [cmd thread::release] command returns zero or negative integer. The handle of the thread goes out of scope and should not be used any more. Any following reference to the same thread handle will result in Tcl error. [para] Optional flag [option -wait] instructs the caller thread to wait for the target thread to exit, if the effect of the command would result in termination of the target thread, i.e. if the return result would be zero (0). Without the flag, the caller thread does not wait for the target thread to exit. Care must be taken when using the [option -wait], since this may block the caller thread indefinitely. This option has been implemented for some special uses of the extension and is deprecated for regular use. Regular users should create joinable threads by using the [option -joinable] option of the [cmd thread::create] command and the [cmd thread::join] to wait for thread to exit. [call [cmd thread::id]] This command returns the ID of the current thread. [call [cmd thread::errorproc] [opt procname]] This command sets a handler for errors that occur in scripts sent asynchronously, using the [option -async] flag of the [cmd thread::send] command, to other threads. If no handler is specified, the current handler is returned. The empty string resets the handler to default (unspecified) value. An uncaught error in a thread causes an error message to be sent to the standard error channel. This default reporting scheme can be changed by registering a procedure which is called to report the error. The [arg procname] is called in the interpreter that invoked the [cmd thread::errorproc] command. The [arg procname] |
︙ | ︙ | |||
183 184 185 186 187 188 189 | until there are no further invocations of the interpreter left on the call stack. If [arg result] is present, it will be used as the error message string; otherwise, a default error message string will be used. [call [cmd thread::unwind]] Use of this command is deprecated in favour of more advanced thread | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 | until there are no further invocations of the interpreter left on the call stack. If [arg result] is present, it will be used as the error message string; otherwise, a default error message string will be used. [call [cmd thread::unwind]] Use of this command is deprecated in favour of more advanced thread reservation system implemented with [cmd thread::preserve] and [cmd thread::release] commands. Support for [cmd thread::unwind] command will disappear in some future major release of the extension. [para] This command stops a prior [cmd thread::wait] command. Execution of the script passed to newly created thread will continue from the [cmd thread::wait] command. If [cmd thread::wait] was the last command in the script, the thread will exit. The command returns empty result but may trigger Tcl error with the message "target thread died" in some situations. [call [cmd thread::exit] [opt status]] Use of this command is deprecated in favour of more advanced thread reservation system implemented with [cmd thread::preserve] and [cmd thread::release] commands. Support for [cmd thread::exit] command will disappear in some future major release of the extension. [para] This command forces a thread stuck in the [cmd thread::wait] command to unconditionally exit. The thread's exit status defaults to 666 and can be specified using the optional [arg status] argument. The execution of [cmd thread::exit] command is guaranteed to leave the program memory in the inconsistent state, produce memory leaks and otherwise affect other subsystem(s) of the Tcl application in an unpredictable manner. The command returns empty result but may trigger Tcl error with the message "target thread died" in some situations. [call [cmd thread::names]] This command returns a list of thread IDs. These are only for threads that have been created via [cmd thread::create] command. If your application creates other threads at the C level, they are not reported by this command. [call [cmd thread::exists] [arg id]] Returns true (1) if thread given by the [arg id] parameter exists, false (0) otherwise. This applies only for threads that have been created via [cmd thread::create] command. [call [cmd thread::send] [opt -async] [opt -head] [arg id] [arg script] [opt varname]] This command passes a [arg script] to another thread and, optionally, waits for the result. If the [option -async] flag is specified, the command does not wait for the result and it returns empty string. The target thread must enter it's event loop in order to receive scripts sent via this command. This is done by default for threads created without a startup script. Threads can enter the event loop explicitly by calling [cmd thread::wait] or any other relevant Tcl/Tk command, like [cmd update], [cmd vwait], etc. [para] Optional [option varname] specifies name of the variable to store the result of the [arg script]. Without the [option -async] flag, the command returns the evaluation code, similarly to the standard Tcl [cmd catch] command. If, however, the [option -async] flag is specified, the command returns immediately and caller can later [cmd vwait] on [opt varname] to get the result of the passed [arg script] [example { set t1 [thread::create] set t2 [thread::create] thread::send -async $t1 "set a 1" result thread::send -async $t2 "set b 2" result for {set i 0} {$i < 2} {incr i} { vwait result } }] In the above example, two threads were fed work and both of them were instructed to signalize the same variable "result" in the calling thread. The caller entered the event loop twice to get both results. Note, however, that the order of the received results may vary, depending on the current system load, type of work done, etc, etc. [para] Many threads can simultaneously send scripts to the target thread for execution. All of them are entered into the event queue of the target thread and executed on the FIFO basis, intermingled with optional other events pending in the event queue of the target thread. Using the optional [opt -head] switch, scripts posted to the thread's event queue can be placed on the head, instead on the tail of the queue, thus being executed in the LIFO fashion. [call [cmd thread::broadcast] [arg script]] This command passes a [arg script] to all threads created by the package for execution. It does not wait for response from any of the threads. [call [cmd thread::wait]] This enters the event loop so a thread can receive messages from the [cmd thread::send] command. This command should only be used within the script passed to the [cmd thread::create]. It should be the very last command in the script. If this is not the case, the exiting thread will continue executing the script lines past the [cmd thread::wait] which is usually not what you want and/or expect. [example { set t1 [thread::create { # # Do some initialization work here # thread::wait ; # Enter the event loop }] }] [call [cmd thread::eval] [opt {-lock mutex}] [arg arg] [opt {arg ...}]] This command concatenates passed arguments and evaluates the resulting script under the mutex protection. If no mutex is specified by using the [opt {-lock mutex}] optional argument, the internal static mutex is used. [call [cmd thread::join] [arg id]] This command waits for the thread with ID [arg id] to exit and then returns it's exit code. Errors will be returned for threads which are not joinable or already waited upon by another thread. Upon the join the handle of the thread has gone out of scope and should not be used any more. [call [cmd thread::configure] [arg id] [opt option] [opt value] [opt ...]] This command configures various low-level aspects of the thread with ID [arg id] in the similar way as the standard Tcl command [cmd fconfigure] configures some Tcl channel options. Options currently supported are: [option -eventmark] and [option -unwindonerror]. [para] The [option -eventmark] option, when set, limits the number of asynchronously posted scripts to the thread event loop. The [cmd {thread::send -async}] command will block until the number of pending scripts in the event loop does not drop below the value configured with [option -eventmark]. Default value for the [option -eventmark] is 0 (zero) which effectively disables the checking, i.e. allows for unlimited number of posted scripts. [para] The [option -unwindonerror] option, when set, causes the target thread to unwind if the result of the script processing resulted in error. Default value for the [option -unwindonerror] is 0 (false), i.e. thread continues to process scripts after one of the posted scripts fails. [call [cmd thread::transfer] [arg id] [arg channel]] This moves the specified [arg channel] from the current thread and interpreter to the main interpreter of the thread with the given [arg id]. After the move the current interpreter has no access to the channel any more, but the main interpreter of the target thread will be able to use it from now on. The command waits until the other thread has incorporated the channel. Because of this it is possible to deadlock the participating threads by commanding the other through a synchronous [cmd thread::send] to transfer a channel to us. This easily extends into longer loops of threads waiting for each other. Other restrictions: the channel in question must not be shared among multiple interpreters running in the sending thread. This automatically excludes the special channels for standard input, output and error. [para] Due to the internal Tcl core implementation and the restriction on transferring shared channels, one has to take extra measures when transferring socket channels created by accepting the connection out of the [cmd socket] commands callback procedures: [example { socket -server _Accept 2200 proc _Accept {s ipaddr port} { after idle [list Accept $s $ipaddr $port] } proc Accept {s ipaddr port} { set tid [thread::create] thread::transfer $tid $s } }] [call [cmd thread::detach] [arg channel]] This detaches the specified [arg channel] from the current thread and interpreter. After that, the current interpreter has no access to the channel any more. The channel is in the parked state until some other (or the same) thread attaches the channel again with [cmd thread::attach]. Restrictions: same as for transferring shared channels with the [cmd thread::transfer] command. [call [cmd thread::attach] [arg channel]] This attaches the previously detached [arg channel] in the current thread/interpreter. For already existing channels, the command does nothing, i.e. it is not an error to attach the same channel more than once. The first operation will actually perform the operation, while all subsequent operation will just do nothing. Command throws error if the [arg channel] cannot be found in the list of detached channels and/or in the current interpreter. [call [cmd thread::mutex]] Mutexes are most common thread synchronization primitives. They are used to synchronize access from two or more threads to one or more shared resources. This command provides script-level access to exclusive and/or recursive mutexes. Exclusive mutexes can be locked only once by one thread, while recursive mutexes can be locked many times by the same thread. For recursive mutexes, number of lock and unlock operations must match, otherwise, the mutex will never be released, which would lead to various deadlock situations. [para] Care has to be taken when using mutexes in an multithreading program. Improper use of mutexes may lead to various deadlock situations, especially when using exclusive mutexes. [para] The [cmd thread::mutex] command supports following subcommands and options: [list_begin definitions] [call [cmd thread::mutex] [method create] [opt -recursive]] Creates the mutex and returns it's opaque handle. This handle should be used for any future reference to the newly created mutex. If no optional [opt -recursive] argument was specified, the command creates the exclusive mutex. With the [opt -recursive] argument, the command creates a recursive mutex. [call [cmd thread::mutex] [method destroy] [arg mutex]] Destroys the [arg mutex]. Mutex should be in unlocked state before the destroy attempt. If the mutex is locked, the command will throw Tcl error. [call [cmd thread::mutex] [method lock] [arg mutex]] Locks the [arg mutex]. Locking the exclusive mutex may throw Tcl error if on attempt to lock the same mutex twice from the same thread. If your program logic forces you to lock the same mutex twice or more from the same thread (this may happen in recursive procedure invocations) you should consider using the recursive mutexes. [call [cmd thread::mutex] [method unlock] [arg mutex]] Unlocks the [arg mutex] so some other thread may lock it again. Attempt to unlock the already unlocked mutex will throw Tcl error. [list_end] [para] [call [cmd thread::rwmutex]] This command creates many-readers/single-writer mutexes. Reader/writer mutexes allow you to serialize access to a shared resource more optimally. In situations where a shared resource gets mostly read and seldom modified, you might gain some performance by using reader/writer mutexes instead of exclusive or recursive mutexes. [para] For reading the resource, thread should obtain a read lock on the resource. Read lock is non-exclusive, meaning that more than one thread can obtain a read lock to the same resource, without waiting on other readers. For changing the resource, however, a thread must obtain a exclusive write lock. This lock effectively blocks all threads from gaining the read-lock while the resource is been modified by the writer thread. Only after the write lock has been released, the resource may be read-locked again. [para] The [cmd thread::rwmutex] command supports following subcommands and options: [list_begin definitions] [call [cmd thread::rwmutex] [method create]] Creates the reader/writer mutex and returns it's opaque handle. This handle should be used for any future reference to the newly created mutex. [call [cmd thread::rwmutex] [method destroy] [arg mutex]] Destroys the reader/writer [arg mutex]. If the mutex is already locked, attempt to destroy it will throw Tcl error. |
︙ | ︙ | |||
505 506 507 508 509 510 511 | [list_end] [para] [call [cmd thread::cond]] This command provides script-level access to condition variables. | | | | | | | | | | | | | | 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 | [list_end] [para] [call [cmd thread::cond]] This command provides script-level access to condition variables. A condition variable creates a safe environment for the program to test some condition, sleep on it when false and be awakened when it might have become true. A condition variable is always used in the conjunction with an exclusive mutex. If you attempt to use other type of mutex in conjunction with the condition variable, a Tcl error will be thrown. [para] The command supports following subcommands and options: [list_begin definitions] [call [cmd thread::cond] [method create]] Creates the condition variable and returns it's opaque handle. This handle should be used for any future reference to newly created condition variable. [call [cmd thread::cond] [method destroy] [arg cond]] Destroys condition variable [arg cond]. Extreme care has to be taken that nobody is using (i.e. waiting on) the condition variable, otherwise unexpected errors may happen. [call [cmd thread::cond] [method notify] [arg cond]] Wakes up all threads waiting on the condition variable [arg cond]. [call [cmd thread::cond] [method wait] [arg cond] [arg mutex] [opt ms]] This command is used to suspend program execution until the condition variable [arg cond] has been signalled or the optional timer has expired. The exclusive [arg mutex] must be locked by the calling thread on entrance to this command. If the mutex is not locked, Tcl error is thrown. While waiting on the [arg cond], the command releases [arg mutex]. Before returning to the calling thread, the command re-acquires the [arg mutex] again. Unlocking the [arg mutex] and waiting on the condition variable [arg cond] is done atomically. [para] The [option ms] command option, if given, must be an integer specifying time interval in milliseconds the command waits to be signalled. Otherwise the command waits on condition notify forever. [para] In multithreading programs, there are many situations where a thread has to wait for some event to happen until it is allowed to proceed. This is usually accomplished by repeatedly testing a condition under the |
︙ | ︙ | |||
571 572 573 574 575 576 577 | while {<some_condition_is_true>} { thread::cond wait $cond $mutex } # Do some work under mutex protection thread::mutex unlock $mutex }] | | | | | | | | 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | while {<some_condition_is_true>} { thread::cond wait $cond $mutex } # Do some work under mutex protection thread::mutex unlock $mutex }] Repeated testing of the condition is needed since the condition variable may get signalled without the condition being actually changed (spurious thread wake-ups, for example). [list_end] [list_end] [section DISCUSSION] The fundamental threading model in Tcl is that there can be one or more Tcl interpreters per thread, but each Tcl interpreter should only be used by a single thread which created it. A "shared memory" abstraction is awkward to provide in Tcl because Tcl makes assumptions about variable and data ownership. Therefore this extension supports a simple form of threading where the main thread can manage several background, or "worker" threads. For example, an event-driven server can pass requests to worker threads, and then await responses from worker threads or new client requests. Everything goes through the common Tcl event loop, so message passing between threads works naturally with event-driven I/O, [cmd vwait] on variables, and so forth. For the transfer of bulk information it is possible to move channels between the threads. [para] For advanced multithreading scripts, script-level access to two basic synchronization primitives, mutex and condition variables, |
︙ | ︙ |
Changes to doc/tpool.man.
1 2 3 4 5 6 7 8 9 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin tpool n 2.8] [moddesc {Tcl Threading}] [titledesc {Part of the Tcl threading extension implementing pools of worker threads.}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] This package creates and manages pools of worker threads. It allows you | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin tpool n 2.8] [moddesc {Tcl Threading}] [titledesc {Part of the Tcl threading extension implementing pools of worker threads.}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] This package creates and manages pools of worker threads. It allows you to post jobs to worker threads and wait for their completion. The threadpool implementation is Tcl event-loop aware. That means that any time a caller is forced to wait for an event (job being completed or a worker thread becoming idle or initialized), the implementation will enter the event loop and allow for servicing of other pending file or timer (or any other supported) events. [section COMMANDS] [list_begin definitions] |
︙ | ︙ | |||
30 31 32 33 34 35 36 | [opt_def -minworkers [arg number]] Minimum number of worker threads needed for this threadpool instance. During threadpool creation, the implementation will create somany worker threads upfront and will keep at least number of them alive during the lifetime of the threadpool instance. Default value of this parameter is 0 (zero). which means that a newly | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | [opt_def -minworkers [arg number]] Minimum number of worker threads needed for this threadpool instance. During threadpool creation, the implementation will create somany worker threads upfront and will keep at least number of them alive during the lifetime of the threadpool instance. Default value of this parameter is 0 (zero). which means that a newly threadpool will have no worker threads initially. All worker threads will be started on demand by callers running [cmd tpool::post] command and posting jobs to the job queue. [opt_def -maxworkers [arg number]] Maximum number of worker threads allowed for this threadpool instance. If a new job is pending and there are no idle worker threads available, the implementation will try to create new worker thread. If the number of available worker threads is lower than the given number, new worker thread will start. The caller will automatically enter the event loop and wait until the worker thread has initialized. If. however, the number of available worker threads is equal to the given number, the caller will enter the event loop and wait for the first worker thread to get idle, thus ready to run the job. Default value of this parameter is 4 (four), which means that the threadpool instance will allow maximum of 4 worker threads running jobs or being idle waiting for new jobs to get posted to the job queue. [opt_def -idletime [arg seconds]] Time in seconds an idle worker thread waits for the job to get posted to the job queue. If no job arrives during this interval and the time expires, the worker thread will check the number of currently available worker threads and if the number is higher than the number set by the [option minthreads] option, it will exit. If an [option exitscript] has been defined, the exiting worker thread will first run the script and then exit. Errors from the exit script, if any, are ignored. [para] The idle worker thread is not servicing the event loop. If you, however, put the worker thread into the event loop, by evaluating the [cmd vwait] or other related Tcl commands, the worker thread will not be in the idle state, hence the idle timer will not be taken into account. Default value for this option is unspecified. [opt_def -initcmd [arg script]] Sets a Tcl script used to initialize new worker thread. This is usually used to load packages and commands in the worker, set default variables, create namespaces, and such. If the passed script runs into a Tcl error, the worker will not be created and the initiating command (either the [cmd tpool::create] or [cmd tpool::post]) will throw error. Default value for this option is unspecified, hence, the Tcl interpreter of the worker thread will contain just the initial set of Tcl commands. [opt_def -exitcmd [arg script]] Sets a Tcl script run when the idle worker thread exits. This is normally used to cleanup the state of the worker thread, release reserved resources, cleanup memory and such. Default value for this option is unspecified, thus no Tcl script will run on the worker thread exit. [list_end] [para] [call [cmd tpool::names]] This command returns a list of IDs of threadpools created with the [cmd tpool::create] command. If no threadpools were found, the command will return empty list. [call [cmd tpool::post] [opt -detached] [opt -nowait] [arg tpool] [arg script]] This command sends a [arg script] to the target [arg tpool] threadpool for execution. The script will be executed in the first available idle worker thread. If there are no idle worker threads available, the command will create new one, enter the event loop and service events until the newly created thread is initialized. If the current number of worker threads is equal to the maximum number of worker threads, as defined during the threadpool creation, the command will enter the event loop and service events while waiting for one of the worker threads to become idle. If the optional [opt -nowait] argument is given, the command will not wait for one idle worker. It will just place the job in the pool's job queue and return immediately. [para] The command returns the ID of the posted job. This ID is used for subsequent [cmd tpool::wait], [cmd tpool::get] and [cmd tpool::cancel] commands to wait for and retrieve result of the posted script, or cancel the posted job respectively. If the optional [opt -detached] argument is specified, the command will post a detached job. A detached job can not be cancelled or waited upon and is not identified by the job ID. [para] If the threadpool [arg tpool] is not found in the list of active thread pools, the command will throw error. The error will also be triggered if the newly created worker thread fails to initialize. [call [cmd tpool::wait] [arg tpool] [arg joblist] [opt varname]] This command waits for one or many jobs, whose job IDs are given in the [arg joblist] to get processed by the worker thread(s). If none of the specified jobs are ready, the command will enter the event loop, service events and wait for the first job to get ready. [para] The command returns the list of completed job IDs. If the optional variable [opt varname] is given, it will be set to the list of jobs in the [arg joblist] which are still pending. If the threadpool [arg tpool] is not found in the list of active thread pools, the command will throw error. [call [cmd tpool::cancel] [arg tpool] [arg joblist] [opt varname]] This command cancels the previously posted jobs given by the [arg joblist] to the pool [arg tpool]. Job cancellation succeeds only for job still waiting to be processed. If the job is already being executed by one of the worker threads, the job will not be cancelled. The command returns the list of cancelled job IDs. If the optional variable [opt varname] is given, it will be set to the list of jobs in the [arg joblist] which were not cancelled. If the threadpool [arg tpool] is not found in the list of active thread pools, the command will throw error. [call [cmd tpool::get] [arg tpool] [arg job]] This command retrieves the result of the previously posted [arg job]. Only results of jobs waited upon with the [cmd tpool::wait] command can be retrieved. If the execution of the script resulted in error, the command will throw the error and update the [var errorInfo] and [var errorCode] variables correspondingly. If the pool [arg tpool] is not found in the list of threadpools, the command will throw error. If the job [arg job] is not ready for retrieval, because it is currently being executed by the worker thread, the command will throw error. [call [cmd tpool::preserve] [arg tpool]] Each call to this command increments the reference counter of the threadpool [arg tpool] by one (1). Command returns the value of the reference counter after the increment. By incrementing the reference counter, the caller signalizes that he/she wishes to use the resource for a longer period of time. [call [cmd tpool::release] [arg tpool]] Each call to this command decrements the reference counter of the threadpool [arg tpool] by one (1).Command returns the value of the reference counter after the decrement. When the reference counter reaches zero (0), the threadpool [arg tpool] is marked for termination. You should not reference the threadpool after the [cmd tpool::release] command returns zero. The [arg tpool] handle goes out of scope and should not be used any more. Any following reference to the same threadpool handle will result in Tcl error. [call [cmd tpool::suspend] [arg tpool]] Suspends processing work on this queue. All pool workers are paused but additional work can be added to the pool. Note that adding the additional work will not increase the number of workers dynamically as the pool processing is suspended. Number of workers is maintained to the count that was found prior suspending worker activity. If you need to assure certain number of worker threads, use the [option minworkers] option of the [cmd tpool::create] command. [call [cmd tpool::resume] [arg tpool]] Resume processing work on this queue. All paused (suspended) workers are free to get work from the pool. Note that resuming pool operation will just let already created workers to proceed. It will not create additional worker threads to handle the work posted to the pool's work queue. [list_end] [section DISCUSSION] Threadpool is one of the most common threading paradigm when it comes to server applications handling a large number of relatively small tasks. A very simplistic model for building a server application would be to create a new thread each time a request arrives and service the request in the new thread. One of the disadvantages of this approach is that the overhead of creating a new thread for each request is significant; a server that created a new thread for each request would spend more time and consume more system resources in creating and destroying threads than in processing actual user requests. In addition to the overhead of creating and destroying threads, active threads consume system resources. Creating too many threads can cause the system to run out of memory or trash due to excessive memory consumption. [para] A thread pool offers a solution to both the problem of thread life-cycle overhead and the problem of resource trashing. By reusing threads for multiple tasks, the thread-creation overhead is spread over many tasks. As a bonus, because the thread already exists when a request arrives, the delay introduced by thread creation is eliminated. Thus, the request can be serviced immediately. Furthermore, by properly tuning the number of threads in the thread pool, resource thrashing may also be eliminated by forcing any request to wait until a thread is available to process it. [see_also tsv ttrace thread] [keywords thread threadpool] [manpage_end] |
Changes to doc/tsv.man.
1 2 3 4 5 6 7 8 9 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin tsv n 2.8] [moddesc {Tcl Threading}] [titledesc {Part of the Tcl threading extension allowing script level manipulation of data shared between threads.}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] This section describes commands implementing thread shared variables. | | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin tsv n 2.8] [moddesc {Tcl Threading}] [titledesc {Part of the Tcl threading extension allowing script level manipulation of data shared between threads.}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] This section describes commands implementing thread shared variables. A thread shared variable is very similar to a Tcl array but in contrast to a Tcl array it is created in shared memory and can be accessed from many threads at the same time. Important feature of thread shared variable is that each access to the variable is internally protected by a mutex so script programmer does not have to take care about locking the variable himself. [para] Thread shared variables are not bound to any thread explicitly. That means that when a thread which created any of thread shared variables exits, the variable and associated memory is not unset/reclaimed. User has to explicitly unset the variable to reclaim the memory consumed by the variable. [section {ELEMENT COMMANDS}] [list_begin definitions] [call [cmd tsv::names] [opt pattern]] Returns names of shared variables matching optional [opt pattern] or all known variables if pattern is omitted. [call [cmd tsv::object] [arg varname] [arg element]] Creates object accessor command for the [arg element] in the shared variable [arg varname]. Using this command, one can apply most of the other shared variable commands as method functions of the element object command. The object command is automatically deleted when the element which this command is pointing to is unset. [example { % tsv::set foo bar "A shared string" % set string [tsv::object foo bar] % $string append " appended" => A shared string appended }] [call [cmd tsv::set] [arg varname] [arg element] [opt value]] Sets the value of the [arg element] in the shared variable [arg varname] to [arg value] and returns the value to caller. The [arg value] may be omitted, in which case the command will return the current value of the element. If the element cannot be found, error is triggered. [call [cmd tsv::get] [arg varname] [arg element] [opt namedvar]] Retrieves the value of the [arg element] from the shared variable [arg varname]. If the optional argument [arg namedvar] is given, the value is stored in the named variable. Return value of the command depends of the existence of the optional argument [arg namedvar]. If the argument is omitted and the requested element cannot be found in the shared array, the command triggers error. If, however, the optional argument is given on the command line, the command returns true (1) if the element is found or false (0) if the element is not found. [call [cmd tsv::unset] [arg varname] [opt element]] Unsets the [arg element] from the shared variable [arg varname]. If the optional element is not given, it deletes the variable. [call [cmd tsv::exists] [arg varname] [arg element]] Checks whether the [arg element] exists in the shared variable [arg varname] and returns true (1) if it does or false (0) if it doesn't. [call [cmd tsv::pop] [arg varname] [arg element]] Returns value of the [arg element] in the shared variable [arg varname] and unsets the element, all in one atomic operation. [call [cmd tsv::move] [arg varname] [arg oldname] [arg newname]] Renames the element [arg oldname] to the [arg newname] in the shared variable [arg varname]. This effectively performs an get/unset/set sequence of operations but all in one atomic step. [call [cmd tsv::incr] [arg varname] [arg element] [opt count]] Similar to standard Tcl [cmd incr] command but increments the value of the [arg element] in shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::append] [arg varname] [arg element] [arg value] [opt {value ...}]] Similar to standard Tcl [cmd append] command but appends one or more values to the [arg element] in shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::lock] [arg varname] [arg arg] [opt {arg ...}]] This command concatenates passed arguments and evaluates the resulting script under the internal mutex protection. During the script evaluation, the entire shared variable is locked. For shared |
︙ | ︙ | |||
127 128 129 130 131 132 133 | is that they operate on elements of shared arrays. [list_begin definitions] [call [cmd tsv::lappend] [arg varname] [arg element] [arg value] [opt {value ...}]] Similar to standard Tcl [cmd lappend] command but appends one | | | | | | | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | is that they operate on elements of shared arrays. [list_begin definitions] [call [cmd tsv::lappend] [arg varname] [arg element] [arg value] [opt {value ...}]] Similar to standard Tcl [cmd lappend] command but appends one or more values to the [arg element] in shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::linsert] [arg varname] [arg element] [arg index] [arg value] [opt {value ...}]] Similar to standard Tcl [cmd linsert] command but inserts one or more values at the [arg index] list position in the [arg element] in the shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::lreplace] [arg varname] [arg element] [arg first] [arg last] [opt {value ...}]] Similar to standard Tcl [cmd lreplace] command but replaces one or more values between the [arg first] and [arg last] position in the [arg element] of the shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::llength] [arg varname] [arg element]] Similar to standard Tcl [cmd llength] command but returns length of the [arg element] in the shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::lindex] [arg varname] [arg element] [opt index]] Similar to standard Tcl [cmd lindex] command but returns the value at the [arg index] list position of the [arg element] from |
︙ | ︙ | |||
175 176 177 178 179 180 181 | Similar to standard Tcl [cmd lset] command but sets the [arg element] in the shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::lpop] [arg varname] [arg element] [opt index]] Similar to the standard Tcl [cmd lindex] command but in addition to returning, it also splices the value out of the [arg element] | | | | | | 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | Similar to standard Tcl [cmd lset] command but sets the [arg element] in the shared variable [arg varname] instead of the Tcl variable. [call [cmd tsv::lpop] [arg varname] [arg element] [opt index]] Similar to the standard Tcl [cmd lindex] command but in addition to returning, it also splices the value out of the [arg element] from the shared variable [arg varname] in one atomic operation. In contrast to the Tcl [cmd lindex] command, this command returns no value to the caller. [call [cmd tsv::lpush] [arg varname] [arg element] [opt index]] This command performs the opposite of the [cmd tsv::lpop] command. As its counterpart, it returns no value to the caller. [list_end] [section {ARRAY COMMANDS}] This command supports most of the options of the standard Tcl [cmd array] command. In addition to those, it allows binding a shared variable to some persistent storage databases. Currently the persistent options supported are the famous GNU Gdbm and LMDB. These options have to be selected during the package compilation time. The implementation provides hooks for defining other persistency layers, if needed. [list_begin definitions] |
︙ | ︙ | |||
229 230 231 232 233 234 235 | "gdbm" for GNU Gdbm and "lmdb" for LMDB and <address> is the path to the database file. [call [cmd {tsv::array unbind}] [arg varname]] Unbinds the shared [arg array] from its bound persistent storage. [call [cmd {tsv::array isbound}] [arg varname]] | | | | | | | | | | | | | | | | | | | | | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 | "gdbm" for GNU Gdbm and "lmdb" for LMDB and <address> is the path to the database file. [call [cmd {tsv::array unbind}] [arg varname]] Unbinds the shared [arg array] from its bound persistent storage. [call [cmd {tsv::array isbound}] [arg varname]] Returns true (1) if the shared [arg varname] is bound to some persistent storage or zero (0) if not. [list_end] [section {KEYED LIST COMMANDS}] Keyed list commands are borrowed from the TclX package. Keyed lists provide a structured data type built upon standard Tcl lists. This is a functionality similar to structs in the C programming language. [para] A keyed list is a list in which each element contains a key and value pair. These element pairs are stored as lists themselves, where the key is the first element of the list, and the value is the second. The key-value pairs are referred to as fields. This is an example of a keyed list: [example { {{NAME {Frank Zappa}} {JOB {musician and composer}}} }] Fields may contain subfields; `.' is the separator character. Subfields are actually fields where the value is another keyed list. Thus the following list has the top level fields ID and NAME, and subfields NAME.FIRST and NAME.LAST: [example { {ID 106} {NAME {{FIRST Frank} {LAST Zappa}}} }] There is no limit to the recursive depth of subfields, allowing one to build complex data structures. Keyed lists are constructed and accessed via a number of commands. All keyed list management commands take the name of the variable containing the keyed list as an argument (i.e. passed by reference), rather than passing the list directly. [list_begin definitions] [call [cmd tsv::keyldel] [arg varname] [arg keylist] [arg key]] Delete the field specified by [arg key] from the keyed list [arg keylist] in the shared variable [arg varname]. This removes both the key and the value from the keyed list. [call [cmd tsv::keylget] [arg varname] [arg keylist] [arg key] [opt retvar]] Return the value associated with [arg key] from the keyed list [arg keylist] in the shared variable [arg varname]. If the optional [arg retvar] is not specified, then the value will be returned as the result of the command. In this case, if key is not found in the list, an error will result. [para] If [arg retvar] is specified and [arg key] is in the list, then the value is returned in the variable [arg retvar] and the command returns 1 if the key was present within the list. If [arg key] isn't in the list, the command will return 0, and [arg retvar] will be left unchanged. If {} is specified for [arg retvar], the value is not returned, allowing the Tcl programmer to determine if a [arg key] is present in a keyed list without setting a variable as a side-effect. [call [cmd tsv::keylkeys] [arg varname] [arg keylist] [opt key]] Return the a list of the keys in the keyed list [arg keylist] in the shared variable [arg varname]. If [arg key] is specified, then it is the name of a key field whose subfield keys are to be retrieved. [call [cmd tsv::keylset] [arg varname] [arg keylist] [arg key] [arg value] [opt {key value..}]] Set the value associated with [arg key], in the keyed list [arg keylist] to [arg value]. If the [arg keylist] does not exists, it is created. If [arg key] is not currently in the list, it will be added. If it already exists, [arg value] replaces the existing value. Multiple keywords and values may be specified, if desired. [list_end] [section DISCUSSION] The current implementation of thread shared variables allows for easy and convenient access to data shared between different threads. Internally, the data is stored in Tcl objects and all package commands operate on internal data representation, thus minimizing shimmering and improving performance. Special care has been taken to assure that all object data is properly locked and deep-copied when moving objects between threads. [para] Due to the internal design of the Tcl core, there is no provision of full integration of shared variables within the Tcl syntax, unfortunately. All access to shared data must be performed with the supplied package commands. Also, variable traces are not supported. But even so, benefits of easy, simple and safe shared data manipulation outweighs imposed limitations. [section CREDITS] Thread shared variables are inspired by the nsv interface found in AOLserver, a highly scalable Web server from America Online. [see_also tpool ttrace thread] [keywords threads synchronization locking {thread shared data}] [manpage_end] |
Changes to doc/ttrace.man.
1 2 3 4 5 6 7 8 9 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin ttrace n 2.8] [moddesc {Tcl Threading}] [titledesc {Trace-based interpreter initialization}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] This package creates a framework for on-demand replication of the | | | | | | | | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | [comment {-*- tcl -*- doctools manpage}] [manpage_begin ttrace n 2.8] [moddesc {Tcl Threading}] [titledesc {Trace-based interpreter initialization}] [require Tcl 8.4] [require Thread [opt 2.8]] [description] This package creates a framework for on-demand replication of the interpreter state across threads in an multithreading application. It relies on the mechanics of Tcl command tracing and the Tcl [cmd unknown] command and mechanism. [para] The package requires Tcl threading extension but can be alternatively used stand-alone within the AOLserver, a scalable webserver from America Online. [para] In a nutshell, a short sample illustrating the usage of the ttrace with the Tcl threading extension: [example { % package require Ttrace 2.8.2 % set t1 [thread::create {package require Ttrace; thread::wait}] tid0x1802800 % ttrace::eval {proc test args {return test-[thread::id]}} % thread::send $t1 test test-tid0x1802800 % set t2 [thread::create {package require Ttrace; thread::wait}] tid0x1804000 % thread::send $t2 test test-tid0x1804000 }] [para] As seen from above, the [cmd ttrace::eval] and [cmd ttrace::update] commands are used to create a thread-wide definition of a simple Tcl procedure and replicate that definition to all, already existing or later created, threads. [section {USER COMMANDS}] This section describes user-level commands. Those commands can be used by script writers to control the execution of the tracing framework. [list_begin definitions] [call [cmd ttrace::eval] [arg arg] [opt {arg ...}]] This command concatenates given arguments and evaluates the resulting Tcl command with trace framework enabled. If the command execution was ok, it takes necessary steps to automatically propagate the trace epoch change to all threads in the application. For AOLserver, only newly created threads actually receive the epoch change. For the Tcl threading extension, all threads created by the extension are automatically updated. If the command execution resulted in Tcl error, no state propagation takes place. [para] This is the most important user-level command of the package as it wraps most of the commands described below. This greatly simplifies things, because user need to learn just this (one) command in order to effectively use the package. Other commands, as described below, are included mostly for the sake of completeness. [call [cmd ttrace::enable]] Activates all registered callbacks in the framework and starts a new trace epoch. The trace epoch encapsulates all changes done to the interpreter during the time traces are activated. [call [cmd ttrace::disable]] Deactivates all registered callbacks in the framework and closes the current trace epoch. [call [cmd ttrace::cleanup]] Used to clean-up all on-demand loaded resources in the interpreter. It effectively brings Tcl interpreter to its pristine state. [call [cmd ttrace::update] [opt epoch]] Used to refresh the state of the interpreter to match the optional trace [opt epoch]. If the optional [opt epoch] is not given, it takes the most recent trace epoch. [call [cmd ttrace::getscript]] Returns a synthesized Tcl script which may be sourced in any interpreter. This script sets the stage for the Tcl [cmd unknown] command so it can load traced resources from the in-memory database. Normally, this command is automatically invoked by other higher-level commands like [cmd ttrace::eval] and [cmd ttrace::update]. [list_end] [section {CALLBACK COMMANDS}] A word upfront: the package already includes callbacks for tracing following Tcl commands: [cmd proc], [cmd namespace], [cmd variable], [cmd load], and [cmd rename]. Additionally, a set of callbacks for tracing resources (object, classes) for the XOTcl v1.3.8+, an OO-extension to Tcl, is also provided. This gives a solid base for solving most of the real-life needs and serves as an example for people wanting to customize the package to cover their specific needs. [para] Below, you can find commands for registering callbacks in the framework and for writing callback scripts. These callbacks are invoked by the framework in order to gather interpreter state changes, build in-memory database, perform custom-cleanups and various other tasks. |
︙ | ︙ | |||
136 137 138 139 140 141 142 | of callback arguments, [arg arglist] and the [arg body] of the callback. Effectively, this actually resembles the call interface of the standard Tcl [cmd proc] command. [call [cmd ttrace::addtrace] [arg cmd] [arg arglist] [arg body]] | | | | | | | | | | | | | | | | | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | of callback arguments, [arg arglist] and the [arg body] of the callback. Effectively, this actually resembles the call interface of the standard Tcl [cmd proc] command. [call [cmd ttrace::addtrace] [arg cmd] [arg arglist] [arg body]] Registers Tcl callback to be activated for tracing the Tcl [cmd cmd] command. The callback definition includes the name of the Tcl command to trace, [arg cmd], a list of callback arguments, [arg arglist] and the [arg body] of the callback. Effectively, this actually resembles the call interface of the standard Tcl [cmd proc] command. [call [cmd ttrace::addscript] [arg name] [arg body]] Registers Tcl callback to be activated for building a Tcl script to be passed to other interpreters. This script is used to set the stage for the Tcl [cmd unknown] command. Registered callbacks are activated on FIFO basis. The callback definition includes the name of the callback, [arg name] and the [arg body] of the callback. [call [cmd ttrace::addresolver] [arg cmd] [arg arglist] [arg body]] Registers Tcl callback to be activated by the overloaded Tcl [cmd unknown] command. Registered callbacks are activated on FIFO basis. This callback is used to resolve the resource and load the resource in the current interpreter. [call [cmd ttrace::addcleanup] [arg body]] Registers Tcl callback to be activated by the [cmd trace::cleanup]. Registered callbacks are activated on FIFO basis. [call [cmd ttrace::addentry] [arg cmd] [arg var] [arg val]] Adds one entry to the named in-memory database. [call [cmd ttrace::getentry] [arg cmd] [arg var]] Returns the value of the entry from the named in-memory database. [call [cmd ttrace::getentries] [arg cmd] [opt pattern]] Returns names of all entries from the named in-memory database. [call [cmd ttrace::delentry] [arg cmd]] Deletes an entry from the named in-memory database. [call [cmd ttrace::preload] [arg cmd]] Registers the Tcl command to be loaded in the interpreter. Commands registered this way will always be the part of the interpreter and not be on-demand loaded by the Tcl [cmd unknown] command. [list_end] [section DISCUSSION] Common introspective state-replication approaches use a custom Tcl script to introspect the running interpreter and synthesize another Tcl script to replicate this state in some other interpreter. This package, on the contrary, uses Tcl command traces. Command traces are registered on selected Tcl commands, like [cmd proc], [cmd namespace], [cmd load] and other standard (and/or user-defined) Tcl commands. When activated, those traces build an in-memory database of created resources. This database is used as a resource repository for the (overloaded) Tcl [cmd unknown] command which creates the requested resource in the interpreter on demand. This way, users can update just one interpreter (master) in one thread and replicate that interpreter state (or part of it) to other threads/interpreters in the process. [para] Immediate benefit of such approach is the much smaller memory footprint of the application and much faster thread creation. By not actually loading all necessary procedures (and other resources) in every thread at the thread initialization time, but by deferring this to the time the resource is actually referenced, significant improvements in both memory consumption and thread initialization time can be achieved. Some tests have shown that memory footprint of an multithreading Tcl application went down more than three times and thread startup time was reduced for about 50 times. Note that your mileage may vary. Other benefits include much finer control about what (and when) gets replicated from the master to other Tcl thread/interpreters. [see_also tsv tpool thread] [keywords {command tracing} introspection] [manpage_end] |
Changes to generic/psLmdb.c.
︙ | ︙ | |||
154 155 156 157 158 159 160 | ps_lmdb_open( const char *path) { LmdbCtx ctx; char *ext; Tcl_DString toext; | | | 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | ps_lmdb_open( const char *path) { LmdbCtx ctx; char *ext; Tcl_DString toext; ctx = ckalloc(sizeof(*ctx)); if (ctx == NULL) { return NULL; } ctx->env = NULL; |
︙ | ︙ |
Changes to generic/tclThreadInt.h.
︙ | ︙ | |||
133 134 135 136 137 138 139 | typedef struct { void *unused1; void *unused2; int errorLine; } tclInterpType; | | < | > | | > | | | > | < | < | | | | < | | < | > > | > > > | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | typedef struct { void *unused1; void *unused2; int errorLine; } tclInterpType; #if defined(TCL_TIP285) && defined(USE_TCL_STUBS) # undef Tcl_GetErrorLine # define Tcl_GetErrorLine(interp) ((threadTclVersion>85)? \ ((int (*)(Tcl_Interp *))((&(tclStubsPtr->tcl_PkgProvideEx))[605]))(interp): \ (((tclInterpType *)(interp))->errorLine)) /* TIP #270 */ # undef Tcl_AddErrorInfo # define Tcl_AddErrorInfo(interp, msg) ((threadTclVersion>85)? \ ((void (*)(Tcl_Interp *, Tcl_Obj *))((&(tclStubsPtr->tcl_PkgProvideEx))[574]))(interp, Tcl_NewStringObj(msg, -1)): \ ((void (*)(Tcl_Interp *, const char *))((&(tclStubsPtr->tcl_PkgProvideEx))[66]))(interp, msg)) /* TIP #337 */ # undef Tcl_BackgroundError # define Tcl_BackgroundError(interp) ((threadTclVersion>85)? \ ((void (*)(Tcl_Interp *, int))((&(tclStubsPtr->tcl_PkgProvideEx))[609]))(interp, TCL_ERROR): \ ((void (*)(Tcl_Interp *))((&(tclStubsPtr->tcl_PkgProvideEx))[76]))(interp)) #elif !TCL_MINIMUM_VERSION(8,6) /* 8.5, 8.4, or less - Emulate access to the error-line information */ # define Tcl_GetErrorLine(interp) (((tclInterpType *)(interp))->errorLine) #endif /* When running on Tcl >= 8.7, make sure that Thread still runs when Tcl is compiled * with -DTCL_NO_DEPRECATED=1. Stub entries for Tcl_SetIntObj/Tcl_NewIntObj are NULL then. * Just use Tcl_SetWideIntObj/Tcl_NewWideIntObj in stead. We don't simply want to use * Tcl_SetWideIntObj/Tcl_NewWideIntObj always, since extensions might not expect to * get an actual "wideInt". */ #if defined(USE_TCL_STUBS) # undef Tcl_SetIntObj # define Tcl_SetIntObj(objPtr, value) ((threadTclVersion>86)? \ ((void (*)(Tcl_Obj *, Tcl_WideInt))((&(tclStubsPtr->tcl_PkgProvideEx))[489]))(objPtr, (int)(value)): \ ((void (*)(Tcl_Obj *, int))((&(tclStubsPtr->tcl_PkgProvideEx))[61]))(objPtr, value)) # undef Tcl_NewIntObj # define Tcl_NewIntObj(value) ((threadTclVersion>86)? \ ((Tcl_Obj * (*)(Tcl_WideInt))((&(tclStubsPtr->tcl_PkgProvideEx))[488]))((int)(value)): \ ((Tcl_Obj * (*)(int))((&(tclStubsPtr->tcl_PkgProvideEx))[52]))(value)) #endif #endif /* _TCL_THREAD_INT_H_ */ |
Changes to generic/tclXkeylist.c.
︙ | ︙ | |||
24 25 26 27 28 29 30 31 32 33 34 35 36 37 | * For any questions, contant Zoran Vasiljevic ([email protected]) *----------------------------------------------------------------------------- */ #include "tclThreadInt.h" #include "threadSvCmd.h" #include "tclXkeylist.h" #ifdef STATIC_BUILD #if TCL_MAJOR_VERSION >= 9 /* * Static build, Tcl >= 9, compile-time decision to disable T_ROT calls. */ #undef Tcl_RegisterObjType | > | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | * For any questions, contant Zoran Vasiljevic ([email protected]) *----------------------------------------------------------------------------- */ #include "tclThreadInt.h" #include "threadSvCmd.h" #include "tclXkeylist.h" #include <stdarg.h> #ifdef STATIC_BUILD #if TCL_MAJOR_VERSION >= 9 /* * Static build, Tcl >= 9, compile-time decision to disable T_ROT calls. */ #undef Tcl_RegisterObjType |
︙ | ︙ | |||
71 72 73 74 75 76 77 | # define TclX_Assert(expr) ((expr) ? (void)0 : \ panic("TclX assertion failure: %s:%d \"%s\"\n",\ __FILE__, __LINE__, "expr")) #else # define TclX_Assert(expr) #endif | < < < | 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | # define TclX_Assert(expr) ((expr) ? (void)0 : \ panic("TclX assertion failure: %s:%d \"%s\"\n",\ __FILE__, __LINE__, "expr")) #else # define TclX_Assert(expr) #endif /* * Macro that behaves like strdup, only uses ckalloc. Also macro that does the * same with a string that might contain zero bytes, */ #define ckstrdup(sourceStr) \ (strcpy (ckalloc (strlen (sourceStr) + 1), sourceStr)) |
︙ | ︙ | |||
101 102 103 104 105 106 107 | * * Check if an object is {}, either in list or zero-lemngth string form, with * out forcing a conversion. * * Parameters: * o objPtr - Object to check. * Returns: | | | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | * * Check if an object is {}, either in list or zero-lemngth string form, with * out forcing a conversion. * * Parameters: * o objPtr - Object to check. * Returns: * 1 if NULL, 0 if not. *----------------------------------------------------------------------------- */ static int TclX_IsNullObj (objPtr) Tcl_Obj *objPtr; { if (objPtr->typePtr == NULL) { |
︙ | ︙ | |||
359 360 361 362 363 364 365 | { int idx; TclX_Assert (keylIntPtr->arraySize >= keylIntPtr->numEntries); TclX_Assert (keylIntPtr->arraySize >= 0); TclX_Assert (keylIntPtr->numEntries >= 0); TclX_Assert ((keylIntPtr->arraySize > 0) ? | | | | | 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 | { int idx; TclX_Assert (keylIntPtr->arraySize >= keylIntPtr->numEntries); TclX_Assert (keylIntPtr->arraySize >= 0); TclX_Assert (keylIntPtr->numEntries >= 0); TclX_Assert ((keylIntPtr->arraySize > 0) ? (keylIntPtr->entries != NULL) : 1); TclX_Assert ((keylIntPtr->numEntries > 0) ? (keylIntPtr->entries != NULL) : 1); for (idx = 0; idx < keylIntPtr->numEntries; idx++) { keylEntry_t *entryPtr = &(keylIntPtr->entries [idx]); TclX_Assert (entryPtr->key != NULL); TclX_Assert (entryPtr->valuePtr->refCount >= 1); if (entryPtr->valuePtr->typePtr == &keyedListType) { ValidateKeyedList (entryPtr->valuePtr->internalRep.twoPtrValue.ptr1); } } } #endif /*----------------------------------------------------------------------------- * ValidateKey -- * Check that a key or keypath string is a valid value. * * Parameters: * o interp - Used to return error messages. * o key - Key string to check. * o keyLen - Length of the string, used to check for binary data. * o isPath - 1 if this is a key path, 0 if its a simple key and * thus "." is illegal. * Returns: * TCL_OK or TCL_ERROR. *----------------------------------------------------------------------------- */ static int ValidateKey(interp, key, keyLen, isPath) |
︙ | ︙ | |||
631 632 633 634 635 636 637 | "element list, found \"", Tcl_GetString(objPtr), "\"", (char *) NULL); return TCL_ERROR; } key = Tcl_GetString(objv[0]); | | | 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 | "element list, found \"", Tcl_GetString(objPtr), "\"", (char *) NULL); return TCL_ERROR; } key = Tcl_GetString(objv[0]); if (ValidateKey(interp, key, objv[0]->length, 0) == TCL_ERROR) { return TCL_ERROR; } entryPtr->key = ckstrdup(key); entryPtr->valuePtr = Tcl_DuplicateObj(objv [1]); Tcl_IncrRefCount(entryPtr->valuePtr); |
︙ | ︙ | |||
1205 1206 1207 1208 1209 1210 1211 | return TCL_ERROR; } /* * Handle retrieving a value for a specified key. */ key = Tcl_GetString(objv[2]); | | | | 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 | return TCL_ERROR; } /* * Handle retrieving a value for a specified key. */ key = Tcl_GetString(objv[2]); if (ValidateKey(interp, key, objv[2]->length, 1) == TCL_ERROR) { return TCL_ERROR; } status = TclX_KeyedListGet (interp, keylPtr, key, &valuePtr); if (status == TCL_ERROR) return TCL_ERROR; /* * Handle key not found. */ if (status == TCL_BREAK) { if (objc == 3) { TclX_AppendObjResult (interp, "key \"", key, "\" not found in keyed list", (char *) NULL); return TCL_ERROR; } else { Tcl_ResetResult(interp); Tcl_SetIntObj(Tcl_GetObjResult (interp), 0); return TCL_OK; } } /* * No variable specified, so return value in the result. */ |
︙ | ︙ | |||
1246 1247 1248 1249 1250 1251 1252 | */ if (!TclX_IsNullObj(objv [3])) { if (Tcl_ObjSetVar2(interp, objv[3], NULL, valuePtr, TCL_LEAVE_ERR_MSG) == NULL) return TCL_ERROR; } Tcl_ResetResult(interp); | | | 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 | */ if (!TclX_IsNullObj(objv [3])) { if (Tcl_ObjSetVar2(interp, objv[3], NULL, valuePtr, TCL_LEAVE_ERR_MSG) == NULL) return TCL_ERROR; } Tcl_ResetResult(interp); Tcl_SetIntObj(Tcl_GetObjResult (interp), 1); return TCL_OK; } /*----------------------------------------------------------------------------- * Tcl_KeylsetObjCmd -- * Implements the TCL keylset command: * keylset listvar key value ?key value...? |
︙ | ︙ | |||
1291 1292 1293 1294 1295 1296 1297 | newVarObj = keylVarPtr; } else { newVarObj = NULL; } for (idx = 2; idx < objc; idx += 2) { key = Tcl_GetString(objv[idx]); | | | 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 | newVarObj = keylVarPtr; } else { newVarObj = NULL; } for (idx = 2; idx < objc; idx += 2) { key = Tcl_GetString(objv[idx]); if (ValidateKey(interp, key, objv[idx]->length, 1) == TCL_ERROR) { goto errorExit; } if (TclX_KeyedListSet (interp, keylVarPtr, key, objv [idx+1]) != TCL_OK) { goto errorExit; } } |
︙ | ︙ | |||
1357 1358 1359 1360 1361 1362 1363 | Tcl_DecrRefCount (keylPtr); } } keylPtr = keylVarPtr; for (idx = 2; idx < objc; idx++) { key = Tcl_GetString(objv[idx]); | | | 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 | Tcl_DecrRefCount (keylPtr); } } keylPtr = keylVarPtr; for (idx = 2; idx < objc; idx++) { key = Tcl_GetString(objv[idx]); if (ValidateKey(interp, key, objv[idx]->length, 1) == TCL_ERROR) { return TCL_ERROR; } status = TclX_KeyedListDelete (interp, keylPtr, key); switch (status) { case TCL_BREAK: TclX_AppendObjResult (interp, "key not found: \"", |
︙ | ︙ | |||
1409 1410 1411 1412 1413 1414 1415 | * If key argument is not specified, then objv [2] is NULL or empty, * meaning get top level keys. */ if (objc < 3) { key = NULL; } else { key = Tcl_GetString(objv[2]); | | | 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 | * If key argument is not specified, then objv [2] is NULL or empty, * meaning get top level keys. */ if (objc < 3) { key = NULL; } else { key = Tcl_GetString(objv[2]); if (ValidateKey(interp, key, objv[2]->length, 1) == TCL_ERROR) { return TCL_ERROR; } } status = TclX_KeyedListGetKeys (interp, keylPtr, key, &listObjPtr); switch (status) { case TCL_BREAK: |
︙ | ︙ |
Changes to generic/threadCmd.c.
︙ | ︙ | |||
23 24 25 26 27 28 29 | /* * Provide package version in build contexts which do not provide * -DPACKAGE_VERSION, like building a shell with the Thread object * files built as part of that shell. Example: basekits. */ #ifndef PACKAGE_VERSION | | | 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /* * Provide package version in build contexts which do not provide * -DPACKAGE_VERSION, like building a shell with the Thread object * files built as part of that shell. Example: basekits. */ #ifndef PACKAGE_VERSION #define PACKAGE_VERSION "2.9a1" #endif /* * Check if this is Tcl 8.5 or higher. In that case, we will have the TIP * #143 APIs (i.e. interpreter resource limiting) available. */ |
︙ | ︙ | |||
431 432 433 434 435 436 437 | #endif static int ThreadInit(interp) Tcl_Interp *interp; /* The current Tcl interpreter */ { if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { | | > > > | > > > | 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | #endif static int ThreadInit(interp) Tcl_Interp *interp; /* The current Tcl interpreter */ { if (Tcl_InitStubs(interp, "8.4", 0) == NULL) { if ((sizeof(size_t) != sizeof(int)) #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 7 && defined(TCL_NO_DEPRECATED) /* As long as Tcl 8.7 is not final, this allows the Thread extension */ /* to be loadable on Tcl 9.0, provided it is compiled against Tcl 8.7+ headers */ || !(Tcl_InitStubs)(interp, "8.4-", (TCL_MAJOR_VERSION<<8)|(TCL_MINOR_VERSION<<16), TCL_STUB_MAGIC) #endif ) { return TCL_ERROR; } Tcl_ResetResult(interp); } if (!threadTclVersion) { |
︙ | ︙ |
Changes to generic/threadPoolCmd.c.
︙ | ︙ | |||
359 360 361 362 363 364 365 366 367 368 369 370 371 372 | detached = 1; } else if (OPT_CMP(opt, "-nowait")) { nowait = 1; } else { goto usage; } } tpoolName = Tcl_GetString(objv[ii]); script = Tcl_GetString(objv[ii+1]); len = objv[ii+1]->length; tpoolPtr = GetTpool(tpoolName); if (tpoolPtr == NULL) { Tcl_AppendResult(interp, "can not find threadpool \"", tpoolName, | > > > > > > > > | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 | detached = 1; } else if (OPT_CMP(opt, "-nowait")) { nowait = 1; } else { goto usage; } } /* * We expect exactly two arguments remaining after options */ if (objc - ii != 2) { goto usage; } tpoolName = Tcl_GetString(objv[ii]); script = Tcl_GetString(objv[ii+1]); len = objv[ii+1]->length; tpoolPtr = GetTpool(tpoolName); if (tpoolPtr == NULL) { Tcl_AppendResult(interp, "can not find threadpool \"", tpoolName, |
︙ | ︙ | |||
619 620 621 622 623 624 625 | char *tpoolName; Tcl_Obj *listVar = NULL; Tcl_Obj *doneList, *waitList, **wObjv; ThreadPool *tpoolPtr; TpoolResult *rPtr; /* | | | 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 | char *tpoolName; Tcl_Obj *listVar = NULL; Tcl_Obj *doneList, *waitList, **wObjv; ThreadPool *tpoolPtr; TpoolResult *rPtr; /* * Syntax: tpool::cancel tpoolId jobIdList ?listVar? */ if (objc < 3 || objc > 4) { Tcl_WrongNumArgs(interp, 1, objv, "tpoolId jobIdList ?listVar"); return TCL_ERROR; } if (objc == 4) { |
︙ | ︙ | |||
1224 1225 1226 1227 1228 1229 1230 | } } else if (tpoolPtr->tearDown) { PushWork(rPtr, tpoolPtr); break; /* Kill worker because pool is going down */ } Tcl_MutexUnlock(&tpoolPtr->mutex); TpoolEval(interp, rPtr->script, rPtr->scriptLen, rPtr); | < > > | 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 | } } else if (tpoolPtr->tearDown) { PushWork(rPtr, tpoolPtr); break; /* Kill worker because pool is going down */ } Tcl_MutexUnlock(&tpoolPtr->mutex); TpoolEval(interp, rPtr->script, rPtr->scriptLen, rPtr); ckfree(rPtr->script); Tcl_MutexLock(&tpoolPtr->mutex); if (!rPtr->detached) { int new; Tcl_SetHashValue(Tcl_CreateHashEntry(&tpoolPtr->jobsDone, (void *)(size_t)rPtr->jobId, &new), (ClientData)rPtr); SignalWaiter(tpoolPtr); } else { ckfree((char*)rPtr); } } /* * Tear down the worker |
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 | SpliceOut(tpoolPtr, tpoolList); InitWaiter(); /* * Signal and wait for all workers to die. */ | < > | 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 | SpliceOut(tpoolPtr, tpoolList); InitWaiter(); /* * Signal and wait for all workers to die. */ Tcl_MutexLock(&tpoolPtr->mutex); tpoolPtr->tearDown = 1; while (tpoolPtr->numWorkers > 0) { PushWaiter(tpoolPtr); Tcl_ConditionNotify(&tpoolPtr->cond); Tcl_MutexUnlock(&tpoolPtr->mutex); tsdPtr->stop = -1; while(tsdPtr->stop == -1) { Tcl_DoOneEvent(TCL_ALL_EVENTS); |
︙ | ︙ |
Changes to generic/threadSvCmd.c.
︙ | ︙ | |||
19 20 21 22 23 24 25 | #include "threadSvListCmd.h" /* Shared variants of list commands */ #include "threadSvKeylistCmd.h" /* Shared variants of list commands */ #include "psGdbm.h" /* The gdbm persistent store implementation */ #include "psLmdb.h" /* The lmdb persistent store implementation */ #define SV_FINALIZE | < < < < < < < < < < < < | 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | #include "threadSvListCmd.h" /* Shared variants of list commands */ #include "threadSvKeylistCmd.h" /* Shared variants of list commands */ #include "psGdbm.h" /* The gdbm persistent store implementation */ #include "psLmdb.h" /* The lmdb persistent store implementation */ #define SV_FINALIZE /* * Number of buckets to spread shared arrays into. Each bucket is * associated with one mutex so locking a bucket locks all arrays * in that bucket as well. The number of buckets should be a prime. */ #define NUMBUCKETS 31 |
︙ | ︙ | |||
55 56 57 58 59 60 61 62 63 64 65 66 67 68 | * Those are referenced read-only, thus no mutex protection. */ static const Tcl_ObjType* booleanObjTypePtr; static const Tcl_ObjType* byteArrayObjTypePtr; static const Tcl_ObjType* doubleObjTypePtr; static const Tcl_ObjType* intObjTypePtr; static const Tcl_ObjType* stringObjTypePtr; /* * In order to be fully stub enabled, a small * hack is needed to query the tclEmptyStringRep * global symbol defined by Tcl. See Sv_Init. */ | > | 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | * Those are referenced read-only, thus no mutex protection. */ static const Tcl_ObjType* booleanObjTypePtr; static const Tcl_ObjType* byteArrayObjTypePtr; static const Tcl_ObjType* doubleObjTypePtr; static const Tcl_ObjType* intObjTypePtr; static const Tcl_ObjType* wideIntObjTypePtr; static const Tcl_ObjType* stringObjTypePtr; /* * In order to be fully stub enabled, a small * hack is needed to query the tclEmptyStringRep * global symbol defined by Tcl. See Sv_Init. */ |
︙ | ︙ | |||
124 125 126 127 128 129 130 | static Array* CreateArray(Bucket*, const char*); static Array* LockArray(Tcl_Interp*, const char*, int); static int ReleaseContainer(Tcl_Interp*, Container*, int); static int DeleteContainer(Container*); static int FlushArray(Array*); | | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | static Array* CreateArray(Bucket*, const char*); static Array* LockArray(Tcl_Interp*, const char*, int); static int ReleaseContainer(Tcl_Interp*, Container*, int); static int DeleteContainer(Container*); static int FlushArray(Array*); static int DeleteArray(Tcl_Interp *, Array*); static void SvAllocateContainers(Bucket*); static void SvRegisterStdCommands(void); #ifdef SV_FINALIZE static void SvFinalizeContainers(Bucket*); static void SvFinalize(ClientData); |
︙ | ︙ | |||
844 845 846 847 848 849 850 | * Side effects: * Memory gets reclaimed. * *----------------------------------------------------------------------------- */ static int | > > > > > > > > > > > > > > > > > > > > | > > | < | < < < < | 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 | * Side effects: * Memory gets reclaimed. * *----------------------------------------------------------------------------- */ static int UnbindArray(Tcl_Interp *interp, Array *arrayPtr) { PsStore *psPtr = arrayPtr->psPtr; if (arrayPtr->bindAddr) { ckfree(arrayPtr->bindAddr); arrayPtr->bindAddr = NULL; } if (psPtr) { if (psPtr->psClose(psPtr->psHandle) == -1) { if (interp) { const char *err = psPtr->psError(psPtr->psHandle); Tcl_SetObjResult(interp, Tcl_NewStringObj(err, -1)); } return TCL_ERROR; } ckfree((char*)arrayPtr->psPtr), arrayPtr->psPtr = NULL; arrayPtr->psPtr = NULL; } return TCL_OK; } static int DeleteArray(Tcl_Interp *interp, Array *arrayPtr) { if (FlushArray(arrayPtr) == -1) { return TCL_ERROR; } if (arrayPtr->psPtr) { if (UnbindArray(interp, arrayPtr) != TCL_OK) { return TCL_ERROR; }; } if (arrayPtr->entryPtr) { Tcl_DeleteHashEntry(arrayPtr->entryPtr); } Tcl_DeleteHashTable(&arrayPtr->vars); ckfree((char*)arrayPtr); |
︙ | ︙ | |||
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 | dupPtr->typePtr = objPtr->typePtr; Tcl_InvalidateStringRep(dupPtr); } else { if ( objPtr->typePtr == booleanObjTypePtr \ || objPtr->typePtr == byteArrayObjTypePtr \ || objPtr->typePtr == doubleObjTypePtr \ || objPtr->typePtr == intObjTypePtr \ || objPtr->typePtr == stringObjTypePtr) { /* * Cover all "safe" obj types (see header comment) */ (*objPtr->typePtr->dupIntRepProc)(objPtr, dupPtr); Tcl_InvalidateStringRep(dupPtr); } else { | > | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 | dupPtr->typePtr = objPtr->typePtr; Tcl_InvalidateStringRep(dupPtr); } else { if ( objPtr->typePtr == booleanObjTypePtr \ || objPtr->typePtr == byteArrayObjTypePtr \ || objPtr->typePtr == doubleObjTypePtr \ || objPtr->typePtr == intObjTypePtr \ || objPtr->typePtr == wideIntObjTypePtr \ || objPtr->typePtr == stringObjTypePtr) { /* * Cover all "safe" obj types (see header comment) */ (*objPtr->typePtr->dupIntRepProc)(objPtr, dupPtr); Tcl_InvalidateStringRep(dupPtr); } else { |
︙ | ︙ | |||
1389 1390 1391 1392 1393 1394 1395 | hPtr = Tcl_CreateHashEntry(&arrayPtr->vars, key, &new); Tcl_SetHashValue(hPtr, CreateContainer(arrayPtr, hPtr, tclObj)); psPtr->psFree(psPtr->psHandle, val); } while (!psPtr->psNext(psPtr->psHandle, &key, &val, &len)); } } else if (index == AUNBIND) { | | < < < < < < < < < > > > > | 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 | hPtr = Tcl_CreateHashEntry(&arrayPtr->vars, key, &new); Tcl_SetHashValue(hPtr, CreateContainer(arrayPtr, hPtr, tclObj)); psPtr->psFree(psPtr->psHandle, val); } while (!psPtr->psNext(psPtr->psHandle, &key, &val, &len)); } } else if (index == AUNBIND) { if (!arrayPtr || !arrayPtr->psPtr) { Tcl_AppendResult(interp, "shared variable is not bound", NULL); ret = TCL_ERROR; goto cmdExit; } if (UnbindArray(interp, arrayPtr) != TCL_OK) { ret = TCL_ERROR; goto cmdExit; } } cmdExit: if (arrayPtr) { UnlockArray(arrayPtr); } |
︙ | ︙ | |||
1454 1455 1456 1457 1458 1459 1460 | arrayPtr = LockArray(interp, arrayName, 0); if (arrayPtr == NULL) { return TCL_ERROR; } if (objc == 2) { UnlockArray(arrayPtr); | | | 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 | arrayPtr = LockArray(interp, arrayName, 0); if (arrayPtr == NULL) { return TCL_ERROR; } if (objc == 2) { UnlockArray(arrayPtr); if (DeleteArray(interp, arrayPtr) != TCL_OK) { return TCL_ERROR; } } else { for (ii = 2; ii < objc; ii++) { const char *key = Tcl_GetString(objv[ii]); Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&arrayPtr->vars, key); if (hPtr) { |
︙ | ︙ | |||
2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 | static int SvHandlersObjCmd( ClientData arg, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { /* * Syntax: * * tsv::handlers */ if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } | > > | | > > > > | 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 | static int SvHandlersObjCmd( ClientData arg, /* Not used. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ Tcl_Obj *const objv[]) /* Argument objects. */ { PsStore *tmpPtr = NULL; /* * Syntax: * * tsv::handlers */ if (objc != 1) { Tcl_WrongNumArgs(interp, 1, objv, NULL); return TCL_ERROR; } Tcl_ResetResult(interp); Tcl_MutexLock(&svMutex); for (tmpPtr = psStore; tmpPtr; tmpPtr = tmpPtr->nextPtr) { Tcl_AppendElement(interp, tmpPtr->type); } Tcl_MutexUnlock(&svMutex); return TCL_OK; } /* *----------------------------------------------------------------------------- |
︙ | ︙ | |||
2154 2155 2156 2157 2158 2159 2160 | Sv_RegisterCommand("exists", SvExistsObjCmd, NULL, 0); Sv_RegisterCommand("append", SvAppendObjCmd, NULL, 0); Sv_RegisterCommand("array", SvArrayObjCmd, NULL, 0); Sv_RegisterCommand("names", SvNamesObjCmd, NULL, 0); Sv_RegisterCommand("pop", SvPopObjCmd, NULL, 0); Sv_RegisterCommand("move", SvMoveObjCmd, NULL, 0); Sv_RegisterCommand("lock", SvLockObjCmd, NULL, 0); | | | 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 | Sv_RegisterCommand("exists", SvExistsObjCmd, NULL, 0); Sv_RegisterCommand("append", SvAppendObjCmd, NULL, 0); Sv_RegisterCommand("array", SvArrayObjCmd, NULL, 0); Sv_RegisterCommand("names", SvNamesObjCmd, NULL, 0); Sv_RegisterCommand("pop", SvPopObjCmd, NULL, 0); Sv_RegisterCommand("move", SvMoveObjCmd, NULL, 0); Sv_RegisterCommand("lock", SvLockObjCmd, NULL, 0); Sv_RegisterCommand("handlers", SvHandlersObjCmd, NULL, 0); initialized = 1; } Tcl_MutexUnlock(&initMutex); } } /* |
︙ | ︙ | |||
2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 | obj = Tcl_NewDoubleObj(0.0); doubleObjTypePtr = obj->typePtr; Tcl_DecrRefCount(obj); obj = Tcl_NewIntObj(0); intObjTypePtr = obj->typePtr; Tcl_DecrRefCount(obj); /* * Plug-in registered commands in current interpreter */ for (cmdPtr = svCmdInfo; cmdPtr; cmdPtr = cmdPtr->nextPtr) { Tcl_CreateObjCommand(interp, cmdPtr->cmdName, cmdPtr->objProcPtr, | > > > > | 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 | obj = Tcl_NewDoubleObj(0.0); doubleObjTypePtr = obj->typePtr; Tcl_DecrRefCount(obj); obj = Tcl_NewIntObj(0); intObjTypePtr = obj->typePtr; Tcl_DecrRefCount(obj); obj = Tcl_NewWideIntObj(((Tcl_WideInt)1)<<35); wideIntObjTypePtr = obj->typePtr; Tcl_DecrRefCount(obj); /* * Plug-in registered commands in current interpreter */ for (cmdPtr = svCmdInfo; cmdPtr; cmdPtr = cmdPtr->nextPtr) { Tcl_CreateObjCommand(interp, cmdPtr->cmdName, cmdPtr->objProcPtr, |
︙ | ︙ | |||
2354 2355 2356 2357 2358 2359 2360 | if (buckets != NULL) { for (i = 0; i < NUMBUCKETS; ++i) { Bucket *bucketPtr = &buckets[i]; hashPtr = Tcl_FirstHashEntry(&bucketPtr->arrays, &search); while (hashPtr != NULL) { Array *arrayPtr = (Array*)Tcl_GetHashValue(hashPtr); UnlockArray(arrayPtr); | > > > | | 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 | if (buckets != NULL) { for (i = 0; i < NUMBUCKETS; ++i) { Bucket *bucketPtr = &buckets[i]; hashPtr = Tcl_FirstHashEntry(&bucketPtr->arrays, &search); while (hashPtr != NULL) { Array *arrayPtr = (Array*)Tcl_GetHashValue(hashPtr); UnlockArray(arrayPtr); /* unbind array before delete (avoid flush of persistent storage) */ UnbindArray(NULL, arrayPtr); /* flush, delete etc. */ DeleteArray(NULL, arrayPtr); hashPtr = Tcl_NextHashEntry(&search); } if (bucketPtr->lock) { Sp_RecursiveMutexFinalize(&bucketPtr->lock); } SvFinalizeContainers(bucketPtr); Tcl_DeleteHashTable(&bucketPtr->handles); |
︙ | ︙ |
Changes to lib/ttrace.tcl.
1 2 3 4 | # # ttrace.tcl -- # # Copyright (C) 2003 Zoran Vasiljevic, Archiware GmbH. All Rights Reserved. | | | 1 2 3 4 5 6 7 8 9 10 11 12 | # # ttrace.tcl -- # # Copyright (C) 2003 Zoran Vasiljevic, Archiware GmbH. All Rights Reserved. # # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # ---------------------------------------------------------------------------- # # User level commands: # # ttrace::eval top-level wrapper (ttrace-savvy eval) |
︙ | ︙ | |||
69 70 71 72 73 74 75 | interp alias {} [namespace current]::_set {} tsv::set interp alias {} [namespace current]::_unset {} tsv::unset } else { error "requires NaviServer/AOLserver or Tcl threading extension" } # Keep in sync with the Thread package | | | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | interp alias {} [namespace current]::_set {} tsv::set interp alias {} [namespace current]::_unset {} tsv::unset } else { error "requires NaviServer/AOLserver or Tcl threading extension" } # Keep in sync with the Thread package package provide Ttrace 2.9a1 # Package variables variable resolvers "" ; # List of registered resolvers variable tracers "" ; # List of registered cmd tracers variable scripts "" ; # List of registered script makers variable enables "" ; # List of trace-enable callbacks variable disables "" ; # List of trace-disable callbacks |
︙ | ︙ | |||
183 184 185 186 187 188 189 | proc isenabled {} { variable enabled expr {$enabled > 0} } proc update {{from -1}} { | | | | 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | proc isenabled {} { variable enabled expr {$enabled > 0} } proc update {{from -1}} { if {$from == -1} { variable epoch [_set ttrace lastepoch] } else { if {[lsearch [_set ttrace epochlist] $from] == -1} { error "no such epoch: $from" } variable epoch $from } uplevel [getscript] } proc getscript {} { variable preloads variable epoch variable scripts append script [_serializensp] \n append script "::namespace eval [namespace current] {" \n |
︙ | ︙ | |||
234 235 236 237 238 239 240 | if {[lsearch $enables $cmd] == -1} { lappend enables $cmd set cmd [namespace current]::enable::_$cmd proc $cmd $arglist $body return $cmd } } | | | | 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | if {[lsearch $enables $cmd] == -1} { lappend enables $cmd set cmd [namespace current]::enable::_$cmd proc $cmd $arglist $body return $cmd } } proc atdisable {cmd arglist body} { variable disables if {[lsearch $disables $cmd] == -1} { lappend disables $cmd set cmd [namespace current]::disable::_$cmd proc $cmd $arglist $body return $cmd } } proc addtrace {cmd arglist body} { variable tracers if {[lsearch $tracers $cmd] == -1} { lappend tracers $cmd set tracer [namespace current]::trace::_$cmd proc $tracer $arglist $body if {[isenabled]} { |
︙ | ︙ | |||
392 393 394 395 396 397 398 | _unset ttrace $epoch } } _set ttrace epochlist $elist } proc _dropepoch {epoch threads} { | | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 | _unset ttrace $epoch } } _set ttrace epochlist $elist } proc _dropepoch {epoch threads} { set self [_getthread] foreach tid [_set ttrace $epoch] { if {$tid != $self && [lsearch $threads $tid] >= 0} { lappend alive $tid } } if {[info exists alive]} { _set ttrace $epoch $alive |
︙ | ︙ | |||
633 634 635 636 637 638 639 | set cns [namespace qual $entry] set var [namespace tail $entry] append res "::namespace eval $cns {" \n append res "::variable $var" if {[array exists $entry]} { append res "\n::array set $var [list [array get $entry]]" \n } elseif {[info exists $entry]} { | | | 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | set cns [namespace qual $entry] set var [namespace tail $entry] append res "::namespace eval $cns {" \n append res "::variable $var" if {[array exists $entry]} { append res "\n::array set $var [list [array get $entry]]" \n } elseif {[info exists $entry]} { append res " [list [set $entry]]" \n } else { append res \n } append res "}" \n } return $res } |
︙ | ︙ | |||
866 867 868 869 870 871 872 | return $result } } ::xotcl::Class instmixin ::xotcl::_creator } ttrace::atdisable XOTclDisabler {args} { | | | 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 | return $result } } ::xotcl::Class instmixin ::xotcl::_creator } ttrace::atdisable XOTclDisabler {args} { if { [info commands ::xotcl::Class] == "" || [info commands ::xotcl::_creator] == ""} { return } ::xotcl::Class instmixin "" ::xotcl::_creator destroy } |
︙ | ︙ | |||
910 911 912 913 914 915 916 | return {::xotcl::Class proc __unknown name {$resolver \$name}} } }] # # Register callback to be called on cleanup. This will trash lazily loaded # procs which have changed since. | | | 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 | return {::xotcl::Class proc __unknown name {$resolver \$name}} } }] # # Register callback to be called on cleanup. This will trash lazily loaded # procs which have changed since. # ttrace::addcleanup { variable resolveproc foreach cmd [array names resolveproc] { set def [ttrace::getentry proc $cmd] if {$def != ""} { set new [lindex $def 0] |
︙ | ︙ |
Changes to license.terms.
︙ | ︙ | |||
24 25 26 27 28 29 30 | FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" | | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. GOVERNMENT USE: If you are acquiring this software on behalf of the U.S. government, the Government shall have only "Restricted Rights" in the software and related documentation as defined in the Federal Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are acquiring the software on behalf of the Department of Defense, the software shall be classified as "Commercial Computer Software" and the Government shall have only "Restricted Rights" as defined in Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the authors grant the U.S. Government and others acting in its behalf permission to use and distribute the software in accordance with the terms specified in this license. |
Added project.shed.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | 7bce708b4197acccd1db4644fdbe5ee249f3b5dd { entity { name: thread shed_class: project version: {} } meta { class: generic description: {The Tcl Thread package} distribution: fossil generated: {2015-10-06 10:32:03 UTC} release: trunk } release/ { ccc83b2283498a2ec86d00bf8593e7de0cf8a456 } distribution/ { e47b6a79a963c99b7de15a4817b3010fbb3dd693 } package/ { 41c2f28a24688f0ad5c1431fbd22f1621b6b0d6e } module/ { 6dbf64aeadfe9d6fb88c0d84562a98a4b33d374b 893421a5151dd42645a1437b6e41ed1943dc4ed6 cf5303e1f3f79bc837e9b1a18e5e2e3f4892c58c 037601b1d656568d18dd3aaaaa2c1bd760b8c16d 41b815e9db25ad951c6b7800c02cd3706468e263 } file/ { 032fb91c412db8ae1a282ae54d353fe33e45ff6a } } ccc83b2283498a2ec86d00bf8593e7de0cf8a456 { entity { name: trunk shed_class: release version: {} } meta { checkout: trunk class: generic timestamp: {2015-10-06 10:32:03 UTC} } } e47b6a79a963c99b7de15a4817b3010fbb3dd693 { entity { name: fossil shed_class: distribution version: {} } meta { class: generic format: fossil project: 7bce708b4197acccd1db4644fdbe5ee249f3b5dd project-name: {Tcl package Thread source code} project-short-name: thread release: trunk url: http://fossil.etoyoc.com/fossil/thread } } 41c2f28a24688f0ad5c1431fbd22f1621b6b0d6e { entity { name: thread shed_class: package version: 2.7.2 } meta { build: tea class: binary } } 6dbf64aeadfe9d6fb88c0d84562a98a4b33d374b { entity { name: lib shed_class: module version: {} } meta { class: source package-provide: {} package-require: {} path: lib } } 893421a5151dd42645a1437b6e41ed1943dc4ed6 { entity { name: tcl shed_class: module version: {} } meta { class: source package-provide: {} package-require: {{Tcl 8.4} {Thread 2.5}} path: tcl } } cf5303e1f3f79bc837e9b1a18e5e2e3f4892c58c { entity { name: generic shed_class: module version: {} } meta { class: source package-provide: {} package-require: {} path: generic } } 037601b1d656568d18dd3aaaaa2c1bd760b8c16d { entity { name: win shed_class: module version: {} } meta { class: source package-provide: {} package-require: {} path: win } } 41b815e9db25ad951c6b7800c02cd3706468e263 { entity { name: unix shed_class: module version: {} } meta { class: source package-provide: {} package-require: {} path: unix } } 032fb91c412db8ae1a282ae54d353fe33e45ff6a { entity { name: ttrace.tcl shed_class: file version: {} } meta { class: source file: lib/ttrace.tcl format: tcl package-require: {} } } |
Changes to tcl/README.
1 2 3 4 5 6 7 8 | Software here is provided as example of making some interesting things and applications using the Tcl threading extension. Currently, following packages are supplied: tpool/ Example Tcl-only implementation of thread pools. The threading extension includes an efficient | | | | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Software here is provided as example of making some interesting things and applications using the Tcl threading extension. Currently, following packages are supplied: tpool/ Example Tcl-only implementation of thread pools. The threading extension includes an efficient threadpool implementation in C. This file is provided as a fully functional example on how this functionality could be implemented in Tcl alone. phttpd/ MT-enabled httpd server. It uses threadpool to distribute incoming requests among several worker threads in the threadpool. This way blocking requests may be handled much better, w/o halting the event loop of the main responder thread. In this directory you will also find the uhttpd. This is the same web-server but operating in the event-loop mode alone, no threadpool support. This is good for comparison purposes. cmdsrv/ Socket command-line server. Each new connection gets new thread, thus allowing multiple outstanding blocking calls without halting the event loop. To play around with above packages, change to the corresponding directory and source files in the Tcl8.4 (or later) Tcl shell. Be sure to have the latest Tcl threading extension installed in your package path. - EOF |
Changes to tcl/cmdsrv/cmdsrv.tcl.
1 2 3 4 5 | # # cmdsrv.tcl -- # # Simple socket command server. Supports many simultaneous sessions. # Works in thread mode with each new connection receiving a new thread. | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | # # cmdsrv.tcl -- # # Simple socket command server. Supports many simultaneous sessions. # Works in thread mode with each new connection receiving a new thread. # # Usage: # cmdsrv::create port ?-idletime value? ?-initcmd cmd? # # port Tcp port where the server listens # -idletime # of sec to idle before tearing down socket (def: 300 sec) # -initcmd script to initialize new worker thread (def: empty) # # Example: # # # tclsh8.4 # % source cmdsrv.tcl # % cmdsrv::create 5000 -idletime 60 # % vwait forever # # Starts the server on the port 5000, sets idle timer to 1 minute. # You can now use "telnet" utility to connect. # # Copyright (c) 2002 by Zoran Vasiljevic. # # See the file "license.terms" for information on usage and # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. # ----------------------------------------------------------------------------- |
︙ | ︙ | |||
62 63 64 65 66 67 68 | # Setup default pool data. # array set data { -idletime 300000 -initcmd {source cmdsrv.tcl} } | | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | # Setup default pool data. # array set data { -idletime 300000 -initcmd {source cmdsrv.tcl} } # # Override with user-supplied data # foreach {arg val} $args { switch -- $arg { -idletime {set data($arg) [expr {$val*1000}]} -initcmd {append data($arg) \n $val} default { error "unsupported pool option \"$arg\"" } } } # # Start the server on the given port. Note that we wrap # the actual accept with a helper after/idle callback. # This is a workaround for a well-known Tcl bug. # socket -server [namespace current]::_Accept -myaddr 127.0.0.1 $port } # # cmdsrv::_Accept -- # # Helper procedure to solve Tcl shared channel bug when responding |
︙ | ︙ | |||
129 130 131 132 133 134 135 | # Results: # None. # proc cmdsrv::Accept {s ipaddr port} { variable data | | | | | | | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | # Results: # None. # proc cmdsrv::Accept {s ipaddr port} { variable data # # Configure socket for sane operation # fconfigure $s -blocking 0 -buffering none -translation {auto crlf} # # Emit the prompt # puts -nonewline $s "% " # # Create worker thread and transfer socket ownership # set tid [thread::create [append data(-initcmd) \n thread::wait]] thread::transfer $tid $s ; # This flushes the socket as well # # Start event-loop processing in the remote thread # thread::send -async $tid [subst { array set [namespace current]::data {[array get data]} fileevent $s readable {[namespace current]::Read $s} proc exit args {[namespace current]::SockDone $s} [namespace current]::StartIdleTimer $s }] } # # cmdsrv::Read -- # # Event loop procedure to read data from socket and collect the # command to execute. If the command read from socket is complete # it executes the command are prints the result back. # # Arguments: # s incoming socket # # Side Effects: # None. # |
︙ | ︙ | |||
197 198 199 200 201 202 203 | } if {$line == "\n" || $line == ""} { if {[catch {puts -nonewline $s "% "}]} { return [SockDone $s] } return [StartIdleTimer $s] } | | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | } if {$line == "\n" || $line == ""} { if {[catch {puts -nonewline $s "% "}]} { return [SockDone $s] } return [StartIdleTimer $s] } # # Construct command line to eval # append data(cmd) $line if {[info complete $data(cmd)] == 0} { if {[catch {puts -nonewline $s "> "}]} { |
︙ | ︙ | |||
229 230 231 232 233 234 235 | StartIdleTimer $s } # # cmdsrv::SockDone -- # # Tears down the thread and closes the socket if the remote peer has | | | | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 | StartIdleTimer $s } # # cmdsrv::SockDone -- # # Tears down the thread and closes the socket if the remote peer has # closed his side of the comm channel. # # Arguments: # s incoming socket # # Side Effects: # Worker thread gets released. # # Results: # None. # proc cmdsrv::SockDone {s} { catch {close $s} thread::release } # # cmdsrv::StopIdleTimer -- # # Cancel the connection idle timer. # # Arguments: # s incoming socket # # Side Effects: # After event gets cancelled. # |
︙ | ︙ | |||
275 276 277 278 279 280 281 | unset data(idleevent) } } # # cmdsrv::StartIdleTimer -- # | | | 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | unset data(idleevent) } } # # cmdsrv::StartIdleTimer -- # # Initiates the connection idle timer. # # Arguments: # s incoming socket # # Side Effects: # After event gets posted. # |
︙ | ︙ |
Changes to tcl/phttpd/phttpd.tcl.
1 2 3 4 5 6 7 8 9 10 11 | # # phttpd.tcl -- # # Simple Sample httpd/1.0 server in 250 lines of Tcl. # Stephen Uhler / Brent Welch (c) 1996 Sun Microsystems. # # Modified to use namespaces, direct url-to-procedure access # and thread pool package. Grown little larger since ;) # # Usage: # phttpd::create port | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # # phttpd.tcl -- # # Simple Sample httpd/1.0 server in 250 lines of Tcl. # Stephen Uhler / Brent Welch (c) 1996 Sun Microsystems. # # Modified to use namespaces, direct url-to-procedure access # and thread pool package. Grown little larger since ;) # # Usage: # phttpd::create port # # port Tcp port where the server listens # # Example: # # # tclsh8.4 # % source phttpd.tcl # % phttpd::create 5000 # % vwait forever # # Starts the server on the port 5000. Also, look at the Httpd array # definition in the "phttpd" namespace declaration to find out # about other options you may put on the command line. # # You can use: http://localhost:5000/monitor URL to test the # server functionality. # # Copyright (c) 2002 by Zoran Vasiljevic. # |
︙ | ︙ | |||
135 136 137 138 139 140 141 | set Httpd(tpid) [tpool::create -maxworkers 8 -initcmd $initcmd] # # Start the server on the given port. Note that we wrap # the actual accept with a helper after/idle callback. # This is a workaround for a well-known Tcl bug. # | | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | set Httpd(tpid) [tpool::create -maxworkers 8 -initcmd $initcmd] # # Start the server on the given port. Note that we wrap # the actual accept with a helper after/idle callback. # This is a workaround for a well-known Tcl bug. # socket -server [namespace current]::_Accept $port } # # phttpd::_Accept -- # # Helper procedure to solve Tcl shared-channel bug when responding |
︙ | ︙ | |||
197 198 199 200 201 202 203 | # One of the worker threads will attach it again. # thread::detach $sock # # Send the work ticket to threadpool. | | | | | | 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 | # One of the worker threads will attach it again. # thread::detach $sock # # Send the work ticket to threadpool. # tpool::post -detached $Httpd(tpid) [list [namespace current]::Ticket $sock] } # # phttpd::Ticket -- # # Job ticket to run in the thread pool thread. # # Arguments: # sock # # Side Effects: # None.. # # Results: # None. # proc phttpd::Ticket {sock} { thread::attach $sock fileevent $sock readable [list [namespace current]::Read $sock] # # End of processing is signalized here. # This will release the worker thread. # vwait [namespace current]::done } # # phttpd::Read -- # |
︙ | ︙ | |||
268 269 270 271 272 273 274 | continue } else { Log error "bad request line: (%s)" $line Error 400 return [Done] } } | | | | 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | continue } else { Log error "bad request line: (%s)" $line Error 400 return [Done] } } # string compare $readCount 0 maps -1 to -1, 0 to 0, and > 0 to 1 set state [string compare $readCount 0],$data(state),$data(proto) switch -- $state { "0,mime,GET" - "0,query,POST" { Respond return [Done] } "0,mime,POST" { |
︙ | ︙ | |||
329 330 331 332 333 334 335 | proc phttpd::Done {} { variable done variable data close $data(sock) | | | 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | proc phttpd::Done {} { variable done variable data close $data(sock) if {[info exists data]} { unset data } set done 1 ; # Releases the request thread (See Ticket procedure) } |
︙ | ︙ | |||
426 427 428 429 430 431 432 | # @c Convert the file suffix into a mime type. variable MimeTypes set type "text/plain" catch {set type $MimeTypes([file extension $path])} | | | 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 | # @c Convert the file suffix into a mime type. variable MimeTypes set type "text/plain" catch {set type $MimeTypes([file extension $path])} return $type } # # phttpd::Error -- # # Emit error page |
︙ | ︙ | |||
613 614 615 616 617 618 619 | # None.. # # Results: # None. # proc phttpd::QueryMap {query} { | | | 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 | # None.. # # Results: # None. # proc phttpd::QueryMap {query} { set res [list] regsub -all {[&=]} $query { } query regsub -all { } $query { {} } query; # Othewise we lose empty values foreach {key val} $query { lappend res [CgiMap $key] [CgiMap $val] |
︙ | ︙ |
Changes to tcl/phttpd/uhttpd.tcl.
1 2 3 4 5 6 7 8 9 10 11 | # # uhttpd.tcl -- # # Simple Sample httpd/1.0 server in 250 lines of Tcl. # Stephen Uhler / Brent Welch (c) 1996 Sun Microsystems. # # Modified to use namespaces and direct url-to-procedure access (zv). # Eh, due to this, and nicer indenting, it's now 150 lines longer :-) # # Usage: # phttpd::create port | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | # # uhttpd.tcl -- # # Simple Sample httpd/1.0 server in 250 lines of Tcl. # Stephen Uhler / Brent Welch (c) 1996 Sun Microsystems. # # Modified to use namespaces and direct url-to-procedure access (zv). # Eh, due to this, and nicer indenting, it's now 150 lines longer :-) # # Usage: # phttpd::create port # # port Tcp port where the server listens # # Example: # # # tclsh8.4 # % source uhttpd.tcl # % uhttpd::create 5000 # % vwait forever # # Starts the server on the port 5000. Also, look at the Httpd array # definition in the "uhttpd" namespace declaration to find out # about other options you may put on the command line. # # You can use: http://localhost:5000/monitor URL to test the # server functionality. # # Copyright (c) Stephen Uhler / Brent Welch (c) 1996 Sun Microsystems. # Copyright (c) 2002 by Zoran Vasiljevic. |
︙ | ︙ | |||
70 71 72 73 74 75 76 | } } proc uhttpd::create {port args} { # @c Start the server by listening for connections on the desired port. | | | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | } } proc uhttpd::create {port args} { # @c Start the server by listening for connections on the desired port. variable Httpd set arglen [llength $args] if {$arglen} { if {$arglen % 2} { error "wrong \# arguments, should be: key1 val1 key2 val2..." } set opts [array names Httpd] |
︙ | ︙ | |||
93 94 95 96 97 98 99 | set Httpd(port) $port set Httpd(host) [info hostname] socket -server [namespace current]::Accept $port } proc uhttpd::respond {s status contype data {length 0}} { | | | | | | 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | set Httpd(port) $port set Httpd(host) [info hostname] socket -server [namespace current]::Accept $port } proc uhttpd::respond {s status contype data {length 0}} { puts $s "HTTP/1.0 $status" puts $s "Date: [Date]" puts $s "Content-Type: $contype" if {$length} { puts $s "Content-Length: $length" } else { puts $s "Content-Length: [string length $data]" } puts $s "" puts $s $data } proc uhttpd::Accept {newsock ipaddr port} { # @c Accept a new connection from the client. variable Httpd upvar \#0 [namespace current]::Httpd$newsock data |
︙ | ︙ | |||
254 255 256 257 258 259 260 | # @c Convert the file suffix into a mime type. variable MimeTypes set type "text/plain" catch {set type $MimeTypes([file extension $path])} | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 | # @c Convert the file suffix into a mime type. variable MimeTypes set type "text/plain" catch {set type $MimeTypes([file extension $path])} return $type } proc uhttpd::Error {s code} { # @c Emit error page. |
︙ | ︙ | |||
302 303 304 305 306 307 308 | if {$seconds == 0} { set seconds [clock seconds] } clock format $seconds -format {%a, %d %b %Y %T %Z} -gmt 1 } proc uhttpd::Log {reason format args} { | | | 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | if {$seconds == 0} { set seconds [clock seconds] } clock format $seconds -format {%a, %d %b %Y %T %Z} -gmt 1 } proc uhttpd::Log {reason format args} { # @c Log an httpd transaction. set messg [eval format [list $format] $args] set stamp [clock format [clock seconds] -format "%d/%b/%Y:%H:%M:%S"] puts stderr "\[$stamp\] $reason: $messg" } |
︙ | ︙ | |||
359 360 361 362 363 364 365 | return [subst $data] } proc uhttpd::QueryMap {query} { # @c Decode url-encoded query into key/value pairs | | | 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | return [subst $data] } proc uhttpd::QueryMap {query} { # @c Decode url-encoded query into key/value pairs set res [list] regsub -all {[&=]} $query { } query regsub -all { } $query { {} } query; # Othewise we lose empty values foreach {key val} $query { lappend res [CgiMap $key] [CgiMap $val] |
︙ | ︙ |
Changes to tcl/tpool/tpool.tcl.
1 2 3 4 | # # tpool.tcl -- # # Tcl implementation of a threadpool paradigm in pure Tcl using | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # # tpool.tcl -- # # Tcl implementation of a threadpool paradigm in pure Tcl using # the Tcl threading extension 2.5 (or higher). # # This file is for example purposes only. The efficient C-level # threadpool implementation is already a part of the threading # extension starting with 2.5 version. Both implementations have # the same Tcl API so both can be used interchangeably. Goal of # this implementation is to serve as an example of using the Tcl # extension to implement some very common threading paradigms. # # Beware: with time, as improvements are made to the C-level # implementation, this Tcl one might lag behind. # Please consider this code as a working example only. # # # # Copyright (c) 2002 by Zoran Vasiljevic. # # See the file "license.terms" for information on usage and # redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. # ----------------------------------------------------------------------------- |
︙ | ︙ | |||
62 63 64 65 66 67 68 | # -initcmd script used to initialize new worker thread # -exitcmd script run at worker thread exit # # Side Effects: # Might create many new threads if "-minworkers" option is > 0. # # Results: | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | # -initcmd script used to initialize new worker thread # -exitcmd script run at worker thread exit # # Side Effects: # Might create many new threads if "-minworkers" option is > 0. # # Results: # The id of the newly created thread pool. This id must be used # in all other tpool::* commands. # proc tpool::create {args} { variable thisScript |
︙ | ︙ | |||
163 164 165 166 167 168 169 | # # tpool::post -- # # Submits the new job to the thread pool. The caller might pass # the job in two modes: synchronous and asynchronous. # For the synchronous mode, the pool implementation will retain | | | | | | | 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | # # tpool::post -- # # Submits the new job to the thread pool. The caller might pass # the job in two modes: synchronous and asynchronous. # For the synchronous mode, the pool implementation will retain # the result of the passed script until the caller collects it # using the "thread::get" command. # For the asynchronous mode, the result of the script is ignored. # # Arguments: # args Variable # of arguments with the following syntax: # tpool::post ?-detached? tpid script # # -detached flag to turn the async operation (ignore result) # tpid the id of the thread pool # script script to pass to the worker thread for execution # # Side Effects: # Depends on the passed script. # # Results: # The id of the posted job. This id is used later on to collect # result of the job and set local variables accordingly. # For asynchronously posted jobs, the return result is ignored # and this function returns empty result. # proc tpool::post {args} { # # Parse command arguments. # set ns [namespace current] set usage "wrong \# args: should be \"[lindex [info level 1] 0]\ ?-detached? tpoolId script\"" if {[llength $args] == 2} { set detached 0 set tpid [lindex $args 0] set cmd [lindex $args 1] } elseif {[llength $args] == 3} { if {[lindex $args 0] != "-detached"} { error $usage } set detached 1 set tpid [lindex $args 1] set cmd [lindex $args 2] } else { error $usage } # # Find idle (or create new) worker thread. This is relatively # a complex issue, since we must honour the limits about number # of allowed worker threads imposed to us by the caller. # set tid "" while {$tid == ""} { tsv::lock $tpid { |
︙ | ︙ | |||
459 460 461 462 463 464 465 | # None. # proc tpool::Timer {tpid} { tsv::lock $tpid { if {[tsv::set $tpid numworkers] > [tsv::set $tpid -minworkers]} { | | | | 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 | # None. # proc tpool::Timer {tpid} { tsv::lock $tpid { if {[tsv::set $tpid numworkers] > [tsv::set $tpid -minworkers]} { # # We have more workers than needed, so kill this one. # We first splice ourselves from the list of active # workers, adjust the number of workers and release # this thread, which may exit eventually. # set x [tsv::lsearch $tpid thrworkers [thread::id]] if {$x >= 0} { tsv::lreplace $tpid thrworkers $x $x tsv::incr $tpid numworkers -1 |
︙ | ︙ | |||
509 510 511 512 513 514 515 | # Cancel the idle timer callback, if any. # variable afterevent if {$afterevent != ""} { after cancel $afterevent } | | | | | 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 | # Cancel the idle timer callback, if any. # variable afterevent if {$afterevent != ""} { after cancel $afterevent } # # Evaluate passed command and build the result list. # set code [catch {uplevel \#0 $cmd} ret] if {$code == 0} { set res [list $jid 0 $ret] } else { set res [list $jid $code $ret $::errorInfo $::errorCode] } # # Check to see if any caller is waiting to be serviced. # If yes, kick it out of the waiting state. # set ns [namespace current] tsv::lock $tpid { tsv::lpush $tpid thrworkers [thread::id] set waiter [tsv::lpop $tpid thrwaiters] if {$waiter != ""} { thread::send -async $waiter [subst { set ${ns}::waiter 1 }] } } # # Release the thread. If this turns out to be # the last refcount held, don't bother to do # any more work, since thread will soon exit. # if {[thread::release] <= 0} { return $res } |
︙ | ︙ |
Changes to tests/thread.test.
︙ | ︙ | |||
488 489 490 491 492 493 494 | close $file ThreadReap set msg } {transfer failed: target thread died} test thread-17.3 {thread::transfer - clearing of fileevents} {chanTransfer} { proc _HandleIt_ {} { | | | 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 | close $file ThreadReap set msg } {transfer failed: target thread died} test thread-17.3 {thread::transfer - clearing of fileevents} {chanTransfer} { proc _HandleIt_ {} { global gotEvents tid file if {$gotEvents == 0} { thread::transfer $tid $file # From now on no events should be delivered anymore, # restricting the end value to 1 } incr gotEvents } |
︙ | ︙ | |||
1010 1011 1012 1013 1014 1015 1016 | thread::rwmutex destroy $rwmutex list $x $msg } {1 {write-locking the same read-write mutex twice from the same thread}} test thread-20.15 {thread::mutex - read-lock write-locked mutex} { set rwmutex [thread::rwmutex create] thread::rwmutex wlock $rwmutex | | | | 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 | thread::rwmutex destroy $rwmutex list $x $msg } {1 {write-locking the same read-write mutex twice from the same thread}} test thread-20.15 {thread::mutex - read-lock write-locked mutex} { set rwmutex [thread::rwmutex create] thread::rwmutex wlock $rwmutex set x [catch {thread::rwmutex rlock $rwmutex} msg] thread::rwmutex unlock $rwmutex thread::rwmutex destroy $rwmutex list $x $msg } {1 {read-locking already write-locked mutex from the same thread}} test thread-20.16 {thread::mutex - unlock not locked mutex} { set rwmutex [thread::rwmutex create] set x [catch {thread::rwmutex unlock $rwmutex} msg] |
︙ | ︙ |
Changes to tests/tsv.test.
︙ | ︙ | |||
34 35 36 37 38 39 40 | test tsv-$backend-1.1 {tsv::array bind - empty} \ -constraints have_$backend \ -setup { setup } -body { tsv::array names b } -cleanup { | | | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | test tsv-$backend-1.1 {tsv::array bind - empty} \ -constraints have_$backend \ -setup { setup } -body { tsv::array names b } -cleanup { cleanup } -result {} test tsv-$backend-1.2 {tsv::set} \ -constraints have_$backend \ -setup { setup } -body { |
︙ | ︙ |
Changes to unix/CONFIG.
︙ | ︙ | |||
13 14 15 16 17 18 19 | # ../configure --enable-threads # # As of 2.6, the threading extension supports persistent # shared variables. As an working example of this, there # is a simple wrapper for the popular Gdbm library. # Uncomment the following line if you like to compile the # Gdbm wrapper for persistent shared variables. | | | | | 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # ../configure --enable-threads # # As of 2.6, the threading extension supports persistent # shared variables. As an working example of this, there # is a simple wrapper for the popular Gdbm library. # Uncomment the following line if you like to compile the # Gdbm wrapper for persistent shared variables. # # ../configure --enable-threads --with-gdbm # # If your Gdbm library is not installed in one of the # default system locations (/usr/lib, /usr/local/lib ...) # please use following directive. Note that both library # file *and* includes should be located in "/my/gdbm". # Of course, you have to replace the "/my/gdbm" below # with the exact location, as found in your system: # # ../configure --enable-threads --with-gdbm=/my/gdbm # # # AOLserver 4.X; Uses public Tcl library. # ---------------------------------------------------- # nsdir="/usr/local/naviserver" # ../configure --enable-threads \ |
︙ | ︙ |
Changes to unix/README.
1 2 3 4 5 6 7 8 9 10 11 12 13 | I. Building the Tcl thread extension for Unix ============================================= Extension can be compiled on several Unix derivates including various distributions of Linux. Build process is pretty straightforward. I've checked some versions of Solaris, Linux and Darwin, but the extension should compile without problems on any Unix-like operating system with a proper pthreads library implementation. To build on Unix-like operating systems, start with the CONFIG script and see if there is already a combination of the "configure" options which may satisfy your needs. If not, you can run the configure script | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | I. Building the Tcl thread extension for Unix ============================================= Extension can be compiled on several Unix derivates including various distributions of Linux. Build process is pretty straightforward. I've checked some versions of Solaris, Linux and Darwin, but the extension should compile without problems on any Unix-like operating system with a proper pthreads library implementation. To build on Unix-like operating systems, start with the CONFIG script and see if there is already a combination of the "configure" options which may satisfy your needs. If not, you can run the configure script located in the root of the distribution directory with a choice of supported options yourself. If yes, you can uncomment corresponding lines from the CONFIG script and do: % sh CONFIG Either way, this will create a Makefile which you use to run "make" and "make install". You can use "make clean" to clean the directory from temporary compilation files and/or "make distclean" to additionaly remove local config files. You might want to do "make test" before doing the "make install" in order to run the regression tests on the package. To explore other building options, look into the CONFIG file for more information. Note for NaviServer/AOLserver users ------------------------ |
︙ | ︙ | |||
52 53 54 55 56 57 58 | So, uncomment the line, recompile and there you go. II. Building optional support libraries ======================================= As of 2.6 release, this extension supports persistent shared variables. | | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | So, uncomment the line, recompile and there you go. II. Building optional support libraries ======================================= As of 2.6 release, this extension supports persistent shared variables. To use this functionality, you might need to download and compile some other supporting libraries. Currently, there is a simple implementation of shared variable persistency built atop of popular GNU Gdbm package. You can obtain the latest version of the Gdbm package from the GNU website at: http://www.gnu.org/software/gdbm/gdbm.html To compile with GNU Gdbm support you must configure with --with-gdbm switch. This option, if used, will try to locate the Gdbm library on your system at couple of standard locations. You might override this behaviour by giving --with-gdbm=/some/dir. Note that both library file and the include file must then reside in this directory. -EOF- |
Changes to win/CONFIG.
︙ | ︙ | |||
10 11 12 13 14 15 16 | # from in those directories with the appropriate flags. # # Note the CC=gcc must be set *before* the "configure" is ran. # This is really needed, otherwise configure will not be able # to compile the small test file which checks the presence # of the MinGW build environment. It is *not* enough to use # "--enable-gcc" configure option; you *need* to define CC. | | | 10 11 12 13 14 15 16 17 18 19 20 21 | # from in those directories with the appropriate flags. # # Note the CC=gcc must be set *before* the "configure" is ran. # This is really needed, otherwise configure will not be able # to compile the small test file which checks the presence # of the MinGW build environment. It is *not* enough to use # "--enable-gcc" configure option; you *need* to define CC. # export CC=gcc sh ../configure --enable-threads --with-tcl=e:/tcl/win |
Changes to win/README.txt.
︙ | ︙ | |||
29 30 31 32 33 34 35 | Files in this directory may be useful if you have not set up your TEA (i.e., MinGW) environment and you're using the MSVC++ from Micro$oft. To build the extension invoke the following command: | | | | > > > > | | > | | | | | | 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | Files in this directory may be useful if you have not set up your TEA (i.e., MinGW) environment and you're using the MSVC++ from Micro$oft. To build the extension invoke the following command: nmake -f makefile.vc INSTALLDIR=<path-to-installed-tcl> INSTALLDIR is the path of the Tcl distribution where tcl.h and other needed Tcl files are installed. To build against a Tcl source build instead, nmake -f makefile.vc TCLDIR=<path-to-tcl-sources> Please look into the makefile.vc file for more options etc. Alternatively, you can open the extension workspace and project files (thread_win.dsw and thread_win.dsp) from within the MSVC++ and press the F7 key to build the extension under the control of the MSVC IDE. NOTE: it is likely that the .dsw and .dsp files are out of date. At least Visual Studio 2017 was not able to open those files. II. Building optional support libraries ======================================= As of 2.6 release, this extension supports persistent shared variables. To use this functionality, you might need to download and compile some other supporting libraries. Currently, there is a simple implementation of shared variable persistency built atop of popular GNU Gdbm package. You can obtain the latest version of the Gdbm from: http://www.gnu.org/software/gdbm/gdbm.html. For the impatient, there are Windows ports of GNU Gdbm found on various places on the Internet. The easiest way to start is to go to the GnuWin32 project: http://sourceforge.net/projects/gnuwin32 and fetch yourself a compiled GNU Gdbm DLL. -EOF- |
Changes to win/makefile.vc.
1 | #------------------------------------------------------------- -*- makefile -*- | > | > | > > > > > > > > > > > > > < < < < < < < < | < < < < < | < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < | < < < < < < < < < < < < < < | < < < | < < < < < < | > | < < < < | < < < < < | < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | #------------------------------------------------------------- -*- makefile -*- # # Makefile for thread extension # # Basic build, test and install # nmake /f makefile.vc INSTALLDIR=c:\tcl # nmake /f makefile.vc INSTALLDIR=c:\tcl test # nmake /f makefile.vc INSTALLDIR=c:\tcl install # # For other build options (debug, static etc.), # See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for # detailed documentation. # # In addition to the command line macros described there the following # may also be defined. # ADDOPTDEFINES - addition compiler options # ADDLINKOPTS - addition link options # E.g. # nmake -nologo -f makefile.vc TCLDIR=%TCLDIR% ... ADDOPTDEFINES="-I%LMDBDIR%" ADDLINKOPTS="%LMDBDIR%\Release\lmdb.lib" # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # #------------------------------------------------------------------------------ PROJECT = thread RCFILE = thread.rc DOCDIR = $(ROOT)\doc\html PRJ_DEFINES = -D _CRT_SECURE_NO_DEPRECATE -D _CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS PRJ_DEFINES = $(PRJ_DEFINES) -DTCL_TIP143 -DTCL_TIP285 -DTCL_NO_DEPRECATED=1 $(ADDOPTDEFINES) PRJ_LIBS = $(ADDLINKOPTS) !include "rules-ext.vc" PRJ_OBJS = \ $(TMP_DIR)\threadNs.obj \ $(TMP_DIR)\threadCmd.obj \ $(TMP_DIR)\threadSvCmd.obj \ $(TMP_DIR)\threadSpCmd.obj \ $(TMP_DIR)\threadPoolCmd.obj \ $(TMP_DIR)\psGdbm.obj \ $(TMP_DIR)\psLmdb.obj \ $(TMP_DIR)\threadSvListCmd.obj \ $(TMP_DIR)\threadSvKeylistCmd.obj \ $(TMP_DIR)\tclXkeylist.obj \ $(TMP_DIR)\threadWin.obj !include "$(_RULESDIR)\targets.vc" install: default-install-docs-html pkgindex: default-pkgindex-tea # Explicit dependency rules $(GENERICDIR)\psGdbm.c: $(GENERICDIR)\psGdbm.h $(GENERICDIR)\psLmdb.c: $(GENERICDIR)\psLmdb.h $(GENERICDIR)\threadCmd.c : $(GENERICDIR)\tclThreadInt.h $(GENERICDIR)\threadSpCmd.c : $(GENERICDIR)\tclThreadInt.h $(GENERICDIR)\threadSvCmd.c : $(GENERICDIR)\tclThreadInt.h $(GENERICDIR)\threadPoolCmd.c : $(GENERICDIR)\tclThreadInt.h $(GENERICDIR)\threadSvListCmd.c : $(GENERICDIR)\tclThreadInt.h $(GENERICDIR)\threadSvKeylistCmd.c : $(GENERICDIR)\tclThreadInt.h |
Changes to win/nmakehlp.c.
︙ | ︙ | |||
10 11 12 13 14 15 16 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include <windows.h> | < < < < < < | > | 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * ---------------------------------------------------------------------------- */ #define _CRT_SECURE_NO_DEPRECATE #include <windows.h> #pragma comment (lib, "user32.lib") #pragma comment (lib, "kernel32.lib") #include <stdio.h> #include <math.h> /* * This library is required for x64 builds with _some_ versions of MSVC */ #if defined(_M_IA64) || defined(_M_AMD64) #if _MSC_VER >= 1400 && _MSC_VER < 1500 #pragma comment(lib, "bufferoverflowU") #endif #endif /* ISO hack for dumb VC++ */ #ifdef _MSC_VER #define snprintf _snprintf #endif /* protos */ static int CheckForCompilerFeature(const char *option); static int CheckForLinkerFeature(const char **options, int count); static int IsIn(const char *string, const char *substring); static int SubstituteFile(const char *substs, const char *filename); static int QualifyPath(const char *path); static int LocateDependency(const char *keyfile); static const char *GetVersionFromFile(const char *filename, const char *match, int numdots); static DWORD WINAPI ReadFromPipe(LPVOID args); /* globals */ #define CHUNK 25 #define STATICBUFFERSIZE 1000 |
︙ | ︙ | |||
70 71 72 73 74 75 76 77 78 79 80 81 82 83 | main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); | > | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | main( int argc, char *argv[]) { char msg[300]; DWORD dwWritten; int chars; const char *s; /* * Make sure children (cl.exe and link.exe) are kept quiet. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
︙ | ︙ | |||
98 99 100 101 102 103 104 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': | | | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForCompilerFeature(argv[2]); case 'l': if (argc < 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -l <linker option> ?<mandatory option> ...?\n" "Tests for whether link.exe supports an option\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return CheckForLinkerFeature(&argv[2], argc-2); case 'f': if (argc == 2) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -f <string> <substring>\n" "Find a substring within another\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, |
︙ | ︙ | |||
149 150 151 152 153 154 155 | "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } | | > > | > > > > > > > > > > > > > > > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | "Extract a version from a file:\n" "eg: pkgIndex.tcl \"package ifneeded http\"", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 0; } s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0'); if (s && *s) { printf("%s\n", s); return 0; } else return 1; /* Version not found. Return non-0 exit code */ case 'Q': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -Q path\n" "Emit the fully qualified path\n" "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return QualifyPath(argv[2]); case 'L': if (argc != 3) { chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -L keypath\n" "Emit the fully qualified path of directory containing keypath\n" "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]); WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL); return 2; } return LocateDependency(argv[2]); } } chars = snprintf(msg, sizeof(msg) - 1, "usage: %s -c|-f|-l|-Q|-s|-V ...\n" "This is a little helper app to equalize shell differences between WinNT and\n" "Win9x and get nmake.exe to accomplish its job.\n", argv[0]); |
︙ | ︙ | |||
309 310 311 312 313 314 315 | || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( | | > > | | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 | || strstr(Err.buffer, "D9002") != NULL || strstr(Out.buffer, "D2021") != NULL || strstr(Err.buffer, "D2021") != NULL); } static int CheckForLinkerFeature( const char **options, int count) { STARTUPINFO si; PROCESS_INFORMATION pi; SECURITY_ATTRIBUTES sa; DWORD threadID; char msg[300]; BOOL ok; HANDLE hProcess, h, pipeThreads[2]; int i; char cmdline[255]; hProcess = GetCurrentProcess(); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES; |
︙ | ︙ | |||
364 365 366 367 368 369 370 | lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ | > | > > > | 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 | lstrcpy(cmdline, "link.exe -nologo "); /* * Append our option for testing. */ for (i = 0; i < count; i++) { lstrcat(cmdline, " \""); lstrcat(cmdline, options[i]); lstrcat(cmdline, "\""); } ok = CreateProcess( NULL, /* Module name. */ cmdline, /* Command line. */ NULL, /* Process handle not inheritable. */ NULL, /* Thread handle not inheritable. */ TRUE, /* yes, inherit handles. */ |
︙ | ︙ | |||
429 430 431 432 433 434 435 | /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || | | > > | 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 | /* * Look for the commandline warning code in the stderr stream. */ return !(strstr(Out.buffer, "LNK1117") != NULL || strstr(Err.buffer, "LNK1117") != NULL || strstr(Out.buffer, "LNK4044") != NULL || strstr(Err.buffer, "LNK4044") != NULL || strstr(Out.buffer, "LNK4224") != NULL || strstr(Err.buffer, "LNK4224") != NULL); } static DWORD WINAPI ReadFromPipe( LPVOID args) { pipeinfo *pi = (pipeinfo *) args; |
︙ | ︙ | |||
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 | list_free(&substPtr); } fclose(fp); return 0; } /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. * Mostly needed to setup paths for testing. */ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > | > > > > > > > > | > > > > > > > > > > > > | > > > > > > > > > > > > > > | > > > > | > > > > > > > | > > > > > > > > > > > > > > > > | > > > | | > > > | 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 | list_free(&substPtr); } fclose(fp); return 0; } BOOL FileExists(LPCTSTR szPath) { #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) #endif DWORD pathAttr = GetFileAttributes(szPath); return (pathAttr != INVALID_FILE_ATTRIBUTES && !(pathAttr & FILE_ATTRIBUTE_DIRECTORY)); } /* * QualifyPath -- * * This composes the current working directory with a provided path * and returns the fully qualified and normalized path. * Mostly needed to setup paths for testing. */ static int QualifyPath( const char *szPath) { char szCwd[MAX_PATH + 1]; GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL); printf("%s\n", szCwd); return 0; } /* * Implements LocateDependency for a single directory. See that command * for an explanation. * Returns 0 if found after printing the directory. * Returns 1 if not found but no errors. * Returns 2 on any kind of error * Basically, these are used as exit codes for the process. */ static int LocateDependencyHelper(const char *dir, const char *keypath) { HANDLE hSearch; char path[MAX_PATH+1]; int dirlen, keylen, ret; WIN32_FIND_DATA finfo; if (dir == NULL || keypath == NULL) return 2; /* Have no real error reporting mechanism into nmake */ dirlen = strlen(dir); if ((dirlen + 3) > sizeof(path)) return 2; strncpy(path, dir, dirlen); strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */ keylen = strlen(keypath); #if 0 /* This function is not available in Visual C++ 6 */ /* * Use numerics 0 -> FindExInfoStandard, * 1 -> FindExSearchLimitToDirectories, * as these are not defined in Visual C++ 6 */ hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0); #else hSearch = FindFirstFile(path, &finfo); #endif if (hSearch == INVALID_HANDLE_VALUE) return 1; /* Not found */ /* Loop through all subdirs checking if the keypath is under there */ ret = 1; /* Assume not found */ do { int sublen; /* * We need to check it is a directory despite the * FindExSearchLimitToDirectories in the above call. See SDK docs */ if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) continue; sublen = strlen(finfo.cFileName); if ((dirlen+1+sublen+1+keylen+1) > sizeof(path)) continue; /* Path does not fit, assume not matched */ strncpy(path+dirlen+1, finfo.cFileName, sublen); path[dirlen+1+sublen] = '\\'; strncpy(path+dirlen+1+sublen+1, keypath, keylen+1); if (FileExists(path)) { /* Found a match, print to stdout */ path[dirlen+1+sublen] = '\0'; QualifyPath(path); ret = 0; break; } } while (FindNextFile(hSearch, &finfo)); FindClose(hSearch); return ret; } /* * LocateDependency -- * * Locates a dependency for a package. * keypath - a relative path within the package directory * that is used to confirm it is the correct directory. * The search path for the package directory is currently only * the parent and grandparent of the current working directory. * If found, the command prints * name_DIRPATH=<full path of located directory> * and returns 0. If not found, does not print anything and returns 1. */ static int LocateDependency(const char *keypath) { int i, ret; static char *paths[] = {"..", "..\\..", "..\\..\\.."}; for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) { ret = LocateDependencyHelper(paths[i], keypath); if (ret == 0) return ret; } return ret; } /* * Local variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * indent-tabs-mode: t * tab-width: 8 * End: */ |
Changes to win/pkg.vc.
1 2 3 4 | # remember to change configure.ac as well when these change # (then re-autoconf) PACKAGE_MAJOR = 2 | | | | 1 2 3 4 5 6 | # remember to change configure.ac as well when these change # (then re-autoconf) PACKAGE_MAJOR = 2 PACKAGE_MINOR = 9 PACKAGE_VERSION = "2.9a1" |
Added win/rules-ext.vc.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | # This file should only be included in makefiles for Tcl extensions, # NOT in the makefile for Tcl itself. !ifndef _RULES_EXT_VC # We need to run from the directory the parent makefile is located in. # nmake does not tell us what makefile was used to invoke it so parent # makefile has to set the MAKEFILEVC macro or we just make a guess and # warn if we think that is not the case. !if "$(MAKEFILEVC)" == "" !if exist("$(PROJECT).vc") MAKEFILEVC = $(PROJECT).vc !elseif exist("makefile.vc") MAKEFILEVC = makefile.vc !endif !endif # "$(MAKEFILEVC)" == "" !if !exist("$(MAKEFILEVC)") MSG = ^ You must run nmake from the directory containing the project makefile.^ If you are doing that and getting this message, set the MAKEFILEVC^ macro to the name of the project makefile. !message WARNING: $(MSG) !endif !if "$(PROJECT)" == "tcl" !error The rules-ext.vc file is not intended for Tcl itself. !endif # We extract version numbers using the nmakehlp program. For now use # the local copy of nmakehlp. Once we locate Tcl, we will use that # one if it is newer. !if [$(CC) -nologo "nmakehlp.c" -link -subsystem:console > nul] !endif # First locate the Tcl directory that we are working with. !if "$(TCLDIR)" != "" _RULESDIR = $(TCLDIR:/=\) !else # If an installation path is specified, that is also the Tcl directory. # Also Tk never builds against an installed Tcl, it needs Tcl sources !if defined(INSTALLDIR) && "$(PROJECT)" != "tk" _RULESDIR=$(INSTALLDIR:/=\) !else # Locate Tcl sources !if [echo _RULESDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] _RULESDIR = ..\..\tcl !else !include nmakehlp.out !endif !endif # defined(INSTALLDIR).... !endif # ifndef TCLDIR # Now look for the targets.vc file under the Tcl root. Note we check this # file and not rules.vc because the latter also exists on older systems. !if exist("$(_RULESDIR)\lib\nmake\targets.vc") # Building against installed Tcl _RULESDIR = $(_RULESDIR)\lib\nmake !elseif exist("$(_RULESDIR)\win\targets.vc") # Building against Tcl sources _RULESDIR = $(_RULESDIR)\win !else # If we have not located Tcl's targets file, most likely we are compiling # against an older version of Tcl and so must use our own support files. _RULESDIR = . !endif !if "$(_RULESDIR)" != "." # Potentially using Tcl's support files. If this extension has its own # nmake support files, need to compare the versions and pick newer. !if exist("rules.vc") # The extension has its own copy !if [echo TCL_RULES_MAJOR = \> versions.vc] \ && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MAJOR >> versions.vc] !endif !if [echo TCL_RULES_MINOR = \>> versions.vc] \ && [nmakehlp -V "$(_RULESDIR)\rules.vc" RULES_VERSION_MINOR >> versions.vc] !endif !if [echo OUR_RULES_MAJOR = \>> versions.vc] \ && [nmakehlp -V "rules.vc" RULES_VERSION_MAJOR >> versions.vc] !endif !if [echo OUR_RULES_MINOR = \>> versions.vc] \ && [nmakehlp -V "rules.vc" RULES_VERSION_MINOR >> versions.vc] !endif !include versions.vc # We have a newer version of the support files, use them !if ($(TCL_RULES_MAJOR) != $(OUR_RULES_MAJOR)) || ($(TCL_RULES_MINOR) < $(OUR_RULES_MINOR)) _RULESDIR = . !endif !endif # if exist("rules.vc") !endif # if $(_RULESDIR) != "." # Let rules.vc know what copy of nmakehlp.c to use. NMAKEHLPC = $(_RULESDIR)\nmakehlp.c # Get rid of our internal defines before calling rules.vc !undef TCL_RULES_MAJOR !undef TCL_RULES_MINOR !undef OUR_RULES_MAJOR !undef OUR_RULES_MINOR !if exist("$(_RULESDIR)\rules.vc") !message *** Using $(_RULESDIR)\rules.vc !include "$(_RULESDIR)\rules.vc" !else !error *** Could not locate rules.vc in $(_RULESDIR) !endif !endif # _RULES_EXT_VC |
Changes to win/rules.vc.
|
| | | | > > < < > > | > > > > > > | > | > > | > > > | > > > > > > > > | > | < > > > > | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < > < < < < < < < < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > < < < < < | < > | | < > | > > > > > > > > > > > > > | | > > > | > > > > | < < < > > > > > < < < < | | | > > > > > > > > | > > | < < < > > > | < | < > > > > < < | < < < < < | | < < | < < < < < < < < < < < < < < < < < < < | > > > > > > > > | > | | < > | > | > > > > > < < > > > | < > | > > > > > | > | > > > > > > | > > | > > > > > > > > > | | > < > > > > > > > > > > > > > > > > > > > | < > > > > > > < > > > | < < | > > > > > > > > > > > > | | > > > > > > > > > > > > > > | > > | > > > > > > > > > > > | > > > | | | > > > > > > < < > | < | < < > > > > > > > > | < > > > > | < < > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > | > > > > > > | > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < | < | > > | > > > > > > > > > > > > > > | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 | #------------------------------------------------------------- -*- makefile -*- # rules.vc -- # # Part of the nmake based build system for Tcl and its extensions. # This file does all the hard work in terms of parsing build options, # compiler switches, defining common targets and macros. The Tcl makefile # directly includes this. Extensions include it via "rules-ext.vc". # # See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for # detailed documentation. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # # Copyright (c) 2001-2003 David Gravereaux. # Copyright (c) 2003-2008 Patrick Thoyts # Copyright (c) 2017 Ashok P. Nadkarni #------------------------------------------------------------------------------ !ifndef _RULES_VC _RULES_VC = 1 # The following macros define the version of the rules.vc nmake build system # For modifications that are not backward-compatible, you *must* change # the major version. RULES_VERSION_MAJOR = 1 RULES_VERSION_MINOR = 2 # The PROJECT macro must be defined by parent makefile. !if "$(PROJECT)" == "" !error *** Error: Macro PROJECT not defined! Please define it before including rules.vc !endif !if "$(PRJ_PACKAGE_TCLNAME)" == "" PRJ_PACKAGE_TCLNAME = $(PROJECT) !endif # Also special case Tcl and Tk to save some typing later DOING_TCL = 0 DOING_TK = 0 !if "$(PROJECT)" == "tcl" DOING_TCL = 1 !elseif "$(PROJECT)" == "tk" DOING_TK = 1 !endif !ifndef NEED_TK # Backwards compatibility !ifdef PROJECT_REQUIRES_TK NEED_TK = $(PROJECT_REQUIRES_TK) !else NEED_TK = 0 !endif !endif !ifndef NEED_TCL_SOURCE NEED_TCL_SOURCE = 0 !endif !ifdef NEED_TK_SOURCE !if $(NEED_TK_SOURCE) NEED_TK = 1 !endif !else NEED_TK_SOURCE = 0 !endif ################################################################ # Nmake is a pretty weak environment in syntax and capabilities # so this file is necessarily verbose. It's broken down into # the following parts. # # 0. Sanity check that compiler environment is set up and initialize # any built-in settings from the parent makefile # 1. First define the external tools used for compiling, copying etc. # as this is independent of everything else. # 2. Figure out our build structure in terms of the directory, whether # we are building Tcl or an extension, etc. # 3. Determine the compiler and linker versions # 4. Build the nmakehlp helper application # 5. Determine the supported compiler options and features # 6. Parse the OPTS macro value for user-specified build configuration # 7. Parse the STATS macro value for statistics instrumentation # 8. Parse the CHECKS macro for additional compilation checks # 9. Extract Tcl, and possibly Tk, version numbers from the headers # 10. Based on this selected configuration, construct the output # directory and file paths # 11. Construct the paths where the package is to be installed # 12. Set up the actual options passed to compiler and linker based # on the information gathered above. # 13. Define some standard build targets and implicit rules. These may # be optionally disabled by the parent makefile. # 14. (For extensions only.) Compare the configuration of the target # Tcl and the extensions and warn against discrepancies. # # One final note about the macro names used. They are as they are # for historical reasons. We would like legacy extensions to # continue to work with this make include file so be wary of # changing them for consistency or clarity. # 0. Sanity check compiler environment # Check to see we are configured to build with MSVC (MSDEVDIR, MSVCDIR or # VCINSTALLDIR) or with the MS Platform SDK (MSSDK or WindowsSDKDir) !if !defined(MSDEVDIR) && !defined(MSVCDIR) && !defined(VCINSTALLDIR) && !defined(MSSDK) && !defined(WINDOWSSDKDIR) MSG = ^ Visual C++ compiler environment not initialized. !error $(MSG) !endif # We need to run from the directory the parent makefile is located in. # nmake does not tell us what makefile was used to invoke it so parent # makefile has to set the MAKEFILEVC macro or we just make a guess and # warn if we think that is not the case. !if "$(MAKEFILEVC)" == "" !if exist("$(PROJECT).vc") MAKEFILEVC = $(PROJECT).vc !elseif exist("makefile.vc") MAKEFILEVC = makefile.vc !endif !endif # "$(MAKEFILEVC)" == "" !if !exist("$(MAKEFILEVC)") MSG = ^ You must run nmake from the directory containing the project makefile.^ If you are doing that and getting this message, set the MAKEFILEVC^ macro to the name of the project makefile. !message WARNING: $(MSG) !endif ################################################################ # 1. Define external programs being used #---------------------------------------------------------- # Set the proper copy method to avoid overwrite questions # to the user when copying files and selecting the right # "delete all" method. #---------------------------------------------------------- RMDIR = rmdir /S /Q CPY = xcopy /i /y >NUL CPYDIR = xcopy /e /i /y >NUL COPY = copy /y >NUL MKDIR = mkdir ###################################################################### # 2. Figure out our build environment in terms of what we're building. # # (a) Tcl itself # (b) Tk # (c) a Tcl extension using libraries/includes from an *installed* Tcl # (d) a Tcl extension using libraries/includes from Tcl source directory # # This last is needed because some extensions still need # some Tcl interfaces that are not publicly exposed. # # The fragment will set the following macros: # ROOT - root of this module sources # COMPATDIR - source directory that holds compatibility sources # DOCDIR - source directory containing documentation files # GENERICDIR - platform-independent source directory # WINDIR - Windows-specific source directory # TESTDIR - directory containing test files # TOOLSDIR - directory containing build tools # _TCLDIR - root of the Tcl installation OR the Tcl sources. Not set # when building Tcl itself. # _INSTALLDIR - native form of the installation path. For Tcl # this will be the root of the Tcl installation. For extensions # this will be the lib directory under the root. # TCLINSTALL - set to 1 if _TCLDIR refers to # headers and libraries from an installed Tcl, and 0 if built against # Tcl sources. Not set when building Tcl itself. Yes, not very well # named. # _TCL_H - native path to the tcl.h file # # If Tk is involved, also sets the following # _TKDIR - native form Tk installation OR Tk source. Not set if building # Tk itself. # TKINSTALL - set 1 if _TKDIR refers to installed Tk and 0 if Tk sources # _TK_H - native path to the tk.h file # Root directory for sources and assumed subdirectories ROOT = $(MAKEDIR)\.. # The following paths CANNOT have spaces in them as they appear on the # left side of implicit rules. !ifndef COMPATDIR COMPATDIR = $(ROOT)\compat !endif !ifndef DOCDIR DOCDIR = $(ROOT)\doc !endif !ifndef GENERICDIR GENERICDIR = $(ROOT)\generic !endif !ifndef TOOLSDIR TOOLSDIR = $(ROOT)\tools !endif !ifndef TESTDIR TESTDIR = $(ROOT)\tests !endif !ifndef LIBDIR !if exist("$(ROOT)\library") LIBDIR = $(ROOT)\library !else LIBDIR = $(ROOT)\lib !endif !endif !ifndef DEMODIR !if exist("$(LIBDIR)\demos") DEMODIR = $(LIBDIR)\demos !else DEMODIR = $(ROOT)\demos !endif !endif # ifndef DEMODIR # Do NOT enclose WINDIR in a !ifndef because Windows always defines # WINDIR env var to point to c:\windows! # TBD - This is a potentially dangerous conflict, rename WINDIR to # something else WINDIR = $(ROOT)\win !ifndef RCDIR !if exist("$(WINDIR)\rc") RCDIR = $(WINDIR)\rc !else RCDIR = $(WINDIR) !endif !endif RCDIR = $(RCDIR:/=\) # The target directory where the built packages and binaries will be installed. # INSTALLDIR is the (optional) path specified by the user. # _INSTALLDIR is INSTALLDIR using the backslash separator syntax !ifdef INSTALLDIR ### Fix the path separators. _INSTALLDIR = $(INSTALLDIR:/=\) !else ### Assume the normal default. _INSTALLDIR = $(HOMEDRIVE)\Tcl !endif !if $(DOING_TCL) # BEGIN Case 2(a) - Building Tcl itself # Only need to define _TCL_H _TCL_H = ..\generic\tcl.h # END Case 2(a) - Building Tcl itself !elseif $(DOING_TK) # BEGIN Case 2(b) - Building Tk TCLINSTALL = 0 # Tk always builds against Tcl source, not an installed Tcl !if "$(TCLDIR)" == "" !if [echo TCLDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] !error *** Could not locate Tcl source directory. !endif !include nmakehlp.out !endif # TCLDIR == "" _TCLDIR = $(TCLDIR:/=\) _TCL_H = $(_TCLDIR)\generic\tcl.h !if !exist("$(_TCL_H)") !error Could not locate tcl.h. Please set the TCLDIR macro to point to the Tcl *source* directory. !endif _TK_H = ..\generic\tk.h # END Case 2(b) - Building Tk !else # BEGIN Case 2(c) or (d) - Building an extension other than Tk # If command line has specified Tcl location through TCLDIR, use it # else default to the INSTALLDIR setting !if "$(TCLDIR)" != "" _TCLDIR = $(TCLDIR:/=\) !if exist("$(_TCLDIR)\include\tcl.h") # Case 2(c) with TCLDIR defined TCLINSTALL = 1 _TCL_H = $(_TCLDIR)\include\tcl.h !elseif exist("$(_TCLDIR)\generic\tcl.h") # Case 2(d) with TCLDIR defined TCLINSTALL = 0 _TCL_H = $(_TCLDIR)\generic\tcl.h !endif !else # # Case 2(c) for extensions with TCLDIR undefined # Need to locate Tcl depending on whether it needs Tcl source or not. # If we don't, check the INSTALLDIR for an installed Tcl first !if exist("$(_INSTALLDIR)\include\tcl.h") && !$(NEED_TCL_SOURCE) TCLINSTALL = 1 TCLDIR = $(_INSTALLDIR)\.. # NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions # later so the \.. accounts for the /lib _TCLDIR = $(_INSTALLDIR)\.. _TCL_H = $(_TCLDIR)\include\tcl.h !else # exist(...) && ! $(NEED_TCL_SOURCE) !if [echo _TCLDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tcl.h >> nmakehlp.out] !error *** Could not locate Tcl source directory. !endif !include nmakehlp.out TCLINSTALL = 0 TCLDIR = $(_TCLDIR) _TCL_H = $(_TCLDIR)\generic\tcl.h !endif # exist(...) && ! $(NEED_TCL_SOURCE) !endif # TCLDIR !ifndef _TCL_H MSG =^ Failed to find tcl.h. The TCLDIR macro is set incorrectly or is not set and default path does not contain tcl.h. !error $(MSG) !endif # Now do the same to locate Tk headers and libs if project requires Tk !if $(NEED_TK) !if "$(TKDIR)" != "" _TKDIR = $(TKDIR:/=\) !if exist("$(_TKDIR)\include\tk.h") TKINSTALL = 1 _TK_H = $(_TKDIR)\include\tk.h !elseif exist("$(_TKDIR)\generic\tk.h") TKINSTALL = 0 _TK_H = $(_TKDIR)\generic\tk.h !endif !else # TKDIR not defined # Need to locate Tcl depending on whether it needs Tcl source or not. # If we don't, check the INSTALLDIR for an installed Tcl first !if exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) TKINSTALL = 1 # NOTE: we will be resetting _INSTALLDIR to _INSTALLDIR/lib for extensions # later so the \.. accounts for the /lib _TKDIR = $(_INSTALLDIR)\.. _TK_H = $(_TKDIR)\include\tk.h TKDIR = $(_TKDIR) !else # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) !if [echo _TKDIR = \> nmakehlp.out] \ || [nmakehlp -L generic\tk.h >> nmakehlp.out] !error *** Could not locate Tk source directory. !endif !include nmakehlp.out TKINSTALL = 0 TKDIR = $(_TKDIR) _TK_H = $(_TKDIR)\generic\tk.h !endif # exist("$(_INSTALLDIR)\include\tk.h") && !$(NEED_TK_SOURCE) !endif # TKDIR !ifndef _TK_H MSG =^ Failed to find tk.h. The TKDIR macro is set incorrectly or is not set and default path does not contain tk.h. !error $(MSG) !endif !endif # NEED_TK !if $(NEED_TCL_SOURCE) && $(TCLINSTALL) MSG = ^ *** Warning: This extension requires the source distribution of Tcl.^ *** Please set the TCLDIR macro to point to the Tcl sources. !error $(MSG) !endif !if $(NEED_TK_SOURCE) !if $(TKINSTALL) MSG = ^ *** Warning: This extension requires the source distribution of Tk.^ *** Please set the TKDIR macro to point to the Tk sources. !error $(MSG) !endif !endif # If INSTALLDIR set to Tcl installation root dir then reset to the # lib dir for installing extensions !if exist("$(_INSTALLDIR)\include\tcl.h") _INSTALLDIR=$(_INSTALLDIR)\lib !endif # END Case 2(c) or (d) - Building an extension !endif # if $(DOING_TCL) ################################################################ # 3. Determine compiler version and architecture # In this section, we figure out the compiler version and the # architecture for which we are building. This sets the # following macros: # VCVERSION - the internal compiler version as 1200, 1400, 1910 etc. # This is also printed by the compiler in dotted form 19.10 etc. # VCVER - the "marketing version", for example Visual C++ 6 for internal # compiler version 1200. This is kept only for legacy reasons as it # does not make sense for recent Microsoft compilers. Only used for # output directory names. # ARCH - set to IX86 or AMD64 depending on 32- or 64-bit target # NATIVE_ARCH - set to IX86 or AMD64 for the host machine # MACHINE - same as $(ARCH) - legacy # _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed # CFG_ENCODING - set to an character encoding. # TBD - this is passed to compiler as TCL_CFGVAL_ENCODING but can't # see where it is used cc32 = $(CC) # built-in default. link32 = link lib32 = lib rc32 = $(RC) # built-in default. #---------------------------------------------------------------- # Figure out the compiler architecture and version by writing # the C macros to a file, preprocessing them with the C # preprocessor and reading back the created file _HASH=^# _VC_MANIFEST_EMBED_EXE= _VC_MANIFEST_EMBED_DLL= VCVER=0 !if ![echo VCVERSION=_MSC_VER > vercl.x] \ && ![echo $(_HASH)if defined(_M_IX86) >> vercl.x] \ && ![echo ARCH=IX86 >> vercl.x] \ && ![echo $(_HASH)elif defined(_M_AMD64) >> vercl.x] \ && ![echo ARCH=AMD64 >> vercl.x] \ && ![echo $(_HASH)endif >> vercl.x] \ && ![$(cc32) -nologo -TC -P vercl.x 2>NUL] !include vercl.i !if $(VCVERSION) < 1900 !if ![echo VCVER= ^\> vercl.vc] \ && ![set /a $(VCVERSION) / 100 - 6 >> vercl.vc] !include vercl.vc !endif !else # The simple calculation above does not apply to new Visual Studio releases # Keep the compiler version in its native form. VCVER = $(VCVERSION) !endif !endif !if ![del 2>NUL /q/f vercl.x vercl.i vercl.vc] !endif #---------------------------------------------------------------- # The MACHINE macro is used by legacy makefiles so set it as well !ifdef MACHINE !if "$(MACHINE)" == "x86" !undef MACHINE MACHINE = IX86 !elseif "$(MACHINE)" == "x64" !undef MACHINE MACHINE = AMD64 !endif !if "$(MACHINE)" != "$(ARCH)" !error Specified MACHINE macro $(MACHINE) does not match detected target architecture $(ARCH). !endif !else MACHINE=$(ARCH) !endif #------------------------------------------------------------ # Figure out the *host* architecture by reading the registry !if ![reg query HKLM\Hardware\Description\System\CentralProcessor\0 /v Identifier | findstr /i x86] NATIVE_ARCH=IX86 !else NATIVE_ARCH=AMD64 !endif # Since MSVC8 we must deal with manifest resources. !if $(VCVERSION) >= 1400 _VC_MANIFEST_EMBED_EXE=if exist [email protected] mt -nologo -manifest [email protected] -outputresource:$@;1 _VC_MANIFEST_EMBED_DLL=if exist [email protected] mt -nologo -manifest [email protected] -outputresource:$@;2 !endif !ifndef CFG_ENCODING CFG_ENCODING = \"cp1252\" !endif ################################################################ # 4. Build the nmakehlp program # This is a helper app we need to overcome nmake's limiting # environment. We will call out to it to get various bits of # information about supported compiler options etc. # # Tcl itself will always use the nmakehlp.c program which is # in its own source. This is the "master" copy and kept updated. # # Extensions built against an installed Tcl will use the installed # copy of Tcl's nmakehlp.c if there is one and their own version # otherwise. In the latter case, they would also be using their own # rules.vc. Note that older versions of Tcl do not install nmakehlp.c # or rules.vc. # # Extensions built against Tcl sources will use the one from the Tcl source. # # When building an extension using a sufficiently new version of Tcl, # rules-ext.vc will define NMAKEHLPC appropriately to point to the # copy of nmakehlp.c to be used. !ifndef NMAKEHLPC # Default to the one in the current directory (the extension's own nmakehlp.c) NMAKEHLPC = nmakehlp.c !if !$(DOING_TCL) !if $(TCLINSTALL) !if exist("$(_TCLDIR)\lib\nmake\nmakehlp.c") NMAKEHLPC = $(_TCLDIR)\lib\nmake\nmakehlp.c !endif !else # ! $(TCLINSTALL) !if exist("$(_TCLDIR)\win\nmakehlp.c") NMAKEHLPC = $(_TCLDIR)\win\nmakehlp.c !endif !endif # $(TCLINSTALL) !endif # !$(DOING_TCL) !endif # NMAKEHLPC # We always build nmakehlp even if it exists since we do not know # what source it was built from. !if [$(cc32) -nologo "$(NMAKEHLPC)" -link -subsystem:console > nul] !endif ################################################################ # 5. Test for compiler features # Visual C++ compiler options have changed over the years. Check # which options are supported by the compiler in use. # # The following macros are set: # OPTIMIZATIONS - the compiler flags to be used for optimized builds # DEBUGFLAGS - the compiler flags to be used for debug builds # LINKERFLAGS - Flags passed to the linker # # Note that these are the compiler settings *available*, not those # that will be *used*. The latter depends on the OPTS macro settings # which we have not yet parsed. # # Also note that some of the flags in OPTIMIZATIONS are not really # related to optimization. They are placed there only for legacy reasons # as some extensions expect them to be included in that macro. # -Op improves float consistency. Note only needed for older compilers # Newer compilers do not need or support this option. !if [nmakehlp -c -Op] FPOPTS = -Op !endif # Strict floating point semantics - present in newer compilers in lieu of -Op !if [nmakehlp -c -fp:strict] FPOPTS = $(FPOPTS) -fp:strict !endif !if "$(MACHINE)" == "IX86" ### test for pentium errata !if [nmakehlp -c -QI0f] !message *** Compiler has 'Pentium 0x0f fix' FPOPTS = $(FPOPTS) -QI0f !else !message *** Compiler does not have 'Pentium 0x0f fix' !endif !endif ### test for optimizations # /O2 optimization includes /Og /Oi /Ot /Oy /Ob2 /Gs /GF /Gy as per # documentation. Note we do NOT want /Gs as that inserts a _chkstk # stack probe at *every* function entry, not just those with more than # a page of stack allocation resulting in a performance hit. However, # /O2 documentation is misleading as its stack probes are simply the # default page size locals allocation probes and not what is implied # by an explicit /Gs option. OPTIMIZATIONS = $(FPOPTS) !if [nmakehlp -c -O2] OPTIMIZING = 1 OPTIMIZATIONS = $(OPTIMIZATIONS) -O2 !else # Legacy, really. All modern compilers support this !message *** Compiler does not have 'Optimizations' OPTIMIZING = 0 !endif # Checks for buffer overflows in local arrays !if [nmakehlp -c -GS] OPTIMIZATIONS = $(OPTIMIZATIONS) -GS !endif # Link time optimization. Note that this option (potentially) makes # generated libraries only usable by the specific VC++ version that # created it. Requires /LTCG linker option !if [nmakehlp -c -GL] OPTIMIZATIONS = $(OPTIMIZATIONS) -GL CC_GL_OPT_ENABLED = 1 !else # In newer compilers -GL and -YX are incompatible. !if [nmakehlp -c -YX] OPTIMIZATIONS = $(OPTIMIZATIONS) -YX !endif !endif # [nmakehlp -c -GL] DEBUGFLAGS = $(FPOPTS) # Run time error checks. Not available or valid in a release, non-debug build # RTC is for modern compilers, -GZ is legacy !if [nmakehlp -c -RTC1] DEBUGFLAGS = $(DEBUGFLAGS) -RTC1 !elseif [nmakehlp -c -GZ] DEBUGFLAGS = $(DEBUGFLAGS) -GZ !endif #---------------------------------------------------------------- # Linker flags # LINKER_TESTFLAGS are for internal use when we call nmakehlp to test # if the linker supports a specific option. Without these flags link will # return "LNK1561: entry point must be defined" error compiling from VS-IDE: # They are not passed through to the actual application / extension # link rules. !ifndef LINKER_TESTFLAGS LINKER_TESTFLAGS = /DLL /NOENTRY /OUT:nmakehlp.out !endif LINKERFLAGS = # If compiler has enabled link time optimization, linker must too with -ltcg !ifdef CC_GL_OPT_ENABLED !if [nmakehlp -l -ltcg $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS) -ltcg !endif !endif ######################################################################## # 6. Parse the OPTS macro to work out the requested build configuration. # Based on this, we will construct the actual switches to be passed to the # compiler and linker using the macros defined in the previous section. # The following macros are defined by this section based on OPTS # STATIC_BUILD - 0 -> Tcl is to be built as a shared library # 1 -> build as a static library and shell # TCL_THREADS - legacy but always 1 on Windows since winsock requires it. # DEBUG - 1 -> debug build, 0 -> release builds # SYMBOLS - 1 -> generate PDB's, 0 -> no PDB's # PROFILE - 1 -> generate profiling info, 0 -> no profiling # PGO - 1 -> profile based optimization, 0 -> no # MSVCRT - 1 -> link to dynamic C runtime even when building static Tcl build # 0 -> link to static C runtime for static Tcl build. # Does not impact shared Tcl builds (STATIC_BUILD == 0) # TCL_USE_STATIC_PACKAGES - 1 -> statically link the registry and dde extensions # in the Tcl shell. 0 -> keep them as shared libraries # Does not impact shared Tcl builds. # USE_THREAD_ALLOC - 1 -> Use a shared global free pool for allocation. # 0 -> Use the non-thread allocator. # UNCHECKED - 1 -> when doing a debug build with symbols, use the release # C runtime, 0 -> use the debug C runtime. # USE_STUBS - 1 -> compile to use stubs interfaces, 0 -> direct linking # CONFIG_CHECK - 1 -> check current build configuration against Tcl # configuration (ignored for Tcl itself) # Further, LINKERFLAGS are modified based on above. # Default values for all the above STATIC_BUILD = 0 TCL_THREADS = 1 DEBUG = 0 SYMBOLS = 0 PROFILE = 0 PGO = 0 MSVCRT = 1 TCL_USE_STATIC_PACKAGES = 0 USE_THREAD_ALLOC = 1 UNCHECKED = 0 CONFIG_CHECK = 1 !if $(DOING_TCL) USE_STUBS = 0 !else USE_STUBS = 1 !endif # If OPTS is not empty AND does not contain "none" which turns off all OPTS # set the above macros based on OPTS content !if "$(OPTS)" != "" && ![nmakehlp -f "$(OPTS)" "none"] # OPTS are specified, parse them !if [nmakehlp -f $(OPTS) "static"] !message *** Doing static STATIC_BUILD = 1 !endif !if [nmakehlp -f $(OPTS) "nostubs"] !message *** Not using stubs USE_STUBS = 0 !endif !if [nmakehlp -f $(OPTS) "nomsvcrt"] !message *** Doing nomsvcrt MSVCRT = 0 !else !if [nmakehlp -f $(OPTS) "msvcrt"] !message *** Doing msvcrt MSVCRT = 1 !else !if !$(STATIC_BUILD) MSVCRT = 1 !else MSVCRT = 0 !endif !endif !endif # [nmakehlp -f $(OPTS) "nomsvcrt"] !if [nmakehlp -f $(OPTS) "staticpkg"] && $(STATIC_BUILD) !message *** Doing staticpkg TCL_USE_STATIC_PACKAGES = 1 !else TCL_USE_STATIC_PACKAGES = 0 !endif !if [nmakehlp -f $(OPTS) "nothreads"] !message *** Compile explicitly for non-threaded tcl TCL_THREADS = 0 USE_THREAD_ALLOC= 0 !else TCL_THREADS = 1 USE_THREAD_ALLOC= 1 !endif !if [nmakehlp -f $(OPTS) "symbols"] !message *** Doing symbols DEBUG = 1 !else DEBUG = 0 !endif !if [nmakehlp -f $(OPTS) "pdbs"] !message *** Doing pdbs SYMBOLS = 1 !else SYMBOLS = 0 !endif !if [nmakehlp -f $(OPTS) "profile"] !message *** Doing profile PROFILE = 1 !else PROFILE = 0 !endif !if [nmakehlp -f $(OPTS) "pgi"] !message *** Doing profile guided optimization instrumentation PGO = 1 !elseif [nmakehlp -f $(OPTS) "pgo"] !message *** Doing profile guided optimization PGO = 2 !else PGO = 0 !endif !if [nmakehlp -f $(OPTS) "loimpact"] !message *** Warning: ignoring option "loimpact" - deprecated on modern Windows. !endif # TBD - should get rid of this option !if [nmakehlp -f $(OPTS) "thrdalloc"] !message *** Doing thrdalloc USE_THREAD_ALLOC = 1 !endif !if [nmakehlp -f $(OPTS) "tclalloc"] USE_THREAD_ALLOC = 0 !endif !if [nmakehlp -f $(OPTS) "unchecked"] !message *** Doing unchecked UNCHECKED = 1 !else UNCHECKED = 0 !endif !if [nmakehlp -f $(OPTS) "noconfigcheck"] CONFIG_CHECK = 1 !else CONFIG_CHECK = 0 !endif !endif # "$(OPTS)" != "" && ... parsing of OPTS # Set linker flags based on above !if $(PGO) > 1 !if [nmakehlp -l -ltcg:pgoptimize $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pgoptimize !else MSG=^ This compiler does not support profile guided optimization. !error $(MSG) !endif !elseif $(PGO) > 0 !if [nmakehlp -l -ltcg:pginstrument $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS:-ltcg=) -ltcg:pginstrument !else MSG=^ This compiler does not support profile guided optimization. !error $(MSG) !endif !endif ################################################################ # 7. Parse the STATS macro to configure code instrumentation # The following macros are set by this section: # TCL_MEM_DEBUG - 1 -> enables memory allocation instrumentation # 0 -> disables # TCL_COMPILE_DEBUG - 1 -> enables byte compiler logging # 0 -> disables # Default both are off TCL_MEM_DEBUG = 0 TCL_COMPILE_DEBUG = 0 !if "$(STATS)" != "" && ![nmakehlp -f "$(STATS)" "none"] !if [nmakehlp -f $(STATS) "memdbg"] !message *** Doing memdbg TCL_MEM_DEBUG = 1 !else TCL_MEM_DEBUG = 0 !endif !if [nmakehlp -f $(STATS) "compdbg"] !message *** Doing compdbg TCL_COMPILE_DEBUG = 1 !else TCL_COMPILE_DEBUG = 0 !endif !endif #################################################################### # 8. Parse the CHECKS macro to configure additional compiler checks # The following macros are set by this section: # WARNINGS - compiler switches that control the warnings level # TCL_NO_DEPRECATED - 1 -> disable support for deprecated functions # 0 -> enable deprecated functions # Defaults - Permit deprecated functions and warning level 3 TCL_NO_DEPRECATED = 0 WARNINGS = -W3 !if "$(CHECKS)" != "" && ![nmakehlp -f "$(CHECKS)" "none"] !if [nmakehlp -f $(CHECKS) "nodep"] !message *** Doing nodep check TCL_NO_DEPRECATED = 1 !endif !if [nmakehlp -f $(CHECKS) "fullwarn"] !message *** Doing full warnings check WARNINGS = -W4 !if [nmakehlp -l -warn:3 $(LINKER_TESTFLAGS)] LINKERFLAGS = $(LINKERFLAGS) -warn:3 !endif !endif !if [nmakehlp -f $(CHECKS) "64bit"] && [nmakehlp -c -Wp64] !message *** Doing 64bit portability warnings WARNINGS = $(WARNINGS) -Wp64 !endif !endif ################################################################ # 9. Extract various version numbers # For Tcl and Tk, version numbers are extracted from tcl.h and tk.h # respectively. For extensions, versions are extracted from the # configure.in or configure.ac from the TEA configuration if it # exists, and unset otherwise. # Sets the following macros: # TCL_MAJOR_VERSION # TCL_MINOR_VERSION # TCL_PATCH_LEVEL # TCL_VERSION # TK_MAJOR_VERSION # TK_MINOR_VERSION # TK_PATCH_LEVEL # TK_VERSION # DOTVERSION - set as (for example) 2.5 # VERSION - set as (for example 25) #-------------------------------------------------------------- !if [echo REM = This file is generated from rules.vc > versions.vc] !endif !if [echo TCL_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_MAJOR_VERSION >> versions.vc] !endif !if [echo TCL_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_MINOR_VERSION >> versions.vc] !endif !if [echo TCL_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V "$(_TCL_H)" TCL_PATCH_LEVEL >> versions.vc] !endif !if defined(_TK_H) !if [echo TK_MAJOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_MAJOR_VERSION >> versions.vc] !endif !if [echo TK_MINOR_VERSION = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_MINOR_VERSION >> versions.vc] !endif !if [echo TK_PATCH_LEVEL = \>> versions.vc] \ && [nmakehlp -V $(_TK_H) TK_PATCH_LEVEL >> versions.vc] !endif !endif # _TK_H !include versions.vc TCL_VERSION = $(TCL_MAJOR_VERSION)$(TCL_MINOR_VERSION) TCL_DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) !if defined(_TK_H) TK_VERSION = $(TK_MAJOR_VERSION)$(TK_MINOR_VERSION) TK_DOTVERSION = $(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) !endif # Set DOTVERSION and VERSION !if $(DOING_TCL) DOTVERSION = $(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) VERSION = $(TCL_VERSION) !elseif $(DOING_TK) DOTVERSION = $(TK_DOTVERSION) VERSION = $(TK_VERSION) !else # Doing a non-Tk extension # If parent makefile has not defined DOTVERSION, try to get it from TEA # first from a configure.in file, and then from configure.ac !ifndef DOTVERSION !if [echo DOTVERSION = \> versions.vc] \ || [nmakehlp -V $(ROOT)\configure.in ^[$(PROJECT)^] >> versions.vc] !if [echo DOTVERSION = \> versions.vc] \ || [nmakehlp -V $(ROOT)\configure.ac ^[$(PROJECT)^] >> versions.vc] !error *** Could not figure out extension version. Please define DOTVERSION in parent makefile before including rules.vc. !endif !endif !include versions.vc !endif # DOTVERSION VERSION = $(DOTVERSION:.=) !endif # $(DOING_TCL) ... etc. ################################################################ # 10. Construct output directory and file paths # Figure-out how to name our intermediate and output directories. # In order to avoid inadvertent mixing of object files built using # different compilers, build configurations etc., # # Naming convention (suffixes): # t = full thread support. # s = static library (as opposed to an import library) # g = linked to the debug enabled C run-time. # x = special static build when it links to the dynamic C run-time. # # The following macros are set in this section: # SUFX - the suffix to use for binaries based on above naming convention # BUILDDIRTOP - the toplevel default output directory # is of the form {Release,Debug}[_AMD64][_COMPILERVERSION] # TMP_DIR - directory where object files are created # OUT_DIR - directory where output executables are created # Both TMP_DIR and OUT_DIR are defaulted only if not defined by the # parent makefile (or command line). The default values are # based on BUILDDIRTOP. # STUBPREFIX - name of the stubs library for this project # PRJIMPLIB - output path of the generated project import library # PRJLIBNAME - name of generated project library # PRJLIB - output path of generated project library # PRJSTUBLIBNAME - name of the generated project stubs library # PRJSTUBLIB - output path of the generated project stubs library # RESFILE - output resource file (only if not static build) SUFX = tsgx !if $(DEBUG) BUILDDIRTOP = Debug !else BUILDDIRTOP = Release !endif |
︙ | ︙ | |||
334 335 336 337 338 339 340 | TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll | < < | 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 | TMP_DIRFULL = .\$(BUILDDIRTOP)\$(PROJECT)_ThreadedDynamicStaticX !if !$(STATIC_BUILD) TMP_DIRFULL = $(TMP_DIRFULL:Static=) SUFX = $(SUFX:s=) EXT = dll TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !else TMP_DIRFULL = $(TMP_DIRFULL:Dynamic=) EXT = lib !if !$(MSVCRT) TMP_DIRFULL = $(TMP_DIRFULL:X=) SUFX = $(SUFX:x=) !endif |
︙ | ︙ | |||
363 364 365 366 367 368 369 370 | !endif !else !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif | > > > > > > > > > > > > | > > | > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | < > | | < > > > > > > | > | > > > > > | | | > | > | > > > > > < > > > > > > > > < < < > > > > > > < < < | | > | | > > > > > > | | > > > > > > > > > < < | < < | > | < | > | > > > > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > | > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > < < < > > > > > > > > > > > | | | > | > > > > > < | < > > > > > > > > > > > | > > > > > > > > > > > | > | < > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | < | < < < < < | | | < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > | > | < > > > > > > > | > > > | > > > | | < < | > > | | | | | | > | > > | > > | > > > | > > | > > > > > > > > > > > > > > > | > > > > > > > > > > > | > | > > > > | > > > > > > > > > | > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | > > | > | | | | < < | | > > > > > > | | | | | > | > > > > | | > > > | > | > | > > > > | | | | < < < | > > > > > > > > > | | > > > > > > > > > | > | | | | | | | | | | | | > | < | > > > | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < > > > > > > > > > | > > > > > > > > > > < | < < | | 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 | !endif !else !ifndef OUT_DIR OUT_DIR = $(TMP_DIR) !endif !endif # Relative paths -> absolute !if [echo OUT_DIR = \> nmakehlp.out] \ || [nmakehlp -Q "$(OUT_DIR)" >> nmakehlp.out] !error *** Could not fully qualify path OUT_DIR=$(OUT_DIR) !endif !if [echo TMP_DIR = \>> nmakehlp.out] \ || [nmakehlp -Q "$(TMP_DIR)" >> nmakehlp.out] !error *** Could not fully qualify path TMP_DIR=$(TMP_DIR) !endif !include nmakehlp.out # The name of the stubs library for the project being built STUBPREFIX = $(PROJECT)stub # Set up paths to various Tcl executables and libraries needed by extensions !if $(DOING_TCL) TCLSHNAME = $(PROJECT)sh$(VERSION)$(SUFX).exe TCLSH = $(OUT_DIR)\$(TCLSHNAME) TCLIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX).lib TCLLIBNAME = $(PROJECT)$(VERSION)$(SUFX).$(EXT) TCLLIB = $(OUT_DIR)\$(TCLLIBNAME) TCLSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib TCLSTUBLIB = $(OUT_DIR)\$(TCLSTUBLIBNAME) TCL_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" !else # ! $(DOING_TCL) !if $(TCLINSTALL) # Building against an installed Tcl # When building extensions, we need to locate tclsh. Depending on version # of Tcl we are building against, this may or may not have a "t" suffix. # Try various possibilities in turn. TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX).exe !if !exist("$(TCLSH)") && $(TCL_THREADS) TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)t$(SUFX).exe !endif !if !exist("$(TCLSH)") TCLSH = $(_TCLDIR)\bin\tclsh$(TCL_VERSION)$(SUFX:t=).exe !endif TCLSTUBLIB = $(_TCLDIR)\lib\tclstub$(TCL_VERSION).lib TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX).lib # When building extensions, may be linking against Tcl that does not add # "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. !if !exist("$(TCLIMPLIB)") TCLIMPLIB = $(_TCLDIR)\lib\tcl$(TCL_VERSION)$(SUFX:t=).lib !endif TCL_LIBRARY = $(_TCLDIR)\lib TCLREGLIB = $(_TCLDIR)\lib\tclreg13$(SUFX:t=).lib TCLDDELIB = $(_TCLDIR)\lib\tcldde14$(SUFX:t=).lib TCLTOOLSDIR = \must\have\tcl\sources\to\build\this\target TCL_INCLUDES = -I"$(_TCLDIR)\include" !else # Building against Tcl sources TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX).exe !if !exist($(TCLSH)) && $(TCL_THREADS) TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)t$(SUFX).exe !endif !if !exist($(TCLSH)) TCLSH = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclsh$(TCL_VERSION)$(SUFX:t=).exe !endif TCLSTUBLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclstub$(TCL_VERSION).lib TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX).lib # When building extensions, may be linking against Tcl that does not add # "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. !if !exist("$(TCLIMPLIB)") TCLIMPLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcl$(TCL_VERSION)$(SUFX:t=).lib !endif TCL_LIBRARY = $(_TCLDIR)\library TCLREGLIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tclreg13$(SUFX:t=).lib TCLDDELIB = $(_TCLDIR)\win\$(BUILDDIRTOP)\tcldde14$(SUFX:t=).lib TCLTOOLSDIR = $(_TCLDIR)\tools TCL_INCLUDES = -I"$(_TCLDIR)\generic" -I"$(_TCLDIR)\win" !endif # TCLINSTALL tcllibs = "$(TCLSTUBLIB)" "$(TCLIMPLIB)" !endif # $(DOING_TCL) # We need a tclsh that will run on the host machine as part of the build. # IX86 runs on all architectures. !ifndef TCLSH_NATIVE !if "$(MACHINE)" == "IX86" || "$(MACHINE)" == "$(NATIVE_ARCH)" TCLSH_NATIVE = $(TCLSH) !else !error You must explicitly set TCLSH_NATIVE for cross-compilation !endif !endif # Do the same for Tk and Tk extensions that require the Tk libraries !if $(DOING_TK) || $(NEED_TK) WISHNAMEPREFIX = wish WISHNAME = $(WISHNAMEPREFIX)$(TK_VERSION)$(SUFX).exe TKLIBNAME = $(PROJECT)$(TK_VERSION)$(SUFX).$(EXT) TKSTUBLIBNAME = tkstub$(TK_VERSION).lib TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX).lib !if $(DOING_TK) WISH = $(OUT_DIR)\$(WISHNAME) TKSTUBLIB = $(OUT_DIR)\$(TKSTUBLIBNAME) TKIMPLIB = $(OUT_DIR)\$(TKIMPLIBNAME) TKLIB = $(OUT_DIR)\$(TKLIBNAME) TK_INCLUDES = -I"$(WINDIR)" -I"$(GENERICDIR)" !else # effectively NEED_TK !if $(TKINSTALL) # Building against installed Tk WISH = $(_TKDIR)\bin\$(WISHNAME) TKSTUBLIB = $(_TKDIR)\lib\$(TKSTUBLIBNAME) TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) # When building extensions, may be linking against Tk that does not add # "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. !if !exist("$(TKIMPLIB)") TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib TKIMPLIB = $(_TKDIR)\lib\$(TKIMPLIBNAME) !endif TK_INCLUDES = -I"$(_TKDIR)\include" !else # Building against Tk sources WISH = $(_TKDIR)\win\$(BUILDDIRTOP)\$(WISHNAME) TKSTUBLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKSTUBLIBNAME) TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) # When building extensions, may be linking against Tk that does not add # "t" suffix (e.g. 8.5 or 8.7). If lib not found check for that possibility. !if !exist("$(TKIMPLIB)") TKIMPLIBNAME = tk$(TK_VERSION)$(SUFX:t=).lib TKIMPLIB = $(_TKDIR)\win\$(BUILDDIRTOP)\$(TKIMPLIBNAME) !endif TK_INCLUDES = -I"$(_TKDIR)\generic" -I"$(_TKDIR)\win" -I"$(_TKDIR)\xlib" !endif # TKINSTALL tklibs = "$(TKSTUBLIB)" "$(TKIMPLIB)" !endif # $(DOING_TK) !endif # $(DOING_TK) || $(NEED_TK) # Various output paths PRJIMPLIB = $(OUT_DIR)\$(PROJECT)$(VERSION)$(SUFX:t=).lib PRJLIBNAME = $(PROJECT)$(VERSION)$(SUFX:t=).$(EXT) PRJLIB = $(OUT_DIR)\$(PRJLIBNAME) PRJSTUBLIBNAME = $(STUBPREFIX)$(VERSION).lib PRJSTUBLIB = $(OUT_DIR)\$(PRJSTUBLIBNAME) # If extension parent makefile has not defined a resource definition file, # we will generate one from standard template. !if !$(DOING_TCL) && !$(DOING_TK) && !$(STATIC_BUILD) !ifdef RCFILE RESFILE = $(TMP_DIR)\$(RCFILE:.rc=.res) !else RESFILE = $(TMP_DIR)\$(PROJECT).res !endif !endif ################################################################### # 11. Construct the paths for the installation directories # The following macros get defined in this section: # LIB_INSTALL_DIR - where libraries should be installed # BIN_INSTALL_DIR - where the executables should be installed # DOC_INSTALL_DIR - where documentation should be installed # SCRIPT_INSTALL_DIR - where scripts should be installed # INCLUDE_INSTALL_DIR - where C include files should be installed # DEMO_INSTALL_DIR - where demos should be installed # PRJ_INSTALL_DIR - where package will be installed (not set for Tcl and Tk) !if $(DOING_TCL) || $(DOING_TK) LIB_INSTALL_DIR = $(_INSTALLDIR)\lib BIN_INSTALL_DIR = $(_INSTALLDIR)\bin DOC_INSTALL_DIR = $(_INSTALLDIR)\doc !if $(DOING_TCL) SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TCL_MAJOR_VERSION).$(TCL_MINOR_VERSION) !else # DOING_TK SCRIPT_INSTALL_DIR = $(_INSTALLDIR)\lib\$(PROJECT)$(TK_MAJOR_VERSION).$(TK_MINOR_VERSION) !endif DEMO_INSTALL_DIR = $(SCRIPT_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\include !else # extension other than Tk PRJ_INSTALL_DIR = $(_INSTALLDIR)\$(PROJECT)$(DOTVERSION) LIB_INSTALL_DIR = $(PRJ_INSTALL_DIR) BIN_INSTALL_DIR = $(PRJ_INSTALL_DIR) DOC_INSTALL_DIR = $(PRJ_INSTALL_DIR) SCRIPT_INSTALL_DIR = $(PRJ_INSTALL_DIR) DEMO_INSTALL_DIR = $(PRJ_INSTALL_DIR)\demos INCLUDE_INSTALL_DIR = $(_INSTALLDIR)\..\include !endif ################################################################### # 12. Set up actual options to be passed to the compiler and linker # Now we have all the information we need, set up the actual flags and # options that we will pass to the compiler and linker. The main # makefile should use these in combination with whatever other flags # and switches are specific to it. # The following macros are defined, names are for historical compatibility: # OPTDEFINES - /Dxxx C macro flags based on user-specified OPTS # COMPILERFLAGS - /Dxxx C macro flags independent of any configuration opttions # crt - Compiler switch that selects the appropriate C runtime # cdebug - Compiler switches related to debug AND optimizations # cwarn - Compiler switches that set warning levels # cflags - complete compiler switches (subsumes cdebug and cwarn) # ldebug - Linker switches controlling debug information and optimization # lflags - complete linker switches (subsumes ldebug) except subsystem type # dlllflags - complete linker switches to build DLLs (subsumes lflags) # conlflags - complete linker switches for console program (subsumes lflags) # guilflags - complete linker switches for GUI program (subsumes lflags) # baselibs - minimum Windows libraries required. Parent makefile can # define PRJ_LIBS before including rules.rc if additional libs are needed OPTDEFINES = -DTCL_CFGVAL_ENCODING=$(CFG_ENCODING) -DSTDC_HEADERS !if $(TCL_MEM_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_MEM_DEBUG !endif !if $(TCL_COMPILE_DEBUG) OPTDEFINES = $(OPTDEFINES) -DTCL_COMPILE_DEBUG -DTCL_COMPILE_STATS !endif !if $(TCL_THREADS) OPTDEFINES = $(OPTDEFINES) -DTCL_THREADS=1 !if $(USE_THREAD_ALLOC) OPTDEFINES = $(OPTDEFINES) -DUSE_THREAD_ALLOC=1 !endif !endif !if $(STATIC_BUILD) OPTDEFINES = $(OPTDEFINES) -DSTATIC_BUILD !endif !if $(TCL_NO_DEPRECATED) OPTDEFINES = $(OPTDEFINES) -DTCL_NO_DEPRECATED !endif !if $(USE_STUBS) # Note we do not define USE_TCL_STUBS even when building tk since some # test targets in tk do not use stubs !if ! $(DOING_TCL) USE_STUBS_DEFS = -DUSE_TCL_STUBS -DUSE_TCLOO_STUBS !if $(NEED_TK) USE_STUBS_DEFS = $(USE_STUBS_DEFS) -DUSE_TK_STUBS !endif !endif !endif # USE_STUBS !if !$(DEBUG) OPTDEFINES = $(OPTDEFINES) -DNDEBUG !if $(OPTIMIZING) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_OPTIMIZED !endif !endif !if $(PROFILE) OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_PROFILED !endif !if "$(MACHINE)" == "AMD64" OPTDEFINES = $(OPTDEFINES) -DTCL_CFG_DO64BIT !endif !if $(VCVERSION) < 1300 OPTDEFINES = $(OPTDEFINES) -DNO_STRTOI64 !endif # _ATL_XP_TARGETING - Newer SDK's need this to build for XP COMPILERFLAGS = /D_ATL_XP_TARGETING # Following is primarily for the benefit of extensions. Tcl 8.5 builds # Tcl without /DUNICODE, while 8.6 builds with it defined. When building # an extension, it is advisable (but not mandated) to use the same Windows # API as the Tcl build. This is accordingly defaulted below. A particular # extension can override this by pre-definining USE_WIDECHAR_API. !ifndef USE_WIDECHAR_API !if $(TCL_VERSION) > 85 USE_WIDECHAR_API = 1 !else USE_WIDECHAR_API = 0 !endif !endif !if $(USE_WIDECHAR_API) COMPILERFLAGS = $(COMPILERFLAGS) /DUNICODE /D_UNICODE !endif # Like the TEA system only set this non empty for non-Tk extensions # Note: some extensions use PACKAGE_NAME and others use PACKAGE_TCLNAME # so we pass both !if !$(DOING_TCL) && !$(DOING_TK) PKGNAMEFLAGS = -DPACKAGE_NAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ -DPACKAGE_TCLNAME="\"$(PRJ_PACKAGE_TCLNAME)\"" \ -DPACKAGE_VERSION="\"$(DOTVERSION)\"" \ -DMODULE_SCOPE=extern !endif # crt picks the C run time based on selected OPTS !if $(MSVCRT) !if $(DEBUG) && !$(UNCHECKED) crt = -MDd !else crt = -MD !endif !else !if $(DEBUG) && !$(UNCHECKED) crt = -MTd !else crt = -MT !endif !endif # cdebug includes compiler options for debugging as well as optimization. !if $(DEBUG) # In debugging mode, optimizations need to be disabled cdebug = -Zi -Od $(DEBUGFLAGS) !else cdebug = $(OPTIMIZATIONS) !if $(SYMBOLS) cdebug = $(cdebug) -Zi !endif !endif # $(DEBUG) # cwarn includes default warning levels. cwarn = $(WARNINGS) !if "$(MACHINE)" == "AMD64" # Disable pointer<->int warnings related to cast between different sizes # There are a gadzillion of these due to use of ClientData and # clutter up compiler # output increasing chance of a real warning getting lost. So disable them. # Eventually some day, Tcl will be 64-bit clean. cwarn = $(cwarn) -wd4311 -wd4312 !endif ### Common compiler options that are architecture specific !if "$(MACHINE)" == "ARM" carch = -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE !else carch = !endif !if $(DEBUG) # Turn warnings into errors cwarn = $(cwarn) -WX !endif INCLUDES = $(TCL_INCLUDES) $(TK_INCLUDES) $(PRJ_INCLUDES) !if !$(DOING_TCL) && !$(DOING_TK) INCLUDES = $(INCLUDES) -I"$(GENERICDIR)" -I"$(WINDIR)" -I"$(COMPATDIR)" !endif # These flags are defined roughly in the order of the pre-reform # rules.vc/makefile.vc to help visually compare that the pre- and # post-reform build logs # cflags contains generic flags used for building practically all object files cflags = -nologo -c $(COMPILERFLAGS) $(carch) $(cwarn) -Fp$(TMP_DIR)^\ $(cdebug) # appcflags contains $(cflags) and flags for building the application # object files (e.g. tclsh, or wish) pkgcflags contains $(cflags) plus # flags used for building shared object files The two differ in the # BUILD_$(PROJECT) macro which should be defined only for the shared # library *implementation* and not for its caller interface appcflags = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) $(USE_STUBS_DEFS) appcflags_nostubs = $(cflags) $(crt) $(INCLUDES) $(TCL_DEFINES) $(PRJ_DEFINES) $(OPTDEFINES) pkgcflags = $(appcflags) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) pkgcflags_nostubs = $(appcflags_nostubs) $(PKGNAMEFLAGS) -DBUILD_$(PROJECT) # stubscflags contains $(cflags) plus flags used for building a stubs # library for the package. Note: -DSTATIC_BUILD is defined in # $(OPTDEFINES) only if the OPTS configuration indicates a static # library. However the stubs library is ALWAYS static hence included # here irrespective of the OPTS setting. # # TBD - tclvfs has a comment that stubs libs should not be compiled with -GL # without stating why. Tcl itself compiled stubs libs with this flag. # so we do not remove it from cflags. -GL may prevent extensions # compiled with one VC version to fail to link against stubs library # compiled with another VC version. Check for this and fix accordingly. stubscflags = $(cflags) $(PKGNAMEFLAGS) $(PRJ_DEFINES) $(OPTDEFINES) -Zl -DSTATIC_BUILD $(INCLUDES) # Link flags !if $(DEBUG) ldebug = -debug -debugtype:cv !else ldebug = -release -opt:ref -opt:icf,3 !if $(SYMBOLS) ldebug = $(ldebug) -debug -debugtype:cv !endif !endif # Note: Profiling is currently only possible with the Visual Studio Enterprise !if $(PROFILE) ldebug= $(ldebug) -profile !endif ### Declarations common to all linker versions lflags = -nologo -machine:$(MACHINE) $(LINKERFLAGS) $(ldebug) !if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 lflags = $(lflags) -nodefaultlib:libucrt.lib !endif dlllflags = $(lflags) -dll conlflags = $(lflags) -subsystem:console guilflags = $(lflags) -subsystem:windows # Libraries that are required for every image. # Extensions should define any additional libraries with $(PRJ_LIBS) winlibs = kernel32.lib advapi32.lib !if $(NEED_TK) winlibs = $(winlibs) gdi32.lib user32.lib uxtheme.lib !endif # Avoid 'unresolved external symbol __security_cookie' errors. # c.f. http://support.microsoft.com/?id=894573 !if "$(MACHINE)" == "AMD64" !if $(VCVERSION) > 1399 && $(VCVERSION) < 1500 winlibs = $(winlibs) bufferoverflowU.lib !endif !endif baselibs = $(winlibs) $(PRJ_LIBS) !if $(MSVCRT) && !($(DEBUG) && !$(UNCHECKED)) && $(VCVERSION) >= 1900 baselibs = $(baselibs) ucrt.lib !endif ################################################################ # 13. Define standard commands, common make targets and implicit rules CCPKGCMD = $(cc32) $(pkgcflags) -Fo$(TMP_DIR)^\ CCAPPCMD = $(cc32) $(appcflags) -Fo$(TMP_DIR)^\ CCSTUBSCMD = $(cc32) $(stubscflags) -Fo$(TMP_DIR)^\ LIBCMD = $(lib32) -nologo $(LINKERFLAGS) -out:$@ DLLCMD = $(link32) $(dlllflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) CONEXECMD = $(link32) $(conlflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) GUIEXECMD = $(link32) $(guilflags) -out:$@ $(baselibs) $(tcllibs) $(tklibs) RESCMD = $(rc32) -fo $@ -r -i "$(GENERICDIR)" -i "$(TMP_DIR)" \ $(TCL_INCLUDES) \ -DDEBUG=$(DEBUG) -d UNCHECKED=$(UNCHECKED) \ -DCOMMAVERSION=$(DOTVERSION:.=,),0 \ -DDOTVERSION=\"$(DOTVERSION)\" \ -DVERSION=\"$(VERSION)\" \ -DSUFX=\"$(SUFX:t=)\" \ -DPROJECT=\"$(PROJECT)\" \ -DPRJLIBNAME=\"$(PRJLIBNAME)\" !ifndef DEFAULT_BUILD_TARGET DEFAULT_BUILD_TARGET = $(PROJECT) !endif default-target: $(DEFAULT_BUILD_TARGET) default-pkgindex: @echo package ifneeded $(PRJ_PACKAGE_TCLNAME) $(DOTVERSION) \ [list load [file join $$dir $(PRJLIBNAME)]] > $(OUT_DIR)\pkgIndex.tcl default-pkgindex-tea: @if exist $(ROOT)\pkgIndex.tcl.in nmakehlp -s << $(ROOT)\pkgIndex.tcl.in > $(OUT_DIR)\pkgIndex.tcl @PACKAGE_VERSION@ $(DOTVERSION) @PACKAGE_NAME@ $(PRJ_PACKAGE_TCLNAME) @PACKAGE_TCLNAME@ $(PRJ_PACKAGE_TCLNAME) @PKG_LIB_FILE@ $(PRJLIBNAME) << default-install: default-install-binaries default-install-libraries default-install-binaries: $(PRJLIB) @echo Installing binaries to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJLIB) "$(SCRIPT_INSTALL_DIR)" >NUL default-install-libraries: $(OUT_DIR)\pkgIndex.tcl @echo Installing libraries to '$(SCRIPT_INSTALL_DIR)' @if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)" @echo Installing package index in '$(SCRIPT_INSTALL_DIR)' @$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR) default-install-stubs: @echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)' @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)" @$(CPY) $(PRJSTUBLIB) "$(SCRIPT_INSTALL_DIR)" >NUL default-install-docs-html: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.html" "$(DOCDIR)\*.css" "$(DOCDIR)\*.png") do @$(COPY) %f "$(DOC_INSTALL_DIR)" default-install-docs-n: @echo Installing documentation files to '$(DOC_INSTALL_DIR)' @if not exist "$(DOC_INSTALL_DIR)" mkdir "$(DOC_INSTALL_DIR)" @if exist $(DOCDIR) for %f in ("$(DOCDIR)\*.n") do @$(COPY) %f "$(DOC_INSTALL_DIR)" default-install-demos: @echo Installing demos to '$(DEMO_INSTALL_DIR)' @if not exist "$(DEMO_INSTALL_DIR)" mkdir "$(DEMO_INSTALL_DIR)" @if exist $(DEMODIR) $(CPYDIR) "$(DEMODIR)" "$(DEMO_INSTALL_DIR)" default-clean: @echo Cleaning $(TMP_DIR)\* ... @if exist $(TMP_DIR)\nul $(RMDIR) $(TMP_DIR) @echo Cleaning $(WINDIR)\nmakehlp.obj, nmakehlp.exe ... @if exist $(WINDIR)\nmakehlp.obj del $(WINDIR)\nmakehlp.obj @if exist $(WINDIR)\nmakehlp.exe del $(WINDIR)\nmakehlp.exe @if exist $(WINDIR)\nmakehlp.out del $(WINDIR)\nmakehlp.out @echo Cleaning $(WINDIR)\nmhlp-out.txt ... @if exist $(WINDIR)\nmhlp-out.txt del $(WINDIR)\nmhlp-out.txt @echo Cleaning $(WINDIR)\_junk.pch ... @if exist $(WINDIR)\_junk.pch del $(WINDIR)\_junk.pch @echo Cleaning $(WINDIR)\vercl.x, vercl.i ... @if exist $(WINDIR)\vercl.x del $(WINDIR)\vercl.x @if exist $(WINDIR)\vercl.i del $(WINDIR)\vercl.i @echo Cleaning $(WINDIR)\versions.vc, version.vc ... @if exist $(WINDIR)\versions.vc del $(WINDIR)\versions.vc @if exist $(WINDIR)\version.vc del $(WINDIR)\version.vc default-hose: default-clean @echo Hosing $(OUT_DIR)\* ... @if exist $(OUT_DIR)\nul $(RMDIR) $(OUT_DIR) # Only for backward compatibility default-distclean: default-hose default-setup: @if not exist $(OUT_DIR)\nul mkdir $(OUT_DIR) @if not exist $(TMP_DIR)\nul mkdir $(TMP_DIR) !if "$(TESTPAT)" != "" TESTFLAGS = $(TESTFLAGS) -file $(TESTPAT) !endif default-test: default-setup $(PROJECT) @set TCLLIBPATH=$(OUT_DIR:\=/) @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" cd "$(TESTDIR)" && $(DEBUGGER) $(TCLSH) all.tcl $(TESTFLAGS) default-shell: default-setup $(PROJECT) @set TCLLIBPATH=$(OUT_DIR:\=/) @if exist $(LIBDIR) for %f in ("$(LIBDIR)\*.tcl") do @$(COPY) %f "$(OUT_DIR)" $(DEBUGGER) $(TCLSH) # Generation of Windows version resource !ifdef RCFILE # Note: don't use $** in below rule because there may be other dependencies # and only the "master" rc must be passed to the resource compiler $(TMP_DIR)\$(PROJECT).res: $(RCDIR)\$(PROJECT).rc $(RESCMD) $(RCDIR)\$(PROJECT).rc !else # If parent makefile has not defined a resource definition file, # we will generate one from standard template. $(TMP_DIR)\$(PROJECT).res: $(TMP_DIR)\$(PROJECT).rc $(TMP_DIR)\$(PROJECT).rc: @$(COPY) << $(TMP_DIR)\$(PROJECT).rc #include <winver.h> VS_VERSION_INFO VERSIONINFO FILEVERSION COMMAVERSION PRODUCTVERSION COMMAVERSION FILEFLAGSMASK 0x3fL #ifdef DEBUG FILEFLAGS VS_FF_DEBUG #else FILEFLAGS 0x0L #endif FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "Tcl extension " PROJECT VALUE "OriginalFilename", PRJLIBNAME VALUE "FileVersion", DOTVERSION VALUE "ProductName", "Package " PROJECT " for Tcl" VALUE "ProductVersion", DOTVERSION END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END << !endif # ifdef RCFILE !ifndef DISABLE_IMPLICIT_RULES DISABLE_IMPLICIT_RULES = 0 !endif !if !$(DISABLE_IMPLICIT_RULES) # Implicit rule definitions - only for building library objects. For stubs and # main application, the master makefile should define explicit rules. {$(ROOT)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(WINDIR)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(GENERICDIR)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(COMPATDIR)}.c{$(TMP_DIR)}.obj:: $(CCPKGCMD) @<< $< << {$(RCDIR)}.rc{$(TMP_DIR)}.res: $(RESCMD) $< {$(WINDIR)}.rc{$(TMP_DIR)}.res: $(RESCMD) $< {$(TMP_DIR)}.rc{$(TMP_DIR)}.res: $(RESCMD) $< .SUFFIXES: .SUFFIXES:.c .rc !endif ################################################################ # 14. Sanity check selected options against Tcl build options # When building an extension, certain configuration options should # match the ones used when Tcl was built. Here we check and # warn on a mismatch. !if ! $(DOING_TCL) !if $(TCLINSTALL) # Building against an installed Tcl !if exist("$(_TCLDIR)\lib\nmake\tcl.nmake") TCLNMAKECONFIG = "$(_TCLDIR)\lib\nmake\tcl.nmake" !endif !else # ! $(TCLINSTALL) - building against Tcl source !if exist("$(OUT_DIR)\tcl.nmake") TCLNMAKECONFIG = "$(OUT_DIR)\tcl.nmake" !endif !endif # TCLINSTALL !if $(CONFIG_CHECK) !ifdef TCLNMAKECONFIG !include $(TCLNMAKECONFIG) !if defined(CORE_MACHINE) && "$(CORE_MACHINE)" != "$(MACHINE)" !error ERROR: Build target ($(MACHINE)) does not match the Tcl library architecture ($(CORE_MACHINE)). !endif !if defined(CORE_USE_THREAD_ALLOC) && $(CORE_USE_THREAD_ALLOC) != $(USE_THREAD_ALLOC) !message WARNING: Value of USE_THREAD_ALLOC ($(USE_THREAD_ALLOC)) does not match its Tcl core value ($(CORE_USE_THREAD_ALLOC)). !endif !if defined(CORE_DEBUG) && $(CORE_DEBUG) != $(DEBUG) !message WARNING: Value of DEBUG ($(DEBUG)) does not match its Tcl library configuration ($(DEBUG)). !endif !endif !endif # TCLNMAKECONFIG !endif # ! $(DOING_TCL) #---------------------------------------------------------- # Display stats being used. #---------------------------------------------------------- !if !$(DOING_TCL) !message *** Building against Tcl at '$(_TCLDIR)' !endif !if !$(DOING_TK) && $(NEED_TK) !message *** Building against Tk at '$(_TKDIR)' !endif !message *** Intermediate directory will be '$(TMP_DIR)' !message *** Output directory will be '$(OUT_DIR)' !message *** Installation, if selected, will be in '$(_INSTALLDIR)' !message *** Suffix for binaries will be '$(SUFX)' !message *** Compiler version $(VCVER). Target $(MACHINE), host $(NATIVE_ARCH). !endif # ifdef _RULES_VC |
Added win/targets.vc.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | #------------------------------------------------------------- -*- makefile -*- # targets.vc -- # # Part of the nmake based build system for Tcl and its extensions. # This file defines some standard targets for the convenience of extensions # and can be optionally included by the extension makefile. # See TIP 477 (https://core.tcl.tk/tips/doc/trunk/tip/477.md) for docs. $(PROJECT): setup pkgindex $(PRJLIB) !ifdef PRJ_STUBOBJS $(PROJECT): $(PRJSTUBLIB) $(PRJSTUBLIB): $(PRJ_STUBOBJS) $(LIBCMD) $** $(PRJ_STUBOBJS): $(CCSTUBSCMD) %s !endif # PRJ_STUBOBJS !ifdef PRJ_MANIFEST $(PROJECT): $(PRJLIB).manifest $(PRJLIB).manifest: $(PRJ_MANIFEST) @nmakehlp -s << $** >$@ @MACHINE@ $(MACHINE:IX86=X86) << !endif !if "$(PROJECT)" != "tcl" && "$(PROJECT)" != "tk" $(PRJLIB): $(PRJ_OBJS) $(RESFILE) !if $(STATIC_BUILD) $(LIBCMD) $** !else $(DLLCMD) $** $(_VC_MANIFEST_EMBED_DLL) !endif -@del $*.exp !endif !if "$(PRJ_HEADERS)" != "" && "$(PRJ_OBJS)" != "" $(PRJ_OBJS): $(PRJ_HEADERS) !endif # If parent makefile has defined stub objects, add their installation # to the default install !if "$(PRJ_STUBOBJS)" != "" default-install: default-install-stubs !endif # Unlike the other default targets, these cannot be in rules.vc because # the executed command depends on existence of macro PRJ_HEADERS_PUBLIC # that the parent makefile will not define until after including rules-ext.vc !if "$(PRJ_HEADERS_PUBLIC)" != "" default-install: default-install-headers default-install-headers: @echo Installing headers to '$(INCLUDE_INSTALL_DIR)' @for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)" !endif !if "$(DISABLE_STANDARD_TARGETS)" == "" DISABLE_STANDARD_TARGETS = 0 !endif !if "$(DISABLE_TARGET_setup)" == "" DISABLE_TARGET_setup = 0 !endif !if "$(DISABLE_TARGET_install)" == "" DISABLE_TARGET_install = 0 !endif !if "$(DISABLE_TARGET_clean)" == "" DISABLE_TARGET_clean = 0 !endif !if "$(DISABLE_TARGET_test)" == "" DISABLE_TARGET_test = 0 !endif !if "$(DISABLE_TARGET_shell)" == "" DISABLE_TARGET_shell = 0 !endif !if !$(DISABLE_STANDARD_TARGETS) !if !$(DISABLE_TARGET_setup) setup: default-setup !endif !if !$(DISABLE_TARGET_install) install: default-install !endif !if !$(DISABLE_TARGET_clean) clean: default-clean realclean: hose hose: default-hose distclean: realclean default-distclean !endif !if !$(DISABLE_TARGET_test) test: default-test !endif !if !$(DISABLE_TARGET_shell) shell: default-shell !endif !endif # DISABLE_STANDARD_TARGETS |
Changes to win/thread.rc.
1 2 3 4 5 6 | // Version resource script // #include <winver.h> #define RESOURCE_INCLUDED | < > > > > > > > > > > > > > > > > | | | | | < | < < < | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | // Version resource script // #include <winver.h> #define RESOURCE_INCLUDED LANGUAGE 0x9, 0x1 /* LANG_ENGLISH, SUBLANG_DEFAULT */ #ifndef COMMAVERSION #define COMMAVERSION PACKAGE_MAJOR,PACKAGE_MINOR,0,0 #endif #ifndef DOTVERSION #define DOTVERSION PACKAGE_VERSION #endif #ifndef PRJLIBNAME #ifdef DEBUG #define PRJLIBNAME "thread" STRINGIFY(JOIN(PACKAGE_MAJOR,PACKAGE_MINOR)) "d.dll\0" #else #define PRJLIBNAME "thread" STRINGIFY(JOIN(PACKAGE_MAJOR,PACKAGE_MINOR)) ".dll\0" #endif #endif VS_VERSION_INFO VERSIONINFO FILEVERSION COMMAVERSION PRODUCTVERSION COMMAVERSION FILEFLAGSMASK 0x3fL #if DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS VOS_NT_WINDOWS32 FILETYPE VFT_DLL FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */ BEGIN VALUE "FileDescription", "Threading extension library for Tcl" VALUE "OriginalFilename", PRJLIBNAME VALUE "CompanyName", "NONE! Open-sourced with no owner\0" VALUE "FileVersion", DOTVERSION VALUE "LegalCopyright", "Under BSD license\0" VALUE "ProductName", "Tcl for Windows\0" VALUE "ProductVersion", DOTVERSION VALUE "Authors", "Brent Welch,\r\n" "Andreas Kupries, \r\n" "David Gravereaux,\r\n" "Zoran Vasiljevic" "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END |
︙ | ︙ |
Changes to win/threadWin.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | * Copyright (c) 1998 by Sun Microsystems, Inc. * Copyright (c) 1999,2000 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ | < > | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | * Copyright (c) 1998 by Sun Microsystems, Inc. * Copyright (c) 1999,2000 by Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include <windows.h> #include <process.h> #include "../generic/tclThread.h" #if 0 /* only Windows 2000 (XP, too??) has this function */ HANDLE (WINAPI *winOpenThreadProc)(DWORD, BOOL, DWORD); void ThreadpInit (void) |
︙ | ︙ |
Changes to win/thread_win.dsp.
1 2 3 4 5 6 7 8 9 | # Microsoft Developer Studio Project File - Name="thread" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=thread - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run | | | | | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | # Microsoft Developer Studio Project File - Name="thread" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=thread - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "thread_win.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "thread_win.mak" CFG="thread - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "thread - Win32 Release" (based on "Win32 (x86) External Target") !MESSAGE "thread - Win32 Debug" (based on "Win32 (x86) External Target") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "thread - Win32 Release" |
︙ | ︙ | |||
64 65 66 67 68 69 70 | # PROP Intermediate_Dir "Debug" # PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols TCLDIR=E:\tcl MSVCDIR=IDE" # PROP Rebuild_Opt "-a" # PROP Target_File "Debug\thread27d.dll" # PROP Bsc_Name "" # PROP Target_Dir "" | | | | 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | # PROP Intermediate_Dir "Debug" # PROP Cmd_Line "nmake -nologo -f makefile.vc OPTS=symbols TCLDIR=E:\tcl MSVCDIR=IDE" # PROP Rebuild_Opt "-a" # PROP Target_File "Debug\thread27d.dll" # PROP Bsc_Name "" # PROP Target_Dir "" !ENDIF # Begin Target # Name "thread - Win32 Release" # Name "thread - Win32 Debug" !IF "$(CFG)" == "thread - Win32 Release" !ELSEIF "$(CFG)" == "thread - Win32 Debug" !ENDIF ROOT=.. # Begin Group "generic" # PROP Default_Filter "" # Begin Source File |
︙ | ︙ |