thread::errorproc establishes a handler for errors that occur in commands that are executed via thread::send -async. This handler is process-global: It is shared by all threads, and it can be set from any thread. errorproc will be invoked in whichever thread set errorproc - not the master thread, nor in the thread that generates the error.
The following script illustrates the interaction of thread::errorproc and bgerror when threads raise errors. Each test occurs during a vwait to ensure the event loop is running.
puts "Tcl: [package require Tcl]" puts "Thread: [package require Thread]" namespace eval d {} proc d::bgerror args {puts "\[BGERROR\]: $args"} proc d::errorproc args {puts "\[THREAD-ERROR\]: $args"} interp bgerror {} d::bgerror thread::errorproc d::errorproc set t0 [thread::create thread::wait] puts "-------------------------" after 100 {incr ::done} after 10 {throw {TEST AFTER} "Error in after!"} vwait ::done puts "-------------------------" after 100 {incr ::done} thread::send -async $t0 {throw {TEST INTHREAD ASYNC RESULT} "Error in thread (async with result)!"} ::res vwait ::done puts "res is $res" puts "-------------------------" after 100 {incr ::done} thread::send -async $t0 {throw {TEST INTHREAD ASYNC VOID} "Error in thread (async void)!"} vwait ::done puts "-------------------------" after 100 { try { thread::send $t0 {throw {TEST INTHREAD SYNCHRONOUS} "Error in thread (synchronous)!"} } on error {e o} { puts "\[CAUGHT-ERROR\]: $e" } finally { incr ::done } } vwait done puts "-------------------------" exit
Note the strange result when -async is used with a result variable (the 2nd test):
Tcl: 8.6.4 Thread: 2.7.2 ------------------------- [BGERROR]: {Error in after!} {-errorcode {TEST AFTER} -code 1 -level 0 -errorstack {INNER {returnImm {Error in after!} {-errorcode {TEST AFTER}}}} -errorinfo {Error in after! while executing "throw {TEST AFTER} "Error in after!"" ("after" script)} -errorline 1} ------------------------- [THREAD-ERROR]: tid0x7f379951c700 {Error in thread (async with result)! while executing "throw {TEST INTHREAD ASYNC RESULT} "Error in thread (async with result)!""} [BGERROR]: {Error in thread (async with result)!} {-code 1 -level 0 -errorstack {INNER {returnImm {Error in after!} {-errorcode {TEST AFTER}}}} -errorcode NONE -errorinfo {Error in thread (async with result)!} -errorline 1} res is Error in thread (async with result)! ------------------------- [THREAD-ERROR]: tid0x7f379951c700 {Error in thread (async void)! while executing "throw {TEST INTHREAD ASYNC VOID} "Error in thread (async void)!""} ------------------------- [CAUGHT-ERROR]: Error in thread (synchronous)! -------------------------
With the test script:
% thread::send -async $t0 {throw ..} ::res
first thread::errorproc fires, then bgerror. This could be useful, as bgerror sees more information than errorproc ... but the error dictionary is not in great shape:
-code = 1 -level = 0 -errorstack = "INNER {returnImm {Error in after!} {-errorcode {TEST AFTER}}}" -errorcode = NONE -errorinfo = "Error in thread (async with result)!" -errorline = 1
it looks like everything but -errorinfo comes from the previous error, and -errorcode is simply wrong. -errorcode NONE might be a good way to filter these errors out if you're using errorproc and bgerror together.
PYK 2015-04-25: It's not that -errorcode is wrong, just that thread only sends the -errorinfo, not the whole return options dictionary to thread::errorproc. When bgerrror is triggered as a result of the failed variable write, a return options dictionary is generated, but isn't going to contain any useful information other than the -errorinfo value, which thread::errorproc also receives.
aspect: this seems to be an effect of [L1 ].