summaryrefslogtreecommitdiff
path: root/ext/tk/tcltklib.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/tk/tcltklib.c')
-rw-r--r--ext/tk/tcltklib.c507
1 files changed, 341 insertions, 166 deletions
diff --git a/ext/tk/tcltklib.c b/ext/tk/tcltklib.c
index 680b8da984..8701cfef27 100644
--- a/ext/tk/tcltklib.c
+++ b/ext/tk/tcltklib.c
@@ -4,7 +4,7 @@
* Oct. 24, 1997 Y. Matsumoto
*/
-#define TCLTKLIB_RELEASE_DATE "2008-05-16"
+#define TCLTKLIB_RELEASE_DATE "2008-05-23"
#include "ruby.h"
@@ -171,7 +171,7 @@ static ID ID_inspect;
static VALUE ip_invoke_real _((int, VALUE*, VALUE));
static VALUE ip_invoke _((int, VALUE*, VALUE));
-
+static VALUE ip_invoke_with_position _((int, VALUE*, VALUE, Tcl_QueuePosition));
static VALUE tk_funcall _((VALUE(), int, VALUE*, VALUE));
/* Tcl's object type */
@@ -397,19 +397,24 @@ static VALUE eventloop_thread;
Tcl_ThreadId tk_eventloop_thread_id; /* native thread ID of Tcl interpreter */
#endif
static VALUE eventloop_stack;
-static int window_event_mode = ~(TCL_WINDOW_EVENTS | TCL_IDLE_EVENTS);
+static int window_event_mode = ( ~ TCL_IDLE_EVENTS | TCL_WINDOW_EVENTS );
static VALUE watchdog_thread;
Tcl_Interp *current_interp;
/* thread control strategy */
-#define CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE 0
+/* multi-tk works with the following settings only ???
+ : CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
+ : USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
+ : DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0
+*/
+#define CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE 1
#define USE_TOGGLE_WINDOW_MODE_FOR_IDLE 0
-#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 1
+#define DO_THREAD_SCHEDULE_AT_CALLBACK_DONE 0
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
-static int have_rb_thread_waited_for_value = 0;
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+static int have_rb_thread_waiting_for_value = 0;
#endif
/*
@@ -426,9 +431,6 @@ static int have_rb_thread_waited_for_value = 0;
#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
-#define DEFAULT_HAS_WAIT_THREAD_TICK 50/*counts*/
-#endif
#else /* ! RUBY_VM */
#define DEFAULT_EVENT_LOOP_MAX 800/*counts*/
#define DEFAULT_NO_EVENT_TICK 10/*counts*/
@@ -436,9 +438,6 @@ static int have_rb_thread_waited_for_value = 0;
#define WATCHDOG_INTERVAL 10/*milliseconds ( 1 -- 999 ) */
#define DEFAULT_TIMER_TICK 0/*milliseconds ( 0 -- 999 ) */
#define NO_THREAD_INTERRUPT_TIME 100/*milliseconds ( 1 -- 999 ) */
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
-#define DEFAULT_HAS_WAIT_THREAD_TICK 50/*counts*/
-#endif
#endif
static int event_loop_max = DEFAULT_EVENT_LOOP_MAX;
@@ -447,9 +446,6 @@ static int no_event_wait = DEFAULT_NO_EVENT_WAIT;
static int timer_tick = DEFAULT_TIMER_TICK;
static int req_timer_tick = DEFAULT_TIMER_TICK;
static int run_timer_flag = 0;
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
-static int has_wait_thread_tick = DEFAULT_HAS_WAIT_THREAD_TICK;
-#endif
static int event_loop_wait_event = 0;
static int event_loop_abort_on_exc = 1;
@@ -967,8 +963,10 @@ call_original_exit(ptr, state)
int thr_crit_bup;
Tcl_CmdInfo *info;
#if TCL_MAJOR_VERSION >= 8
+ Tcl_Obj *cmd_obj;
Tcl_Obj *state_obj;
#endif
+ DUMP1("original_exit is called");
if (!(ptr->has_orig_exit)) return;
@@ -986,36 +984,55 @@ call_original_exit(ptr, state)
if (info->isNativeObjectProc) {
Tcl_Obj **argv;
- /* argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3); */ /* XXXXXXXXXX */
+#define USE_RUBY_ALLOC 0
+#if USE_RUBY_ALLOC
+ argv = (Tcl_Obj **)ALLOC_N(Tcl_Obj *, 3);
+#else /* not USE_RUBY_ALLOC */
argv = (Tcl_Obj **)ckalloc(sizeof(Tcl_Obj *) * 3);
#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
#endif
- argv[0] = Tcl_NewStringObj("exit", 4);
+#endif
+ cmd_obj = Tcl_NewStringObj("exit", 4);
+ Tcl_IncrRefCount(cmd_obj);
+
+ argv[0] = cmd_obj;
argv[1] = state_obj;
argv[2] = (Tcl_Obj *)NULL;
ptr->return_value
= (*(info->objProc))(info->objClientData, ptr->ip, 2, argv);
+ Tcl_DecrRefCount(cmd_obj);
+
+#if USE_RUBY_ALLOC
+ free(argv);
+#else /* not USE_RUBY_ALLOC */
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* free(argv); */
ckfree((char*)argv);
#endif
+#endif
+#endif
+#undef USE_RUBY_ALLOC
} else {
/* string interface */
char **argv;
- /* argv = (char **)ALLOC_N(char *, 3); */ /* XXXXXXXXXX */
+#define USE_RUBY_ALLOC 0
+#if USE_RUBY_ALLOC
+ argv = (char **)ALLOC_N(char *, 3); /* XXXXXXXXXX */
+#else /* not USE_RUBY_ALLOC */
argv = (char **)ckalloc(sizeof(char *) * 3);
#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
#endif
+#endif
argv[0] = "exit";
/* argv[1] = Tcl_GetString(state_obj); */
argv[1] = Tcl_GetStringFromObj(state_obj, (int*)NULL);
@@ -1024,15 +1041,21 @@ call_original_exit(ptr, state)
ptr->return_value = (*(info->proc))(info->clientData, ptr->ip,
2, (CONST84 char **)argv);
+#if USE_RUBY_ALLOC
+ free(argv);
+#else /* not USE_RUBY_ALLOC */
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* free(argv); */
ckfree((char*)argv);
#endif
+#endif
+#endif
+#undef USE_RUBY_ALLOC
}
Tcl_DecrRefCount(state_obj);
@@ -1041,11 +1064,15 @@ call_original_exit(ptr, state)
{
/* string interface */
char **argv;
- /* argv = (char **)ALLOC_N(char *, 3); */
+#define USE_RUBY_ALLOC 0
+#if USE_RUBY_ALLOC
+ argv = (char **)ALLOC_N(char *, 3);
+#else /* not USE_RUBY_ALLOC */
argv = (char **)ckalloc(sizeof(char *) * 3);
#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve((ClientData)argv); /* XXXXXXXX */
#endif
+#endif
argv[0] = "exit";
argv[1] = RSTRING_PTR(rb_fix2str(INT2NUM(state), 10));
argv[2] = (char *)NULL;
@@ -1053,17 +1080,24 @@ call_original_exit(ptr, state)
ptr->return_value = (*(info->proc))(info->clientData, ptr->ip,
2, argv);
+#if USE_RUBY_ALLOC
+ free(argv);
+#else /* not USE_RUBY_ALLOC */
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* free(argv); */
ckfree(argv);
#endif
+#endif
+#endif
+#undef USE_RUBY_ALLOC
}
#endif
+ DUMP1("complete original_exit");
rb_thread_critical = thr_crit_bup;
}
@@ -1110,10 +1144,14 @@ static int
toggle_eventloop_window_mode_for_idle()
{
if (window_event_mode & TCL_IDLE_EVENTS) {
+ /* idle -> event */
+ window_event_mode |= TCL_WINDOW_EVENTS;
window_event_mode &= ~TCL_IDLE_EVENTS;
return 1;
} else {
+ /* event -> idle */
window_event_mode |= TCL_IDLE_EVENTS;
+ window_event_mode &= ~TCL_WINDOW_EVENTS;
return 0;
}
}
@@ -1443,7 +1481,11 @@ static VALUE
lib_num_of_mainwindows(self)
VALUE self;
{
+#ifdef RUBY_VM /* Ruby 1.9+ !!! */
return tk_funcall(lib_num_of_mainwindows_core, 0, (VALUE*)NULL, self);
+#else
+ return lib_num_of_mainwindows_core(self, 0, (VALUE*)NULL);
+#endif
}
@@ -1789,10 +1831,10 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
if (!st) {
if (toggle_eventloop_window_mode_for_idle()) {
/* idle-mode -> event-mode*/
- tick_counter = 0;
+ tick_counter = event_loop_max;
} else {
/* event-mode -> idle-mode */
- tick_counter = event_loop_max;
+ tick_counter = 0;
}
}
#endif
@@ -1802,6 +1844,14 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
st = RTEST(rb_protect(call_DoOneEvent,
INT2FIX(event_flag), &status));
#endif
+
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ if (have_rb_thread_waiting_for_value) {
+ have_rb_thread_waiting_for_value = 0;
+ rb_thread_schedule();
+ }
+#endif
+
if (status) {
switch (status) {
case TAG_RAISE:
@@ -1877,13 +1927,6 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
return 0;
}
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
- if (have_rb_thread_waited_for_value) {
- tick_counter += no_event_tick;
- have_rb_thread_waited_for_value = 0;
- }
-#endif
-
if (st) {
tick_counter++;
} else {
@@ -1950,7 +1993,8 @@ lib_eventloop_core(check_root, update_flag, check_var, interp)
} else {
DUMP2("sleep eventloop %lx", current);
DUMP2("eventloop thread is %lx", eventloop_thread);
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
if (!NIL_P(watchdog_thread) && eventloop_thread != current) {
@@ -2126,7 +2170,8 @@ lib_eventloop_ensure(args)
break;
}
- if (RTEST(rb_funcall(eventloop_thread, ID_alive_p, 0, 0))) {
+ /* if (RTEST(rb_funcall(eventloop_thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(eventloop_thread))) {
DUMP2("eventloop-enshure: wake up parent %lx", eventloop_thread);
rb_thread_wakeup(eventloop_thread);
@@ -2444,7 +2489,8 @@ lib_thread_callback(argc, argv, self)
foundEvent = RTEST(lib_eventloop_launcher(/* not check root-widget */0, 0,
q->done, (Tcl_Interp*)NULL));
- if (RTEST(rb_funcall(th, ID_alive_p, 0))) {
+ /* if (RTEST(rb_funcall(th, ID_alive_p, 0))) { */
+ if (RTEST(rb_thread_alive_p(th))) {
rb_funcall(th, ID_kill, 0);
ret = Qnil;
} else {
@@ -2658,12 +2704,15 @@ tcl_protect_core(interp, proc, data) /* should not raise exception */
int status = 0;
int thr_crit_bup = rb_thread_critical;
+ Tcl_ResetResult(interp);
+
rb_thread_critical = Qfalse;
ret = rb_protect(proc, data, &status);
rb_thread_critical = Qtrue;
if (status) {
char *buf;
- VALUE old_gc, type, str;
+ VALUE old_gc;
+ volatile VALUE type, str;
old_gc = rb_gc_disable();
@@ -3125,10 +3174,6 @@ ip_ruby_cmd(clientData, interp, argc, argv)
#endif
}
- /* allocate */
- arg = ALLOC(struct cmd_body_arg);
- /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */
-
/* get arguments from Tcl objects */
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
@@ -3194,6 +3239,10 @@ ip_ruby_cmd(clientData, interp, argc, argv)
if (old_gc == Qfalse) rb_gc_enable();
rb_thread_critical = thr_crit_bup;
+ /* allocate */
+ arg = ALLOC(struct cmd_body_arg);
+ /* arg = (struct cmd_body_arg *)ckalloc(sizeof(struct cmd_body_arg)); */
+
arg->receiver = receiver;
arg->method = method;
arg->args = args;
@@ -3393,6 +3442,8 @@ ip_rbUpdateCommand(clientData, interp, objc, objv)
#endif
#endif
+ Tcl_ResetResult(interp);
+
if (objc == 1) {
flags = TCL_DONT_WAIT;
@@ -3561,6 +3612,8 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
DUMP1("start Ruby's 'thread_update' body");
+ Tcl_ResetResult(interp);
+
if (objc == 1) {
flags = TCL_DONT_WAIT;
@@ -3620,7 +3673,8 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
while(!param->done) {
DUMP1("wait for complete idle proc");
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
#if 0 /* use Tcl_EventuallyFree */
@@ -3628,10 +3682,11 @@ ip_rb_threadUpdateCommand(clientData, interp, objc, objv)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
DUMP1("finish Ruby's 'thread_update'");
return TCL_OK;
@@ -3743,6 +3798,8 @@ ip_rbVwaitCommand(clientData, interp, objc, objv)
#endif
#endif
+ Tcl_ResetResult(interp);
+
if (objc != 2) {
#ifdef Tcl_WrongNumArgs
Tcl_WrongNumArgs(interp, 1, objv, "name");
@@ -3978,6 +4035,7 @@ ip_rbTkWaitCommand(clientData, interp, objc, objv)
#endif
Tcl_Preserve(interp);
+ Tcl_ResetResult(interp);
if (objc != 3) {
#ifdef Tcl_WrongNumArgs
@@ -4334,7 +4392,7 @@ rb_threadVwaitProc(clientData, interp, name1, name2, flags)
} else {
param->done = 1;
}
- rb_thread_wakeup(param->thread);
+ if (param->done != 0) rb_thread_wakeup(param->thread);
return (char *)NULL;
}
@@ -4356,7 +4414,7 @@ rb_threadWaitVisibilityProc(clientData, eventPtr)
if (eventPtr->type == DestroyNotify) {
param->done = TKWAIT_MODE_DESTROY;
}
- rb_thread_wakeup(param->thread);
+ if (param->done != 0) rb_thread_wakeup(param->thread);
}
static void rb_threadWaitWindowProc _((ClientData, XEvent *));
@@ -4370,7 +4428,7 @@ rb_threadWaitWindowProc(clientData, eventPtr)
if (eventPtr->type == DestroyNotify) {
param->done = TKWAIT_MODE_DESTROY;
}
- rb_thread_wakeup(param->thread);
+ if (param->done != 0) rb_thread_wakeup(param->thread);
}
#if TCL_MAJOR_VERSION >= 8
@@ -4413,6 +4471,7 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
}
Tcl_Preserve(interp);
+ Tcl_ResetResult(interp);
if (objc != 2) {
#ifdef Tcl_WrongNumArgs
@@ -4449,7 +4508,7 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
/* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */
param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param));
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Preserve((ClientData)param);
#endif
param->thread = current_thread;
@@ -4472,12 +4531,13 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[1]);
@@ -4486,9 +4546,9 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
return TCL_ERROR;
}
- /* if (!param->done) { */
while(!param->done) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
thr_crit_bup = rb_thread_critical;
@@ -4503,12 +4563,13 @@ ip_rb_threadVwaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
rb_thread_critical = thr_crit_bup;
@@ -4567,6 +4628,8 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
Tcl_Preserve(interp);
Tcl_Preserve(tkwin);
+ Tcl_ResetResult(interp);
+
if (objc != 3) {
#ifdef Tcl_WrongNumArgs
Tcl_WrongNumArgs(interp, 1, objv, "variable|visibility|window name");
@@ -4651,7 +4714,7 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
/* param = (struct th_vwait_param *)Tcl_Alloc(sizeof(struct th_vwait_param)); */
param = (struct th_vwait_param *)ckalloc(sizeof(struct th_vwait_param));
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Preserve((ClientData)param);
#endif
param->thread = current_thread;
@@ -4680,12 +4743,13 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
@@ -4696,9 +4760,9 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
return TCL_ERROR;
}
- /* if (!param->done) { */
while(!param->done) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
thr_crit_bup = rb_thread_critical;
@@ -4752,12 +4816,13 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
@@ -4774,15 +4839,10 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
rb_thread_critical = thr_crit_bup;
- /* if (!param->done) { */
- /*
- while(!param->done) {
- rb_thread_stop();
- }
- */
while(param->done != TKWAIT_MODE_VISIBILITY) {
if (param->done == TKWAIT_MODE_DESTROY) break;
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
thr_crit_bup = rb_thread_critical;
@@ -4809,12 +4869,13 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(objv[2]);
@@ -4873,12 +4934,13 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release(param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
Tcl_Release(tkwin);
Tcl_Release(interp);
@@ -4892,14 +4954,9 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
rb_thread_critical = thr_crit_bup;
- /* if (!param->done) { */
- /*
- while(!param->done) {
- rb_thread_stop();
- }
- */
while(param->done != TKWAIT_MODE_DESTROY) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
Tcl_Release(window);
@@ -4920,12 +4977,13 @@ ip_rb_threadTkWaitCommand(clientData, interp, objc, objv)
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)param, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 0 /* use Tcl_Preserve/Release */
+#if 1 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)param);
-#endif
+#else
/* Tcl_Free((char *)param); */
ckfree((char *)param);
#endif
+#endif
/*
* Clear out the interpreter's result, since it may have been set
@@ -4950,7 +5008,7 @@ ip_thread_vwait(self, var)
argv[0] = cmd_str;
argv[1] = var;
- return ip_invoke_real(2, argv, self);
+ return ip_invoke_with_position(2, argv, self, TCL_QUEUE_TAIL);
}
static VALUE
@@ -4966,7 +5024,7 @@ ip_thread_tkwait(self, mode, target)
argv[1] = mode;
argv[2] = target;
- return ip_invoke_real(3, argv, self);
+ return ip_invoke_with_position(3, argv, self, TCL_QUEUE_TAIL);
}
@@ -5156,15 +5214,17 @@ ip_finalize(ip)
Tcl_CreateCommand(ip, "ruby_cmd", ip_null_proc,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
#endif
- rb_thread_critical = thr_crit_bup;
- return;
+ /*
+ rb_thread_critical = thr_crit_bup;
+ return;
+ */
}
/* delete root widget */
-#if 0
+#if 1
DUMP1("check `destroy'");
if (Tcl_GetCommandInfo(ip, "destroy", &info)) {
- DUMP1("call `destroy'");
+ DUMP1("call `destroy .'");
Tcl_GlobalEval(ip, "catch {destroy .}");
}
#endif
@@ -5183,10 +5243,14 @@ ip_finalize(ip)
* Although it is the problem, it is possibly avoidable by
* rescuing exceptions and the finalize hook of the interp.
*/
+ Tk_Window win = Tk_MainWindow(ip);
+
DUMP1("call Tk_DestroyWindow");
ruby_debug = Qfalse;
ruby_verbose = Qnil;
- Tk_DestroyWindow(Tk_MainWindow(ip));
+ if (! (((Tk_FakeWin*)win)->flags & TK_ALREADY_DEAD)) {
+ Tk_DestroyWindow(win);
+ }
ruby_debug = rb_debug_bup;
ruby_verbose = rb_verbose_bup;
}
@@ -5209,7 +5273,7 @@ ip_finalize(ip)
DUMP1("cancel after callbacks");
ruby_debug = Qfalse;
ruby_verbose = Qnil;
- Tcl_GlobalEval(ip, "foreach id [after info] {after cancel $id}");
+ Tcl_GlobalEval(ip, "catch {foreach id [after info] {after cancel $id}}");
ruby_debug = rb_debug_bup;
ruby_verbose = rb_verbose_bup;
}
@@ -5251,8 +5315,8 @@ ip_free(ptr)
if (ptr->ip == (Tcl_Interp*)NULL) {
DUMP1("ip_free is called for deleted IP");
- /* free(ptr); */
- ckfree((char*)ptr);
+ free(ptr);
+ /* ckfree((char*)ptr); */
rb_thread_critical = thr_crit_bup;
return;
}
@@ -5405,10 +5469,11 @@ ip_rbNamespaceObjCmd(clientData, interp, objc, objv)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* Tcl_Free((char*)argv); */
ckfree((char*)argv);
#endif
+#endif
}
DUMP2("namespace wrapper exit depth == %d", rbtk_eventloop_depth);
@@ -6282,12 +6347,12 @@ call_queue_handler(evPtr, flags)
struct call_queue *q = (struct call_queue *)evPtr;
volatile VALUE ret;
volatile VALUE q_dat;
+ volatile VALUE thread = q->thread;
struct tcltkip *ptr;
DUMP2("do_call_queue_handler : evPtr = %p", evPtr);
DUMP2("call_queue_handler thread : %lx", rb_thread_current());
- DUMP2("added by thread : %lx", q->thread);
-
+ DUMP2("added by thread : %lx", thread);
if (*(q->done)) {
DUMP1("processed by another event-loop");
@@ -6296,6 +6361,12 @@ call_queue_handler(evPtr, flags)
DUMP1("process it on current event-loop");
}
+ if (RTEST(rb_thread_alive_p(thread))
+ && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) {
+ DUMP1("caller is not yet ready to receive the result -> pending");
+ return 0;
+ }
+
/* process it */
*(q->done) = 1;
@@ -6316,14 +6387,16 @@ call_queue_handler(evPtr, flags)
ret = rb_funcall(rb_proc_new(callq_safelevel_handler, q_dat),
ID_call, 0);
rb_gc_force_recycle(q_dat);
+ q_dat = (VALUE)NULL;
} else {
- DUMP2("call function (for caller thread:%lx)", q->thread);
+ DUMP2("call function (for caller thread:%lx)", thread);
DUMP2("call function (current thread:%lx)", rb_thread_current());
ret = (q->func)(q->interp, q->argc, q->argv);
}
/* set result */
RARRAY_PTR(q->result)[0] = ret;
+ ret = (VALUE)NULL;
/* decr internal handler mark */
rbtk_internal_eventloop_handler--;
@@ -6331,22 +6404,29 @@ call_queue_handler(evPtr, flags)
/* complete */
*(q->done) = -1;
+ /* unlink ruby objects */
+ q->argv = (VALUE*)NULL;
+ q->interp = (VALUE)NULL;
+ q->result = (VALUE)NULL;
+ q->thread = (VALUE)NULL;
+
/* back to caller */
- if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) {
- DUMP2("back to caller (caller thread:%lx)", q->thread);
+ /* if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(thread))) {
+ DUMP2("back to caller (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
- have_rb_thread_waited_for_value = 1;
- rb_thread_wakeup(q->thread);
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ have_rb_thread_waiting_for_value = 1;
+ rb_thread_wakeup(thread);
#else
- rb_thread_run(q->thread);
+ rb_thread_run(thread);
#endif
DUMP1("finish back to caller");
#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE
rb_thread_schedule();
#endif
} else {
- DUMP2("caller is dead (caller thread:%lx)", q->thread);
+ DUMP2("caller is dead (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
}
@@ -6434,7 +6514,7 @@ tk_funcall(func, argc, argv, obj)
/* allocate memory (freed by Tcl_ServiceEvent) */
/* callq = (struct call_queue *)Tcl_Alloc(sizeof(struct call_queue)); */
callq = (struct call_queue *)ckalloc(sizeof(struct call_queue));
-#if 1 /* use Tcl_Preserve/Release */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve(callq);
#endif
@@ -6456,17 +6536,24 @@ tk_funcall(func, argc, argv, obj)
DUMP1("add handler");
#ifdef RUBY_VM
if (ptr && ptr->tk_thread_id) {
- Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(callq->ev), TCL_QUEUE_HEAD);
+ /* Tcl_ThreadQueueEvent(ptr->tk_thread_id,
+ &(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_ThreadQueueEvent(ptr->tk_thread_id,
+ (Tcl_Event*)callq, TCL_QUEUE_HEAD);
Tcl_ThreadAlert(ptr->tk_thread_id);
} else if (tk_eventloop_thread_id) {
+ /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ &(callq->ev), TCL_QUEUE_HEAD); */
Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
- &(callq->ev), TCL_QUEUE_HEAD);
+ (Tcl_Event*)callq, TCL_QUEUE_HEAD);
Tcl_ThreadAlert(tk_eventloop_thread_id);
} else {
- Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD);
+ /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD);
}
#else
- Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD);
+ /* Tcl_QueueEvent(&(callq->ev), TCL_QUEUE_HEAD); */
+ Tcl_QueueEvent((Tcl_Event*)callq, TCL_QUEUE_HEAD);
#endif
rb_thread_critical = thr_crit_bup;
@@ -6475,7 +6562,8 @@ tk_funcall(func, argc, argv, obj)
DUMP2("wait for handler (current thread:%lx)", current);
while(*alloc_done >= 0) {
DUMP2("*** wait for handler (current thread:%lx)", current);
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
DUMP2("*** wakeup (current thread:%lx)", current);
}
DUMP2("back from handler (current thread:%lx)", current);
@@ -6487,28 +6575,35 @@ tk_funcall(func, argc, argv, obj)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */
-#endif
+#else
/* free(alloc_done); */
ckfree((char*)alloc_done);
#endif
+#endif
/* if (argv) free(argv); */
if (argv) {
/* if argv != NULL, alloc as 'temp' */
+ int i;
+ for(i = 0; i < argc; i++) { argv[i] = (VALUE)NULL; }
+
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)argv, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
ckfree((char*)argv);
#endif
+#endif
}
-#if 1 /* use Tcl_Preserve/Release */
+#if 0 /* callq is freed by Tcl_ServiceEvent */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Release(callq);
#else
ckfree((char*)callq);
#endif
+#endif
/* exception? */
if (rb_obj_is_kind_of(ret, rb_eException)) {
@@ -6714,11 +6809,12 @@ eval_queue_handler(evPtr, flags)
struct eval_queue *q = (struct eval_queue *)evPtr;
volatile VALUE ret;
volatile VALUE q_dat;
+ volatile VALUE thread = q->thread;
struct tcltkip *ptr;
DUMP2("do_eval_queue_handler : evPtr = %p", evPtr);
DUMP2("eval_queue_thread : %lx", rb_thread_current());
- DUMP2("added by thread : %lx", q->thread);
+ DUMP2("added by thread : %lx", thread);
if (*(q->done)) {
DUMP1("processed by another event-loop");
@@ -6727,6 +6823,12 @@ eval_queue_handler(evPtr, flags)
DUMP1("process it on current event-loop");
}
+ if (RTEST(rb_thread_alive_p(thread))
+ && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) {
+ DUMP1("caller is not yet ready to receive the result -> pending");
+ return 0;
+ }
+
/* process it */
*(q->done) = 1;
@@ -6760,12 +6862,14 @@ eval_queue_handler(evPtr, flags)
ret = rb_funcall(rb_proc_new(evq_safelevel_handler, q_dat),
ID_call, 0);
rb_gc_force_recycle(q_dat);
+ q_dat = (VALUE)NULL;
} else {
ret = ip_eval_real(q->interp, q->str, q->len);
}
/* set result */
RARRAY_PTR(q->result)[0] = ret;
+ ret = (VALUE)NULL;
/* decr internal handler mark */
rbtk_internal_eventloop_handler--;
@@ -6773,22 +6877,28 @@ eval_queue_handler(evPtr, flags)
/* complete */
*(q->done) = -1;
+ /* unlink ruby objects */
+ q->interp = (VALUE)NULL;
+ q->result = (VALUE)NULL;
+ q->thread = (VALUE)NULL;
+
/* back to caller */
- if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) {
- DUMP2("back to caller (caller thread:%lx)", q->thread);
+ /* if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(thread))) {
+ DUMP2("back to caller (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
- have_rb_thread_waited_for_value = 1;
- rb_thread_wakeup(q->thread);
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ have_rb_thread_waiting_for_value = 1;
+ rb_thread_wakeup(thread);
#else
- rb_thread_run(q->thread);
+ rb_thread_run(thread);
#endif
DUMP1("finish back to caller");
#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE
rb_thread_schedule();
#endif
} else {
- DUMP2("caller is dead (caller thread:%lx)", q->thread);
+ DUMP2("caller is dead (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
}
@@ -6847,7 +6957,7 @@ ip_eval(self, str)
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qtrue;
- /* allocate memory (protected from Tcl_ServiceEvent) */
+ /* allocate memory (keep result) */
/* alloc_done = (int*)ALLOC(int); */
alloc_done = (int*)ckalloc(sizeof(int));
#if 0 /* use Tcl_Preserve/Release */
@@ -6866,7 +6976,7 @@ ip_eval(self, str)
/* allocate memory (freed by Tcl_ServiceEvent) */
/* evq = (struct eval_queue *)Tcl_Alloc(sizeof(struct eval_queue)); */
evq = (struct eval_queue *)ckalloc(sizeof(struct eval_queue));
-#if 1 /* use Tcl_Preserve/Release */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve(evq);
#endif
@@ -6889,13 +6999,21 @@ ip_eval(self, str)
DUMP1("add handler");
#ifdef RUBY_VM
if (ptr->tk_thread_id) {
- Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(evq->ev), position);
+ /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(evq->ev), position); */
+ Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)evq, position);
Tcl_ThreadAlert(ptr->tk_thread_id);
+ } else if (tk_eventloop_thread_id) {
+ Tcl_ThreadQueueEvent(tk_eventloop_thread_id, (Tcl_Event*)evq, position);
+ /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ &(evq->ev), position); */
+ Tcl_ThreadAlert(tk_eventloop_thread_id);
} else {
- Tcl_QueueEvent(&(evq->ev), position);
+ /* Tcl_QueueEvent(&(evq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)evq, position);
}
#else
- Tcl_QueueEvent(&(evq->ev), position);
+ /* Tcl_QueueEvent(&(evq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)evq, position);
#endif
rb_thread_critical = thr_crit_bup;
@@ -6904,7 +7022,8 @@ ip_eval(self, str)
DUMP2("wait for handler (current thread:%lx)", current);
while(*alloc_done >= 0) {
DUMP2("*** wait for handler (current thread:%lx)", current);
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
DUMP2("*** wakeup (current thread:%lx)", current);
}
DUMP2("back from handler (current thread:%lx)", current);
@@ -6917,24 +7036,28 @@ ip_eval(self, str)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */
-#endif
+#else
/* free(alloc_done); */
ckfree((char*)alloc_done);
#endif
+#endif
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)eval_str, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)eval_str); /* XXXXXXXX */
-#endif
+#else
/* free(eval_str); */
ckfree(eval_str);
#endif
-#if 1 /* use Tcl_Preserve/Release */
+#endif
+#if 0 /* evq is freed by Tcl_ServiceEvent */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Release(evq);
#else
ckfree((char*)evq);
#endif
+#endif
if (rb_obj_is_kind_of(ret, rb_eException)) {
DUMP1("raise exception");
@@ -7112,11 +7235,15 @@ lib_toUTF8_core(ip_obj, src, encodename)
/* StringValue(enc); */
enc = rb_funcall(enc, ID_to_s, 0, 0);
/* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
- encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
- RSTRING_PTR(enc));
- if (encoding == (Tcl_Encoding)NULL) {
+ if (!RSTRING_LEN(enc)) {
+ encoding = (Tcl_Encoding)NULL;
+ } else {
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
+ RSTRING_PTR(enc));
+ if (encoding == (Tcl_Encoding)NULL) {
rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc));
- }
+ }
+ }
}
}
} else {
@@ -7299,13 +7426,17 @@ lib_fromUTF8_core(ip_obj, src, encodename)
/* StringValue(enc); */
enc = rb_funcall(enc, ID_to_s, 0, 0);
/* encoding = Tcl_GetEncoding(interp, RSTRING_PTR(enc)); */
- encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
- RSTRING_PTR(enc));
- if (encoding == (Tcl_Encoding)NULL) {
+ if (!RSTRING_LEN(enc)) {
+ encoding = (Tcl_Encoding)NULL;
+ } else {
+ encoding = Tcl_GetEncoding((Tcl_Interp*)NULL,
+ RSTRING_PTR(enc));
+ if (encoding == (Tcl_Encoding)NULL) {
rb_warning("Tk-interp has unknown encoding information (@encoding:'%s')", RSTRING_PTR(enc));
- } else {
- encodename = rb_obj_dup(enc);
- }
+ } else {
+ encodename = rb_obj_dup(enc);
+ }
+ }
}
}
@@ -7313,14 +7444,17 @@ lib_fromUTF8_core(ip_obj, src, encodename)
StringValue(encodename);
if (strcmp(RSTRING_PTR(encodename), "binary") == 0) {
+ Tcl_Obj *tclstr;
char *s;
int len;
StringValue(str);
- s = Tcl_GetByteArrayFromObj(Tcl_NewStringObj(RSTRING_PTR(str),
- RSTRING_LEN(str)),
- &len);
+ tclstr = Tcl_NewStringObj(RSTRING_PTR(str), RSTRING_LEN(str));
+ Tcl_IncrRefCount(tclstr);
+ s = Tcl_GetByteArrayFromObj(tclstr, &len);
str = rb_tainted_str_new(s, len);
+ s = (char*)NULL;
+ Tcl_DecrRefCount(tclstr);
#ifdef RUBY_VM
rb_enc_associate_index(str, ENCODING_INDEX_BINARY);
#endif
@@ -7482,19 +7616,21 @@ lib_UTF_backslash_core(self, str, all_bs)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)src_buf); /* XXXXXXXX */
-#endif
+#else
/* free(src_buf); */
ckfree(src_buf);
#endif
+#endif
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)dst_buf, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)dst_buf); /* XXXXXXXX */
-#endif
+#else
/* free(dst_buf); */
ckfree(dst_buf);
#endif
+#endif
rb_thread_critical = thr_crit_bup;
#endif
@@ -7619,10 +7755,11 @@ invoke_tcl_proc(arg)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* free(argv); */
ckfree((char*)argv);
#endif
+#endif
#else /* TCL_MAJOR_VERSION < 8 */
inf->ptr->return_value
@@ -7852,10 +7989,11 @@ ip_invoke_core(interp, argc, argv)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* free(argv); */
ckfree((char*)argv);
#endif
+#endif
#else /* TCL_MAJOR_VERSION < 8 */
ptr->return_value = (*info.proc)(info.clientData, ptr->ip,
@@ -7873,11 +8011,12 @@ ip_invoke_core(interp, argc, argv)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)objv); /* XXXXXXXX */
-#endif
+#else
/* free(objv); */
ckfree((char*)objv);
#endif
-#else
+#endif
+#else /* TCL_MAJOR_VERSION < 8 */
free(argv[0]);
/* ckfree(argv[0]); */
#if 0 /* use Tcl_EventuallyFree */
@@ -7885,11 +8024,12 @@ ip_invoke_core(interp, argc, argv)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)argv); /* XXXXXXXX */
-#endif
+#else
/* free(argv); */
ckfree((char*)argv);
#endif
#endif
+#endif
}
/* exception on mainloop */
@@ -7986,8 +8126,10 @@ free_invoke_arguments(argc, av)
for (i = 0; i < argc; ++i) {
#if TCL_MAJOR_VERSION >= 8
Tcl_DecrRefCount(av[i]);
+ av[i] = (Tcl_Obj*)NULL;
#else /* TCL_MAJOR_VERSION < 8 */
free(av[i]);
+ av[i] = (char*)NULL;
#endif
}
#if TCL_MAJOR_VERSION >= 8
@@ -7996,20 +8138,22 @@ free_invoke_arguments(argc, av)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)av); /* XXXXXXXX */
-#endif
+#else
ckfree((char*)av);
#endif
+#endif
#else /* TCL_MAJOR_VERSION < 8 */
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)av, TCL_DYNAMIC); /* XXXXXXXX */
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)av); /* XXXXXXXX */
-#endif
+#else
/* free(av); */
ckfree((char*)av);
#endif
#endif
+#endif
}
static VALUE
@@ -8072,11 +8216,12 @@ invoke_queue_handler(evPtr, flags)
struct invoke_queue *q = (struct invoke_queue *)evPtr;
volatile VALUE ret;
volatile VALUE q_dat;
+ volatile VALUE thread = q->thread;
struct tcltkip *ptr;
DUMP2("do_invoke_queue_handler : evPtr = %p", evPtr);
DUMP2("invoke queue_thread : %lx", rb_thread_current());
- DUMP2("added by thread : %lx", q->thread);
+ DUMP2("added by thread : %lx", thread);
if (*(q->done)) {
DUMP1("processed by another event-loop");
@@ -8085,6 +8230,12 @@ invoke_queue_handler(evPtr, flags)
DUMP1("process it on current event-loop");
}
+ if (RTEST(rb_thread_alive_p(thread))
+ && ! RTEST(rb_funcall(thread, ID_stop_p, 0))) {
+ DUMP1("caller is not yet ready to receive the result -> pending");
+ return 0;
+ }
+
/* process it */
*(q->done) = 1;
@@ -8105,14 +8256,16 @@ invoke_queue_handler(evPtr, flags)
ret = rb_funcall(rb_proc_new(ivq_safelevel_handler, q_dat),
ID_call, 0);
rb_gc_force_recycle(q_dat);
+ q_dat = (VALUE)NULL;
} else {
- DUMP2("call invoke_real (for caller thread:%lx)", q->thread);
+ DUMP2("call invoke_real (for caller thread:%lx)", thread);
DUMP2("call invoke_real (current thread:%lx)", rb_thread_current());
ret = ip_invoke_core(q->interp, q->argc, q->argv);
}
/* set result */
RARRAY_PTR(q->result)[0] = ret;
+ ret = (VALUE)NULL;
/* decr internal handler mark */
rbtk_internal_eventloop_handler--;
@@ -8120,22 +8273,28 @@ invoke_queue_handler(evPtr, flags)
/* complete */
*(q->done) = -1;
+ /* unlink ruby objects */
+ q->interp = (VALUE)NULL;
+ q->result = (VALUE)NULL;
+ q->thread = (VALUE)NULL;
+
/* back to caller */
- if (RTEST(rb_funcall(q->thread, ID_alive_p, 0, 0))) {
- DUMP2("back to caller (caller thread:%lx)", q->thread);
+ /* if (RTEST(rb_funcall(thread, ID_alive_p, 0, 0))) { */
+ if (RTEST(rb_thread_alive_p(thread))) {
+ DUMP2("back to caller (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
-#if CONTROL_BY_STATUS_OF_RB_THREAD_WAIT_FOR_VALUE
- have_rb_thread_waited_for_value = 1;
- rb_thread_wakeup(q->thread);
+#if CONTROL_BY_STATUS_OF_RB_THREAD_WAITING_FOR_VALUE
+ have_rb_thread_waiting_for_value = 1;
+ rb_thread_wakeup(thread);
#else
- rb_thread_run(q->thread);
+ rb_thread_run(thread);
#endif
DUMP1("finish back to caller");
#if DO_THREAD_SCHEDULE_AT_CALLBACK_DONE
rb_thread_schedule();
#endif
} else {
- DUMP2("caller is dead (caller thread:%lx)", q->thread);
+ DUMP2("caller is dead (caller thread:%lx)", thread);
DUMP2(" (current thread:%lx)", rb_thread_current());
}
@@ -8216,7 +8375,7 @@ ip_invoke_with_position(argc, argv, obj, position)
/* allocate memory (freed by Tcl_ServiceEvent) */
/* ivq = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); */
ivq = (struct invoke_queue *)ckalloc(sizeof(struct invoke_queue));
-#if 1 /* use Tcl_Preserve/Release */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Preserve((ClientData)ivq); /* XXXXXXXX */
#endif
@@ -8237,13 +8396,22 @@ ip_invoke_with_position(argc, argv, obj, position)
DUMP1("add handler");
#ifdef RUBY_VM
if (ptr->tk_thread_id) {
- Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(ivq->ev), position);
+ /* Tcl_ThreadQueueEvent(ptr->tk_thread_id, &(ivq->ev), position); */
+ Tcl_ThreadQueueEvent(ptr->tk_thread_id, (Tcl_Event*)ivq, position);
Tcl_ThreadAlert(ptr->tk_thread_id);
+ } else if (tk_eventloop_thread_id) {
+ /* Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ &(ivq->ev), position); */
+ Tcl_ThreadQueueEvent(tk_eventloop_thread_id,
+ (Tcl_Event*)ivq, position);
+ Tcl_ThreadAlert(tk_eventloop_thread_id);
} else {
- Tcl_QueueEvent(&(ivq->ev), position);
+ /* Tcl_QueueEvent(&(ivq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)ivq, position);
}
#else
- Tcl_QueueEvent(&(ivq->ev), position);
+ /* Tcl_QueueEvent(&(ivq->ev), position); */
+ Tcl_QueueEvent((Tcl_Event*)ivq, position);
#endif
rb_thread_critical = thr_crit_bup;
@@ -8251,7 +8419,8 @@ ip_invoke_with_position(argc, argv, obj, position)
/* wait for the handler to be processed */
DUMP2("wait for handler (current thread:%lx)", current);
while(*alloc_done >= 0) {
- rb_thread_stop();
+ /* rb_thread_stop(); */
+ rb_thread_sleep_forever();
}
DUMP2("back from handler (current thread:%lx)", current);
@@ -8262,20 +8431,23 @@ ip_invoke_with_position(argc, argv, obj, position)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)alloc_done); /* XXXXXXXX */
-#endif
+#else
/* free(alloc_done); */
ckfree((char*)alloc_done);
#endif
+#endif
+#if 0 /* ivq is freed by Tcl_ServiceEvent */
#if 0 /* use Tcl_EventuallyFree */
Tcl_EventuallyFree((ClientData)ivq, TCL_DYNAMIC); /* XXXXXXXX */
#else
-#if 1 /* use Tcl_Preserve/Release */
+#if 0 /* use Tcl_Preserve/Release */
Tcl_Release(ivq);
#else
ckfree((char*)ivq);
#endif
#endif
+#endif
/* free allocated memory */
free_invoke_arguments(argc, av);
@@ -8961,10 +9133,11 @@ lib_merge_tklist(argc, argv, obj)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)flagPtr);
-#endif
+#else
/* free(flagPtr); */
ckfree((char*)flagPtr);
#endif
+#endif
/* create object */
str = rb_str_new(result, dst - result - 1);
@@ -8974,10 +9147,11 @@ lib_merge_tklist(argc, argv, obj)
#else
#if 0 /* use Tcl_Preserve/Release */
Tcl_Release((ClientData)result); /* XXXXXXXXXXX */
-#endif
+#else
/* Tcl_Free(result); */
ckfree(result);
#endif
+#endif
if (old_gc == Qfalse) rb_gc_enable();
rb_thread_critical = thr_crit_bup;
@@ -9727,6 +9901,7 @@ ip_make_menu_embeddable_core(interp, argc, argv)
char *s = "normal";
/* Tcl_SetStringObj((menuRefPtr->menuPtr)->menuTypePtr, s, strlen(s));*/
(menuRefPtr->menuPtr)->menuTypePtr = Tcl_NewStringObj(s, strlen(s));
+ /* Tcl_IncrRefCount((menuRefPtr->menuPtr)->menuTypePtr); */
/* (menuRefPtr->menuPtr)->menuType = TEAROFF_MENU; */
(menuRefPtr->menuPtr)->menuType = MASTER_MENU;
}