[#25636] [Oniguruma 3.X] reggnu.c — "K.Kosako" <sndgk393@...>

さっき気がついたのですが、元々は

15 messages 2005/02/05

[#25655] openssl binding for SSL_CTX_set_default_verify_paths and X509_STORE_set_default_paths — Tanaka Akira <akr@...17n.org>

open-uri で https を扱うことを考えていろいろと調べていた所、openssl で、

9 messages 2005/02/08
[#25670] Re: openssl binding for SSL_CTX_set_default_verify_paths and X509_STORE_set_default_paths — GOTOU Yuuzou <gotoyuzo@...> 2005/02/10

In message <876513vce0.fsf@serein.a02.aist.go.jp>,

[#25713] pthread trouble on sighandler — Hidetoshi NAGAI <nagai@...>

永井@知能.九工大です.

17 messages 2005/02/18
[#25714] Re: pthread trouble on sighandler — Yukihiro Matsumoto <matz@...> 2005/02/18

まつもと ゆきひろです

[#25755] I/O operation differs signal handler — Minero Aoki <aamine@...>

青木です。

14 messages 2005/02/24
[#25756] Re: I/O operation differs signal handler — Tanaka Akira <akr@...17n.org> 2005/02/24

In article <20050224091450P.aamine@loveruby.net>,

[ruby-dev:25663] Re: some problems on ext/tk/sample/**/*.rb

From: Hidetoshi NAGAI <nagai@...>
Date: 2005-02-09 09:06:42 UTC
List: ruby-dev #25663
永井@知能.九工大です.

From: H.Yamamoto <ocean@m2.ccsnet.ne.jp>
Subject: [ruby-dev:25656] Re: some problems on ext/tk/sample/**/*.rb
Date: Tue, 8 Feb 2005 15:37:00 +0900
Message-ID: <20050208153646.6DDB8540.ocean@m2.ccsnet.ne.jp>
> 試した限りでは落ちなくなったようです。ただ、multi-ip の
> サンプルがうまく動いていないようでした。

これについてはオオボケをかましてました.
その修正 + α を行いましたのでお試し頂ければ幸いです.
CVS HEAD からの差分になってます.

> menu_spec = [
>   [['File', 0],
>   ['exit(Crash)', proc{exit}, 0]]
> ]
> 
> TkMenubar.new(nil, menu_spec).pack
> Tk.mainloop
> 
> でメニューから終了すると、画面中央に一瞬何かのウィンドウが表示される
> ことがあります。すぐ閉じるので、なんて書いてあるのかは読めません。

こちらについても少しは対策してみたつもりですが,
問題の現象を手元で再現できないため,確信が持てません.
結果を報告頂けますと助かります.

Index: tcltklib.c
===================================================================
RCS file: /var/cvs/src/ruby/ext/tk/tcltklib.c,v
retrieving revision 1.2
diff -u -r1.2 tcltklib.c
--- tcltklib.c	31 Jan 2005 04:14:50 -0000	1.2
+++ tcltklib.c	9 Feb 2005 08:53:11 -0000
@@ -4,7 +4,7 @@
  *              Oct. 24, 1997   Y. Matsumoto
  */
 
-#define TCLTKLIB_RELEASE_DATE "2005-01-28"
+#define TCLTKLIB_RELEASE_DATE "2005-02-09"
 
 #include "ruby.h"
 #include "rubysig.h"
@@ -73,10 +73,6 @@
 /* finalize_proc_name */
 static char *finalize_hook_name = "INTERP_FINALIZE_HOOK";
 
-/* to cancel remained after-scripts when deleting IP */
-#define CANCEL_AFTER_SCRIPTS "__ruby_tcltklib_cancel_after_scripts__"
-#define DEF_CANCEL_AFTER_SCRIPTS_PROC "proc __ruby_tcltklib_cancel_after_scripts__ {} {foreach id [after info] {after cancel $id}}"
-
 /* for callback break & continue */
 static VALUE eTkCallbackReturn;
 static VALUE eTkCallbackBreak;
@@ -106,6 +102,9 @@
 static VALUE ip_invoke_real _((int, VALUE*, VALUE));
 static VALUE ip_invoke _((int, VALUE*, VALUE));
 
+static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE));
+
+
 /* from tkAppInit.c */
 
 #if TCL_MAJOR_VERSION < 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 4)
@@ -148,6 +147,18 @@
     VALUE thread;
 };
 
+struct call_queue {
+    Tcl_Event ev;
+    VALUE (*func)();
+    int argc;
+    VALUE *argv;
+    VALUE interp;
+    int *done;
+    int safe_level;
+    VALUE result;
+    VALUE thread;
+};
+
 void 
 invoke_queue_mark(struct invoke_queue *q)
 {
@@ -164,9 +175,26 @@
     rb_gc_mark(q->thread);
 }
 
+void 
+call_queue_mark(struct call_queue *q)
+{
+    int i;
+
+    for(i = 0; i < q->argc; i++) {
+        rb_gc_mark(q->argv[i]);
+    }
+
+    rb_gc_mark(q->interp);
+    rb_gc_mark(q->result);
+    rb_gc_mark(q->thread);
+}
+
  
 static VALUE eventloop_thread;
 static VALUE watchdog_thread;
+
+static VALUE rbtk_pending_exception;
+
 Tcl_Interp  *current_interp;
 
 /* 
@@ -204,6 +232,20 @@
 static int ip_ruby_cmd _((ClientData, Tcl_Interp *, int, char **));
 #endif
 
+/*----------------------------*/
+/* use Tcl internal functions */
+/*----------------------------*/
+#ifndef TCL_NAMESPACE_DEBUG
+#define TCL_NAMESPACE_DEBUG 0
+#endif
+
+#if TCL_NAMESPACE_DEBUG
+
+#if TCL_MAJOR_VERSION >= 8
+EXTERN struct TclIntStubs *tclIntStubsPtr;
+#endif
+
+/*-- Tcl_GetCurrentNamespace --*/
 #if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION < 5
 /* Tcl7.x doesn't have namespace support.                            */
 /* Tcl8.5+ has definition of Tcl_GetCurrentNamespace() in tclDecls.h */
@@ -213,26 +255,186 @@
 #  if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)
 #    ifndef Tcl_GetCurrentNamespace
 #      ifndef FunctionNum_of_GetCurrentNamespace
-#        define FunctionNum_of_GetCurrentNamespace 124
+#define FunctionNum_of_GetCurrentNamespace 124
 #      endif
-struct DummyTclIntStubs {
-  int magic;
-  struct TclIntStubHooks *hooks;
-  void (*func[FunctionNum_of_GetCurrentNamespace])();
-  Tcl_Namespace * (*tcl_GetCurrentNamespace) _((Tcl_Interp *));
+struct DummyTclIntStubs_for_GetCurrentNamespace {
+    int magic;
+    struct TclIntStubHooks *hooks;
+    void (*func[FunctionNum_of_GetCurrentNamespace])();
+    Tcl_Namespace * (*tcl_GetCurrentNamespace) _((Tcl_Interp *));
 };
-EXTERN struct TclIntStubs *tclIntStubsPtr;
+
 #define Tcl_GetCurrentNamespace \
-   (((struct DummyTclIntStubs *)tclIntStubsPtr)->tcl_GetCurrentNamespace)
+   (((struct DummyTclIntStubs_for_GetCurrentNamespace *)tclIntStubsPtr)->tcl_GetCurrentNamespace)
+#    endif
+#  endif
+#endif
+
+/* namespace check */
+/* ip_null_namespace(Tcl_Interp *interp) */
+#if TCL_MAJOR_VERSION < 8
+#define ip_null_namespace(interp) (0)
+#else /* support namespace */
+#define ip_null_namespace(interp) \
+    (Tcl_GetCurrentNamespace(interp) == (Tcl_Namespace *)NULL)
+#endif
+
+/* rbtk_invalid_namespace(tcltkip *ptr) */
+#if TCL_MAJOR_VERSION < 8
+#define rbtk_invalid_namespace(ptr) (0)
+#else /* support namespace */
+#define rbtk_invalid_namespace(ptr) \
+    ((ptr)->default_ns == (Tcl_Namespace*)NULL || Tcl_GetCurrentNamespace((ptr)->ip) != (ptr)->default_ns)
+#endif
+
+/*-- Tcl_PopCallFrame & Tcl_PushCallFrame --*/
+#if TCL_MAJOR_VERSION >= 8
+#  ifndef CallFrame
+typedef struct CallFrame {
+    Tcl_Namespace *nsPtr;
+    int dummy1;
+    int dummy2;
+    char *dummy3;
+    struct CallFrame *callerPtr;
+    struct CallFrame *callerVarPtr;
+    int level;
+    char *dummy7;
+    char *dummy8;
+    int dummy9;
+    char* dummy10;
+} CallFrame;
+#  endif
+
+#  if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED)
+EXTERN int  TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **));
+#  endif
+#  if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)
+#    ifndef TclGetFrame
+#      ifndef FunctionNum_of_GetFrame
+#define FunctionNum_of_GetFrame 32
+#      endif
+struct DummyTclIntStubs_for_GetFrame {
+    int magic;
+    struct TclIntStubHooks *hooks;
+    void (*func[FunctionNum_of_GetFrame])();
+    int (*tclGetFrame) _((Tcl_Interp *, CONST char *, CallFrame **));
+};
+#define TclGetFrame \
+   (((struct DummyTclIntStubs_for_GetFrame *)tclIntStubsPtr)->tclGetFrame)
+#    endif
+#  endif
+
+#  if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED)
+EXTERN void Tcl_PopCallFrame _((Tcl_Interp *));
+EXTERN int  Tcl_PushCallFrame _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int));
+#  endif
+#  if defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS)
+#    ifndef Tcl_PopCallFrame
+#      ifndef FunctionNum_of_PopCallFrame
+#define FunctionNum_of_PopCallFrame 128
+#      endif
+struct DummyTclIntStubs_for_PopCallFrame {
+    int magic;
+    struct TclIntStubHooks *hooks;
+    void (*func[FunctionNum_of_PopCallFrame])();
+    void (*tcl_PopCallFrame) _((Tcl_Interp *));
+    int  (*tcl_PushCallFrame) _((Tcl_Interp *, Tcl_CallFrame *, Tcl_Namespace *, int));
+};
+
+#define Tcl_PopCallFrame \
+   (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PopCallFrame)
+#define Tcl_PushCallFrame \
+   (((struct DummyTclIntStubs_for_PopCallFrame *)tclIntStubsPtr)->tcl_PushCallFrame)
 #    endif
 #  endif
+
+#else /* Tcl7.x */
+#  ifndef CallFrame
+typedef struct CallFrame {
+    Tcl_HashTable varTable;
+    int level;
+    int argc;
+    char **argv;
+    struct CallFrame *callerPtr;
+    struct CallFrame *callerVarPtr;
+} CallFrame;
+#  endif
+#  ifndef Tcl_CallFrame
+#define Tcl_CallFrame CallFrame
+#  endif
+
+#  if !defined(TclGetFrame) && !defined(TclGetFrame_TCL_DECLARED)
+EXTERN int  TclGetFrame _((Tcl_Interp *, CONST char *, CallFrame **));
+#  endif
+
+#  if !defined(Tcl_PopCallFrame) && !defined(Tcl_PopCallFrame_TCL_DECLARED)
+typedef struct DummyInterp {
+    char *dummy1;
+    char *dummy2;
+    int  dummy3;
+    Tcl_HashTable dummy4;
+    Tcl_HashTable dummy5;
+    Tcl_HashTable dummy6;
+    int numLevels;
+    int maxNestingDepth;
+    CallFrame *framePtr;
+    CallFrame *varFramePtr;
+} DummyInterp;
+
+static void
+Tcl_PopCallFrame(interp)
+    Tcl_Interp *interp;
+{
+    DummyInterp *iPtr = (DummyInterp*)interp;
+    CallFrame *frame = iPtr->varFramePtr;
+
+    /* **** DUMMY **** */
+    iPtr->framePtr = frame.callerPtr;
+    iPtr->varFramePtr = frame.callerVarPtr;
+
+    return TCL_OK;
+}
+
+/* dummy */
+#define Tcl_Namespace char
+
+static int
+Tcl_PushCallFrame(interp, framePtr, nsPtr, isProcCallFrame)
+    Tcl_Interp *interp;
+    Tcl_CallFrame *framePtr;
+    Tcl_Namespace *nsPtr;
+    int isProcCallFrame;
+{
+    DummyInterp *iPtr = (DummyInterp*)interp;
+    CallFrame *frame = (CallFrame *)framePtr;
+
+    /* **** DUMMY **** */
+    Tcl_InitHashTable(&frame.varTable, TCL_STRING_KEYS);
+    if (iPtr->varFramePtr != NULL) {
+        frame.level = iPtr->varFramePtr->level + 1;
+    } else {
+        frame.level = 1;
+    }
+    frame.callerPtr = iPtr->framePtr;
+    frame.callerVarPtr = iPtr->varFramePtr;
+    iPtr->framePtr = &frame;
+    iPtr->varFramePtr = &frame;
+
+    return TCL_OK;
+}
+#  endif
+
 #endif
 
+#endif /* TCL_NAMESPACE_DEBUG */
+
 
 /*---- class TclTkIp ----*/
 struct tcltkip {
     Tcl_Interp *ip;             /* the interpreter */
+#if TCL_NAMESPACE_DEBUG
     Tcl_Namespace *default_ns;  /* default namespace */
+#endif
     int has_orig_exit;          /* has original 'exit' command ? */
     Tcl_CmdInfo orig_exit_info; /* command info of original 'exit' command */
     int ref_count;              /* reference count of rbtk_preserve_ip call */
@@ -248,37 +450,28 @@
 
     Data_Get_Struct(self, struct tcltkip, ptr);
     if (ptr == 0) {
-        rb_raise(rb_eTypeError, "uninitialized TclTkIp");
+        /* rb_raise(rb_eTypeError, "uninitialized TclTkIp"); */
+        return((struct tcltkip *)NULL);
+    }
+    if (ptr->ip == (Tcl_Interp*)NULL) {
+        /* rb_raise(rb_eRuntimeError, "deleted IP"); */
     }
     return ptr;
 }
 
 
-/* namespace check */
-/* ip_null_namespace(Tcl_Interp *interp) */
-#if TCL_MAJOR_VERSION < 8
-#define ip_null_namespace(interp) (0)
-#else /* support namespace */
-#define ip_null_namespace(interp) \
-    (Tcl_GetCurrentNamespace(interp) == (Tcl_Namespace *)NULL)
-#endif
-
-/* rbtk_invalid_namespace(tcltkip *ptr) */
-#if TCL_MAJOR_VERSION < 8
-#define rbtk_invalid_namespace(ptr) (0)
-#else /* support namespace */
-#define rbtk_invalid_namespace(ptr) \
-    ((ptr)->default_ns == (Tcl_Namespace*)NULL || Tcl_GetCurrentNamespace((ptr)->ip) != (ptr)->default_ns)
-#endif
-
-
 /* increment/decrement reference count of tcltkip */
 static int
 rbtk_preserve_ip(ptr)
     struct tcltkip *ptr;
 {
     ptr->ref_count++;
-    Tcl_Preserve((ClientData)ptr->ip);
+    if (ptr->ip == (Tcl_Interp*)NULL) {
+        /* deleted IP */
+        ptr->ref_count = 0;
+    } else {
+        Tcl_Preserve((ClientData)ptr->ip);
+    }
     return(ptr->ref_count);
 }
 
@@ -289,6 +482,9 @@
     ptr->ref_count--;
     if (ptr->ref_count < 0) {
         ptr->ref_count = 0;
+    } else if (ptr->ip == (Tcl_Interp*)NULL) {
+        /* deleted IP */
+        ptr->ref_count = 0;
     } else {
         Tcl_Release((ClientData)ptr->ip);
     }
@@ -454,7 +650,7 @@
     struct tcltkip *ptr = get_ip(self);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return get_eventloop_tick(self);
     }
