summaryrefslogtreecommitdiffstats
path: root/generic/tclTimer.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclTimer.c')
-rw-r--r--generic/tclTimer.c446
1 files changed, 254 insertions, 192 deletions
diff --git a/generic/tclTimer.c b/generic/tclTimer.c
index ce07825..c10986a 100644
--- a/generic/tclTimer.c
+++ b/generic/tclTimer.c
@@ -8,8 +8,6 @@
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tclTimer.c,v 1.17 2005/07/24 22:56:44 dkf Exp $
*/
#include "tclInt.h"
@@ -74,7 +72,7 @@ typedef struct AfterAssocData {
*/
typedef struct IdleHandler {
- Tcl_IdleProc (*proc); /* Function to call. */
+ Tcl_IdleProc *proc; /* Function to call. */
ClientData clientData; /* Value to pass to proc. */
int generation; /* Used to distinguish older handlers from
* recently-created ones. */
@@ -126,28 +124,44 @@ static Tcl_ThreadDataKey dataKey;
(((t1).sec<(t2).sec) || ((t1).sec==(t2).sec && (t1).usec<(t2).usec))
#define TCL_TIME_DIFF_MS(t1, t2) \
- (1000*((long)(t1).sec - (long)(t2).sec) + \
+ (1000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
((long)(t1).usec - (long)(t2).usec)/1000)
+#define TCL_TIME_DIFF_MS_CEILING(t1, t2) \
+ (1000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
+ ((long)(t1).usec - (long)(t2).usec + 999)/1000)
+
+/*
+ * Sleeps under that number of milliseconds don't get double-checked
+ * and are done in exactly one Tcl_Sleep(). This to limit gettimeofday()s.
+ */
+
+#define SLEEP_OFFLOAD_GETTIMEOFDAY 20
+
+/*
+ * The maximum number of milliseconds for each Tcl_Sleep call in AfterDelay.
+ * This is used to limit the maximum lag between interp limit and script
+ * cancellation checks.
+ */
+
+#define TCL_TIME_MAXIMUM_SLICE 500
+
/*
* Prototypes for functions referenced only in this file:
*/
-static void AfterCleanupProc _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp));
-static int AfterDelay _ANSI_ARGS_((Tcl_Interp *interp, int ms));
-static void AfterProc _ANSI_ARGS_((ClientData clientData));
-static void FreeAfterPtr _ANSI_ARGS_((AfterInfo *afterPtr));
-static AfterInfo * GetAfterEvent _ANSI_ARGS_((AfterAssocData *assocPtr,
- Tcl_Obj *commandPtr));
-static ThreadSpecificData *InitTimer _ANSI_ARGS_((void));
-static void TimerExitProc _ANSI_ARGS_((ClientData clientData));
-static int TimerHandlerEventProc _ANSI_ARGS_((Tcl_Event *evPtr,
- int flags));
-static void TimerCheckProc _ANSI_ARGS_((ClientData clientData,
- int flags));
-static void TimerSetupProc _ANSI_ARGS_((ClientData clientData,
- int flags));
+static void AfterCleanupProc(ClientData clientData,
+ Tcl_Interp *interp);
+static int AfterDelay(Tcl_Interp *interp, Tcl_WideInt ms);
+static void AfterProc(ClientData clientData);
+static void FreeAfterPtr(AfterInfo *afterPtr);
+static AfterInfo * GetAfterEvent(AfterAssocData *assocPtr,
+ Tcl_Obj *commandPtr);
+static ThreadSpecificData *InitTimer(void);
+static void TimerExitProc(ClientData clientData);
+static int TimerHandlerEventProc(Tcl_Event *evPtr, int flags);
+static void TimerCheckProc(ClientData clientData, int flags);
+static void TimerSetupProc(ClientData clientData, int flags);
/*
*----------------------------------------------------------------------
@@ -166,10 +180,9 @@ static void TimerSetupProc _ANSI_ARGS_((ClientData clientData,
*/
static ThreadSpecificData *
-InitTimer()
+InitTimer(void)
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- TclThreadDataKeyGet(&dataKey);
+ ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);
if (tsdPtr == NULL) {
tsdPtr = TCL_TSD_INIT(&dataKey);
@@ -197,11 +210,10 @@ InitTimer()
*/
static void
-TimerExitProc(clientData)
- ClientData clientData; /* Not used. */
+TimerExitProc(
+ ClientData clientData) /* Not used. */
{
- ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
- TclThreadDataKeyGet(&dataKey);
+ ThreadSpecificData *tsdPtr = TclThreadDataKeyGet(&dataKey);
Tcl_DeleteEventSource(TimerSetupProc, TimerCheckProc, NULL);
if (tsdPtr != NULL) {
@@ -210,7 +222,7 @@ TimerExitProc(clientData)
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
while (timerHandlerPtr != NULL) {
tsdPtr->firstTimerHandlerPtr = timerHandlerPtr->nextPtr;
- ckfree((char *) timerHandlerPtr);
+ ckfree(timerHandlerPtr);
timerHandlerPtr = tsdPtr->firstTimerHandlerPtr;
}
}
@@ -235,11 +247,11 @@ TimerExitProc(clientData)
*/
Tcl_TimerToken
-Tcl_CreateTimerHandler(milliseconds, proc, clientData)
- int milliseconds; /* How many milliseconds to wait before
+Tcl_CreateTimerHandler(
+ int milliseconds, /* How many milliseconds to wait before
* invoking proc. */
- Tcl_TimerProc *proc; /* Function to invoke. */
- ClientData clientData; /* Arbitrary data to pass to proc. */
+ Tcl_TimerProc *proc, /* Function to invoke. */
+ ClientData clientData) /* Arbitrary data to pass to proc. */
{
Tcl_Time time;
@@ -277,26 +289,25 @@ Tcl_CreateTimerHandler(milliseconds, proc, clientData)
*/
Tcl_TimerToken
-TclCreateAbsoluteTimerHandler(timePtr, proc, clientData)
- Tcl_Time *timePtr;
- Tcl_TimerProc *proc;
- ClientData clientData;
+TclCreateAbsoluteTimerHandler(
+ Tcl_Time *timePtr,
+ Tcl_TimerProc *proc,
+ ClientData clientData)
{
register TimerHandler *timerHandlerPtr, *tPtr2, *prevPtr;
- ThreadSpecificData *tsdPtr;
+ ThreadSpecificData *tsdPtr = InitTimer();
- tsdPtr = InitTimer();
- timerHandlerPtr = (TimerHandler *) ckalloc(sizeof(TimerHandler));
+ timerHandlerPtr = ckalloc(sizeof(TimerHandler));
/*
* Fill in fields for the event.
*/
- memcpy((void *)&timerHandlerPtr->time, (void *)timePtr, sizeof(Tcl_Time));
+ memcpy(&timerHandlerPtr->time, timePtr, sizeof(Tcl_Time));
timerHandlerPtr->proc = proc;
timerHandlerPtr->clientData = clientData;
tsdPtr->lastTimerId++;
- timerHandlerPtr->token = (Tcl_TimerToken) tsdPtr->lastTimerId;
+ timerHandlerPtr->token = (Tcl_TimerToken) INT2PTR(tsdPtr->lastTimerId);
/*
* Add the event to the queue in the correct position
@@ -340,14 +351,17 @@ TclCreateAbsoluteTimerHandler(timePtr, proc, clientData)
*/
void
-Tcl_DeleteTimerHandler(token)
- Tcl_TimerToken token; /* Result previously returned by
+Tcl_DeleteTimerHandler(
+ Tcl_TimerToken token) /* Result previously returned by
* Tcl_DeleteTimerHandler. */
{
register TimerHandler *timerHandlerPtr, *prevPtr;
- ThreadSpecificData *tsdPtr;
+ ThreadSpecificData *tsdPtr = InitTimer();
+
+ if (token == NULL) {
+ return;
+ }
- tsdPtr = InitTimer();
for (timerHandlerPtr = tsdPtr->firstTimerHandlerPtr, prevPtr = NULL;
timerHandlerPtr != NULL; prevPtr = timerHandlerPtr,
timerHandlerPtr = timerHandlerPtr->nextPtr) {
@@ -359,7 +373,7 @@ Tcl_DeleteTimerHandler(token)
} else {
prevPtr->nextPtr = timerHandlerPtr->nextPtr;
}
- ckfree((char *) timerHandlerPtr);
+ ckfree(timerHandlerPtr);
return;
}
}
@@ -383,9 +397,9 @@ Tcl_DeleteTimerHandler(token)
*/
static void
-TimerSetupProc(data, flags)
- ClientData data; /* Not used. */
- int flags; /* Event flags as passed to Tcl_DoOneEvent. */
+TimerSetupProc(
+ ClientData data, /* Not used. */
+ int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
Tcl_Time blockTime;
ThreadSpecificData *tsdPtr = InitTimer();
@@ -398,7 +412,6 @@ TimerSetupProc(data, flags)
blockTime.sec = 0;
blockTime.usec = 0;
-
} else if ((flags & TCL_TIMER_EVENTS) && tsdPtr->firstTimerHandlerPtr) {
/*
* Compute the timeout for the next timer on the list.
@@ -442,9 +455,9 @@ TimerSetupProc(data, flags)
*/
static void
-TimerCheckProc(data, flags)
- ClientData data; /* Not used. */
- int flags; /* Event flags as passed to Tcl_DoOneEvent. */
+TimerCheckProc(
+ ClientData data, /* Not used. */
+ int flags) /* Event flags as passed to Tcl_DoOneEvent. */
{
Tcl_Event *timerEvPtr;
Tcl_Time blockTime;
@@ -475,7 +488,7 @@ TimerCheckProc(data, flags)
if (blockTime.sec == 0 && blockTime.usec == 0 &&
!tsdPtr->timerPending) {
tsdPtr->timerPending = 1;
- timerEvPtr = (Tcl_Event *) ckalloc(sizeof(Tcl_Event));
+ timerEvPtr = ckalloc(sizeof(Tcl_Event));
timerEvPtr->proc = TimerHandlerEventProc;
Tcl_QueueEvent(timerEvPtr, TCL_QUEUE_TAIL);
}
@@ -504,9 +517,9 @@ TimerCheckProc(data, flags)
*/
static int
-TimerHandlerEventProc(evPtr, flags)
- Tcl_Event *evPtr; /* Event to service. */
- int flags; /* Flags that indicate what events to handle,
+TimerHandlerEventProc(
+ Tcl_Event *evPtr, /* Event to service. */
+ int flags) /* Flags that indicate what events to handle,
* such as TCL_FILE_EVENTS. */
{
TimerHandler *timerHandlerPtr, **nextPtrPtr;
@@ -567,7 +580,7 @@ TimerHandlerEventProc(evPtr, flags)
* Bail out if the next timer is of a newer generation.
*/
- if ((currentTimerId - (int)timerHandlerPtr->token) < 0) {
+ if ((currentTimerId - PTR2INT(timerHandlerPtr->token)) < 0) {
break;
}
@@ -576,9 +589,9 @@ TimerHandlerEventProc(evPtr, flags)
* potential reentrancy problems.
*/
- (*nextPtrPtr) = timerHandlerPtr->nextPtr;
- (*timerHandlerPtr->proc)(timerHandlerPtr->clientData);
- ckfree((char *) timerHandlerPtr);
+ *nextPtrPtr = timerHandlerPtr->nextPtr;
+ timerHandlerPtr->proc(timerHandlerPtr->clientData);
+ ckfree(timerHandlerPtr);
}
TimerSetupProc(NULL, TCL_TIMER_EVENTS);
return 1;
@@ -604,15 +617,15 @@ TimerHandlerEventProc(evPtr, flags)
*/
void
-Tcl_DoWhenIdle(proc, clientData)
- Tcl_IdleProc *proc; /* Function to invoke. */
- ClientData clientData; /* Arbitrary value to pass to proc. */
+Tcl_DoWhenIdle(
+ Tcl_IdleProc *proc, /* Function to invoke. */
+ ClientData clientData) /* Arbitrary value to pass to proc. */
{
register IdleHandler *idlePtr;
Tcl_Time blockTime;
ThreadSpecificData *tsdPtr = InitTimer();
- idlePtr = (IdleHandler *) ckalloc(sizeof(IdleHandler));
+ idlePtr = ckalloc(sizeof(IdleHandler));
idlePtr->proc = proc;
idlePtr->clientData = clientData;
idlePtr->generation = tsdPtr->idleGeneration;
@@ -648,9 +661,9 @@ Tcl_DoWhenIdle(proc, clientData)
*/
void
-Tcl_CancelIdleCall(proc, clientData)
- Tcl_IdleProc *proc; /* Function that was previously registered. */
- ClientData clientData; /* Arbitrary value to pass to proc. */
+Tcl_CancelIdleCall(
+ Tcl_IdleProc *proc, /* Function that was previously registered. */
+ ClientData clientData) /* Arbitrary value to pass to proc. */
{
register IdleHandler *idlePtr, *prevPtr;
IdleHandler *nextPtr;
@@ -661,7 +674,7 @@ Tcl_CancelIdleCall(proc, clientData)
while ((idlePtr->proc == proc)
&& (idlePtr->clientData == clientData)) {
nextPtr = idlePtr->nextPtr;
- ckfree((char *) idlePtr);
+ ckfree(idlePtr);
idlePtr = nextPtr;
if (prevPtr == NULL) {
tsdPtr->idleList = idlePtr;
@@ -696,7 +709,7 @@ Tcl_CancelIdleCall(proc, clientData)
*/
int
-TclServiceIdle()
+TclServiceIdle(void)
{
IdleHandler *idlePtr;
int oldGeneration;
@@ -735,8 +748,8 @@ TclServiceIdle()
if (tsdPtr->idleList == NULL) {
tsdPtr->lastIdlePtr = NULL;
}
- (*idlePtr->proc)(idlePtr->clientData);
- ckfree((char *) idlePtr);
+ idlePtr->proc(idlePtr->clientData);
+ ckfree(idlePtr);
}
if (tsdPtr->idleList) {
blockTime.sec = 0;
@@ -765,27 +778,26 @@ TclServiceIdle()
/* ARGSUSED */
int
-Tcl_AfterObjCmd(clientData, interp, objc, objv)
- ClientData clientData; /* Unused */
- Tcl_Interp *interp; /* Current interpreter. */
- int objc; /* Number of arguments. */
- Tcl_Obj *CONST objv[]; /* Argument objects. */
+Tcl_AfterObjCmd(
+ ClientData clientData, /* Unused */
+ Tcl_Interp *interp, /* Current interpreter. */
+ int objc, /* Number of arguments. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
{
- int ms;
+ Tcl_WideInt ms = 0; /* Number of milliseconds to wait */
+ Tcl_Time wakeup;
AfterInfo *afterPtr;
AfterAssocData *assocPtr;
int length;
- char *argString;
int index;
- char buf[16 + TCL_INTEGER_SPACE];
- static CONST char *afterSubCmds[] = {
- "cancel", "idle", "info", (char *) NULL
+ static const char *const afterSubCmds[] = {
+ "cancel", "idle", "info", NULL
};
enum afterSubCmds {AFTER_CANCEL, AFTER_IDLE, AFTER_INFO};
ThreadSpecificData *tsdPtr = InitTimer();
if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg ...?");
return TCL_ERROR;
}
@@ -796,39 +808,55 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
assocPtr = Tcl_GetAssocData(interp, "tclAfter", NULL);
if (assocPtr == NULL) {
- assocPtr = (AfterAssocData *) ckalloc(sizeof(AfterAssocData));
+ assocPtr = ckalloc(sizeof(AfterAssocData));
assocPtr->interp = interp;
assocPtr->firstAfterPtr = NULL;
- Tcl_SetAssocData(interp, "tclAfter", AfterCleanupProc,
- (ClientData) assocPtr);
+ Tcl_SetAssocData(interp, "tclAfter", AfterCleanupProc, assocPtr);
}
/*
* First lets see if the command was passed a number as the first argument.
*/
- if (objv[1]->typePtr == &tclIntType) {
- ms = (int) objv[1]->internalRep.longValue;
- goto processInteger;
- }
- argString = Tcl_GetStringFromObj(objv[1], &length);
- if (isdigit(UCHAR(argString[0]))) { /* INTL: digit */
- if (Tcl_GetIntFromObj(interp, objv[1], &ms) != TCL_OK) {
+ if (objv[1]->typePtr == &tclIntType
+#ifndef TCL_WIDE_INT_IS_LONG
+ || objv[1]->typePtr == &tclWideIntType
+#endif
+ || objv[1]->typePtr == &tclBignumType
+ || (Tcl_GetIndexFromObj(NULL, objv[1], afterSubCmds, "", 0,
+ &index) != TCL_OK)) {
+ index = -1;
+ if (Tcl_GetWideIntFromObj(NULL, objv[1], &ms) != TCL_OK) {
+ const char *arg = Tcl_GetString(objv[1]);
+
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "bad argument \"%s\": must be"
+ " cancel, idle, info, or an integer", arg));
+ Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "argument",
+ arg, NULL);
return TCL_ERROR;
}
- processInteger:
+ }
+
+ /*
+ * At this point, either index = -1 and ms contains the number of ms
+ * to wait, or else index is the index of a subcommand.
+ */
+
+ switch (index) {
+ case -1: {
if (ms < 0) {
ms = 0;
}
if (objc == 2) {
return AfterDelay(interp, ms);
}
- afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo)));
+ afterPtr = ckalloc(sizeof(AfterInfo));
afterPtr->assocPtr = assocPtr;
if (objc == 3) {
afterPtr->commandPtr = objv[2];
} else {
- afterPtr->commandPtr = Tcl_ConcatObj(objc-2, objv+2);
+ afterPtr->commandPtr = Tcl_ConcatObj(objc-2, objv+2);
}
Tcl_IncrRefCount(afterPtr->commandPtr);
@@ -844,31 +872,23 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
afterPtr->id = tsdPtr->afterId;
tsdPtr->afterId += 1;
- afterPtr->token = Tcl_CreateTimerHandler(ms, AfterProc,
- (ClientData) afterPtr);
+ Tcl_GetTime(&wakeup);
+ wakeup.sec += (long)(ms / 1000);
+ wakeup.usec += ((long)(ms % 1000)) * 1000;
+ if (wakeup.usec > 1000000) {
+ wakeup.sec++;
+ wakeup.usec -= 1000000;
+ }
+ afterPtr->token = TclCreateAbsoluteTimerHandler(&wakeup,
+ AfterProc, afterPtr);
afterPtr->nextPtr = assocPtr->firstAfterPtr;
assocPtr->firstAfterPtr = afterPtr;
- sprintf(buf, "after#%d", afterPtr->id);
- Tcl_AppendResult(interp, buf, (char *) NULL);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
return TCL_OK;
}
-
- /*
- * If it's not a number it must be a subcommand. Note that we're using a
- * custom error message here, so we do not pass an interpreter to T_GIFO.
- */
-
- if (Tcl_GetIndexFromObj(NULL, objv[1], afterSubCmds, "argument", 0,
- &index) != TCL_OK) {
- Tcl_AppendResult(interp, "bad argument \"", argString,
- "\": must be cancel, idle, info, or a number",
- (char *) NULL);
- return TCL_ERROR;
- }
- switch ((enum afterSubCmds) index) {
case AFTER_CANCEL: {
Tcl_Obj *commandPtr;
- char *command, *tempCommand;
+ const char *command, *tempCommand;
int tempLength;
if (objc < 3) {
@@ -886,8 +906,7 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
tempCommand = Tcl_GetStringFromObj(afterPtr->commandPtr,
&tempLength);
if ((length == tempLength)
- && (memcmp((void*) command, (void*) tempCommand,
- (unsigned) length) == 0)) {
+ && !memcmp(command, tempCommand, (unsigned) length)) {
break;
}
}
@@ -901,7 +920,7 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
if (afterPtr->token != NULL) {
Tcl_DeleteTimerHandler(afterPtr->token);
} else {
- Tcl_CancelIdleCall(AfterProc, (ClientData) afterPtr);
+ Tcl_CancelIdleCall(AfterProc, afterPtr);
}
FreeAfterPtr(afterPtr);
}
@@ -909,10 +928,10 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
}
case AFTER_IDLE:
if (objc < 3) {
- Tcl_WrongNumArgs(interp, 2, objv, "script script ...");
+ Tcl_WrongNumArgs(interp, 2, objv, "script ?script ...?");
return TCL_ERROR;
}
- afterPtr = (AfterInfo *) ckalloc((unsigned) (sizeof(AfterInfo)));
+ afterPtr = ckalloc(sizeof(AfterInfo));
afterPtr->assocPtr = assocPtr;
if (objc == 3) {
afterPtr->commandPtr = objv[2];
@@ -925,21 +944,21 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
afterPtr->token = NULL;
afterPtr->nextPtr = assocPtr->firstAfterPtr;
assocPtr->firstAfterPtr = afterPtr;
- Tcl_DoWhenIdle(AfterProc, (ClientData) afterPtr);
- sprintf(buf, "after#%d", afterPtr->id);
- Tcl_AppendResult(interp, buf, (char *) NULL);
+ Tcl_DoWhenIdle(AfterProc, afterPtr);
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf("after#%d", afterPtr->id));
break;
- case AFTER_INFO: {
- Tcl_Obj *resultListPtr;
-
+ case AFTER_INFO:
if (objc == 2) {
+ Tcl_Obj *resultObj = Tcl_NewObj();
+
for (afterPtr = assocPtr->firstAfterPtr; afterPtr != NULL;
afterPtr = afterPtr->nextPtr) {
if (assocPtr->interp == interp) {
- sprintf(buf, "after#%d", afterPtr->id);
- Tcl_AppendElement(interp, buf);
+ Tcl_ListObjAppendElement(NULL, resultObj, Tcl_ObjPrintf(
+ "after#%d", afterPtr->id));
}
}
+ Tcl_SetObjResult(interp, resultObj);
return TCL_OK;
}
if (objc != 3) {
@@ -948,17 +967,22 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
}
afterPtr = GetAfterEvent(assocPtr, objv[2]);
if (afterPtr == NULL) {
- Tcl_AppendResult(interp, "event \"", Tcl_GetString(objv[2]),
- "\" doesn't exist", (char *) NULL);
+ const char *eventStr = TclGetString(objv[2]);
+
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "event \"%s\" doesn't exist", eventStr));
+ Tcl_SetErrorCode(interp, "TCL","LOOKUP","EVENT", eventStr, NULL);
return TCL_ERROR;
- }
- resultListPtr = Tcl_NewObj();
- Tcl_ListObjAppendElement(interp, resultListPtr, afterPtr->commandPtr);
- Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
- (afterPtr->token == NULL) ? "idle" : "timer", -1));
- Tcl_SetObjResult(interp, resultListPtr);
+ } else {
+ Tcl_Obj *resultListPtr = Tcl_NewObj();
+
+ Tcl_ListObjAppendElement(interp, resultListPtr,
+ afterPtr->commandPtr);
+ Tcl_ListObjAppendElement(interp, resultListPtr, Tcl_NewStringObj(
+ (afterPtr->token == NULL) ? "idle" : "timer", -1));
+ Tcl_SetObjResult(interp, resultListPtr);
+ }
break;
- }
default:
Tcl_Panic("Tcl_AfterObjCmd: bad subcommand index to afterSubCmds");
}
@@ -975,7 +999,7 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
*
* Results:
* Standard Tcl result code (with error set if an error occurred due to a
- * time limit being exceeded).
+ * time limit being exceeded or being canceled).
*
* Side effects:
* May adjust the time limit granularity marker.
@@ -984,44 +1008,83 @@ Tcl_AfterObjCmd(clientData, interp, objc, objv)
*/
static int
-AfterDelay(interp, ms)
- Tcl_Interp *interp;
- int ms;
+AfterDelay(
+ Tcl_Interp *interp,
+ Tcl_WideInt ms)
{
Interp *iPtr = (Interp *) interp;
- if (iPtr->limit.timeEvent != NULL) {
- Tcl_Time endTime, now;
+ Tcl_Time endTime, now;
+ Tcl_WideInt diff;
- Tcl_GetTime(&endTime);
- endTime.sec += ms/1000;
- endTime.usec += (ms%1000)*1000;
- if (endTime.usec >= 1000000) {
- endTime.sec++;
- endTime.usec -= 1000000;
- }
+ Tcl_GetTime(&now);
+ endTime = now;
+ endTime.sec += (long)(ms/1000);
+ endTime.usec += ((int)(ms%1000))*1000;
+ if (endTime.usec >= 1000000) {
+ endTime.sec++;
+ endTime.usec -= 1000000;
+ }
- do {
- Tcl_GetTime(&now);
- if (TCL_TIME_BEFORE(iPtr->limit.time, now)) {
- iPtr->limit.granularityTicker = 0;
- if (Tcl_LimitCheck(interp) != TCL_OK) {
- return TCL_ERROR;
- }
+ do {
+ if (Tcl_AsyncReady()) {
+ if (Tcl_AsyncInvoke(interp, TCL_OK) != TCL_OK) {
+ return TCL_ERROR;
}
- if (TCL_TIME_BEFORE(endTime, iPtr->limit.time)) {
- Tcl_Sleep(TCL_TIME_DIFF_MS(endTime, now));
- break;
- } else {
- Tcl_Sleep(TCL_TIME_DIFF_MS(iPtr->limit.time, now));
- if (Tcl_LimitCheck(interp) != TCL_OK) {
+ }
+ if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (iPtr->limit.timeEvent != NULL
+ && TCL_TIME_BEFORE(iPtr->limit.time, now)) {
+ iPtr->limit.granularityTicker = 0;
+ if (Tcl_LimitCheck(interp) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ if (iPtr->limit.timeEvent == NULL
+ || TCL_TIME_BEFORE(endTime, iPtr->limit.time)) {
+ diff = TCL_TIME_DIFF_MS_CEILING(endTime, now);
+#ifndef TCL_WIDE_INT_IS_LONG
+ if (diff > LONG_MAX) {
+ diff = LONG_MAX;
+ }
+#endif
+ if (diff > TCL_TIME_MAXIMUM_SLICE) {
+ diff = TCL_TIME_MAXIMUM_SLICE;
+ }
+ if (diff == 0 && TCL_TIME_BEFORE(now, endTime)) diff = 1;
+ if (diff > 0) {
+ Tcl_Sleep((long) diff);
+ if (diff < SLEEP_OFFLOAD_GETTIMEOFDAY) break;
+ } else break;
+ } else {
+ diff = TCL_TIME_DIFF_MS(iPtr->limit.time, now);
+#ifndef TCL_WIDE_INT_IS_LONG
+ if (diff > LONG_MAX) {
+ diff = LONG_MAX;
+ }
+#endif
+ if (diff > TCL_TIME_MAXIMUM_SLICE) {
+ diff = TCL_TIME_MAXIMUM_SLICE;
+ }
+ if (diff > 0) {
+ Tcl_Sleep((long) diff);
+ }
+ if (Tcl_AsyncReady()) {
+ if (Tcl_AsyncInvoke(interp, TCL_OK) != TCL_OK) {
return TCL_ERROR;
}
}
- } while (TCL_TIME_BEFORE(now, endTime));
- } else {
- Tcl_Sleep(ms);
- }
+ if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (Tcl_LimitCheck(interp) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ Tcl_GetTime(&now);
+ } while (TCL_TIME_BEFORE(now, endTime));
return TCL_OK;
}
@@ -1045,18 +1108,18 @@ AfterDelay(interp, ms)
*/
static AfterInfo *
-GetAfterEvent(assocPtr, commandPtr)
- AfterAssocData *assocPtr; /* Points to "after"-related information for
+GetAfterEvent(
+ AfterAssocData *assocPtr, /* Points to "after"-related information for
* this interpreter. */
- Tcl_Obj *commandPtr;
+ Tcl_Obj *commandPtr)
{
- char *cmdString; /* Textual identifier for after event, such as
+ const char *cmdString; /* Textual identifier for after event, such as
* "after#6". */
AfterInfo *afterPtr;
int id;
char *end;
- cmdString = Tcl_GetString(commandPtr);
+ cmdString = TclGetString(commandPtr);
if (strncmp(cmdString, "after#", 6) != 0) {
return NULL;
}
@@ -1094,16 +1157,14 @@ GetAfterEvent(assocPtr, commandPtr)
*/
static void
-AfterProc(clientData)
- ClientData clientData; /* Describes command to execute. */
+AfterProc(
+ ClientData clientData) /* Describes command to execute. */
{
- AfterInfo *afterPtr = (AfterInfo *) clientData;
+ AfterInfo *afterPtr = clientData;
AfterAssocData *assocPtr = afterPtr->assocPtr;
AfterInfo *prevPtr;
int result;
Tcl_Interp *interp;
- char *script;
- int numBytes;
/*
* First remove the callback from our list of callbacks; otherwise someone
@@ -1126,21 +1187,20 @@ AfterProc(clientData)
*/
interp = assocPtr->interp;
- Tcl_Preserve((ClientData) interp);
- script = Tcl_GetStringFromObj(afterPtr->commandPtr, &numBytes);
- result = Tcl_EvalEx(interp, script, numBytes, TCL_EVAL_GLOBAL);
+ Tcl_Preserve(interp);
+ result = Tcl_EvalObjEx(interp, afterPtr->commandPtr, TCL_EVAL_GLOBAL);
if (result != TCL_OK) {
Tcl_AddErrorInfo(interp, "\n (\"after\" script)");
- Tcl_BackgroundError(interp);
+ Tcl_BackgroundException(interp, result);
}
- Tcl_Release((ClientData) interp);
+ Tcl_Release(interp);
/*
* Free the memory for the callback.
*/
Tcl_DecrRefCount(afterPtr->commandPtr);
- ckfree((char *) afterPtr);
+ ckfree(afterPtr);
}
/*
@@ -1162,8 +1222,8 @@ AfterProc(clientData)
*/
static void
-FreeAfterPtr(afterPtr)
- AfterInfo *afterPtr; /* Command to be deleted. */
+FreeAfterPtr(
+ AfterInfo *afterPtr) /* Command to be deleted. */
{
AfterInfo *prevPtr;
AfterAssocData *assocPtr = afterPtr->assocPtr;
@@ -1178,7 +1238,7 @@ FreeAfterPtr(afterPtr)
prevPtr->nextPtr = afterPtr->nextPtr;
}
Tcl_DecrRefCount(afterPtr->commandPtr);
- ckfree((char *) afterPtr);
+ ckfree(afterPtr);
}
/*
@@ -1200,12 +1260,12 @@ FreeAfterPtr(afterPtr)
/* ARGSUSED */
static void
-AfterCleanupProc(clientData, interp)
- ClientData clientData; /* Points to AfterAssocData for the
+AfterCleanupProc(
+ ClientData clientData, /* Points to AfterAssocData for the
* interpreter. */
- Tcl_Interp *interp; /* Interpreter that is being deleted. */
+ Tcl_Interp *interp) /* Interpreter that is being deleted. */
{
- AfterAssocData *assocPtr = (AfterAssocData *) clientData;
+ AfterAssocData *assocPtr = clientData;
AfterInfo *afterPtr;
while (assocPtr->firstAfterPtr != NULL) {
@@ -1214,12 +1274,12 @@ AfterCleanupProc(clientData, interp)
if (afterPtr->token != NULL) {
Tcl_DeleteTimerHandler(afterPtr->token);
} else {
- Tcl_CancelIdleCall(AfterProc, (ClientData) afterPtr);
+ Tcl_CancelIdleCall(AfterProc, afterPtr);
}
Tcl_DecrRefCount(afterPtr->commandPtr);
- ckfree((char *) afterPtr);
+ ckfree(afterPtr);
}
- ckfree((char *) assocPtr);
+ ckfree(assocPtr);
}
/*
@@ -1227,5 +1287,7 @@ AfterCleanupProc(clientData, interp)
* mode: c
* c-basic-offset: 4
* fill-column: 78
+ * tab-width: 8
+ * indent-tabs-mode: nil
* End:
*/