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

Delayed script invoke

6 views
Skip to first unread message

twister

unread,
Jan 19, 2009, 10:49:05 AM1/19/09
to
Hello all,
Recently I asked you for a help with callbacks in Tcl C Api. I decided
to use Tcl_EvalObjv. It all works fine when script is invoked directly
in the function registered within interpreter. But my idea is to save
Tcl_Interp pointer and a script outside this interface function and
execute it after some time. Then problem appears. If callback function
uses "puts" command, Tcl_EvalObjv returns an error "can not find
channel name "stdout"". In other cases procedures get called properly.
Is there any solution to prevent such situation?

Best regards,
Twister

Cameron Laird

unread,
Jan 19, 2009, 11:44:06 AM1/19/09
to
In article <607496de-d101-40f5...@20g2000yqt.googlegroups.com>,
.
.
.
Don't do that.

While I haven't taken the time to understand your situation in detail,
it seems as though it'll admit expression in pure Tcl either with
[after], or perhaps Miguel's new co-routines. That's where *I* would
start looking for a solution.

Alexandre Ferrieux

unread,
Jan 19, 2009, 1:23:04 PM1/19/09
to

twister

unread,
Jan 19, 2009, 4:37:55 PM1/19/09
to
On Jan 19, 7:23 pm, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
wrote:

> On Jan 19, 4:49 pm, twister <dariusz.boczkow...@gmail.com> wrote:
>
> > Hello all,
> > Recently I asked you for a help with callbacks in Tcl C Api.
>
> Yes, but since you never replied to:
>
> http://groups.google.com/group/comp.lang.tcl/tree/browse_frm/thread/7...

>
> I for one cannot help further.
>
> -Alex

That's true, but I realized my need a C funciotn pointer wasn't so
desirable. Sorry for that and thanks for try to give me a hand.

@Cameron Laird: "After" command is not an answer here because the
callback trigger source is out of the program control. This function
should be executed asynchronously and I cannot determine the time when
it will happen.
The other thing: why the procedure which is to be called on the C side
should not have "puts" commands inside? Besides it works even with
"puts" but only within function registered with Tcl_Init function.

Alexandre Ferrieux

unread,
Jan 19, 2009, 6:29:41 PM1/19/09
to
On Jan 19, 10:37 pm, twister <dariusz.boczkow...@gmail.com> wrote:
> On Jan 19, 7:23 pm, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
> wrote:
>
> > On Jan 19, 4:49 pm, twister <dariusz.boczkow...@gmail.com> wrote:
>
> > > Hello all,
> > > Recently I asked you for a help with callbacks in Tcl C Api.
>
> > Yes, but since you never replied to:
>
> >http://groups.google.com/group/comp.lang.tcl/tree/browse_frm/thread/7...
>
> > I for one cannot help further.
>
> > -Alex
>
> That's true, but I realized my need a C funciotn pointer wasn't so
> desirable. Sorry for that and thanks for try to give me a hand.

You're still not answering. That's too bad, because I suspect (and
Cameron too it seems) that we'd be able to suggest a much simpler
solution than the Tcl-C-Tcl nightmare you are diving into.

-Alex

twister

unread,
Jan 20, 2009, 2:44:21 AM1/20/09
to
On 20 Sty, 00:29, Alexandre Ferrieux <alexandre.ferri...@gmail.com>

wrote:
> On Jan 19, 10:37 pm, twister <dariusz.boczkow...@gmail.com> wrote:
>
>
>
> > On Jan 19, 7:23 pm, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
> > wrote:
>
> > > On Jan 19, 4:49 pm, twister <dariusz.boczkow...@gmail.com> wrote:
>
> > > > Hello all,
> > > > Recently I asked you for a help with callbacks in Tcl C Api.
>
> > > Yes, but since you never replied to:
>
> > >http://groups.google.com/group/comp.lang.tcl/tree/browse_frm/thread/7...
>
> > > I for one cannot help further.
>
> > > -Alex
>
> > That's true, but I realized my need a C funciotn pointer wasn't so
> > desirable. Sorry for that and thanks for try to give me a hand.
>
> You're still not answering. That's too bad, because I suspect (and
> Cameron too it seems) that we'd be able to suggest a much simpler
> solution than the Tcl-C-Tcl nightmare you are diving into.
>
> -Alex

Ok, I didn't realize previous things matters. So this is my idea:
I wanted to create an extention from my library which manages an
external device. The device is able to aquire or generate some
signals. For both operations usually it is necessary to register a
callback function you can read/write the data to be aquired/generated.
I have made such callback in C but since the main control is from Tcl
side I have to invoke tcl procedure (from the callback body) which
allows me to read or update the data buffers.
I didn't insist on using C-like-pointers, but now when I have such
implementation it is the easiest thing to invoke the script, I
guess...