@@ -507,7 +703,7 @@
     struct tcltkip *ptr = get_ip(self);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return get_no_event_wait(self);
     }
@@ -563,7 +759,7 @@
     struct tcltkip *ptr = get_ip(self);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return get_eventloop_weight(self);
     }
@@ -659,7 +855,7 @@
     rb_secure(4);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return lib_evloop_abort_on_exc(self);
     }
@@ -734,6 +930,15 @@
 
             found_event = Tcl_DoOneEvent(event_flag);
 
+            if (rbtk_pending_exception != 0) {
+                volatile VALUE exc = rbtk_pending_exception;
+                DUMP1("find a pending exception");
+                rbtk_pending_exception = 0;
+                if (rb_obj_is_kind_of(exc, rb_eException)) {
+                    rb_exc_raise(exc);
+                }
+            }
+
             if (update_flag != 0) {
               if (found_event) {
                 DUMP1("next update loop");
@@ -759,7 +964,7 @@
             }
 
         } else {
-            int tick_counter;
+            int st, tick_counter;
 
             DUMP1("there are other threads");
             event_loop_wait_event = 1;
@@ -781,15 +986,31 @@
                     }
                 }
 
-                if (Tcl_DoOneEvent(event_flag)) {
-                    tick_counter++;
-                } else {
-                    if (update_flag != 0) {
-                        DUMP1("update complete");
-                        return 0;
+                if (eventloop_thread == 0 || current == eventloop_thread) {
+                    st = Tcl_DoOneEvent(event_flag);
+
+                    if (rbtk_pending_exception != 0) {
+                        volatile VALUE exc = rbtk_pending_exception;
+                        DUMP1("find a pending exception");
+                        rbtk_pending_exception = 0;
+                        if (rb_obj_is_kind_of(exc, rb_eException)) {
+                            rb_exc_raise(exc);
+                        }
+                    }
+
+                    if (st) {
+                        tick_counter++;
+                    } else {
+                        if (update_flag != 0) {
+                            DUMP1("update complete");
+                            return 0;
+                        }
+                        tick_counter += no_event_tick;
+                        rb_thread_wait_for(t);
                     }
-                    tick_counter += no_event_tick;
-                    rb_thread_wait_for(t);
+                } else {
+                    DUMP2("sleep eventloop %lx", current);
+                    rb_thread_stop();
                 }
 
                 if (watchdog_thread != 0 && eventloop_thread != current) {
@@ -851,12 +1072,22 @@
 {
     Tk_DeleteTimerHandler(timer_token);
     timer_token = (Tcl_TimerToken)NULL;
-    DUMP2("eventloop-ensure: current-thread : %lx\n", rb_thread_current());
-    DUMP2("eventloop-ensure: eventloop-thread : %lx\n", eventloop_thread);
-    if (eventloop_thread == rb_thread_current()) {
-        DUMP2("eventloop-thread -> %lx\n", parent_evloop);
-        eventloop_thread = parent_evloop;
+
+    DUMP2("eventloop-ensure: current-thread : %lx", rb_thread_current());
+    DUMP2("eventloop-ensure: eventloop-thread : %lx", eventloop_thread);
+    while (eventloop_thread != rb_thread_current()) {
+        DUMP2("current-eventloop %lx waits for child", rb_thread_current());
+        rb_thread_stop();
     }
+ 
+    DUMP2("eventloop-enshure: eventloop-thread -> %lx", parent_evloop);
+    eventloop_thread = parent_evloop;
+    if (eventloop_thread != 0) {
+        DUMP2("eventloop-enshure: wake up parent %lx", eventloop_thread);
+        rb_thread_wakeup(eventloop_thread);
+    }
+    DUMP2("FINISH eventloop %lx", rb_thread_current());
+
     return Qnil;
 }
 
@@ -864,10 +1095,19 @@
 lib_eventloop_launcher(check_rootwidget)
     VALUE check_rootwidget;
 {
-    VALUE parent_evloop = eventloop_thread;
+    volatile VALUE parent_evloop = eventloop_thread;
 
     eventloop_thread = rb_thread_current();
 
+    if (parent_evloop != 0) {
+        DUMP2("wait for stop of parent_evloop %lx", parent_evloop);
+        while(!RTEST(rb_funcall(parent_evloop, ID_stop_p, 0))) {
+            DUMP2("parent_evloop %lx doesn't stop", parent_evloop);
+            rb_thread_run(parent_evloop);
+        }
+        DUMP1("succeed to stop parent");
+    }
+
     if (ruby_debug) { 
         fprintf(stderr, "tcltklib: eventloop-thread : %lx -> %lx\n", 
                 parent_evloop, eventloop_thread);
@@ -906,7 +1146,8 @@
     struct tcltkip *ptr = get_ip(self);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return Qnil;
     }
@@ -1011,7 +1252,7 @@
     struct tcltkip *ptr = get_ip(self);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return Qnil;
     }
@@ -1034,6 +1275,10 @@
     int flags;
     int found_event;
 
+    if (eventloop_thread) {
+        rb_raise(rb_eRuntimeError, "eventloop is already running");
+    }
+
     if (rb_scan_args(argc, argv, "01", &vflags) == 0) {
         flags = TCL_ALL_EVENTS | TCL_DONT_WAIT;
     } else {
@@ -1050,7 +1295,8 @@
         struct tcltkip *ptr = get_ip(self);
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip)) {
             DUMP1("ip is deleted");
             return Qfalse;
         }
@@ -1064,6 +1310,15 @@
     /* found_event = Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT); */
     found_event = Tcl_DoOneEvent(flags);
 
+    if (rbtk_pending_exception != 0) {
+        volatile VALUE exc = rbtk_pending_exception;
+        DUMP1("find a pending exception");
+        rbtk_pending_exception = 0;
+        if (rb_obj_is_kind_of(exc, rb_eException)) {
+            rb_exc_raise(exc);
+        }
+    }
+
     if (found_event) {
         return Qtrue;
     } else {
@@ -1347,8 +1602,23 @@
 
     /* ruby command has 1 arg. */
     if (argc != 2) {
-        rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", 
-                 argc - 1);
+#if 0
+        rb_raise(rb_eArgError, 
+                 "wrong number of arguments (%d for 1)", argc - 1);
+#else
+        char buf[sizeof(int)*8 + 1];
+        Tcl_ResetResult(interp);
+        sprintf(buf, "%d", argc-1);
+        Tcl_AppendResult(interp, "wrong number of arguments (", 
+                         buf, " for 1)", (char *)NULL);
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eArgError, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eArgError, interp->result);
+#endif
+        return TCL_ERROR;
+#endif
     }
 
     /* allocate */
@@ -1435,9 +1705,15 @@
             return TCL_CONTINUE;
 
         } else if (eclass == rb_eSystemExit) {
+            ip_set_exc_message(interp, res);
+            rbtk_pending_exception = res;
+            return TCL_ERROR;
+
+#if 0
             thr_crit_bup = rb_thread_critical;
             rb_thread_critical = Qtrue;
 
+#if 0 /* REMOVE : fail to rescue SystemExit */
             /* Tcl_Eval(interp, "destroy ."); */
             if (Tk_GetNumMainWindows() > 0) {
                 Tk_Window main_win = Tk_MainWindow(interp);
@@ -1445,6 +1721,7 @@
                     Tk_DestroyWindow(main_win);
                 }
             }
+#endif
 
             /* StringValue(res); */
             res = rb_funcall(res, ID_message, 0, 0);
@@ -1454,6 +1731,7 @@
             rb_thread_critical = thr_crit_bup;
 
             rb_raise(rb_eSystemExit, RSTRING(res)->ptr);
+#endif
 
         } else if (rb_obj_is_kind_of(res, eLocalJumpError)) {
             VALUE reason = rb_ivar_get(res, ID_at_reason);
@@ -1707,7 +1985,19 @@
     VALUE old_gc;
 
     if (argc < 3) {
+#if 0
         rb_raise(rb_eArgError, "too few arguments");
+#else
+        Tcl_ResetResult(interp);
+        Tcl_AppendResult(interp, "too few arguments", (char *)NULL);
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eArgError, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eArgError, interp->result);
+#endif
+        return TCL_ERROR;
+#endif
     }
 
     /* allocate */
