Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Injecting exception from other thread / C api

65 views
Skip to first unread message

Sebastian Biały

unread,
Dec 3, 2018, 9:50:38 AM12/3/18
to
Hello,

is there any way I can inject exception into working interpreter from
different thread?

a) embedded tcl thread is evaluating something inside Tcl_Eval. It might
take a lot of time.

b) I do have different C thread that would like to break tcl thread (for
example user "break" action in IDE). Preferably by injecting some kind
of exception or terminate evaluation with TCL_ABORT.

c) I do not want to use trace since it is slow.

Is there any legal way to do it? I know that I want to mess with threads
in this case, however I would like to do it as nicely as it can be. That
is why I'm hoping to generate exception in evaluation.

BTW. Is it possible to create trace hook from different thread? It would
solve my problem: create trace hook, return ABORT when called by
original thread, remove trace.

jda...@gmail.com

unread,
Dec 4, 2018, 2:25:02 PM12/4/18
to
if you are using tcl 8.6 you might try thread::cancel

package require Thread

proc start {} {
thread::create {
set t1 [clock microseconds]
while {[clock microseconds] - $t1 < 20000000} {}
}
}

proc stop {id} {
puts [thread::names]
thread::cancel -unwind $id ""
puts "after: [thread::names]"
after 1 {puts "after 1 [thread::names]"}
}

stop [start]

starts a child thread, which should run for 20 sec, then immediately stops it from the original thread. Note the child does not stop immediately, but is gone after 1 millisecond. Probably waiting until the next time it is scheduled to run.

I'm not sure how to do this directly from C. However if you create the worker thread as a child of a controlling thread, the controlling thread should be waiting in the event loop, and hence respond quickly.

Dave B

heinrichmartin

unread,
Dec 5, 2018, 9:29:10 AM12/5/18
to
On Monday, December 3, 2018 at 3:50:38 PM UTC+1, Sebastian Biały wrote:
> b) I do have different C thread that would like to break tcl thread (for
> example user "break" action in IDE). Preferably by injecting some kind
> of exception or terminate evaluation with TCL_ABORT.

TCL_ABORT is not standard Tcl, is it?
Be aware that the script must deal (or actually must not deal) with the exception to make this work. I.e. a [catch] could silently ignore your interception.

Also, by strictly denying any further action, you will prevent execution of cleanup code, too.

> c) I do not want to use trace since it is slow.

Have you tried? On C level, you could really just check a (global) flag and return anything but TCL_OK. Obviously, your script must be aware of your special break code.

Also see the TCL_ALLOW_INLINE_COMPILATION flag.

> BTW. Is it possible to create trace hook from different thread? It would
> solve my problem: create trace hook, return ABORT when called by
> original thread, remove trace.

Not a core dev here, but quite sure that Tcl_CreateObjTrace is *not* thread safe.

Sebastian Biały

unread,
Dec 6, 2018, 3:33:14 AM12/6/18
to
On 2018-12-05 15:29, heinrichmartin wrote:
> TCL_ABORT is not standard Tcl, is it?

Just an example of unwind idea.

> Be aware that the script must deal (or actually must not deal) with the exception to make this work. I.e. a [catch] could silently ignore your interception.

I would like to kill interpreter regardless of way script handles
exception. I prefer *not* to emit TCL exception, I prefer to emit C++
exception or any other way to jump out of TCL_*Eval*.

> Also, by strictly denying any further action, you will prevent execution of cleanup code, too.

Does not really matter. In my scenario tcl is embedded in application.
One just clicked "quit" in application while script was running. I have
no way to pause/break tcl script except for low level thread interrupt
that can destroy not only tcl internal state but also mine.

Did already asked for coroutine NRE solution but TCL does not have one,
instead there is "do everything in one call including hang" solution. In
other words I am a prisoner of TCL internal loop and there is no way to
escape.

>> c) I do not want to use trace since it is slow.
> Have you tried?

Yes. It is.

> On C level, you could really just check a (global) flag and return anything but TCL_OK.

From where? In case of tight loop that is compiled to bytecode there is
no escape and no way to return anything for me. TCL is just having fun
inside it's internals and I'm not invited to this party.

> Obviously, your script must be aware of your special break code.

No way, random user can and will create tight loop inside embedded tcl
and report bug to me that application hangs.

> Also see the TCL_ALLOW_INLINE_COMPILATION flag.

Will not help much on speed in real examples.

> Not a core dev here, but quite sure that Tcl_CreateObjTrace is *not* thread safe.

I bet it is not. I'm out of ideas how to break tcl NRE engine in legal
way since no TCL developer figured out single step NRE as public API.

Sebastian Biały

unread,
Dec 6, 2018, 3:39:21 AM12/6/18
to
On 2018-12-04 20:24, jda...@gmail.com wrote:
> if you are using tcl 8.6 you might try thread::cancel

I'm using native C++ threads. TCL does really know that it is used in
different that main thread.

> package require Thread

And to be worse, TCL is compiled with thread support disabled.

gustafn

unread,
Dec 6, 2018, 4:36:52 AM12/6/18
to
On Thursday, December 6, 2018 at 9:33:14 AM UTC+1, Sebastian Biały wrote:
>
> No way, random user can and will create tight loop inside embedded tcl
> and report bug to me that application hangs.

If you are talking about Tcl loops, you might get an idea how to implement custom loop constructs (to provide means to pause/interrupt/cancel such loops)
from the following NaviServer module:

https://bitbucket.org/naviserver/nsloopctl/src/default/

On the C-level, one can extend these commands for application specific semantics.

Sebastian Biały

unread,
Dec 6, 2018, 4:40:37 AM12/6/18
to
On 2018-12-06 10:36, gustafn wrote:
>> No way, random user can and will create tight loop inside embedded tcl
>> and report bug to me that application hangs.
> https://bitbucket.org/naviserver/nsloopctl/src/default/
> On the C-level, one can extend these commands for application specific semantics.

Thanks. Will look into it.

However I'm just puzzled, why TCL does not have any legal way to do it
just like that. Or I do not see any.

heinrichmartin

unread,
Dec 6, 2018, 7:19:49 AM12/6/18
to
On Thursday, December 6, 2018 at 9:33:14 AM UTC+1, Sebastian Biały wrote:
> > On C level, you could really just check a (global) flag and return anything but TCL_OK.
>
> From where?

I thought of a C level trace proc.

> In case of tight loop that is compiled to bytecode there is
> no escape and no way to return anything for me. TCL is just having fun
> inside it's internals and I'm not invited to this party.
>
> > Obviously, your script must be aware of your special break code.
>
> No way, random user can and will create tight loop inside embedded tcl
> and report bug to me that application hangs.

Have you considered [interp limit] resp its implementation? (I don't know the details.)

From http://tcl.tk/man/tcl8.6/TclCmd/interp.htm#M47:
"When a limit is exceeded for an interpreter, first any handler callbacks defined by master interpreters are called. [...] If the limit is still in force, an error is generated at that point and *normal processing of errors within the interpreter (by the catch command) is disabled*, [...] (e.g. by interp eval) where it becomes the responsibility of the calling code to catch and handle."
0 new messages