Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch bug-f583715154-v2 Excluding Merge-Ins
This is equivalent to a diff from 2616eb1a29 to c082062e57
|
2020-04-02
| ||
| 14:12 | merge bug-f583715154-v2: added tests covering [f583715154] and few other RC similar situations aroun... check-in: b8112b0642 user: sebres tags: core-8-6-branch | |
|
2020-04-01
| ||
| 13:28 | improve stability of socket*-13.2.* tests (e. g. windows compatibility, etc) Closed-Leaf check-in: c082062e57 user: sebres tags: bug-f583715154-v2 | |
| 12:06 | added tests covering [f583715154] and few other RC similar situations around socket thread transfer ... check-in: 9b7bd94769 user: sebres tags: bug-f583715154-v2 | |
|
2020-03-31
| ||
| 20:04 | fixes [f583715154] - tclUnixSock.c: introduced ThreadActionProc considering a transfer of async-conn... check-in: 532506ef71 user: sebres tags: bug-f583715154-v2 | |
| 15:59 | [b8e82d293b] Restrict the options of [binary encode uuencode] to values that will not prevent abilit... check-in: 94b6f3c028 user: dgp tags: core-8-6-branch | |
| 10:46 | Merge 8.6 check-in: 5f099cb477 user: jan.nijtmans tags: core-8-branch | |
| 10:30 | Other suggested solution for [b8e82d293b] check-in: cba0dea6a2 user: jan.nijtmans tags: bug-b8e82d293b-2 | |
| 10:17 | Remove MODULE_SCOPE function TclpSetInterfaces(), which is just empty. Increase size of MSG structu... check-in: 2616eb1a29 user: jan.nijtmans tags: core-8-6-branch | |
|
2020-03-30
| ||
| 15:48 | Optimize [binary decode hex] to process bytearray without string generation when it can. check-in: 84f81d94cf user: dgp tags: core-8-6-branch | |
Changes to generic/tclIO.c.
| ︙ | |||
3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 | 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 | + + + |
statePtr->nextCSPtr = NULL;
/*
* TIP #218, Channel Thread Actions
*/
ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE);
/* Channel is not managed by any thread */
statePtr->managingThread = NULL;
}
void
Tcl_CutChannel(
Tcl_Channel chan) /* The channel being added. Must not be
* referenced in any interpreter. */
{
|
| ︙ | |||
3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 | 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 | + + + |
* TIP #218, Channel Thread Actions
* For all transformations and the base channel.
*/
for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) {
ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE);
}
/* Channel is not managed by any thread */
statePtr->managingThread = NULL;
}
/*
*----------------------------------------------------------------------
*
* Tcl_SpliceChannel --
* SpliceChannel --
|
| ︙ | |||
8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 | 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 | + + + + + + + |
* Now call the channel handlers as usual.
*
* Preserve the channel struct in case the script closes it.
*/
TclChannelPreserve((Tcl_Channel)channel);
Tcl_Preserve(statePtr);
/*
* Avoid processing if the channel owner has been changed.
*/
if (statePtr->managingThread != Tcl_GetCurrentThread()) {
goto done;
}
/*
* If we are flushing in the background, be sure to call FlushChannel for
* writable events. Note that we have to discard the writable event so we
* don't call any write handlers before the flush is complete.
*/
|
| ︙ | |||
8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 | 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 | + + + + + + + + |
if ((chPtr->mask & mask) != 0) {
nh.nextHandlerPtr = chPtr->nextPtr;
chPtr->proc(chPtr->clientData, chPtr->mask & mask);
chPtr = nh.nextHandlerPtr;
} else {
chPtr = chPtr->nextPtr;
}
/*
* Stop if the channel owner has been changed in-between.
*/
if (chanPtr->state->managingThread != Tcl_GetCurrentThread()) {
goto done;
}
}
/*
* Update the notifier interest, since it may have changed after invoking
* event handlers. Skip that if the channel was deleted in the call to the
* channel handler.
*/
if (chanPtr->typePtr != NULL) {
/*
* TODO: This call may not be needed. If a handler induced a
* change in interest, that handler should have made its own
* UpdateInterest() call, one would think.
*/
UpdateInterest(chanPtr);
}
done:
Tcl_Release(statePtr);
TclChannelRelease(channel);
tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr;
}
/*
|
| ︙ | |||
8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 | 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 | + + + + + |
int result; /* Result of call to eval script. */
esPtr = (EventScriptRecord *)clientData;
chanPtr = esPtr->chanPtr;
mask = esPtr->mask;
interp = esPtr->interp;
/*
* Be sure event executed in managed channel (covering bugs similar [f583715154]).
*/
assert(chanPtr->state->managingThread == Tcl_GetCurrentThread());
/*
* We must preserve the interpreter so we can report errors on it later.
* Note that we do not need to preserve the channel because that is done
* by Tcl_NotifyChannel before calling channel handlers.
*/
Tcl_Preserve(interp);
|
| ︙ |
Changes to tests/socket.test.
| ︙ | |||
58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | + |
# server will be performed; otherwise, it will attempt to start the remote
# server (via exec) on platforms that support this, on the local host,
# listening at port 2048. If all fails, a message is printed and the tests
# using the remote server are not performed.
package require tcltest 2
namespace import -force ::tcltest::*
::tcltest::loadTestedCommands
if {[expr {[info exists ::env(TRAVIS_OSX_IMAGE)] && [string match xcode* $::env(TRAVIS_OSX_IMAGE)]}]} {
return
}
# Some tests require the Thread package or exec command
testConstraint thread [expr {0 == [catch {package require Thread 2.7-}]}]
|
| ︙ | |||
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 | 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 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |
puts $s "hello"
gets $s result
}
close $s
thread::release $serverthread
append result " " [llength [thread::names]]
} -result {hello 1} -constraints [list socket supported_$af thread]
proc transf_test {{testmode transfer} {maxIter 1000} {maxTime 10000}} {
try {
set ::count 0
set ::testmode $testmode
set port 0
set srvsock {}
# if binding on port 0 is not possible (system related, blocked on ISPs etc):
if {[catch {close [socket -async $::localhost $port]}]} {
# simplest server on random port (immediatelly closing a connect):
set port [randport]
set srvsock [socket -server {apply {{ch args} {close $ch}}} -myaddr $::localhost $port]
# socket on windows has some issues yet (e. g. bug [b6d0d8cc2c]), so we simply decrease iteration count (to 1/4):
if {$::tcl_platform(platform) eq "windows" && $maxIter > 50} {
set ::count [expr {$maxIter / 4 * 3 - 1}]; # bypass 3/4 iterations
}
}
tcltest::DebugPuts 1 "== test \[$::localhost\]:$port $testmode =="
set ::master [thread::id]
# helper thread creating async connection and initiating transfer (detach) to master:
set ::helper [thread::create]
thread::send -async $::helper [list \
lassign [list $::master $::localhost $port $testmode] \
::master ::localhost ::port ::testmode
]
thread::send -async $::helper {
set ::helper [thread::id]
proc iteration {args} {
set fd [socket -async $::localhost $::port]
if {"helper-writable" in $::testmode} {;# to test both sides during connect
fileevent $fd writable [list apply {{fd} {
if {[thread::id] ne $::helper} {
thread::send -async $::master {set ::count "ERROR: invalid thread, $::helper is expecting"}
close $fd
return
}
}} $fd]
};#
thread::detach $fd
thread::send -async $::master [list transf_master $fd {*}$args]
}
iteration first
}
# master proc commiting transfer attempt (attach) and checking acquire was successful:
proc transf_master {fd args} {
tcltest::DebugPuts 1 "** trma / $::count ** $args **"
thread::attach $fd
if {"master-close" in $::testmode} {;# to test close during connect
set ::count $::count
close $fd
return
};#
fileevent $fd writable [list apply {{fd} {
if {[thread::id] ne $::master} {
thread::send -async $::master {set ::count "ERROR: invalid thread, $::master is expecting"}
close $fd
return
}
set ::count $::count
close $fd
}} $fd]
}
# repeat maxIter times (up to maxTime ms as timeout):
set tout [after $maxTime {set ::count "TIMEOUT"}]
while 1 {
vwait ::count
if {![string is integer $::count]} {
# if timeout just skip (test was successful until now):
if {$::count eq "TIMEOUT"} {::tcltest::Skip "timing issue"}
break
}
if {[incr ::count] >= $maxIter} break
tcltest::DebugPuts 1 "** iter / $::count **"
thread::send -async $::helper [list iteration nr $::count]
}
update
set ::count
} finally {
catch {after cancel $tout}
if {$srvsock ne {}} {close $srvsock}
if {[info exists ::helper]} {thread::release -wait $::helper}
tcltest::DebugPuts 1 "== stop / $::count =="
unset -nocomplain ::count ::testmode ::master ::helper
}
}
test socket_$af-13.2.tr1 {Testing socket transfer between threads during async connect} -body {
transf_test {transfer} 1000
} -result 1000 -constraints [list socket supported_$af thread]
test socket_$af-13.2.tr2 {Testing socket transfer between threads during async connect} -body {
transf_test {transfer helper-writable} 100
} -result 100 -constraints [list socket supported_$af thread]
test socket_$af-13.2.cl1 {Testing socket transfer between threads during async connect} -body {
transf_test {master-close} 100
} -result 100 -constraints [list socket supported_$af thread]
test socket_$af-13.2.cl2 {Testing socket transfer between threads during async connect} -body {
transf_test {master-close helper-writable} 100
} -result 100 -constraints [list socket supported_$af thread]
catch {rename transf_master {}}
rename transf_test {}
# ----------------------------------------------------------------------
removeFile script1
removeFile script2
# cleanup
|
| ︙ |
Changes to unix/tclUnixSock.c.
| ︙ | |||
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 | 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 | + + | #define SOCKET_BUFSIZE 4096 /* * Static routines for this file: */ static void TcpAsyncCallback(ClientData clientData, int mask); static int TcpConnect(Tcl_Interp *interp, TcpState *state); static void TcpAccept(ClientData data, int mask); static int TcpBlockModeProc(ClientData data, int mode); static int TcpCloseProc(ClientData instanceData, Tcl_Interp *interp); static int TcpClose2Proc(ClientData instanceData, Tcl_Interp *interp, int flags); static int TcpGetHandleProc(ClientData instanceData, int direction, ClientData *handlePtr); static int TcpGetOptionProc(ClientData instanceData, Tcl_Interp *interp, const char *optionName, Tcl_DString *dsPtr); static int TcpInputProc(ClientData instanceData, char *buf, int toRead, int *errorCode); static int TcpOutputProc(ClientData instanceData, const char *buf, int toWrite, int *errorCode); static void TcpThreadActionProc(ClientData instanceData, int action); static void TcpWatchProc(ClientData instanceData, int mask); static int WaitForConnect(TcpState *statePtr, int *errorCodePtr); static void WrapNotify(ClientData clientData, int mask); /* * This structure describes the channel type structure for TCP socket * based IO: |
| ︙ | |||
155 156 157 158 159 160 161 | 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | - + |
TcpWatchProc, /* Initialize notifier. */
TcpGetHandleProc, /* Get OS handles out of channel. */
TcpClose2Proc, /* Close2 proc. */
TcpBlockModeProc, /* Set blocking or non-blocking mode.*/
NULL, /* flush proc. */
NULL, /* handler proc. */
NULL, /* wide seek proc. */
|
| ︙ | |||
950 951 952 953 954 955 956 957 958 959 960 961 962 963 | 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 1003 1004 1005 1006 1007 1008 1009 1010 | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + |
if (len > 0) {
return Tcl_BadChannelOption(interp, optionName,
"connecting peername sockname");
}
return TCL_OK;
}
/*
* ----------------------------------------------------------------------
*
* TcpThreadActionProc --
*
* Handles detach/attach for asynchronously connecting socket.
*
* Reassigning the file handler associated with thread-related channel
* notification, responsible for callbacks (signaling that asynchronous
* connection attempt has succeeded or failed).
*
* Results:
* None.
*
* ----------------------------------------------------------------------
*/
static void
TcpThreadActionProc(
ClientData instanceData,
int action)
{
TcpState *statePtr = (TcpState *)instanceData;
if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
/*
* Async-connecting socket must get reassigned handler if it have been
* transferred to another thread. Remove the handler if the socket is
* not managed by this thread anymore and create new handler (TSD related)
* so the callback will run in the correct thread, bug [f583715154].
*/
switch (action) {
case TCL_CHANNEL_THREAD_REMOVE:
CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
Tcl_DeleteFileHandler(statePtr->fds.fd);
break;
case TCL_CHANNEL_THREAD_INSERT:
Tcl_CreateFileHandler(statePtr->fds.fd,
TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback, statePtr);
SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
break;
}
}
}
/*
* ----------------------------------------------------------------------
*
* TcpWatchProc --
*
* Initialize the notifier to watch the fd from this channel.
|
| ︙ |