@@ -1744,8 +2034,21 @@
         free(buf);
     }
     if (NIL_P(receiver)) {
-        rb_raise(rb_eArgError, "unknown class/module/global-variable '%s'", 
-                 str);
+#if 0
+        rb_raise(rb_eArgError, 
+                 "unknown class/module/global-variable '%s'", str);
+#else
+        Tcl_ResetResult(interp);
+        Tcl_AppendResult(interp, "unknown class/module/global-variable '", 
+                         str, "'", (char *)NULL);
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eArgError, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eArgError, interp->result);
+#endif
+        return TCL_ERROR;
+#endif
     }
 
     /* get metrhod */
@@ -1835,6 +2138,7 @@
             thr_crit_bup = rb_thread_critical;
             rb_thread_critical = Qtrue;
 
+#if 0 /* REMOVE : fail to rescue SystemExit */
             /* Tcl_Eval(interp, "destroy ."); */
             if (Tk_GetNumMainWindows() > 0) {
                 Tk_Window main_win = Tk_MainWindow(interp);
@@ -1842,6 +2146,7 @@
                     Tk_DestroyWindow(main_win);
                 }
             }
+#endif
 
             /* StringValue(res); */
             res = rb_funcall(res, ID_message, 0, 0);
@@ -1850,8 +2155,21 @@
 
             rb_thread_critical = thr_crit_bup;
 
+#if 0
             rb_raise(rb_eSystemExit, RSTRING(res)->ptr);
-
+#else
+            Tcl_ResetResult(interp);
+            Tcl_AppendResult(interp, "raise SystemExit on `ruby_cmd'", 
+                             (char *)NULL);
+#if TCL_MAJOR_VERSION >= 8
+            rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, 
+                                                 Tcl_GetStringResult(interp));
+#else
+            rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, 
+                                                 interp->result);
+#endif
+            return TCL_ERROR;
+#endif
         } else if (rb_obj_is_kind_of(res, eLocalJumpError)) {
             VALUE reason = rb_ivar_get(res, ID_at_reason);
 
@@ -1926,7 +2244,11 @@
     char *argv[];
 #endif
 {
-    if (!Tcl_InterpDeleted(interp) && !ip_null_namespace(interp)) {
+    if (!Tcl_InterpDeleted(interp)
+#if TCL_NAMESPACE_DEBUG
+        && !ip_null_namespace(interp)
+#endif
+        ) {
         Tcl_Preserve(interp);
         Tcl_Eval(interp, "interp eval {} {destroy .}; interp delete {}");
         Tcl_Release(interp);
@@ -1961,12 +2283,42 @@
 #endif
 
     if (rb_safe_level() >= 4) {
+#if 0
         rb_raise(rb_eSecurityError, 
                  "Insecure operation `exit' at level %d", 
                  rb_safe_level());
+#else
+        char buf[sizeof(int)*8 + 1];
+        Tcl_ResetResult(interp);
+        sprintf(buf, "%d", rb_safe_level());
+        Tcl_AppendResult(interp, "Insecure operation `exit' at level ",
+                         buf, (char *)NULL);
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eSecurityError, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eSecurityError, 
+                                             interp->result);
+#endif
+        return TCL_ERROR;
+#endif
     } else if (Tcl_IsSafe(interp)) {
+#if 0
         rb_raise(rb_eSecurityError, 
                  "Insecure operation `exit' on a safe interpreter");
+#else
+        Tcl_AppendResult(interp, 
+                         "Insecure operation `exit' on a safe interpreter", 
+                         (char *)NULL);
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eSecurityError, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eSecurityError, 
+                                             interp->result);
+#endif
+        return TCL_ERROR;
+#endif
 #if 0
     } else if (Tcl_GetMaster(interp) != (Tcl_Interp *)NULL) {
         Tcl_Preserve(interp);
@@ -1981,10 +2333,18 @@
 
     switch(argc) {
     case 1:
-        rb_exit(0); /* not return if succeed */
-
+        /* rb_exit(0); */ /* not return if succeed */
         Tcl_AppendResult(interp, 
                          "fail to call \"", cmd, "\"", (char *)NULL);
+
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, interp->result);
+#endif
+        rb_iv_set(rbtk_pending_exception, "status", INT2FIX(0));
+
         return TCL_ERROR;
 
     case 2:
@@ -2002,11 +2362,21 @@
         }
         param = argv[1];
 #endif
-        rb_exit(state); /* not return if succeed */
+        /* rb_exit(state); */ /* not return if succeed */
 
         Tcl_AppendResult(interp, "fail to call \"", cmd, " ", 
                          param, "\"", (char *)NULL);
+
+#if TCL_MAJOR_VERSION >= 8
+        rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, 
+                                             Tcl_GetStringResult(interp));
+#else
+        rbtk_pending_exception = rb_exc_new2(rb_eSystemExit, interp->result);
+#endif
+        rb_iv_set(rbtk_pending_exception, "status", INT2FIX(state));
+
         return TCL_ERROR;
+
     default:
         /* arguemnt error */
         Tcl_AppendResult(interp, 
@@ -3275,12 +3645,19 @@
     VALUE self;
     VALUE var;
 {
-    VALUE argv[2];
+    VALUE *argv;
+    VALUE retval;
     volatile VALUE cmd_str = rb_str_new2("thread_vwait");
 
+    argv = ALLOC_N(VALUE, 2);
     argv[0] = cmd_str;
     argv[1] = var;
-    return ip_invoke_real(2, argv, self);
+
+    retval = ip_invoke_real(2, argv, self);
+
+    free(argv);
+
+    return retval;
 }
 
 static VALUE
@@ -3289,13 +3666,20 @@
     VALUE mode;
     VALUE target;
 {
-    VALUE argv[3];
+    VALUE *argv;
+    VALUE retval;
     volatile VALUE cmd_str = rb_str_new2("thread_tkwait");
 
+    argv = ALLOC_N(VALUE, 3);
     argv[0] = cmd_str;
     argv[1] = mode;
     argv[2] = target;
-    return ip_invoke_real(3, argv, self);
+
+    retval = ip_invoke_real(3, argv, self);
+
+    free(argv);
+
+    return retval;
 }
 
 /* destroy interpreter */
@@ -3329,7 +3713,11 @@
     char *slave_name;
     int i, len;
 
-    if (Tcl_InterpDeleted(ip) || ip_null_namespace(ip)) {
+    if (Tcl_InterpDeleted(ip)
+#if TCL_NAMESPACE_DEBUG
+        || ip_null_namespace(ip)
+#endif
+        ) {
         DUMP2("call delete_slaves() for deleted ip(%lx)", ip);
         return;
     }
@@ -3370,20 +3758,22 @@
 
         Tcl_Preserve(slave);
 
-        if (!Tcl_InterpDeleted(slave) && !ip_null_namespace(slave) && 
-            Tcl_GetCommandInfo(slave, finalize_hook_name, &info)) {
+        if (!Tcl_InterpDeleted(slave) 
+#if TCL_NAMESPACE_DEBUG
+            && !ip_null_namespace(slave) 
+#endif
+            && Tcl_GetCommandInfo(slave, finalize_hook_name, &info)) {
             DUMP2("call finalize hook proc '%s'", finalize_hook_name);
             Tcl_Eval(slave, finalize_hook_name);
         }
 
-        if (!Tcl_InterpDeleted(slave) && 
-            Tcl_Eval(slave, DEF_CANCEL_AFTER_SCRIPTS_PROC) == TCL_OK) {
-            if (!Tcl_InterpDeleted(slave) && !ip_null_namespace(slave) && 
-                Tcl_GetCommandInfo(slave, CANCEL_AFTER_SCRIPTS, &info)) {
-                DUMP2("call cancel after scripts proc '%s'", 
-                      CANCEL_AFTER_SCRIPTS);
-                Tcl_Eval(slave, CANCEL_AFTER_SCRIPTS);
-            }
+        if (!Tcl_InterpDeleted(slave)
+#if TCL_NAMESPACE_DEBUG
+            && !ip_null_namespace(slave)
+#endif
+            ) {
+          DUMP1("call cancel after scripts");
+          Tcl_Eval(slave, "foreach id [after info] {after cancel $id}");
         }
 
         /* delete slaves of slave */
@@ -3408,69 +3798,124 @@
     Tcl_Release(ip);
 }
 
-static void
-ip_free(ptr)
-    struct tcltkip *ptr;
+
+static int 
+ip_free_core(ip)
+    Tcl_Interp *ip;
 {
     Tcl_CmdInfo info;
     int thr_crit_bup;
-    char* argv[2];
 
-    DUMP2("free Tcl Interp %lx", ptr->ip);
-    if (ptr) {
-        thr_crit_bup = rb_thread_critical;
-        rb_thread_critical = Qtrue;
+    /* deleted ipterp ? */
+    if (ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ip)) {
+        /* deleted IP --> ignore */
+        return 1;
+    }
 
-        DUMP2("IP ref_count = %d", ptr->ref_count);
+    thr_crit_bup = rb_thread_critical;
+    rb_thread_critical = Qtrue;
 
-        if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)) {
-            DUMP2("IP(%lx) is not deleted", ptr->ip);
-            /* Tcl_Preserve(ptr->ip); */
-            rbtk_preserve_ip(ptr);
+    Tcl_Preserve(ip);
 
-            delete_slaves(ptr->ip);
+    delete_slaves(ip);
 
-            Tcl_ResetResult(ptr->ip);
+    Tcl_ResetResult(ip);
 
-            if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)
-                && Tcl_GetCommandInfo(ptr->ip, finalize_hook_name, &info)) {
-                DUMP2("call finalize hook proc '%s'", finalize_hook_name);
-                Tcl_Eval(ptr->ip, finalize_hook_name);
-            }
+    if (!Tcl_InterpDeleted(ip)
+#if TCL_NAMESPACE_DEBUG
+        && !ip_null_namespace(ip)
+#endif
+        && Tcl_GetCommandInfo(ip, finalize_hook_name, &info)) {
+        DUMP2("call finalize hook proc '%s'", finalize_hook_name);
+        Tcl_Eval(ip, finalize_hook_name);
+    }
 
-            if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)
-                && Tcl_Eval(ptr->ip, DEF_CANCEL_AFTER_SCRIPTS_PROC) == TCL_OK) {
-                if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)
-                    && Tcl_GetCommandInfo(ptr->ip, CANCEL_AFTER_SCRIPTS, &info)) {
-                    DUMP2("call cancel after scripts proc '%s'", 
-                          CANCEL_AFTER_SCRIPTS);
-                    Tcl_Eval(ptr->ip, CANCEL_AFTER_SCRIPTS);
-                }
-            }
+    if (!Tcl_InterpDeleted(ip)
+#if TCL_NAMESPACE_DEBUG
+        && !ip_null_namespace(ip)
+#endif
+        ) {
+        DUMP1("call cancel aftern scripts");
+        Tcl_Eval(ip, "foreach id [after info] {after cancel $id}");
+    }
 
