Compare commits

...
9 changed files with 78 additions and 27 deletions
+8
View File
@@ -1,3 +1,11 @@
2011-08-30 Don Porter <dgp@users.sourceforge.net>
* generic/tclBasic.c: Prevent leak of interps when
* generic/tclExecute.c: using the [testthread exit] command.
* generic/tclIORChan.c:
* generic/tclIORTrans.c:
* generic/tclThreadtest.c:
2011-08-30 Donal K. Fellows <dkf@users.sf.net>
* generic/tclInterp.c (SlaveCommandLimitCmd, SlaveTimeLimitCmd):
+5 -4
View File
@@ -1359,7 +1359,7 @@ DeleteInterpProc(
* unless we are exiting.
*/
if ((iPtr->numLevels > 0) && !TclInExit()) {
if ((iPtr->numLevels > 0) && !TclInExit() && !TclInThreadExit()) {
Tcl_Panic("DeleteInterpProc called with active evals");
}
@@ -1482,7 +1482,8 @@ DeleteInterpProc(
* namespace. The order is important [Bug 1658572].
*/
if ((iPtr->framePtr != iPtr->rootFramePtr) && !TclInExit()) {
if ((iPtr->framePtr != iPtr->rootFramePtr) && !TclInExit()
&& !TclInThreadExit()) {
Tcl_Panic("DeleteInterpProc: popping rootCallFrame with other frames on top");
}
Tcl_PopCallFrame(interp);
@@ -1607,7 +1608,7 @@ DeleteInterpProc(
* know which arguments will be used as scripts and which will not.
*/
if (iPtr->lineLAPtr->numEntries && !TclInExit()) {
if (iPtr->lineLAPtr->numEntries && !TclInExit() && !TclInThreadExit()) {
/*
* When the interp goes away we have nothing on the stack, so there
* are no arguments, so this table has to be empty.
@@ -1620,7 +1621,7 @@ DeleteInterpProc(
ckfree((char *) iPtr->lineLAPtr);
iPtr->lineLAPtr = NULL;
if (iPtr->lineLABCPtr->numEntries && !TclInExit()) {
if (iPtr->lineLABCPtr->numEntries && !TclInExit() && !TclInThreadExit()) {
/*
* When the interp goes away we have nothing on the stack, so there
* are no arguments, so this table has to be empty.
+3 -3
View File
@@ -898,7 +898,7 @@ static void
DeleteExecStack(
ExecStack *esPtr)
{
if (esPtr->markerPtr && !cachedInExit) {
if (esPtr->markerPtr && !cachedInExit && !TclInThreadExit()) {
Tcl_Panic("freeing an execStack which is still in use");
}
@@ -934,10 +934,10 @@ TclDeleteExecEnv(
TclDecrRefCount(eePtr->constants[0]);
TclDecrRefCount(eePtr->constants[1]);
if (eePtr->callbackPtr && !cachedInExit) {
if (eePtr->callbackPtr && !cachedInExit && !TclInThreadExit()) {
Tcl_Panic("Deleting execEnv with pending TEOV callbacks!");
}
if (eePtr->corPtr && !cachedInExit) {
if (eePtr->corPtr && !cachedInExit &&!TclInThreadExit()) {
Tcl_Panic("Deleting execEnv with existing coroutine");
}
ckfree(eePtr);
+3
View File
@@ -2525,6 +2525,9 @@ DeleteReflectedChannelMap(
* interpreter. They have already been marked as dead.
*/
if (TclInThreadExit()) {
return;
}
rcmPtr = GetThreadReflectedChannelMap();
for (hPtr = Tcl_FirstHashEntry(&rcmPtr->map, &hSearch);
hPtr != NULL;
+3
View File
@@ -2200,6 +2200,9 @@ DeleteReflectedTransformMap(
* interpreter. They have already been marked as dead.
*/
if (TclInThreadExit()) {
return;
}
rtmPtr = GetThreadReflectedTransformMap();
for (hPtr = Tcl_FirstHashEntry(&rtmPtr->map, &hSearch);
hPtr != NULL;
+18 -8
View File
@@ -1029,31 +1029,31 @@ TclParseNumber(
state = sINFI;
break;
}
goto endgame;
goto checktrail;
case sINFI:
if (c == 'n' || c == 'N') {
state = sINFIN;
break;
}
goto endgame;
goto checktrail;
case sINFIN:
if (c == 'i' || c == 'I') {
state = sINFINI;
break;
}
goto endgame;
goto checktrail;
case sINFINI:
if (c == 't' || c == 'T') {
state = sINFINIT;
break;
}
goto endgame;
goto checktrail;
case sINFINIT:
if (c == 'y' || c == 'Y') {
state = sINFINITY;
break;
}
goto endgame;
goto checktrail;
/*
* Parse NaN's.
@@ -1079,7 +1079,7 @@ TclParseNumber(
state = sNANPAREN;
break;
}
goto endgame;
goto checktrail;
/*
* Parse NaN(hexdigits)
@@ -1114,13 +1114,23 @@ TclParseNumber(
acceptState = state;
acceptPoint = p;
acceptLen = len;
goto endgame;
goto checktrail;
}
p++;
len--;
while(0) {
checktrail:
if (isalnum(UCHAR(c))||(c=='_')) {
/* bareword prefixed by Nan, Inf, etc. */
acceptState = INITIAL;
}
goto endgame;
}
}
endgame:
endgame:
if (acceptState == INITIAL) {
/*
* No numeric string at all found.
+27 -1
View File
@@ -139,6 +139,7 @@ static void ThreadFreeProc(ClientData clientData);
static int ThreadDeleteEvent(Tcl_Event *eventPtr,
ClientData clientData);
static void ThreadExitProc(ClientData clientData);
static void ReleaseInterp(ClientData clientData);
extern int Tcltest_Init(Tcl_Interp *interp);
/*
@@ -326,8 +327,9 @@ ThreadObjCmd(
return TCL_ERROR;
}
ListRemove(NULL);
Tcl_DeleteInterp(interp);
Tcl_ExitThread(0);
return TCL_OK;
return TCL_ERROR;
case THREAD_ID:
if (objc == 2 || objc == 3) {
Tcl_Obj *idObj;
@@ -564,6 +566,7 @@ NewTestThread(
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int result;
char *threadEvalScript;
int fullFinal = TclFullFinalizationRequested();
/*
* Initialize the interpreter. This should be more general.
@@ -614,7 +617,13 @@ NewTestThread(
*/
Tcl_Preserve(tsdPtr->interp);
if (fullFinal) {
Tcl_CreateThreadExitHandler(ReleaseInterp, tsdPtr->interp);
}
result = Tcl_Eval(tsdPtr->interp, threadEvalScript);
if (fullFinal) {
Tcl_DeleteThreadExitHandler(ReleaseInterp, tsdPtr->interp);
}
if (result != TCL_OK) {
ThreadErrorProc(tsdPtr->interp);
}
@@ -631,6 +640,15 @@ NewTestThread(
TCL_THREAD_CREATE_RETURN;
}
static void
ReleaseInterp(
ClientData clientData)
{
Tcl_Interp *interp = (Tcl_Interp *) clientData;
Tcl_Release(interp);
}
/*
*------------------------------------------------------------------------
*
@@ -1024,11 +1042,19 @@ ThreadEventProc(
errorCode = "THREAD";
errorInfo = "";
} else {
int fullFinal = TclFullFinalizationRequested();
Tcl_Preserve(interp);
Tcl_ResetResult(interp);
if (fullFinal) {
Tcl_CreateThreadExitHandler(ReleaseInterp, tsdPtr->interp);
}
Tcl_CreateThreadExitHandler(ThreadFreeProc, threadEventPtr->script);
code = Tcl_GlobalEval(interp, threadEventPtr->script);
Tcl_DeleteThreadExitHandler(ThreadFreeProc, threadEventPtr->script);
if (fullFinal) {
Tcl_DeleteThreadExitHandler(ReleaseInterp, tsdPtr->interp);
}
if (code != TCL_OK) {
errorCode = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);
errorInfo = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);
+3
View File
@@ -907,6 +907,9 @@ test expr-22.9 {non-numeric floats: shared object equality and NaN} {
set x NaN
expr {$x == $x}
} 0
test expr-22.10 {bareword prefixed by a non-numeric} -body {
list [catch {expr {nancy}} msg] $msg
} -match glob -result {1 {invalid bareword "nancy"*}}
# Tests for exponentiation handling
test expr-23.1 {CompileExponentialExpr: just exponential expr} {expr 4**2} 16
+8 -11
View File
@@ -51,14 +51,13 @@ if {![file exists $httpdFile]} {
set removeHttpd 1
}
if {[info commands testthread] == "testthread" && [file exists $httpdFile]} {
set httpthread [testthread create "
source [list $httpdFile]
testthread wait
"]
testthread send $httpthread [list set port $port]
testthread send $httpthread [list set bindata $bindata]
testthread send $httpthread {httpd_init $port}
catch {package require Thread 2.6}
if {[catch {package present Thread}] == 0 && [file exists $httpdFile]} {
set httpthread [thread::create -preserved]
thread::send $httpthread [list source $httpdFile]
thread::send $httpthread [list set port $port]
thread::send $httpthread [list set bindata $bindata]
thread::send $httpthread {httpd_init $port}
puts "Running httpd in thread $httpthread"
} else {
if {![file exists $httpdFile]} {
@@ -590,9 +589,7 @@ catch {unset badurl}
catch {unset port}
catch {unset data}
if {[info exists httpthread]} {
testthread send -async $httpthread {
testthread exit
}
thread::release $httpthread
} else {
close $listen
}