Alexandre Ferrieux

unread,
Jan 20, 2009, 5:48:46 AM1/20/09
to
On Jan 20, 8:44 am, twister <dariusz.boczkow...@gmail.com> wrote:
>
> > You're still not answering. That's too bad, because I suspect (and
> > Cameron too it seems) that we'd be able to suggest a much simpler
> > solution than the Tcl-C-Tcl nightmare you are diving into.
>
> Ok, I didn't realize previous things matters. So this is my idea:
> I wanted to create an extention from my library which manages an
> external device. The device is able to aquire or generate some
> signals. For both operations usually it is necessary to register a
> callback function you can read/write the data to be aquired/generated.
> I have made such callback in C but since the main control is from Tcl
> side I have to invoke tcl procedure (from the callback body) which
> allows me to read or update the data buffers.
> I didn't insist on using C-like-pointers, but now when I have such
> implementation it is the easiest thing to invoke the script, I
> guess...


Ok. Funnily this situation is one I've encountered dozens of time at
work.
The real winner here is to avoid premature optimization. This means:
start with a looser coupling, with a child process in C doing the
device interaction, and I/O for data and control between Tcl and the
child. That's the Tcl-as-glue silver bullet. Then do some profiling.
Then, *if* profiling shows that context switches are killing you, but
only in that case, start thinking about tighter couplings, like
extensions.

But maybe you've already conducted this analysis. Just tell me.

-Alex

twister

unread,
Jan 20, 2009, 6:33:38 AM1/20/09
to
On 20 Sty, 11:48, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
wrote:

> Then, *if* profiling shows that context switches are killing you, but
> only in that case, start thinking about tighter couplings, like
> extensions.
>
> But maybe you've already conducted this analysis. Just tell me.
>
> -Alex

Hi Alex,
Unfortunately there is no other way now to solve the problem than
extention, because the time is high and I cannot spend too long
searching for a new possibility. All I did work very well except the
one with callbacks using "stdout" channel. Do you have any idea how to
work this out.
The funniest thing "stdout" is reachable within registered C function.
But causes an error when you want to invoke it from other place.

Twister

Cameron Laird

unread,
Jan 20, 2009, 6:52:02 AM1/20/09
to
In article <e8c55eac-3be0-4e92...@s9g2000prg.googlegroups.com>,

Perhaps we should explain the benefits: with this C-coded stand-alone
executable we're recommending, development and testing of the hardware-
specific aspects does NOT depend on Tcl expertise. There are no
particular issues of synchronicity or thread of control or who owns
which stdio handle. Test the serial-line management in isolation.
With known-good behavior in that domain, manage the behavior with a
Tcl wrapper. There is no complex thinking about callbacks and control
sequences and such.

twister

unread,
Jan 20, 2009, 1:44:23 PM1/20/09
to
On Jan 20, 12:52 pm, cla...@lairds.us (Cameron Laird) wrote:

> Perhaps we should explain the benefits


Thanks for giving me number of advantages for creating executable
instead of C Api extension, but it still doesn't solve my problem why
I can't "Eval" some procedures from C code.
Thanks in advance.

Twister

Christian Gollwitzer

unread,
Jan 20, 2009, 1:55:04 PM1/20/09
to
twister schrieb:

You are trying to call Tcl_Eval from within the callback function? That
almost never works. Often, it's not allowed to call the C library from
within the signal handler. The only safe pssobility is

1) Use Tcl_AsyncMark in the callback handler, which is thread safe
2) In the Tcl_AsyncProc, fire an event
3) React to that event from Tcl

Christian

Alexandre Ferrieux

unread,
Jan 20, 2009, 3:39:59 PM1/20/09
to
On Jan 20, 12:33 pm, twister <dariusz.boczkow...@gmail.com> wrote:
> On 20 Sty, 11:48, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
> wrote:
>
> > Then, *if* profiling shows that context switches are killing you, but
> > only in that case, start thinking about tighter couplings, like
> > extensions.
>
> > But maybe you've already conducted this analysis. Just tell me.
>
> > -Alex
>
> Hi Alex,
> Unfortunately there is no other way now to solve the problem than
> extention, because the time is high and I cannot spend too long
> searching for a new possibility.