-            /* del_root(ptr->ip); */
+    /* del_root(ip); */
 
-            DUMP1("delete interp");
-            /* while(!rbtk_InterpDeleted(ptr->ip)) { */
-            if (!Tcl_InterpDeleted(ptr->ip)) {
-                DUMP2("delete ip(%lx)", ptr->ip);
-                Tcl_DeleteInterp(ptr->ip);
-            }
+    /* while(!rbtk_InterpDeleted(ip)) { */
+    if (!Tcl_InterpDeleted(ip)) {
+        DUMP2("delete ip(%lx)", ip);
+        Tcl_DeleteInterp(ip);
+    }
 
-            /* Tcl_Release(ptr->ip); */
-            rbtk_release_ip(ptr);
-        }
+    Tcl_Release(ip);
 
-        rbtk_release_ip(ptr);
-        DUMP2("IP ref_count = %d", ptr->ref_count);
+    rb_thread_critical = thr_crit_bup;
 
-        free(ptr);
+    return 1;
+}
 
-        rb_thread_critical = thr_crit_bup;
+struct ip_free_queue {
+    Tcl_Event ev;
+    Tcl_Interp *ip;
+};
+
+static int 
+ip_free_queue_handler(evPtr, flags)
+    Tcl_Event *evPtr;
+    int flags;
+{
+    struct ip_free_queue *ptr = (struct ip_free_queue *)evPtr;
+    int st;
+
+    st = ip_free_core(ptr->ip);
+
+    Tcl_Release(evPtr);
+
+    return st;
+}
+
+static void
+ip_free(ptr)
+    struct tcltkip *ptr;
+{
+    struct ip_free_queue *q;
+
+    DUMP2("free Tcl Interp %lx", ptr->ip);
+    if (ptr) {
+        if ( ptr->ip != (Tcl_Interp*)NULL 
+             && Tcl_GetMaster(ptr->ip) != (Tcl_Interp*)NULL 
+             && !Tcl_InterpDeleted(Tcl_GetMaster(ptr->ip)) ) {
+            DUMP2("parent IP(%lx) is not deleted", Tcl_GetMaster(ptr->ip));
+            DUMP2("slave IP(%lx) should not be deleted", ptr->ip);
+            free(ptr);
+            return;
+        }
+
+        if (ptr->ip == (Tcl_Interp*)NULL) {
+            DUMP1("ip_free is called for deleted IP");
+            free(ptr);
+            return;
+        }
+
+        if (eventloop_thread != 0 && rb_thread_current() != eventloop_thread) {
+            /* queueing */
+            q = (struct ip_free_queue*)Tcl_Alloc(sizeof(struct ip_free_queue));
+            Tcl_Preserve(q);
+            q->ip = ptr->ip;
+            q->ev.proc = ip_free_queue_handler;
+            Tcl_QueueEvent(&(q->ev), TCL_QUEUE_HEAD);
+        } else {
+            /* direct call */
+            ip_free_core(ptr->ip);
+        }
+
+        free(ptr);
     }
+
     DUMP1("complete freeing Tcl Interp");
 }
 
+
 /* create and initialize interpreter */
 static VALUE ip_alloc _((VALUE));
 static VALUE
@@ -3494,7 +3939,9 @@
 
     /* security check */
     if (ruby_safe_level >= 4) {
-        rb_raise(rb_eSecurityError, "Cannot create a TclTkIp object at level %d", ruby_safe_level);
+        rb_raise(rb_eSecurityError, 
+                 "Cannot create a TclTkIp object at level %d", 
+                 ruby_safe_level);
     }
 
     /* create object */
@@ -3513,12 +3960,14 @@
     }
 
 #if TCL_MAJOR_VERSION >= 8
+#if TCL_NAMESPACE_DEBUG
     DUMP1("get current namespace");
     if ((ptr->default_ns = Tcl_GetCurrentNamespace(ptr->ip)) 
         == (Tcl_Namespace*)NULL) {
       rb_raise(rb_eRuntimeError, "a new Tk interpreter has a NULL namespace");
     }
 #endif
+#endif
 
     rbtk_preserve_ip(ptr);
     DUMP2("IP ref_count = %d", ptr->ref_count);
@@ -3715,12 +4164,12 @@
 }
 
 static VALUE
-ip_create_slave(argc, argv, self)
+ip_create_slave_core(interp, argc, argv)
+    VALUE interp;
     int   argc;
     VALUE *argv;
-    VALUE self;
 {
-    struct tcltkip *master = get_ip(self);
+    struct tcltkip *master = get_ip(interp);
     struct tcltkip *slave = ALLOC(struct tcltkip);
     VALUE safemode;
     VALUE name;
@@ -3728,15 +4177,22 @@
     int thr_crit_bup;
     Tk_Window mainWin;
 
-    /* safe-mode check */
-    if (rb_scan_args(argc, argv, "11", &name, &safemode) == 1) {
-        safemode = Qfalse;
+    /* ip is deleted? */
+    if (master == (struct tcltkip *)NULL || master->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(master->ip)) {
+        DUMP1("master-ip is deleted");
+        return rb_exc_new2(rb_eRuntimeError, 
+                           "deleted master cannot create a new slave");
     }
+
+    name = argv[0];
+    safemode = argv[1];
+
     if (Tcl_IsSafe(master->ip) == 1) {
         safe = 1;
     } else if (safemode == Qfalse || NIL_P(safemode)) {
         safe = 0;
-        rb_secure(4);
+        /* rb_secure(4); */ /* already checked */
     } else {
         safe = 1;
     }
@@ -3744,26 +4200,22 @@
     thr_crit_bup = rb_thread_critical;
     rb_thread_critical = Qtrue;
 
-    /* ip is deleted? */
-    if (Tcl_InterpDeleted(master->ip)) {
-        DUMP1("master-ip is deleted");
-        rb_thread_critical = thr_crit_bup;
-        rb_raise(rb_eRuntimeError, "deleted master cannot create a new slave interpreter");
-    }
-
     /* create slave-ip */
     slave->ref_count = 0;
     slave->allow_ruby_exit = 0;
     slave->return_value = 0;
 
-    slave->ip = Tcl_CreateSlave(master->ip, StringValuePtr(name), safe);
+    slave->ip = Tcl_CreateSlave(master->ip, RSTRING(name)->ptr, safe);
     if (slave->ip == NULL) {
         rb_thread_critical = thr_crit_bup;
-        rb_raise(rb_eRuntimeError, "fail to create the new slave interpreter");
+        return rb_exc_new2(rb_eRuntimeError, 
+                           "fail to create the new slave interpreter");
     }
 #if TCL_MAJOR_VERSION >= 8
+#if TCL_NAMESPACE_DEBUG
     slave->default_ns = Tcl_GetCurrentNamespace(slave->ip);
 #endif
+#endif
     rbtk_preserve_ip(slave);
 
     slave->has_orig_exit 
@@ -3783,28 +4235,72 @@
 
     rb_thread_critical = thr_crit_bup;
 
-    return Data_Wrap_Struct(CLASS_OF(self), 0, ip_free, slave);
+    return Data_Wrap_Struct(CLASS_OF(interp), 0, ip_free, slave);
 }
 
-/* make ip "safe" */
 static VALUE
-ip_make_safe(self)
+ip_create_slave(argc, argv, self)
+    int   argc;
+    VALUE *argv;
     VALUE self;
 {
-    struct tcltkip *ptr = get_ip(self);
+    struct tcltkip *master = get_ip(self);
+    VALUE safemode;
+    VALUE name;
+    VALUE *callargv;
+    VALUE retval;
+
+    /* ip is deleted? */
+    if (master == (struct tcltkip *)NULL || master->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(master->ip)) {
+        DUMP1("master-ip is deleted");
+        rb_raise(rb_eRuntimeError, 
+                 "deleted master cannot create a new slave interpreter");
+    }
+
+    /* safe-mode check */
+    if (rb_scan_args(argc, argv, "11", &name, &safemode) == 1) {
+        safemode = Qfalse;
+    }
+    if (Tcl_IsSafe(master->ip) != 1
+        && (safemode == Qfalse || NIL_P(safemode))) {
+        rb_secure(4);
+    }
+
+    callargv = ALLOC_N(VALUE, 2);
+    StringValue(name);
+    callargv[0] = name;
+    callargv[1] = safemode;
+
+    retval = tk_funcall(ip_create_slave_core, 2, callargv, self);
+
+    free(callargv);
+
+    return retval;
+}
+
+/* make ip "safe" */
+static VALUE
+ip_make_safe_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;   /* dummy */
+    VALUE *argv;  /* dummy */
+{
+    struct tcltkip *ptr = get_ip(interp);
     Tk_Window mainWin;
     
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
-        rb_raise(rb_eRuntimeError, "interpreter is deleted");
+        return rb_exc_new2(rb_eRuntimeError, "interpreter is deleted");
     }
 
     if (Tcl_MakeSafe(ptr->ip) == TCL_ERROR) {
 #if TCL_MAJOR_VERSION >= 8
-        rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(ptr->ip));
+        return rb_exc_new2(rb_eRuntimeError, Tcl_GetStringResult(ptr->ip));
 #else /* TCL_MAJOR_VERSION < 8 */
-        rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
+        return rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
 #endif
     }
 
