summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog23
-rw-r--r--generic/tclIO.c34
-rw-r--r--generic/tclIORTrans.c2
-rw-r--r--generic/tclTest.c52
-rw-r--r--tests/async.test2
5 files changed, 92 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 64a25dd..5e7821a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2011-08-19 Don Porter <dgp@users.sourceforge.net>
+
+ * generic/tclIORTrans.c: [Bugs 3393279, 3393280] ReflectClose(.) is
+ missing Tcl_EventuallyFree() calls at some of its exits.
+
+ * generic/tclIO.c: [Bugs 3394654, 3393276] Revise FlushChannel() to
+ account for the possibility that the ChanWrite() call might recycle
+ the buffer out from under us.
+
+ * generic/tclIO.c: Preserve the chanPtr during FlushChannel so that
+ channel drivers don't yank it away before we're done with it.
+
+2011-08-19 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
+
+ * generic/tclTest.c: [Bug 2981154] async-4.3 segfault.
+ * tests/async.test: [Bug 1774689] async-4.3 sometimes fails.
+
+2011-08-18 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
+
+ * generic/tclIO.c: [Bug 3096275] Sync fcopy buffers input.
+
2011-08-18 Jan Nijtmans <nijtmans@users.sf.net>
* generic/tclUniData.c: [Bug 3393714] overflow in toupper delta
@@ -12,7 +33,7 @@
2011-08-17 Alexandre Ferrieux <ferrieux@users.sourceforge.net>
* doc/interp.n: Document TIP 378's one-way-ness.
-
+
2011-08-17 Don Porter <dgp@users.sourceforge.net>
* generic/tclGet.c: [Bug 3393150] Overlooked free of intreps.
diff --git a/generic/tclIO.c b/generic/tclIO.c
index a19fde8..ae1b89a 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -79,7 +79,7 @@ static int DetachChannel(Tcl_Interp *interp, Tcl_Channel chan);
static void DiscardInputQueued(ChannelState *statePtr,
int discardSavedBuffers);
static void DiscardOutputQueued(ChannelState *chanPtr);
-static int DoRead(Channel *chanPtr, char *srcPtr, int slen);
+static int DoRead(Channel *chanPtr, char *srcPtr, int slen, int allowShortReads);
static int DoWrite(Channel *chanPtr, const char *src, int srcLen);
static int DoReadChars(Channel *chan, Tcl_Obj *objPtr, int toRead,
int appendFlag);
@@ -2356,6 +2356,7 @@ FlushChannel(
* of the queued output to the channel.
*/
+ Tcl_Preserve(chanPtr);
while (1) {
/*
* If the queue is empty and there is a ready current buffer, OR if
@@ -2385,7 +2386,8 @@ FlushChannel(
*/
if (!calledFromAsyncFlush && GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
- return 0;
+ errorCode = 0;
+ goto done;
}
/*
@@ -2508,7 +2510,9 @@ FlushChannel(
wroteSome = 1;
}
- bufPtr->nextRemoved += written;
+ if (!IsBufferEmpty(bufPtr)) {
+ bufPtr->nextRemoved += written;
+ }
/*
* If this buffer is now empty, recycle it.
@@ -2532,7 +2536,7 @@ FlushChannel(
if (GotFlag(statePtr, BG_FLUSH_SCHEDULED)) {
if (wroteSome) {
- return errorCode;
+ goto done;
} else if (statePtr->outQueueHead == NULL) {
ResetFlag(statePtr, BG_FLUSH_SCHEDULED);
ChanWatch(chanPtr, statePtr->interestMask);
@@ -2549,7 +2553,8 @@ FlushChannel(
(statePtr->outQueueHead == NULL) &&
((statePtr->curOutPtr == NULL) ||
IsBufferEmpty(statePtr->curOutPtr))) {
- return CloseChannel(interp, chanPtr, errorCode);
+ errorCode = CloseChannel(interp, chanPtr, errorCode);
+ goto done;
}
/*
@@ -2562,8 +2567,12 @@ FlushChannel(
(statePtr->outQueueHead == NULL) &&
((statePtr->curOutPtr == NULL) ||
IsBufferEmpty(statePtr->curOutPtr))) {
- return CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE);
+ errorCode = CloseChannelPart(interp, chanPtr, errorCode, TCL_CLOSE_WRITE);
+ goto done;
}
+
+ done:
+ Tcl_Release(chanPtr);
return errorCode;
}
@@ -5444,7 +5453,7 @@ Tcl_Read(
return -1;
}
- return DoRead(chanPtr, dst, bytesToRead);
+ return DoRead(chanPtr, dst, bytesToRead, 0);
}
/*
@@ -9169,7 +9178,8 @@ CopyData(
}
if (inBinary || sameEncoding) {
- size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb);
+ size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb,
+ !GotFlag(inStatePtr, CHANNEL_NONBLOCKING));
} else {
size = DoReadChars(inStatePtr->topChanPtr, bufObj, sizeb,
0 /* No append */);
@@ -9408,7 +9418,8 @@ static int
DoRead(
Channel *chanPtr, /* The channel from which to read. */
char *bufPtr, /* Where to store input read. */
- int toRead) /* Maximum number of bytes to read. */
+ int toRead, /* Maximum number of bytes to read. */
+ int allowShortReads) /* Allow half-blocking (pipes,sockets) */
{
ChannelState *statePtr = chanPtr->state;
/* State info for channel */
@@ -9449,7 +9460,10 @@ DoRead(
}
goto done;
}
- }
+ } else if (allowShortReads) {
+ copied += copiedNow;
+ break;
+ }
}
ResetFlag(statePtr, CHANNEL_BLOCKED);
diff --git a/generic/tclIORTrans.c b/generic/tclIORTrans.c
index 272306b..4806690 100644
--- a/generic/tclIORTrans.c
+++ b/generic/tclIORTrans.c
@@ -940,6 +940,7 @@ ReflectClose(
int errorCode;
if (!TransformDrain(rtPtr, &errorCode)) {
+ Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
return errorCode;
}
}
@@ -948,6 +949,7 @@ ReflectClose(
int errorCode;
if (!TransformFlush(rtPtr, &errorCode, FLUSH_WRITE)) {
+ Tcl_EventuallyFree (rtPtr, (Tcl_FreeProc *) FreeReflectedTransform);
return errorCode;
}
}
diff --git a/generic/tclTest.c b/generic/tclTest.c
index bac0c7f..3e3bc09 100644
--- a/generic/tclTest.c
+++ b/generic/tclTest.c
@@ -75,6 +75,8 @@ typedef struct TestAsyncHandler {
/* Next is list of handlers. */
} TestAsyncHandler;
+TCL_DECLARE_MUTEX(asyncTestMutex);
+
static TestAsyncHandler *firstHandler = NULL;
/*
@@ -791,17 +793,20 @@ TestasyncCmd(
goto wrongNumArgs;
}
asyncPtr = ckalloc(sizeof(TestAsyncHandler));
+ asyncPtr->command = ckalloc(strlen(argv[2]) + 1);
+ strcpy(asyncPtr->command, argv[2]);
+ Tcl_MutexLock(&asyncTestMutex);
asyncPtr->id = nextId;
nextId++;
asyncPtr->handler = Tcl_AsyncCreate(AsyncHandlerProc,
- (ClientData) asyncPtr);
- asyncPtr->command = ckalloc(strlen(argv[2]) + 1);
- strcpy(asyncPtr->command, argv[2]);
+ (ClientData) asyncPtr->id);
asyncPtr->nextPtr = firstHandler;
firstHandler = asyncPtr;
+ Tcl_MutexUnlock(&asyncTestMutex);
Tcl_SetObjResult(interp, Tcl_NewIntObj(asyncPtr->id));
} else if (strcmp(argv[1], "delete") == 0) {
if (argc == 2) {
+ Tcl_MutexLock(&asyncTestMutex);
while (firstHandler != NULL) {
asyncPtr = firstHandler;
firstHandler = asyncPtr->nextPtr;
@@ -809,6 +814,7 @@ TestasyncCmd(
ckfree(asyncPtr->command);
ckfree(asyncPtr);
}
+ Tcl_MutexUnlock(&asyncTestMutex);
return TCL_OK;
}
if (argc != 3) {
@@ -817,6 +823,7 @@ TestasyncCmd(
if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK) {
return TCL_ERROR;
}
+ Tcl_MutexLock(&asyncTestMutex);
for (prevPtr = NULL, asyncPtr = firstHandler; asyncPtr != NULL;
prevPtr = asyncPtr, asyncPtr = asyncPtr->nextPtr) {
if (asyncPtr->id != id) {
@@ -832,6 +839,7 @@ TestasyncCmd(
ckfree(asyncPtr);
break;
}
+ Tcl_MutexUnlock(&asyncTestMutex);
} else if (strcmp(argv[1], "mark") == 0) {
if (argc != 5) {
goto wrongNumArgs;
@@ -862,7 +870,7 @@ TestasyncCmd(
if (asyncPtr->id == id) {
Tcl_ThreadId threadID;
if (Tcl_CreateThread(&threadID, AsyncThreadProc,
- (ClientData) asyncPtr, TCL_THREAD_STACK_DEFAULT,
+ (ClientData) id, TCL_THREAD_STACK_DEFAULT,
TCL_THREAD_NOFLAGS) != TCL_OK) {
Tcl_SetResult(interp, "can't create thread", TCL_STATIC);
return TCL_ERROR;
@@ -886,15 +894,29 @@ TestasyncCmd(
static int
AsyncHandlerProc(
- ClientData clientData, /* Pointer to TestAsyncHandler structure. */
+ ClientData clientData, /* If of TestAsyncHandler structure.
+ * in global list. */
Tcl_Interp *interp, /* Interpreter in which command was
* executed, or NULL. */
int code) /* Current return code from command. */
{
- TestAsyncHandler *asyncPtr = (TestAsyncHandler *) clientData;
+ TestAsyncHandler *asyncPtr;
+ int id = (int) clientData;
const char *listArgv[4], *cmd;
char string[TCL_INTEGER_SPACE];
+ Tcl_MutexLock(&asyncTestMutex);
+ for (asyncPtr = firstHandler; asyncPtr != NULL;
+ asyncPtr = asyncPtr->nextPtr) {
+ if (asyncPtr->id == id) break;
+ }
+ Tcl_MutexUnlock(&asyncTestMutex);
+
+ if (!asyncPtr) {
+ /* Woops - this one was deleted between the AsyncMark and now */
+ return TCL_OK;
+ }
+
TclFormatInt(string, code);
listArgv[0] = asyncPtr->command;
listArgv[1] = Tcl_GetString(Tcl_GetObjResult(interp));
@@ -932,12 +954,22 @@ AsyncHandlerProc(
#ifdef TCL_THREADS
static Tcl_ThreadCreateType
AsyncThreadProc(
- ClientData clientData) /* Parameter is a pointer to a
+ ClientData clientData) /* Parameter is the id of a
* TestAsyncHandler, defined above. */
{
- TestAsyncHandler *asyncPtr = clientData;
+ TestAsyncHandler *asyncPtr;
+ int id = (int) clientData;
+
Tcl_Sleep(1);
- Tcl_AsyncMark(asyncPtr->handler);
+ Tcl_MutexLock(&asyncTestMutex);
+ for (asyncPtr = firstHandler; asyncPtr != NULL;
+ asyncPtr = asyncPtr->nextPtr) {
+ if (asyncPtr->id == id) {
+ Tcl_AsyncMark(asyncPtr->handler);
+ break;
+ }
+ }
+ Tcl_MutexUnlock(&asyncTestMutex);
Tcl_ExitThread(TCL_OK);
TCL_THREAD_CREATE_RETURN;
}
@@ -7054,5 +7086,7 @@ TestconcatobjCmd(
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/
diff --git a/tests/async.test b/tests/async.test
index db21333..7834ed5 100644
--- a/tests/async.test
+++ b/tests/async.test
@@ -196,7 +196,7 @@ test async-4.3 {async interrupting loop-less bytecode sequence} -constraints {
set aresult {Async event not delivered}
testasync marklater $handle
set i 0
- } [string repeat {;incr i;} 1500000] {
+ } "[string repeat {;incr i;} 1500000]after 10;" {
return $aresult
}]] $hm
} -result {test pattern} -cleanup {