From: Andreas Otto on

Hi,

I'm using a workaround to address the following problem in my
project called "libmsgque" with a tcl extension support "tclmsgque"

The question is:

Is an "official" solution available for the missing "Main" problem ?


mfg

Andreas Otto


http://nhi1.berlios.de/theLink/tclmsgque/group__tclmsgqueref.htm
===================================================================
Tcl has a special requirement, for every new server-thread a new
interpreter is created and this interpreter source the toplevel file for
initialization. This file is set on library startup and
can be changed with "Init". The problem is the server startup code from
the toplevel. For internal purpose this code should only be executed on
"application-startup" (like the C \b main function)and not for every
thread again, use "tclmsgque Main" to achieve this.
\verbatim
package require TclMsgque
....
proc ServerSetup {ctx} ...
proc ServerCleanup {ctx} ...
....
tclmsgque Main {
set srv [tclmsgque MqS]
$srv ConfigSetServerSetup ServerSetup
$srv ConfigSetServerCleanup ServerCleanup
$srv ConfigSetFactory
if {[catch {
$srv LinkCreate {*}$argv
$srv ProcessEvent -wait FOREVER
}]} {
$srv ErrorSet
}
$srv Exit
}
\endverbatim

From: Alexandre Ferrieux on
On Feb 4, 9:11 am, Andreas Otto <aotto1...(a)users.sourceforge.net>
wrote:
> Hi,
>
>   I'm using a workaround to address the following problem in my
>   project called "libmsgque" with a tcl extension support "tclmsgque"
>
>   The question is:
>
> Is an "official" solution available for the missing "Main" problem ?
>
> mfg
>
>   Andreas Otto
>
> http://nhi1.berlios.de/theLink/tclmsgque/group__tclmsgqueref.htm
> ===================================================================
> Tcl has a special requirement, for every new server-thread a new
> interpreter is created and this interpreter source the toplevel file for
> initialization. This file is set on library startup and
> can be changed with "Init". The problem is the server startup code from
> the toplevel. For internal purpose this code should only be executed on
> "application-startup" (like the C \b main function)and not for every
> thread again, use "tclmsgque Main" to achieve this.
> \verbatim
> package require TclMsgque
> ...
> proc ServerSetup {ctx} ...
> proc ServerCleanup {ctx} ...
> ...
> tclmsgque Main {
>   set srv [tclmsgque MqS]
>   $srv ConfigSetServerSetup ServerSetup
>   $srv ConfigSetServerCleanup ServerCleanup
>   $srv ConfigSetFactory
>   if {[catch {
>     $srv LinkCreate {*}$argv
>     $srv ProcessEvent -wait FOREVER
>   }]} {
>     $srv ErrorSet
>   }
>   $srv Exit}
>
> \endverbatim

Do you realize that _nothing_ forces the newly created thread-interps
to source the same "toplevel" file ?

Or are you talking about your loadable extension's Init function,
which indeed must be called in each thread-interp (because
Tcl_Create*Command is per-interp) ?
In that case, just use a singleton:

MyExt_Init(...)
{
...
static int first=1;
if (first) {
first=0;
DoSomethingOnce();
}
CreateTheTclCommands();
}

Notice that the static var access doesn't need a mutex because the
first [load] of the extension can trivially be done way ahead of the
first thread creation. So the subsequent per-thread code can safely do
a [load] again, "first" will be 0.

-Alex
From: Andreas Otto on
Thanks for your help,


Am 04.02.2010 09:24, schrieb Alexandre Ferrieux:
> On Feb 4, 9:11 am, Andreas Otto <aotto1...(a)users.sourceforge.net>
> wrote:
>
>
> Do you realize that _nothing_ forces the newly created thread-interps
> to source the same "toplevel" file ?

For my problem a "server" in tcl is defined as a toplevel file
and this file is sourced (even in a thread) to define the server
behavior. Splitting this file into two independent files is possible
but difficult to maintain and in fact a "single-file" solution is
always best like one "server.exe" is C# or one "server.jar" in JAVA.

>
> Or are you talking about your loadable extension's Init function,
> which indeed must be called in each thread-interp (because
> Tcl_Create*Command is per-interp) ?
> In that case, just use a singleton:
>
> MyExt_Init(...)
> {
> ...
> static int first=1;
> if (first) {
> first=0;
> DoSomethingOnce();
> }
> CreateTheTclCommands();
> }
>
> Notice that the static var access doesn't need a mutex because the
> first [load] of the extension can trivially be done way ahead of the
> first thread creation. So the subsequent per-thread code can safely do
> a [load] again, "first" will be 0.

as my internal coding-convention I never use "static-variables" to
achieve some behaviour, but this only belongs to me. I found an
solution close to yours, and set a "flag" variable in the interpreter
to identify a "thread" startup ...

-> the question was more interesting for "other" tcl projects
as well, because near all languages have a "Main" like
behavior ...

C,C++,C#,JAVA,VB.NET - have main (or Main)

perl - has a interpreter "perl_clone" command (this is close to main)

python - has a "main" (if __name__ == "__main__": ...)
but this is not needed because python has no mature thread support at all

tcl - has mature thread support but no "main" -> extra code needed to
simulate "main"



my solution ....................

static int NS(Main) (
Tcl_Interp * interp,
int objc,
Tcl_Obj * const objv[]
)
{
if (3 != objc) {
Tcl_WrongNumArgs(interp, 2, objv, "code");
return TCL_ERROR;
}
if (Tcl_UnsetVar (interp, "MQ_STARTUP_IS_THREAD", TCL_GLOBAL_ONLY) ==
TCL_ERROR) {
TclErrorCheck (Tcl_EvalObjEx (interp, objv[2], TCL_EVAL_GLOBAL));
}
return TCL_OK;
}



mfg

Andreas Otto
From: Alexandre Ferrieux on
On Feb 4, 9:58 am, Andreas Otto <aotto1...(a)users.sourceforge.net>
wrote:
> Thanks for your help,
>
> Am 04.02.2010 09:24, schrieb Alexandre Ferrieux:
>
> > On Feb 4, 9:11 am, Andreas Otto <aotto1...(a)users.sourceforge.net>
> > wrote:
>
> > Do you realize that _nothing_ forces the newly created thread-interps
> > to source the same "toplevel" file ?
>
> For my problem a "server" in tcl is defined as a toplevel file
> and this file is sourced (even in a thread) to define the server
> behavior. Splitting this file into two independent files is possible
> but difficult to maintain and in fact a "single-file" solution is
> always best like one "server.exe" is C# or one "server.jar" in JAVA.

Are you kidding ?

thread::send $id "set i_am_a_thread 1;source toplevel.tcl"

>
> as my internal coding-convention I never use "static-variables" to
> achieve some behaviour, but this only belongs to me. I found an
> solution close to yours, and set a "flag" variable in the interpreter
> to identify a "thread" startup ...

Very contorted. If you have religious reservations about static
variables, and prefer complicated workarounds, that's your problem.
The static method (1) works without mutex for arbitrary uncooperating
threads as soon as the main thread has first done a [load] before
spawning, and (2) can be refined with a self-initialized mutex if you
want to support the even more general case of N symmetric threads
doing [load] concurrently.

-Alex