@@ -3822,7 +4318,23 @@
                       (ClientData)mainWin, (Tcl_CmdDeleteProc *)NULL);
 #endif
 
-    return self;
+    return interp;
+}
+
+static VALUE
+ip_make_safe(self)
+    VALUE self;
+{
+    struct tcltkip *ptr = get_ip(self);
+    
+    /* ip is deleted? */
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
+        DUMP1("ip is deleted");
+        rb_raise(rb_eRuntimeError, "interpreter is deleted");
+    }
+
+    return tk_funcall(ip_make_safe_core, 0, (VALUE*)NULL, self);
 }
 
 /* is safe? */
@@ -3833,7 +4345,8 @@
     struct tcltkip *ptr = get_ip(self);
     
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         rb_raise(rb_eRuntimeError, "interpreter is deleted");
     }
@@ -3853,7 +4366,8 @@
     struct tcltkip *ptr = get_ip(self);
     
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         rb_raise(rb_eRuntimeError, "interpreter is deleted");
     }
@@ -3876,7 +4390,8 @@
     rb_secure(4);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         rb_raise(rb_eRuntimeError, "interpreter is deleted");
     }
@@ -3918,11 +4433,19 @@
 
 /* delete interpreter */
 static VALUE
-ip_delete(self)
-    VALUE self;
+ip_delete_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;   /* dummy */
+    VALUE *argv;  /* dummy */
 {
     Tcl_CmdInfo info;
-    struct tcltkip *ptr = get_ip(self);
+    struct tcltkip *ptr = get_ip(interp);
+
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
+        DUMP1("delete deleted IP");
+        return Qnil;
+    }
 
     /* Tcl_Preserve(ptr->ip); */
     rbtk_preserve_ip(ptr);
@@ -3931,20 +4454,22 @@
     delete_slaves(ptr->ip);
 
     DUMP1("finalize operation");
-    if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)
+    if (!Tcl_InterpDeleted(ptr->ip)
+#if TCL_NAMESPACE_DEBUG
+        && !rbtk_invalid_namespace(ptr)
+#endif
         && Tcl_GetCommandInfo(ptr->ip, finalize_hook_name, &info)) {
         DUMP2("call finalize hook proc '%s'", finalize_hook_name);
         Tcl_Eval(ptr->ip, finalize_hook_name);
     }
 
-    if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)
-        && Tcl_Eval(ptr->ip, DEF_CANCEL_AFTER_SCRIPTS_PROC) == TCL_OK) {
-        if (!Tcl_InterpDeleted(ptr->ip) && !rbtk_invalid_namespace(ptr)
-            && Tcl_GetCommandInfo(ptr->ip, CANCEL_AFTER_SCRIPTS, &info)) {
-            DUMP2("call cancel after scripts proc '%s'", 
-                  CANCEL_AFTER_SCRIPTS);
-            Tcl_Eval(ptr->ip, CANCEL_AFTER_SCRIPTS);
-        }
+    if (!Tcl_InterpDeleted(ptr->ip)
+#if TCL_NAMESPACE_DEBUG
+        && !ip_null_namespace(ptr->ip)
+#endif
+        ) {
+      DUMP1("call cancel after scripts");
+      Tcl_Eval(ptr->ip, "foreach id [after info] {after cancel $id}");
     }
 
     del_root(ptr->ip);
@@ -3955,6 +4480,7 @@
         DUMP2("delete ip(%lx)", ptr->ip);
         Tcl_DeleteInterp(ptr->ip);
     }
+    ptr->ip = (Tcl_Interp*)NULL;
 
     /* Tcl_Release(ptr->ip); */
     rbtk_release_ip(ptr);
@@ -3962,6 +4488,21 @@
     return Qnil;
 }
 
+static VALUE
+ip_delete(self)
+    VALUE self;
+{
+    struct tcltkip *ptr = get_ip(self);
+
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
+        return Qnil;
+    } else {
+        return tk_funcall(ip_delete_core, 0, (VALUE*)NULL, self);
+    }
+}
+
+
 /* is deleted? */
 static VALUE
 ip_has_invalid_namespace_p(self)
@@ -3969,11 +4510,20 @@
 {
     struct tcltkip *ptr = get_ip(self);
 
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL) {
+        /* deleted IP */
+        return Qtrue;
+    }
+
+#if TCL_NAMESPACE_DEBUG
     if (rbtk_invalid_namespace(ptr)) {
         return Qtrue;
     } else {
         return Qfalse;
     }
+#else
+    return Qfalse;
+#endif
 }
 
 static VALUE
@@ -3982,7 +4532,8 @@
 {
     struct tcltkip *ptr = get_ip(self);
 
-    if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp *)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         return Qtrue;
     } else {
         return Qfalse;
@@ -4004,6 +4555,7 @@
     va_list args;
     char buf[BUFSIZ];
     VALUE einfo;
+    struct tcltkip *ptr = get_ip(interp);
 
     va_init_list(args,fmt);
     vsnprintf(buf, BUFSIZ, fmt, args);
@@ -4011,7 +4563,9 @@
     va_end(args);
     einfo = rb_exc_new2(exc, buf);
     rb_ivar_set(einfo, ID_at_interp, interp);
-    Tcl_ResetResult(get_ip(interp)->ip);
+    if (ptr) {
+        Tcl_ResetResult(ptr->ip);
+    }
 
     return einfo;
 }
@@ -4073,6 +4627,175 @@
 #endif
 }
 
+
+/* call Tcl/Tk functions on the eventloop thread */
+static VALUE
+callq_safelevel_handler(arg, callq)
+    VALUE arg;
+    VALUE callq;
+{
+    struct call_queue *q;
+
+    Data_Get_Struct(callq, struct call_queue, q);
+    DUMP2("(safe-level handler) $SAFE = %d", q->safe_level);
+    rb_set_safe_level(q->safe_level);
+    return((q->func)(q->interp, q->argc, q->argv));
+}
+
+static int call_queue_handler _((Tcl_Event *, int));
+static int
+call_queue_handler(evPtr, flags)
+    Tcl_Event *evPtr;
+    int flags;
+{
+    struct call_queue *q = (struct call_queue *)evPtr;
+    volatile VALUE ret;
+    volatile VALUE q_dat;
+    struct tcltkip *ptr;
+
+    DUMP2("do_call_queue_handler : evPtr = %p", evPtr);
+    DUMP2("queue_handler thread : %lx", rb_thread_current());
+    DUMP2("added by thread : %lx", q->thread);
+
+    if (*(q->done)) {
+        DUMP1("processed by another event-loop");
+        return 0;
+    } else {
+        DUMP1("process it on current event-loop");
+    }
+
+    /* process it */
+    *(q->done) = 1;
+
+    /* deleted ipterp ? */
+    ptr = get_ip(q->interp);
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
+        /* deleted IP --> ignore */
+        return 1;
+    }
+
+    /* check safe-level */
+    if (rb_safe_level() != q->safe_level) {
+        /* q_dat = Data_Wrap_Struct(rb_cData,0,0,q); */
+        q_dat = Data_Wrap_Struct(rb_cData,call_queue_mark,0,q);
+        ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat), 
+                         ID_call, 0);
+        rb_gc_force_recycle(q_dat);
+    } else {
+        DUMP2("call function (for caller thread:%lx)", q->thread);
+        DUMP2("call function (current thread:%lx)", rb_thread_current());
+        ret = (q->func)(q->interp, q->argc, q->argv);
+    }
+
+    /* set result */
+    RARRAY(q->result)->ptr[0] = ret;
+
+    /* complete */
+    *(q->done) = -1;
+
+    /* back to caller */
+    DUMP2("back to caller (caller thread:%lx)", q->thread);
+    DUMP2("               (current thread:%lx)", rb_thread_current());
+    rb_thread_run(q->thread);
+    DUMP1("finish back to caller");
+
+    /* end of handler : remove it */
+    return 1;
+}
+
+static VALUE
+tk_funcall(func, argc, argv, obj)
+    VALUE (*func)();
+    int argc;
+    VALUE *argv;
+    VALUE obj;
+{
+    struct call_queue *callq;
+    int  *alloc_done;
+    int  thr_crit_bup;
+    volatile VALUE current = rb_thread_current();
+    volatile VALUE ip_obj = obj;
+    volatile VALUE result;
+    volatile VALUE ret;
+
+ 
+    if (!NIL_P(ip_obj) && Tcl_InterpDeleted(get_ip(ip_obj)->ip)) {
+        return Qnil;
+    }
+
+    if (eventloop_thread == 0 || current == eventloop_thread) {
+        if (eventloop_thread) {
+            DUMP2("tk_funcall from current eventloop %lx", current);
+        } else {
+            DUMP2("tk_funcall from thread:%lx but no eventloop", current);
+        }
+        result = (func)(ip_obj, argc, argv);
+        if (rb_obj_is_kind_of(result, rb_eException)) {
+            rb_exc_raise(result);
+        }
+        return result;
+    }
+
+    DUMP2("tk_funcall from thread %lx (NOT current eventloop)", current);
+
+    thr_crit_bup = rb_thread_critical;
+    rb_thread_critical = Qtrue;
+
+    /* allocate memory (keep result) */
+    alloc_done = (int*)ALLOC(int);
+    *alloc_done = 0;
+
+    /* allocate memory (freed by Tcl_ServiceEvent) */
+    callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue));
+    Tcl_Preserve(callq);
+
+    /* allocate result obj */
+    result = rb_ary_new2(1);
+    RARRAY(result)->ptr[0] = Qnil;
+    RARRAY(result)->len = 1;
+
+    /* construct event data */
+    callq->done = alloc_done;
+    callq->func = func;
+    callq->argc = argc;
+    callq->argv = argv;
+    callq->interp = ip_obj;
+    callq->result = result;
+    callq->thread = current;
+    callq->safe_level = rb_safe_level();
+    callq->ev.proc = call_queue_handler;
+
+    /* add the handler to Tcl event queue */
+    DUMP1("add handler");
+    Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD);
+
+    rb_thread_critical = thr_crit_bup;
+
+    /* wait for the handler to be processed */
+    DUMP2("wait for handler (current thread:%lx)", current);
+    while(*alloc_done >= 0) {
+        rb_thread_stop();
+    }
+    DUMP2("back from handler (current thread:%lx)", current);
+
+    /* get result & free allocated memory */
+    ret = RARRAY(result)->ptr[0];
+    free(alloc_done);
+
+    Tcl_Release(callq);
+
+    /* exception? */
+    if (rb_obj_is_kind_of(ret, rb_eException)) {
+        DUMP1("raise exception");
+        rb_exc_raise(ret);
+    }
+
+    DUMP1("exit tk_funcall");
+    return ret;
+}
+
+
 /* eval string in tcl by Tcl_Eval() */
 static VALUE
 ip_eval_real(self, cmd_str, cmd_len)