In my experience this reasoning has always proven wrong. You're
overestimating the cost of the switch *and* you're underestimating the
brittleness of what you're sticking to. Post a summary of your
extension's API (just the added Tcl commands) and we'll give you the
skeleton of the standalone main().

-Alex

twister

unread,
Jan 21, 2009, 1:32:50 AM1/21/09
to
On 20 Sty, 21:39, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
wrote:

Now I am very confused. I am aware of the risk of asynchronous "eval",
but from the other side why Tcl_Eval (Tcl_EvalObjv is probably the
same) wouldn't be asynchronous-protected. That's the purpose of using
Tcl_Eval in my opinion. Maybe you can show me the larger description
of Tcl_Eval-like procedures then man pages?
To be honest posting the interface functions may take lots of space
here and it won't probably show the heart of the problem. This is
because the "callback handler" (or everything that is needed to create
one) is stored in dynamic object which controls the data exchange
program system and external device. But if you need only added
commands body I will post it. I just ask to make sure what is
neccessary for you exactly. Some examples would also be very helpful.
The next issue: when the extension is exchanged with standalone
executable how it will communicate with the other part of the program?
Pipes? Sugnals?
It seems I have to learn more than more to understand well all the
integration issues. Will you guide me?

Twister

Alexandre Ferrieux

unread,
Jan 21, 2009, 2:49:24 AM1/21/09
to
On Jan 21, 7:32 am, twister <dariusz.boczkow...@gmail.com> wrote:
>
> > Post a summary of your
> > extension's API (just the added Tcl commands) and we'll give you the
> > skeleton of the standalone main().
>
> To be honest posting the interface functions may take lots of space
> here and it won't probably show the heart of the problem. This is
> because the "callback handler" (or everything that is needed to create
> one) is stored in dynamic object which controls the data exchange
> program system and external device.
> [...] Some examples would also be very helpful.

OK here is the sketch:


int main(int argc,char **argv)
{
InitWhateverNeedsBe();
while(fgets(line,SIZE,stdin))
{
if (2==sscanf(line,"foo %d %d",&x,&y)) res=Foo(x,y);
elseif (2==sscanf(line,"bar %s",a)) res=Bar(a);
...
else {printf("SYNTAX\n");fflush(stdout);continue;}
printf(res?"ERROR\n":"OK\n");fflush(stdout);
}
}

Here, InitWhateverNeedsBe, Foo, and Bar are your domain-dependent
synchronous functions.
So basically your standalone program is a kind of "shell" wrapped
around your device calls.
Presumably one of their side-effects would have started some thread or
registered some signal handler, so that callbacks can be called while
blocking on the fgets() or inside the execution of a Foo(). For these
callbacks to have a useful effect, one can imagine them doing
something like

sprintf(buf,"EVT: foo bar baz\n");
write(1,buf,strlen(buf));

(here I'm assuming signal handler context which precludes the use of
the non-reentrant parts of stdio like fprintf or fwrite)

> The next issue: when the extension is exchanged with standalone
> executable how it will communicate with the other part of the program?
> Pipes? Sugnals?

Pipes. On the Tcl side you open a bidirectional pipe (stored in a
single channel):

set pi [open "|mymain" r+]
fconfigure $pi -buffering line

When you need to issue a synchronous command:

proc Foo {x y} {
puts $::pi "Foo $x $y"
while {1} {
if {[gets $::pi line]<0} {fatal "Unexpected end of
mymain !!!"}
switch -glob -- $line {
OK* return
ERROR* {error "Oops in Foo"}
EVT* {evtcallback $line}
}
}
}

But events can also occur in between sync commands:

proc gotevent {} {
if {[gets $::pi line]<0} {fatal "Unexpected end of
mymain !!!"}
switch -glob -- $line {
EVT* {evtcallback $line}
* {fatal "Loss of sync: '$line' outside commands"}
}
}

fileevent $::pi readable gotevent
...
vwait forever


To summarize:

- the main() is a simple shell, with blocking, acknowledged commands
(OK/ERROR) and async events (EVT), all three being lines on its stdout
- the Tcl script spawns it between pipes
- synchronous commands are just a pair of I/O
- asynchronous events get picked up by [fileevent] in the Tcl event
loop

Benefits:

- the shell itself is unit-testable without Tcl (huge bonus, believe
me)
- your Tcl callbacks are called by a proven Tcl mechanism, no
Panics, no segfaults.

Drawbacks:

- you may be wasting a few microseconds of CPU per call/event.

> It seems I have to learn more than more to understand well all the
> integration issues. Will you guide me?

Yes, that's the deal :)
Tell me if the above still holds dark areas.

-Alex

0 new messages