@@ -4098,7 +4821,12 @@
       Tcl_IncrRefCount(cmd);
 
       /* ip is deleted? */
-      if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+      if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+          || Tcl_InterpDeleted(ptr->ip)
+#if TCL_NAMESPACE_DEBUG
+          || rbtk_invalid_namespace(ptr)
+#endif
+          ) {
           DUMP1("ip is deleted");
           Tcl_DecrRefCount(cmd);
           rb_thread_critical = thr_crit_bup;
@@ -4118,8 +4846,15 @@
 
     if (ptr->return_value == TCL_ERROR) {
         volatile VALUE exc;
-        exc = create_ip_exc(self, rb_eRuntimeError, 
-                            "%s", Tcl_GetStringResult(ptr->ip));
+
+        if (rbtk_pending_exception != 0) {
+            exc = rbtk_pending_exception;
+            rbtk_pending_exception = 0;
+        } else {
+            exc = create_ip_exc(self, rb_eRuntimeError, 
+                                "%s", Tcl_GetStringResult(ptr->ip));
+        }
+
         /* Tcl_Release(ptr->ip); */
         rbtk_release_ip(ptr);
 
@@ -4139,7 +4874,12 @@
     DUMP2("Tcl_Eval(%s)", cmd_str);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)
+#if TCL_NAMESPACE_DEBUG
+        || rbtk_invalid_namespace(ptr)
+#endif
+        ) {
         DUMP1("ip is deleted");
         ptr->return_value = TCL_OK;
         return rb_tainted_str_new2("");
@@ -4152,7 +4892,14 @@
 
     if (ptr->return_value == TCL_ERROR) {
         volatile VALUE exc;
-        exc = create_ip_exc(self, rb_eRuntimeError, "%s", ptr->ip->result);
+
+        if (rbtk_pending_exception != 0) {
+            exc = rbtk_pending_exception;
+            rbtk_pending_exception = 0;
+        } else {
+            exc = create_ip_exc(self, rb_eRuntimeError, "%s", ptr->ip->result);
+        }
+
         /* Tcl_Release(ptr->ip); */
         rbtk_release_ip(ptr);
         rb_exc_raise(exc);
@@ -4334,19 +5081,26 @@
 
 /* restart Tk */
 static VALUE
-lib_restart(self)
-    VALUE self;
+lib_restart_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;   /* dummy */
+    VALUE *argv;  /* dummy */
 {
     volatile VALUE exc;
-    struct tcltkip *ptr = get_ip(self);
+    struct tcltkip *ptr = get_ip(interp);
     int  thr_crit_bup;
 
-    rb_secure(4);
+    /* rb_secure(4); */ /* already checked */
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)
+#if TCL_NAMESPACE_DEBUG
+        || rbtk_invalid_namespace(ptr)
+#endif
+        ) {
         DUMP1("ip is deleted");
-        rb_raise(rb_eRuntimeError, "interpreter is deleted");
+        return rb_exc_new2(rb_eRuntimeError, "interpreter is deleted");
     }
 
     thr_crit_bup = rb_thread_critical;
@@ -4361,11 +5115,13 @@
     DUMP2("(TCL_Eval result) %d", ptr->return_value);
     Tcl_ResetResult(ptr->ip);
 
+#if TCL_MAJOR_VERSION >= 8
     /* delete namespace ( tested on tk8.4.5 ) */
     ptr->return_value = Tcl_Eval(ptr->ip, "namespace delete ::tk::msgcat");
     /* ignore ERROR */
     DUMP2("(TCL_Eval result) %d", ptr->return_value);
     Tcl_ResetResult(ptr->ip);
+#endif
 
     /* delete trace proc ( tested on tk8.4.5 ) */
     ptr->return_value = Tcl_Eval(ptr->ip, "trace vdelete ::tk_strictMotif w ::tk::EventMotifBindings");
@@ -4382,7 +5138,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
     } else {
         DUMP1("Tk_Init");
@@ -4391,7 +5147,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
     }
 #else /* TCL_MAJOR_VERSION < 8 */
@@ -4400,7 +5156,7 @@
         exc = rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
         /* Tcl_Release(ptr->ip); */
         rbtk_release_ip(ptr);
-        rb_exc_raise(exc);
+        return exc;
     }
 #endif
 
@@ -4412,6 +5168,30 @@
     return Qnil;
 }
 
+static VALUE
+lib_restart(self)
+    VALUE self;
+{
+    volatile VALUE exc;
+    struct tcltkip *ptr = get_ip(self);
+    int  thr_crit_bup;
+
+    rb_secure(4);
+
+    /* ip is deleted? */
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)
+#if TCL_NAMESPACE_DEBUG
+        || rbtk_invalid_namespace(ptr)
+#endif
+        ) {
+        DUMP1("ip is deleted");
+        rb_raise(rb_eRuntimeError, "interpreter is deleted");
+    }
+
+    return tk_funcall(lib_restart_core, 0, (VALUE*)NULL, self);
+}
+
 
 static VALUE
 ip_restart(self)
@@ -4422,7 +5202,8 @@
     rb_secure(4);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         rb_raise(rb_eRuntimeError, "interpreter is deleted");
     }
@@ -4454,12 +5235,15 @@
     if (NIL_P(ip_obj)) {
         interp = (Tcl_Interp *)NULL;
     } else {
-        interp = get_ip(ip_obj)->ip;
+        ptr = get_ip(ip_obj);
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(interp)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip)) {
             DUMP1("ip is deleted");
             interp = (Tcl_Interp *)NULL;
+        } else {
+            interp = ptr->ip;
         }
     }
 
@@ -4597,6 +5381,8 @@
 
     if (NIL_P(ip_obj)) {
         interp = (Tcl_Interp *)NULL;
+    } else if (get_ip(ip_obj) == (struct tcltkip *)NULL) {
+        interp = (Tcl_Interp *)NULL;
     } else {
         interp = get_ip(ip_obj)->ip;
     }
@@ -4833,7 +5619,12 @@
     ptr = get_ip(interp);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+        || rbtk_invalid_namespace(ptr)
+#endif
+        ) {
         DUMP1("ip is deleted");
         return rb_tainted_str_new2("");
     }
@@ -4908,6 +5699,15 @@
     /* exception on mainloop */
     if (ptr->return_value == TCL_ERROR) {
         if (event_loop_abort_on_exc > 0 && !Tcl_InterpDeleted(ptr->ip)) {
+
+            if (rbtk_pending_exception != 0) {
+                volatile VALUE exc;
+                DUMP1("find a pending exception");
+                exc = rbtk_pending_exception;
+                rbtk_pending_exception = 0;
+                return exc;
+            }
+
 #if TCL_MAJOR_VERSION >= 8
             return create_ip_exc(interp, rb_eRuntimeError, 
                                  "%s", Tcl_GetStringResult(ptr->ip));
@@ -5062,7 +5862,7 @@
     ptr = get_ip(interp);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return rb_tainted_str_new2("");
     }
@@ -5258,7 +6058,8 @@
     ptr = get_ip(self);
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip)) {
         DUMP1("ip is deleted");
         return rb_tainted_str_new2("");
     }
@@ -5284,21 +6085,22 @@
     return ip_invoke_with_position(argc, argv, obj, TCL_QUEUE_HEAD);
 }
 
+
 /* access Tcl variables */
 static VALUE
-ip_get_variable(self, varname_arg, flag_arg)
-    VALUE self;
-    VALUE varname_arg;
-    VALUE flag_arg;
+ip_get_variable_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;
+    VALUE *argv;
 {
-    struct tcltkip *ptr = get_ip(self);
+    struct tcltkip *ptr = get_ip(interp);
     int thr_crit_bup;
     volatile VALUE varname, flag;
 
-    varname = varname_arg;
-    flag    = flag_arg;
+    varname = argv[0];
+    flag    = argv[1];
 
-    StringValue(varname);
+    /* StringValue(varname); */
 
 #if TCL_MAJOR_VERSION >= 8
     {
@@ -5315,7 +6117,12 @@
         Tcl_IncrRefCount(nameobj);
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             Tcl_DecrRefCount(nameobj);
             rb_thread_critical = thr_crit_bup;
@@ -5339,7 +6146,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
 
         Tcl_IncrRefCount(ret);
@@ -5379,7 +6186,12 @@
         char *ret;
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             return rb_tainted_str_new2("");
         } else {
@@ -5399,7 +6211,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
 
         strval = rb_tainted_str_new2(ret);
@@ -5413,26 +6225,44 @@
 }
 
 static VALUE
-ip_get_variable2(self, varname_arg, index_arg, flag_arg)
+ip_get_variable(self, varname, flag)
     VALUE self;
-    VALUE varname_arg;
-    VALUE index_arg;
-    VALUE flag_arg;
+    VALUE varname;
+    VALUE flag;
 {
-    struct tcltkip *ptr = get_ip(self);
+    VALUE *argv;
+    VALUE retval;
+
+    argv = ALLOC_N(VALUE, 2);
+    StringValue(varname);
+    argv[0] = varname;
+    argv[1] = flag;
+
+    retval = tk_funcall(ip_get_variable_core, 2, argv, self);
+
+    free(argv);
+
+    return retval;
+}
+
+static VALUE
+ip_get_variable2_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;
+    VALUE *argv;
+{
+    struct tcltkip *ptr = get_ip(interp);
     int thr_crit_bup;
     volatile VALUE varname, index, flag;
 
-    if (NIL_P(index_arg)) {
-      return ip_get_variable(self, varname_arg, flag_arg);
-    }
-
-    varname = varname_arg;
-    index   = index_arg;
-    flag    = flag_arg;
+    varname = argv[0];
+    index   = argv[1];
+    flag    = argv[2];
 
+    /* 
     StringValue(varname);
     StringValue(index);
+    */
 
 #if TCL_MAJOR_VERSION >= 8
     {
@@ -5451,7 +6281,12 @@
         Tcl_IncrRefCount(idxobj);
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             Tcl_DecrRefCount(nameobj);
             Tcl_DecrRefCount(idxobj);
@@ -5476,7 +6311,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
 
         Tcl_IncrRefCount(ret);
@@ -5516,7 +6351,12 @@
         char *ret;
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             return rb_tainted_str_new2("");
         } else {
@@ -5536,7 +6376,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
 
         strval = rb_tainted_str_new2(ret);
@@ -5550,22 +6390,52 @@
 }
 
 static VALUE
-ip_set_variable(self, varname_arg, value_arg, flag_arg)
+ip_get_variable2(self, varname, index, flag)
     VALUE self;
-    VALUE varname_arg;
-    VALUE value_arg;
-    VALUE flag_arg;
+    VALUE varname;
+    VALUE index;
+    VALUE flag;
 {
-    struct tcltkip *ptr = get_ip(self);
+    VALUE *argv;
+    VALUE retval;
+
+    argv = ALLOC_N(VALUE, 3);
+    StringValue(varname);
+    argv[0] = varname;
+
+    if (NIL_P(index)) {
+        argv[1] = flag;
+        retval = tk_funcall(ip_get_variable_core, 2, argv, self);
+    } else {
+        StringValue(index);
+        argv[1] = index;
+        argv[2] = flag;
+        retval = tk_funcall(ip_get_variable2_core, 3, argv, self);
+    }
+
+    free(argv);
+
+    return retval;
+}
+
+static VALUE
+ip_set_variable_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;
+    VALUE *argv;
+{
+    struct tcltkip *ptr = get_ip(interp);
     int thr_crit_bup;
     volatile VALUE varname, value, flag;
 
-    varname = varname_arg;
-    value   = value_arg;
-    flag    = flag_arg;
+    varname = argv[0];
+    value   = argv[1];
+    flag    = argv[2];
 
+    /*
     StringValue(varname);
     StringValue(value);
+    */
 
 #if TCL_MAJOR_VERSION >= 8
     {
@@ -5613,7 +6483,12 @@
 # endif
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             Tcl_DecrRefCount(nameobj);
             Tcl_DecrRefCount(valobj);
@@ -5639,7 +6514,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
 
         Tcl_IncrRefCount(ret);
@@ -5680,7 +6555,12 @@
         CONST char *ret;
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             return rb_tainted_str_new2("");
         } else {
@@ -5691,7 +6571,7 @@
         }
 
         if (ret == NULL) {
-            rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
+            return rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
         }
 
         strval = rb_tainted_str_new2(ret);
@@ -5705,29 +6585,50 @@
 }
 
 static VALUE
-ip_set_variable2(self, varname_arg, index_arg, value_arg, flag_arg)
+ip_set_variable(self, varname, value, flag)
     VALUE self;
-    VALUE varname_arg;
-    VALUE index_arg;
-    VALUE value_arg;
-    VALUE flag_arg;
+    VALUE varname;
+    VALUE value;
+    VALUE flag;
 {
-    struct tcltkip *ptr = get_ip(self);
+    VALUE *argv;
+    VALUE retval;
+
+    StringValue(varname);
+    StringValue(value);
+
+    argv = ALLOC_N(VALUE, 3);
+    argv[0] = varname;
+    argv[1] = value;
+    argv[2] = flag;
+
+    retval = tk_funcall(ip_set_variable_core, 3, argv, self);
+
+    free(argv);
+
+    return retval;
+}
+
+static VALUE
+ip_set_variable2_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;
+    VALUE *argv;
+{
+    struct tcltkip *ptr = get_ip(interp);
     int thr_crit_bup;
     volatile VALUE varname, index, value, flag;
 
-    if (NIL_P(index_arg)) {
-      return ip_set_variable(self, varname_arg, value_arg, flag_arg);
-    }
-
-    varname = varname_arg;
-    index   = index_arg;
-    value   = value_arg;
-    flag    = flag_arg;
+    varname = argv[0];
+    index   = argv[1];
+    value   = argv[2];
+    flag    = argv[3];
 
+    /*
     StringValue(varname);
     StringValue(index);
     StringValue(value);
+    */
 
 #if TCL_MAJOR_VERSION >= 8
     {
@@ -5777,7 +6678,12 @@
         Tcl_IncrRefCount(valobj);
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             Tcl_DecrRefCount(nameobj);
             Tcl_DecrRefCount(idxobj);
@@ -5805,7 +6711,7 @@
             /* Tcl_Release(ptr->ip); */
             rbtk_release_ip(ptr);
             rb_thread_critical = thr_crit_bup;
-            rb_exc_raise(exc);
+            return exc;
         }
 
         Tcl_IncrRefCount(ret);
@@ -5838,7 +6744,12 @@
         CONST char *ret;
 
         /* ip is deleted? */
-        if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+        if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+            || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+            || rbtk_invalid_namespace(ptr)
+#endif
+            ) {
             DUMP1("ip is deleted");
             return rb_tainted_str_new2("");
         } else {
@@ -5850,7 +6761,7 @@
         }
 
         if (ret == (char*)NULL) {
-            rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
+            return rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
         }
 
         Tcl_IncrRefCount(ret);
@@ -5868,21 +6779,62 @@
 }
 
 static VALUE
-ip_unset_variable(self, varname_arg, flag_arg)
+ip_set_variable2(self, varname, index, value, flag)
     VALUE self;
-    VALUE varname_arg;
-    VALUE flag_arg;
+    VALUE varname;
+    VALUE index;
+    VALUE value;
+    VALUE flag;
 {
-    struct tcltkip *ptr = get_ip(self);
-    volatile VALUE varname, value, flag;
+    VALUE *argv;
+    VALUE retval;
 
-    varname = varname_arg;
-    flag    = flag_arg;
+    argv = ALLOC_N(VALUE, 4);
+    StringValue(varname);
+    argv[0] = varname;
 
+    if (NIL_P(index)) {
+        StringValue(value);
+        argv[1] = value;
+        argv[2] = flag;
+        retval = tk_funcall(ip_set_variable_core, 3, argv, self);
+    } else {
+        StringValue(index);
+        StringValue(value);
+        argv[1] = index;
+        argv[2] = value;
+        argv[3] = flag;
+        retval = tk_funcall(ip_set_variable2_core, 4, argv, self);
+    }
+
+    free(argv);
+
+    return retval;
+}
+
+static VALUE
+ip_unset_variable_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;
+    VALUE *argv;
+{
+    struct tcltkip *ptr = get_ip(interp);
+    volatile VALUE varname, flag;
+
+    varname = argv[0];
+    flag    = argv[1];
+
+    /*
     StringValue(varname);
+    */
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+        || rbtk_invalid_namespace(ptr)
+#endif
+        ) {
         DUMP1("ip is deleted");
         return Qtrue;
     }
@@ -5892,9 +6844,9 @@
     if (ptr->return_value == TCL_ERROR) {
         if (FIX2INT(flag) & TCL_LEAVE_ERR_MSG) {
 #if TCL_MAJOR_VERSION >= 8
-            rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(ptr->ip));
+            return rb_exc_new2(rb_eRuntimeError, Tcl_GetStringResult(ptr->ip));
 #else /* TCL_MAJOR_VERSION < 8 */
-            rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
+            return rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
 #endif
         }
         return Qfalse;
@@ -5903,28 +6855,51 @@
 }
 
 static VALUE
-ip_unset_variable2(self, varname_arg, index_arg, flag_arg)
+ip_unset_variable(self, varname, flag)
     VALUE self;
-    VALUE varname_arg;
-    VALUE index_arg;
-    VALUE flag_arg;
+    VALUE varname;
+    VALUE flag;
 {
-    struct tcltkip *ptr = get_ip(self);
-    volatile VALUE varname, index, value, flag;
+    VALUE *argv;
+    VALUE retval;
 
-    if (NIL_P(index_arg)) {
-      return ip_unset_variable(self, varname_arg, flag_arg);
-    }
+    argv = ALLOC_N(VALUE, 2);
+    StringValue(varname);
+    argv[0] = varname;
+    argv[1] = flag;
+
+    retval = tk_funcall(ip_unset_variable_core, 2, argv, self);
 
-    varname = varname_arg;
-    index   = index_arg;
-    flag    = flag_arg;
+    free(argv);
+
+    return retval;
+}
 
+static VALUE
+ip_unset_variable2_core(interp, argc, argv)
+    VALUE interp;
+    int   argc;
+    VALUE *argv;
+{
+    struct tcltkip *ptr = get_ip(interp);
+    volatile VALUE varname, index, flag;
+
+    varname = argv[0];
+    index   = argv[1];
+    flag    = argv[2];
+
+    /* 
     StringValue(varname);
     StringValue(index);
+    */
 
     /* ip is deleted? */
-    if (Tcl_InterpDeleted(ptr->ip) || rbtk_invalid_namespace(ptr)) {
+    if (ptr == (struct tcltkip *)NULL || ptr->ip == (Tcl_Interp*)NULL 
+        || Tcl_InterpDeleted(ptr->ip) 
+#if TCL_NAMESPACE_DEBUG
+        || rbtk_invalid_namespace(ptr)
+#endif
+        ) {
         DUMP1("ip is deleted");
         return Qtrue;
     }
@@ -5934,9 +6909,9 @@
     if (ptr->return_value == TCL_ERROR) {
         if (FIX2INT(flag) & TCL_LEAVE_ERR_MSG) {
 #if TCL_MAJOR_VERSION >= 8
-            rb_raise(rb_eRuntimeError, "%s", Tcl_GetStringResult(ptr->ip));
+            return rb_exc_new2(rb_eRuntimeError, Tcl_GetStringResult(ptr->ip));
 #else /* TCL_MAJOR_VERSION < 8 */
-            rb_raise(rb_eRuntimeError, "%s", ptr->ip->result);
+            return rb_exc_new2(rb_eRuntimeError, ptr->ip->result);
 #endif
         }
         return Qfalse;
@@ -5945,6 +6920,35 @@
 }
 
 static VALUE
+ip_unset_variable2(self, varname, index, flag)
+    VALUE self;
+    VALUE varname;
+    VALUE index;
+    VALUE flag;
+{
+    VALUE *argv;
+    VALUE retval;
+
+    argv = ALLOC_N(VALUE, 3);
+    StringValue(varname);
+    argv[0] = varname;
+
+    if (NIL_P(index)) {
+        argv[1] = flag;
+        retval = tk_funcall(ip_unset_variable_core, 2, argv, self);
+    } else {
+        StringValue(index);
+        argv[1] = index;
+        argv[2] = flag;
+        retval = tk_funcall(ip_unset_variable2_core, 3, argv, self);
+    }
+
+    free(argv);
+
+    return retval;
+}
+
+static VALUE
 ip_get_global_var(self, varname)
     VALUE self;
     VALUE varname;
@@ -6019,6 +7023,8 @@
 
     if (NIL_P(ip_obj)) {
         interp = (Tcl_Interp *)NULL;
+    } else if (get_ip(ip_obj) == (struct tcltkip *)NULL) {
+        interp = (Tcl_Interp *)NULL;
     } else {
         interp = get_ip(ip_obj)->ip;
     }
@@ -6403,6 +7409,8 @@
     rb_global_variable(&eventloop_thread);
     rb_global_variable(&watchdog_thread);
 
+    rb_global_variable(&rbtk_pending_exception);
+
    /* --------------------------------------------------------------- */
 
     rb_define_const(lib, "COMPILE_INFO", tcltklib_compile_info());
@@ -6569,6 +7577,8 @@
 
     eventloop_thread = 0;
     watchdog_thread  = 0;
+
+    rbtk_pending_exception = 0;
 
     /* --------------------------------------------------------------- */
 
Index: lib/multi-tk.rb
===================================================================
RCS file: /var/cvs/src/ruby/ext/tk/lib/multi-tk.rb,v
retrieving revision 1.38
diff -u -r1.38 multi-tk.rb
--- lib/multi-tk.rb	31 Jan 2005 04:14:50 -0000	1.38
+++ lib/multi-tk.rb	9 Feb 2005 08:53:11 -0000
@@ -411,7 +411,8 @@
   def _receiver_mainloop(check_root)
     Thread.new{
       while !@interp.deleted?
-        break if @interp._invoke_without_enc('info', 'command', '.').size == 0
+        inf = @interp._invoke_without_enc('info', 'command', '.')
+        break if !inf.kind_of?(String) || inf != '.'
         sleep 0.5
       end
     }
@@ -970,9 +971,11 @@
   ######################################
 
   def _default_delete_hook(slave)
-    if @slave_ip_top[slave].kind_of?(String)
+    @slave_ip_tbl.delete(slave)
+    top = @slave_ip_top.delete(slave)
+    if top.kind_of?(String)
       # call default hook of safetk.tcl (ignore exceptions)
-      if @slave_ip_top[slave] == ''
+      if top == ''
         begin
           @interp._eval("::safe::disallowTk #{slave}")
         rescue
@@ -980,20 +983,19 @@
         end
       else # toplevel path
         begin
-          @interp._eval("::safe::tkDelete {} #{@slave_ip_top[slave]} #{slave}")
+          @interp._eval("::safe::tkDelete {} #{top} #{slave}")
         rescue
           warn("Waring: fail to call '::safe::tkDelete'") if $DEBUG
           begin
-            @interp._eval("destroy #{@slave_ip_top[slave]}")
+            @interp._eval("destroy #{top}")
           rescue
             warn("Waring: fail to destroy toplevel") if $DEBUG
           end
         end
       end
     end
-    @slave_ip_tbl.delete(slave)
-    @slave_ip_top.delete(slave)
   end
+
 end
 
 
@@ -1739,7 +1741,7 @@
 
 # depend on TclTkIp
 class MultiTkIp
-  def mainloop(check_root = true, restart_on_dead = false)
+  def mainloop(check_root = true, restart_on_dead = true)
     #return self if self.slave?
     #return self if self != @@DEFAULT_MASTER
     if self != @@DEFAULT_MASTER
@@ -1752,7 +1754,11 @@
         rescue MultiTkIp_OK => ret
           # return value
           @wait_on_mainloop[1] = false
-          return ret.value.value
+          if ret.value.kind_of?(Thread)
+            return ret.value.value
+          else
+            return ret.value
+          end
         rescue SystemExit
           # exit IP
           warn("Warning: " + $! + " on " + self.inspect) if $DEBUG
@@ -1762,7 +1768,7 @@
           rescue Exception
           end
           self.delete
-        rescue Exception => e
+        rescue StandardError => e
           if $DEBUG
             warn("Warning: " + e.class.inspect + 
                  ((e.message.length > 0)? ' "' + e.message + '"': '') +  
@@ -1779,31 +1785,47 @@
 
     unless restart_on_dead
       @wait_on_mainloop[1] = true
+=begin
+      begin
+        @interp.mainloop(check_root)
+      rescue StandardError => e
+        if $DEBUG
+          warn("Warning: " + e.class.inspect + 
+               ((e.message.length > 0)? ' "' + e.message + '"': '') +  
+               " on " + self.inspect) 
+        end
+      end
+=end
       @interp.mainloop(check_root)
       @wait_on_mainloop[1] = false
     else
-      begin
+      loop do
         @wait_on_mainloop[1] = true
-        loop do
-          break unless self.alive?
-          if check_root
-            begin
-              break if TclTkLib.num_of_mainwindows == 0
-            rescue Exception
-              break
-            end
+        break unless self.alive?
+        if check_root
+          begin
+            break if TclTkLib.num_of_mainwindows == 0
+          rescue StandardError
+            break
           end
-          @interp.mainloop(check_root)
         end
-      #rescue StandardError
-      rescue Exception
-        if TclTkLib.mainloop_abort_on_exception != nil
-          STDERR.print("Warning: Tk mainloop receives ", $!.class.inspect, 
-                       " exception (ignore) : ", $!.message, "\n");
+        break if @interp.deleted?
+        begin
+          @interp.mainloop(check_root)
+        rescue StandardError
+          if TclTkLib.mainloop_abort_on_exception != nil
+            #STDERR.print("Warning: Tk mainloop receives ", $!.class.inspect, 
+            #             " exception (ignore) : ", $!.message, "\n");
+            if $DEBUG
+              warn("Warning: Tk mainloop receives ", $!.class.inspect, 
+                   " exception (ignore) : ", $!.message, "\n");
+            end
+          end
+        rescue Exception=>e
+        ensure
+          @wait_on_mainloop[1] = false
+          Thread.pass
         end
-        retry
-      ensure
-        @wait_on_mainloop[1] = false
       end
     end
     self
@@ -1875,18 +1897,17 @@
       @interp._eval_without_enc("foreach i {#{after_ids}} {after cancel $i}")
     rescue Exception
     end
-=begin
+
     begin
       @interp._invoke('destroy', '.') unless @interp.deleted?
     rescue Exception
     end
-=end
+
     if @safe_base && !@interp.deleted?
       # do 'exit' to call the delete_hook procedure
       @interp._eval_without_enc('exit')
-    else
-      @interp.delete unless @interp.deleted?
     end
+    @interp.delete
     self
   end
 
Index: lib/tk.rb
===================================================================
RCS file: /var/cvs/src/ruby/ext/tk/lib/tk.rb,v
retrieving revision 1.141
diff -u -r1.141 tk.rb
--- lib/tk.rb	31 Jan 2005 04:14:50 -0000	1.141
+++ lib/tk.rb	9 Feb 2005 08:53:13 -0000
@@ -3940,7 +3940,7 @@
 #Tk.freeze
 
 module Tk
-  RELEASE_DATE = '2005-01-28'.freeze
+  RELEASE_DATE = '2005-02-09'.freeze
 
   autoload :AUTO_PATH,        'tk/variable'
   autoload :TCL_PACKAGE_PATH, 'tk/variable'
Index: lib/tk/clock.rb
===================================================================
RCS file: /var/cvs/src/ruby/ext/tk/lib/tk/clock.rb,v
retrieving revision 1.3
diff -u -r1.3 clock.rb
--- lib/tk/clock.rb	20 Dec 2004 05:10:59 -0000	1.3
+++ lib/tk/clock.rb	9 Feb 2005 08:53:13 -0000
@@ -10,8 +10,9 @@
     end
 
     def self.clicks(ms=nil)
+      ms = ms.to_s if ms.kind_of?(Symbol)
       case ms
-      when nil
+      when nil, ''
         tk_call_without_enc('clock','clicks').to_i
       when /^mic/
         tk_call_without_enc('clock','clicks','-microseconds').to_i
Index: lib/tk/timer.rb
===================================================================
RCS file: /var/cvs/src/ruby/ext/tk/lib/tk/timer.rb,v
retrieving revision 1.10
diff -u -r1.10 timer.rb
--- lib/tk/timer.rb	16 Dec 2004 07:13:12 -0000	1.10
+++ lib/tk/timer.rb	9 Feb 2005 08:53:13 -0000
@@ -420,6 +420,7 @@
     @wait_var.value = 0
     tk_call 'after', 'cancel', @after_id if @after_id
     @after_id = nil
+
     Tk_CBTBL.delete(@id) ;# for GC
     self
   end
Index: lib/tk/variable.rb
===================================================================
RCS file: /var/cvs/src/ruby/ext/tk/lib/tk/variable.rb,v
retrieving revision 1.10
diff -u -r1.10 variable.rb
--- lib/tk/variable.rb	4 Nov 2004 06:03:53 -0000	1.10
+++ lib/tk/variable.rb	9 Feb 2005 08:53:13 -0000
@@ -306,6 +306,7 @@
       }
       self.value
     elsif val.kind_of?(Array)
+=begin
       INTERP._set_global_var(@id, '')
       val.each{|v|
         #INTERP._set_variable(@id, _toUTF8(_get_eval_string(v)), 
@@ -316,6 +317,8 @@
                              TclTkLib::VarAccessFlag::LIST_ELEMENT)
       }
       self.value
+=end
+      _fromUTF8(INTERP._set_global_var(@id, array2tk_list(val)))
     else
       #_fromUTF8(INTERP._set_global_var(@id, _toUTF8(_get_eval_string(val))))
       _fromUTF8(INTERP._set_global_var(@id, _get_eval_string(val, true)))
@@ -554,6 +557,29 @@
       raise ArgumentError, "Array is expected"
     end
     val
+  end
+
+  def lappend(*elems)
+    tk_call('lappend', @id, *elems)
+    self
+  end
+
+  def lindex(idx)
+    tk_call('lindex', self.value, idx)
+  end
+  alias lget lindex
+
+  def lget_i(idx)
+    number(lget(idx)).to_i
+  end
+
+  def lget_f(idx)
+    number(lget(idx)).to_f
+  end
+
+  def lset(idx, val)
+    tk_call('lset', @id, idx, val)
+    self
   end
 
   def inspect

-- 
                                       永井 秀利 (九工大 知能情報)
                                           nagai@ai.kyutech.ac.jp

In This Thread