Compare commits
87
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bac7d95422 | ||
|
|
9b0968b734 | ||
|
|
67dabc08b1 | ||
|
|
3136db14ad | ||
|
|
aebbbf1416 | ||
|
|
0c8bcac14f | ||
|
|
42ef0efbad | ||
|
|
eb195382ca | ||
|
|
27e53946ba | ||
|
|
f765969711 | ||
|
|
f85c7eeaf8 | ||
|
|
ac0c06864a | ||
|
|
e5d47fe818 | ||
|
|
b2bb2605af | ||
|
|
8abf59b9b4 | ||
|
|
9f8a01e5f2 | ||
|
|
b19f192517 | ||
|
|
986c4cd50c | ||
|
|
64868abf4f | ||
|
|
54bd87018c | ||
|
|
efb54576ca | ||
|
|
cd593b31a8 | ||
|
|
7cc472b9ec | ||
|
|
604246ba34 | ||
|
|
29f2fde4ef | ||
|
|
c0f37e88f4 | ||
|
|
f5896b1435 | ||
|
|
5ac5e7e0f2 | ||
|
|
ea33ec285f | ||
|
|
5fd912f410 | ||
|
|
d7726170f8 | ||
|
|
b927c80c2d | ||
|
|
b2fccb4530 | ||
|
|
16fcaa5d3a | ||
|
|
3e620d567b | ||
|
|
06a11ad743 | ||
|
|
99b3de0698 | ||
|
|
0a42a5fe3a | ||
|
|
d668a02838 | ||
|
|
ce98b00663 | ||
|
|
33f0088fcc | ||
|
|
b760247052 | ||
|
|
15fcf0b7ba | ||
|
|
33851b7f36 | ||
|
|
91e0326db8 | ||
|
|
1dfe753462 | ||
|
|
7d840e941c | ||
|
|
6fbf38944b | ||
|
|
b5a1844e1f | ||
|
|
2d12e7c898 | ||
|
|
741679e635 | ||
|
|
c5e7df0399 | ||
|
|
5083075a48 | ||
|
|
4ab56fa512 | ||
|
|
e64ebe1e2f | ||
|
|
ecba820579 | ||
|
|
eade5586f0 | ||
|
|
93ca48c01a | ||
|
|
422ee51c0c | ||
|
|
53c0b2b00e | ||
|
|
6ab0cbe861 | ||
|
|
587bcb0602 | ||
|
|
31c3f2f9da | ||
|
|
1965a89571 | ||
|
|
43560cb286 | ||
|
|
74a050a430 | ||
|
|
de9efce993 | ||
|
|
4139f96329 | ||
|
|
1640c780c0 | ||
|
|
3fac560e1a | ||
|
|
22a93826f0 | ||
|
|
f1c50ac724 | ||
|
|
dc494be758 | ||
|
|
e7aa7663aa | ||
|
|
c648fba3f0 | ||
|
|
2b5f5fbefe | ||
|
|
5b3bc219ba | ||
|
|
b6f5caf13e | ||
|
|
0d02e93910 | ||
|
|
41b3d45cfe | ||
|
|
c5ad1c88af | ||
|
|
82c68cbe3d | ||
|
|
25c8ef9477 | ||
|
|
58358848bb | ||
|
|
41aab74fa0 | ||
|
|
e25427b7d7 | ||
|
|
88d0bfbe6b |
+3
-1
@@ -755,6 +755,7 @@ typedef void (Tcl_PanicProc) (const char *format, ...);
|
||||
typedef void (Tcl_TcpAcceptProc) (ClientData callbackData, Tcl_Channel chan,
|
||||
char *address, int port);
|
||||
typedef void (Tcl_TimerProc) (ClientData clientData);
|
||||
typedef void (Tcl_TimerDeleteProc) _ANSI_ARGS_((ClientData clientData));
|
||||
typedef int (Tcl_SetFromAnyProc) (Tcl_Interp *interp, struct Tcl_Obj *objPtr);
|
||||
typedef void (Tcl_UpdateStringProc) (struct Tcl_Obj *objPtr);
|
||||
typedef char * (Tcl_VarTraceProc) (ClientData clientData, Tcl_Interp *interp,
|
||||
@@ -1359,6 +1360,7 @@ typedef struct {
|
||||
* events:
|
||||
*/
|
||||
|
||||
#define TCL_ASYNC_EVENTS (1<<0)
|
||||
#define TCL_DONT_WAIT (1<<1)
|
||||
#define TCL_WINDOW_EVENTS (1<<2)
|
||||
#define TCL_FILE_EVENTS (1<<3)
|
||||
@@ -1385,7 +1387,7 @@ struct Tcl_Event {
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK
|
||||
TCL_QUEUE_TAIL, TCL_QUEUE_HEAD, TCL_QUEUE_MARK, TCL_QUEUE_RETARDED
|
||||
} Tcl_QueuePosition;
|
||||
|
||||
/*
|
||||
|
||||
@@ -184,6 +184,9 @@ static int ClockMicrosecondsObjCmd(
|
||||
static int ClockMillisecondsObjCmd(
|
||||
ClientData clientData, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const objv[]);
|
||||
static int ClockMonotonicObjCmd(
|
||||
ClientData clientData, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const objv[]);
|
||||
static int ClockParseformatargsObjCmd(
|
||||
ClientData clientData, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const objv[]);
|
||||
@@ -257,6 +260,7 @@ TclClockInit(
|
||||
{"format", NULL, TclCompileBasicMin1ArgCmd, NULL, NULL, 0},
|
||||
{"microseconds", ClockMicrosecondsObjCmd, TclCompileClockReadingCmd, NULL, INT2PTR(1), 0},
|
||||
{"milliseconds", ClockMillisecondsObjCmd, TclCompileClockReadingCmd, NULL, INT2PTR(2), 0},
|
||||
{"monotonic", ClockMonotonicObjCmd, NULL, NULL, NULL, 0},
|
||||
{"scan", NULL, TclCompileBasicMin1ArgCmd, NULL, NULL , 0},
|
||||
{"seconds", ClockSecondsObjCmd, TclCompileClockReadingCmd, NULL, INT2PTR(3), 0},
|
||||
{NULL, NULL, NULL, NULL, NULL, 0}
|
||||
@@ -1850,6 +1854,40 @@ ClockMicrosecondsObjCmd(
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
*
|
||||
* ClockMonotonicObjCmd -
|
||||
*
|
||||
* Returns a count of microseconds since some starting point.
|
||||
* This represents monotonic time not affected from the time-jumps.
|
||||
*
|
||||
* Results:
|
||||
* Returns a standard Tcl result.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
* This function implements the 'clock monotonic' Tcl command. Refer to the
|
||||
* user documentation for details on what it does.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int
|
||||
ClockMonotonicObjCmd(
|
||||
ClientData clientData, /* Client data is unused */
|
||||
Tcl_Interp* interp, /* Tcl interpreter */
|
||||
int objc, /* Parameter count */
|
||||
Tcl_Obj* const* objv) /* Parameter values */
|
||||
{
|
||||
if (objc != 1) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
Tcl_SetObjResult(interp, Tcl_NewWideIntObj(TclpGetUTimeMonotonic()));
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+176
-38
@@ -1368,6 +1368,62 @@ TclInThreadExit(void)
|
||||
}
|
||||
return tsdPtr->inExit;
|
||||
}
|
||||
|
||||
|
||||
static CONST char *updateEventOptions[] = {
|
||||
"-idle", "-noidle", /* new options */
|
||||
"-timer", "-notimer",
|
||||
"-file", "-nofile",
|
||||
"-window", "-nowindow",
|
||||
"-async", "-noasync",
|
||||
"-nowait", "-wait",
|
||||
"idletasks", /* backwards compat. */
|
||||
NULL
|
||||
};
|
||||
|
||||
static int
|
||||
GetEventFlagsFromOpts(
|
||||
Tcl_Interp *interp, /* Used for error reporting if not NULL. */
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *CONST objv[], /* Arguments containing the option to lookup. */
|
||||
int *flagsPtr) /* Input and resulting flags. */
|
||||
{
|
||||
int i, optionIndex, result = TCL_ERROR;
|
||||
int flags = *flagsPtr; /* default flags */
|
||||
static CONST struct {
|
||||
int mask;
|
||||
int flags;
|
||||
} *updateFlag, updateFlags[] = {
|
||||
{0, TCL_IDLE_EVENTS}, {TCL_IDLE_EVENTS, 0}, /* -idle, -noidle */
|
||||
{0, TCL_TIMER_EVENTS}, {TCL_TIMER_EVENTS, 0}, /* -timer, -notimer */
|
||||
{0, TCL_FILE_EVENTS}, {TCL_FILE_EVENTS, 0}, /* -file, -nofile */
|
||||
{0, TCL_WINDOW_EVENTS}, {TCL_WINDOW_EVENTS, 0}, /* -window, -nowindow */
|
||||
{0, TCL_ASYNC_EVENTS}, {TCL_ASYNC_EVENTS, 0}, /* -async, -noasync */
|
||||
{0, TCL_DONT_WAIT}, {TCL_DONT_WAIT, 0}, /* -nowait, -wait */
|
||||
{TCL_ALL_EVENTS, TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS}, /* idletasks */
|
||||
{0, 0} /* dummy / place holder */
|
||||
};
|
||||
|
||||
for (i = 0; i < objc; i++) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[i], updateEventOptions,
|
||||
"option", 0, &optionIndex) != TCL_OK) {
|
||||
goto done;
|
||||
}
|
||||
updateFlag = &updateFlags[optionIndex];
|
||||
/* pure positive option and still default,
|
||||
* reset all events (only this flag) */
|
||||
if (!updateFlag->mask && flags == *flagsPtr) {
|
||||
flags &= ~TCL_ALL_EVENTS;
|
||||
}
|
||||
flags &= ~updateFlag->mask;
|
||||
flags |= updateFlag->flags;
|
||||
}
|
||||
result = TCL_OK;
|
||||
|
||||
done:
|
||||
*flagsPtr = flags;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -1394,45 +1450,129 @@ Tcl_VwaitObjCmd(
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
int done, foundEvent;
|
||||
int done = 0, foundEvent = 1, checktime = 0;
|
||||
int flags = TCL_ALL_EVENTS; /* default flags */
|
||||
const char *nameString;
|
||||
int optc = objc - 2; /* options count without cmd and varname */
|
||||
Tcl_WideInt usec = -1;
|
||||
Tcl_WideInt now = 0, wakeup = 0;
|
||||
|
||||
if (objc != 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "name");
|
||||
if (objc < 2) {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?options? ?timeout? name");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
nameString = Tcl_GetString(objv[1]);
|
||||
|
||||
/* if arguments available - wrap options to flags */
|
||||
if (objc >= 3) {
|
||||
/* first try to recognize options up to the possible end, thereby
|
||||
* we assume that option is not an integer, try to get numeric timeout
|
||||
*/
|
||||
if (!TclObjIsIndexOfTable(objv[optc], updateEventOptions)
|
||||
&& TclpGetUTimeFromObj(NULL, objv[optc], &usec, 1000) == TCL_OK) {
|
||||
if (usec < 0) { usec = 0; };
|
||||
optc--;
|
||||
}
|
||||
|
||||
/* now try to parse options (if available) */
|
||||
if ( optc > 0
|
||||
&& GetEventFlagsFromOpts(interp, optc, objv+1, &flags) != TCL_OK
|
||||
) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If timeout specified - create timer event or no-wait by 0ms.
|
||||
* Note the time can be switched (time-jump), so use monotonic time here.
|
||||
*/
|
||||
if (usec != -1) {
|
||||
if (usec > 0) {
|
||||
now = TclpGetUTimeMonotonic();
|
||||
wakeup = now + usec;
|
||||
} else {
|
||||
flags |= TCL_DONT_WAIT;
|
||||
}
|
||||
}
|
||||
|
||||
nameString = Tcl_GetString(objv[objc-1]);
|
||||
if (Tcl_TraceVar2(interp, nameString, NULL,
|
||||
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
|
||||
VwaitVarProc, &done) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
};
|
||||
done = 0;
|
||||
foundEvent = 1;
|
||||
while (!done && foundEvent) {
|
||||
foundEvent = Tcl_DoOneEvent(TCL_ALL_EVENTS);
|
||||
|
||||
do {
|
||||
/* if wait - set blocking time */
|
||||
if (usec > 0) {
|
||||
Tcl_Time blockTime;
|
||||
Tcl_WideInt diff;
|
||||
|
||||
now = TclpGetUTimeMonotonic();
|
||||
|
||||
/* calculate blocking time */
|
||||
diff = wakeup - now;
|
||||
diff -= 1; /* overhead for this code (e. g. Tcl_TraceVar/Tcl_UntraceVar) */
|
||||
/* be sure process at least one event */
|
||||
if (diff <= 0) {
|
||||
/* timeout occurs */
|
||||
if (checktime) {
|
||||
done = -1;
|
||||
break;
|
||||
}
|
||||
/* expired, be sure non-negative values here */
|
||||
diff = 0;
|
||||
checktime = 1;
|
||||
}
|
||||
blockTime.sec = diff / 1000000;
|
||||
blockTime.usec = diff % 1000000;
|
||||
Tcl_SetMaxBlockTime(&blockTime);
|
||||
}
|
||||
if ((foundEvent = Tcl_DoOneEvent(flags)) <= 0) {
|
||||
/*
|
||||
* If don't wait flag set - no error, and two cases:
|
||||
* option -nowait for vwait means - we don't wait for events;
|
||||
* if no timeout (0) - just stop waiting (no more events)
|
||||
*/
|
||||
if (foundEvent == 0 && (flags & TCL_DONT_WAIT || usec != -1)) {
|
||||
foundEvent = 1;
|
||||
if (usec == 0) { /* timeout occurs */
|
||||
done = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* don't stop wait - no event expected here
|
||||
* (stop only on error case foundEvent <= 0). */
|
||||
if (foundEvent < 0) {
|
||||
done = -2;
|
||||
}
|
||||
}
|
||||
/* check canceled or interpreter limit exceeded */
|
||||
if (Tcl_Canceled(interp, TCL_LEAVE_ERR_MSG) == TCL_ERROR) {
|
||||
done = -3;
|
||||
break;
|
||||
}
|
||||
if (Tcl_LimitExceeded(interp)) {
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1));
|
||||
done = -4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!done);
|
||||
|
||||
Tcl_UntraceVar2(interp, nameString, NULL,
|
||||
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
|
||||
VwaitVarProc, &done);
|
||||
|
||||
if (!foundEvent) {
|
||||
Tcl_ResetResult(interp);
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't wait for variable \"%s\": would wait forever",
|
||||
nameString));
|
||||
Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_SOURCES", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if (!done) {
|
||||
/* if some error */
|
||||
if (done <= -2) {
|
||||
|
||||
if (done == -2) {
|
||||
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
|
||||
"can't wait for variable \"%s\": would wait forever",
|
||||
nameString));
|
||||
Tcl_SetErrorCode(interp, "TCL", "EVENT", "NO_SOURCES", NULL);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* The interpreter's result was already set to the right error message
|
||||
* prior to exiting the loop above.
|
||||
@@ -1441,6 +1581,16 @@ Tcl_VwaitObjCmd(
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* if timeout specified (and no errors) */
|
||||
if (usec != -1) {
|
||||
Tcl_Obj *objPtr;
|
||||
|
||||
/* done - true, timeout false */
|
||||
TclNewLongObj(objPtr, (done > 0));
|
||||
Tcl_SetObjResult(interp, objPtr);
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear out the interpreter's result, since it may have been set by event
|
||||
* handlers.
|
||||
@@ -1492,28 +1642,13 @@ Tcl_UpdateObjCmd(
|
||||
int objc, /* Number of arguments. */
|
||||
Tcl_Obj *const objv[]) /* Argument objects. */
|
||||
{
|
||||
int optionIndex;
|
||||
int flags = 0; /* Initialized to avoid compiler warning. */
|
||||
static const char *const updateOptions[] = {"idletasks", NULL};
|
||||
enum updateOptions {OPT_IDLETASKS};
|
||||
int flags = TCL_ALL_EVENTS|TCL_DONT_WAIT; /* default flags */
|
||||
|
||||
if (objc == 1) {
|
||||
flags = TCL_ALL_EVENTS|TCL_DONT_WAIT;
|
||||
} else if (objc == 2) {
|
||||
if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions,
|
||||
"option", 0, &optionIndex) != TCL_OK) {
|
||||
/* if arguments available - wrap options to flags */
|
||||
if (objc > 1) {
|
||||
if (GetEventFlagsFromOpts(interp, objc-1, objv+1, &flags) != TCL_OK) {
|
||||
return TCL_ERROR;
|
||||
}
|
||||
switch ((enum updateOptions) optionIndex) {
|
||||
case OPT_IDLETASKS:
|
||||
flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT;
|
||||
break;
|
||||
default:
|
||||
Tcl_Panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions");
|
||||
}
|
||||
} else {
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
while (Tcl_DoOneEvent(flags) != 0) {
|
||||
@@ -1525,6 +1660,9 @@ Tcl_UpdateObjCmd(
|
||||
Tcl_SetObjResult(interp, Tcl_NewStringObj("limit exceeded", -1));
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
/* be sure not to produce infinite wait (wait only once) */
|
||||
flags |= TCL_DONT_WAIT;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+74
-34
@@ -156,7 +156,7 @@ static void PreserveChannelBuffer(ChannelBuffer *bufPtr);
|
||||
static void ReleaseChannelBuffer(ChannelBuffer *bufPtr);
|
||||
static int IsShared(ChannelBuffer *bufPtr);
|
||||
static void ChannelFree(Channel *chanPtr);
|
||||
static void ChannelTimerProc(ClientData clientData);
|
||||
static int ChannelScheduledProc(Tcl_Event *evPtr, int flags);
|
||||
static int ChanRead(Channel *chanPtr, char *dst, int dstSize);
|
||||
static int CheckChannelErrors(ChannelState *statePtr,
|
||||
int direction);
|
||||
@@ -1697,7 +1697,7 @@ Tcl_CreateChannel(
|
||||
statePtr->interestMask = 0;
|
||||
statePtr->scriptRecordPtr = NULL;
|
||||
statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE;
|
||||
statePtr->timer = NULL;
|
||||
statePtr->schedEvent = NULL;
|
||||
statePtr->csPtrR = NULL;
|
||||
statePtr->csPtrW = NULL;
|
||||
statePtr->outputStage = NULL;
|
||||
@@ -3085,10 +3085,17 @@ CloseChannel(
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel any outstanding timer.
|
||||
* Cancel any outstanding scheduled event.
|
||||
*/
|
||||
|
||||
Tcl_DeleteTimerHandler(statePtr->timer);
|
||||
if (statePtr->schedEvent) {
|
||||
/* reset channel in event (cancel delayed) */
|
||||
*(Channel**)(statePtr->schedEvent+1) = NULL;
|
||||
#if 0
|
||||
TclpCancelEvent(statePtr->schedEvent);
|
||||
#endif
|
||||
statePtr->schedEvent = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the channel as deleted by clearing the type structure.
|
||||
@@ -3881,10 +3888,17 @@ Tcl_ClearChannelHandlers(
|
||||
chanPtr = statePtr->topChanPtr;
|
||||
|
||||
/*
|
||||
* Cancel any outstanding timer.
|
||||
* Cancel any outstanding scheduled event.
|
||||
*/
|
||||
|
||||
Tcl_DeleteTimerHandler(statePtr->timer);
|
||||
if (statePtr->schedEvent) {
|
||||
/* reset channel in event (cancel delayed) */
|
||||
*(Channel**)(statePtr->schedEvent+1) = NULL;
|
||||
#if 0
|
||||
TclpCancelEvent(statePtr->schedEvent);
|
||||
#endif
|
||||
statePtr->schedEvent = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove any references to channel handlers for this channel that may be
|
||||
@@ -4820,7 +4834,7 @@ Tcl_GetsObj(
|
||||
/*
|
||||
* We didn't get a complete line so we need to indicate to UpdateInterest
|
||||
* that the gets blocked. It will wait for more data instead of firing a
|
||||
* timer, avoiding a busy wait. This is where we are assuming that the
|
||||
* event, avoiding a busy wait. This is where we are assuming that the
|
||||
* next operation is a gets. No more file events will be delivered on this
|
||||
* channel until new data arrives or some operation is performed on the
|
||||
* channel (e.g. gets, read, fconfigure) that changes the blocking state.
|
||||
@@ -5105,7 +5119,7 @@ TclGetsObjBinary(
|
||||
/*
|
||||
* We didn't get a complete line so we need to indicate to UpdateInterest
|
||||
* that the gets blocked. It will wait for more data instead of firing a
|
||||
* timer, avoiding a busy wait. This is where we are assuming that the
|
||||
* event, avoiding a busy wait. This is where we are assuming that the
|
||||
* next operation is a gets. No more file events will be delivered on this
|
||||
* channel until new data arrives or some operation is performed on the
|
||||
* channel (e.g. gets, read, fconfigure) that changes the blocking state.
|
||||
@@ -8389,6 +8403,21 @@ Tcl_NotifyChannel(
|
||||
tsdPtr->nestedHandlerPtr = nh.nestedHandlerPtr;
|
||||
}
|
||||
|
||||
static inline Tcl_Event *
|
||||
CreateChannelScheduledEvent(
|
||||
Channel *chanPtr)
|
||||
{
|
||||
#ifdef SYNTHETIC_EVENT_TIME
|
||||
Tcl_Time blckTime;
|
||||
|
||||
blckTime.sec = SYNTHETIC_EVENT_TIME / 1000000;
|
||||
blckTime.usec = SYNTHETIC_EVENT_TIME % 1000000;
|
||||
Tcl_SetMaxBlockTime(&blckTime);
|
||||
#endif
|
||||
return TclpQueueEventClientData(ChannelScheduledProc, chanPtr,
|
||||
TCL_QUEUE_RETARDED);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -8401,7 +8430,7 @@ Tcl_NotifyChannel(
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* May schedule a timer or driver handler.
|
||||
* May schedule a event or driver handler.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
@@ -8430,7 +8459,7 @@ UpdateInterest(
|
||||
|
||||
/*
|
||||
* If there is data in the input queue, and we aren't waiting for more
|
||||
* data, then we need to schedule a timer so we don't block in the
|
||||
* data, then we need to schedule an event so we don't block in the
|
||||
* notifier. Also, cancel the read interest so we don't get duplicate
|
||||
* events.
|
||||
*/
|
||||
@@ -8459,7 +8488,7 @@ UpdateInterest(
|
||||
*
|
||||
* - Tcl drops READABLE here, because it has data in its own
|
||||
* buffers waiting to be read by the extension.
|
||||
* - A READABLE event is syntesized via timer.
|
||||
* - A READABLE event is syntesized via tcl-event (on queue tail).
|
||||
* - The OS still reports the EXCEPTION condition on the file.
|
||||
* - And the extension gets the EXCPTION event first, and handles
|
||||
* this as EOF.
|
||||
@@ -8481,9 +8510,8 @@ UpdateInterest(
|
||||
|
||||
mask &= ~TCL_EXCEPTION;
|
||||
|
||||
if (!statePtr->timer) {
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc, chanPtr);
|
||||
if (!statePtr->schedEvent) {
|
||||
statePtr->schedEvent = CreateChannelScheduledEvent(chanPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8493,9 +8521,9 @@ UpdateInterest(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* ChannelTimerProc --
|
||||
* ChannelScheduledProc --
|
||||
*
|
||||
* Timer handler scheduled by UpdateInterest to monitor the channel
|
||||
* Event handler scheduled by UpdateInterest to monitor the channel
|
||||
* buffers until they are empty.
|
||||
*
|
||||
* Results:
|
||||
@@ -8507,32 +8535,41 @@ UpdateInterest(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
ChannelTimerProc(
|
||||
ClientData clientData)
|
||||
static int
|
||||
ChannelScheduledProc(
|
||||
Tcl_Event *evPtr, int flags)
|
||||
{
|
||||
Channel *chanPtr = clientData;
|
||||
ChannelState *statePtr = chanPtr->state;
|
||||
/* State info for channel */
|
||||
Channel *chanPtr = *(Channel**)(evPtr+1);
|
||||
ChannelState *statePtr; /* State info for channel */
|
||||
|
||||
if (!chanPtr) { /* channel deleted */
|
||||
return 1;
|
||||
}
|
||||
|
||||
statePtr = chanPtr->state;
|
||||
|
||||
if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
|
||||
&& (statePtr->interestMask & TCL_READABLE)
|
||||
&& (statePtr->inQueueHead != NULL)
|
||||
&& IsBufferReady(statePtr->inQueueHead)) {
|
||||
|
||||
/*
|
||||
* Restart the timer in case a channel handler reenters the event loop
|
||||
* Prolong the event in case a channel handler reenters the event loop
|
||||
* before UpdateInterest gets called by Tcl_NotifyChannel.
|
||||
*/
|
||||
|
||||
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
|
||||
ChannelTimerProc,chanPtr);
|
||||
statePtr->schedEvent = CreateChannelScheduledEvent(chanPtr);
|
||||
|
||||
Tcl_Preserve(statePtr);
|
||||
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
|
||||
Tcl_Release(statePtr);
|
||||
} else {
|
||||
statePtr->timer = NULL;
|
||||
UpdateInterest(chanPtr);
|
||||
|
||||
return 1; /* next cycle */
|
||||
}
|
||||
|
||||
statePtr->schedEvent = NULL; /* event done. */
|
||||
UpdateInterest(chanPtr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8987,9 +9024,9 @@ Tcl_FileEventObjCmd(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* ZeroTransferTimerProc --
|
||||
* ZeroTransferEventProc --
|
||||
*
|
||||
* Timer handler scheduled by TclCopyChannel so that -command is
|
||||
* Event handler scheduled by TclCopyChannel so that -command is
|
||||
* called asynchronously even when -size is 0.
|
||||
*
|
||||
* Results:
|
||||
@@ -9001,14 +9038,17 @@ Tcl_FileEventObjCmd(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
ZeroTransferTimerProc(
|
||||
ClientData clientData)
|
||||
static int
|
||||
ZeroTransferEventProc(
|
||||
Tcl_Event *evPtr, int flags)
|
||||
{
|
||||
/* calling CopyData with mask==0 still implies immediate invocation of the
|
||||
* -command callback, and completion of the fcopy.
|
||||
*/
|
||||
ClientData clientData = *(ClientData*)(evPtr+1);
|
||||
CopyData(clientData, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9153,7 +9193,7 @@ TclCopyChannel(
|
||||
*/
|
||||
|
||||
if ((nonBlocking == CHANNEL_NONBLOCKING) && (toRead == 0)) {
|
||||
Tcl_CreateTimerHandler(0, ZeroTransferTimerProc, csPtr);
|
||||
TclpQueueEventClientData(ZeroTransferEventProc, csPtr, TCL_QUEUE_TAIL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -187,7 +187,7 @@ typedef struct ChannelState {
|
||||
/* Chain of all scripts registered for event
|
||||
* handlers ("fileevent") on this channel. */
|
||||
int bufSize; /* What size buffers to allocate? */
|
||||
Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */
|
||||
Tcl_Event *schedEvent; /* Scheduler event to wakeup this channel. */
|
||||
struct CopyState *csPtrR; /* State of background copy for which channel
|
||||
* is input, or NULL. */
|
||||
struct CopyState *csPtrW; /* State of background copy for which channel
|
||||
|
||||
+46
-9
@@ -43,7 +43,7 @@ static void PrintUsage(Tcl_Interp *interp,
|
||||
* that can be invoked by generic object code.
|
||||
*/
|
||||
|
||||
static const Tcl_ObjType indexType = {
|
||||
const Tcl_ObjType tclIndexType = {
|
||||
"index", /* name */
|
||||
FreeIndex, /* freeIntRepProc */
|
||||
DupIndex, /* dupIntRepProc */
|
||||
@@ -76,6 +76,43 @@ typedef struct {
|
||||
#define EXPAND_OF(indexRep) \
|
||||
STRING_AT((indexRep)->tablePtr, (indexRep)->offset*(indexRep)->index)
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclObjIsIndexOfStruct --
|
||||
*
|
||||
* This function looks up an object's is a index of given table.
|
||||
*
|
||||
* Used for fast lookup by dynamic options count to check for other
|
||||
* object types.
|
||||
*
|
||||
* Results:
|
||||
* 1 if object is an option of table, otherwise 0.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
int
|
||||
TclObjIsIndexOfStruct(
|
||||
Tcl_Obj *objPtr, /* Object containing the string to lookup. */
|
||||
const void *tablePtr) /* Array of strings to compare against the
|
||||
* value of objPtr; last entry must be NULL
|
||||
* and there must not be duplicate entries. */
|
||||
{
|
||||
IndexRep *indexRep;
|
||||
if (objPtr->typePtr != &tclIndexType) {
|
||||
return 0;
|
||||
}
|
||||
indexRep = objPtr->internalRep.twoPtrValue.ptr1;
|
||||
|
||||
if (indexRep->tablePtr != (void *) tablePtr) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -121,7 +158,7 @@ Tcl_GetIndexFromObj(
|
||||
* the common case where the result is cached).
|
||||
*/
|
||||
|
||||
if (objPtr->typePtr == &indexType) {
|
||||
if (objPtr->typePtr == &tclIndexType) {
|
||||
IndexRep *indexRep = objPtr->internalRep.twoPtrValue.ptr1;
|
||||
|
||||
/*
|
||||
@@ -279,7 +316,7 @@ Tcl_GetIndexFromObjStruct(
|
||||
* See if there is a valid cached result from a previous lookup.
|
||||
*/
|
||||
|
||||
if (objPtr->typePtr == &indexType) {
|
||||
if (objPtr->typePtr == &tclIndexType) {
|
||||
indexRep = objPtr->internalRep.twoPtrValue.ptr1;
|
||||
if (indexRep->tablePtr==tablePtr && indexRep->offset==offset) {
|
||||
*indexPtr = indexRep->index;
|
||||
@@ -340,13 +377,13 @@ Tcl_GetIndexFromObjStruct(
|
||||
* operation.
|
||||
*/
|
||||
|
||||
if (objPtr->typePtr == &indexType) {
|
||||
if (objPtr->typePtr == &tclIndexType) {
|
||||
indexRep = objPtr->internalRep.twoPtrValue.ptr1;
|
||||
} else {
|
||||
TclFreeIntRep(objPtr);
|
||||
indexRep = ckalloc(sizeof(IndexRep));
|
||||
objPtr->internalRep.twoPtrValue.ptr1 = indexRep;
|
||||
objPtr->typePtr = &indexType;
|
||||
objPtr->typePtr = &tclIndexType;
|
||||
}
|
||||
indexRep->tablePtr = (void *) tablePtr;
|
||||
indexRep->offset = offset;
|
||||
@@ -488,7 +525,7 @@ DupIndex(
|
||||
|
||||
memcpy(dupIndexRep, srcIndexRep, sizeof(IndexRep));
|
||||
dupPtr->internalRep.twoPtrValue.ptr1 = dupIndexRep;
|
||||
dupPtr->typePtr = &indexType;
|
||||
dupPtr->typePtr = &tclIndexType;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -960,7 +997,7 @@ Tcl_WrongNumArgs(
|
||||
* Add the element, quoting it if necessary.
|
||||
*/
|
||||
|
||||
if (origObjv[i]->typePtr == &indexType) {
|
||||
if (origObjv[i]->typePtr == &tclIndexType) {
|
||||
register IndexRep *indexRep =
|
||||
origObjv[i]->internalRep.twoPtrValue.ptr1;
|
||||
|
||||
@@ -1010,7 +1047,7 @@ Tcl_WrongNumArgs(
|
||||
* Otherwise, just use the string rep.
|
||||
*/
|
||||
|
||||
if (objv[i]->typePtr == &indexType) {
|
||||
if (objv[i]->typePtr == &tclIndexType) {
|
||||
register IndexRep *indexRep = objv[i]->internalRep.twoPtrValue.ptr1;
|
||||
|
||||
Tcl_AppendStringsToObj(objPtr, EXPAND_OF(indexRep), NULL);
|
||||
@@ -1458,7 +1495,7 @@ TclGetCompletionCodeFromObj(
|
||||
"ok", "error", "return", "break", "continue", NULL
|
||||
};
|
||||
|
||||
if ((value->typePtr != &indexType)
|
||||
if ((value->typePtr != &tclIndexType)
|
||||
&& TclGetIntFromObj(NULL, value, codePtr) == TCL_OK) {
|
||||
return TCL_OK;
|
||||
}
|
||||
|
||||
+213
-5
@@ -55,6 +55,16 @@
|
||||
typedef int ptrdiff_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* [MSVC] fallback to replace C++ keyword "inline" with C keyword "__inline"
|
||||
* Otherwise depending on the VC-version, context, include-order it can cause:
|
||||
* error C2054: expected '(' to follow 'inline'
|
||||
*/
|
||||
#if defined(_MSC_VER) && !defined(inline)
|
||||
# define inline __inline
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Ensure WORDS_BIGENDIAN is defined correctly:
|
||||
* Needs to happen here in addition to configure to work with fat compiles on
|
||||
@@ -123,6 +133,58 @@ typedef int ptrdiff_t;
|
||||
# define vsnprintf _vsnprintf
|
||||
#endif
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------
|
||||
* Data structures related to timer / idle events.
|
||||
*----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#define TCL_TMREV_PROMPT (1 << 0) /* Mark immediate event (0 microseconds) */
|
||||
#define TCL_TMREV_AT (1 << 1) /* Mark timer event to execute verbatim
|
||||
* at the due-time (regardless any
|
||||
* time-jumps). */
|
||||
#define TCL_TMREV_IDLE (1 << 3) /* Mark idle event */
|
||||
#define TCL_TMREV_LISTED (1 << 5) /* Event listed (attached to queue). */
|
||||
#define TCL_TMREV_DELETE (1 << 7) /* Event will be deleted. */
|
||||
|
||||
/*
|
||||
* This structure used for handling of timer events (with or without time to
|
||||
* invoke, e. g. created with "after 0") or declared in a call to Tcl_DoWhenIdle
|
||||
* (created with "after idle"). All of the currently-active handlers are linked
|
||||
* together into corresponding list.
|
||||
*
|
||||
* For each timer callback that's pending there is one record of the following
|
||||
* type. The normal handlers (created by Tcl_CreateTimerHandler) are chained
|
||||
* together in a list via TclTimerEvent sorted by time (earliest event first).
|
||||
*/
|
||||
|
||||
typedef struct TclTimerEvent {
|
||||
Tcl_TimerProc *proc; /* Function to call timer/idle event */
|
||||
Tcl_TimerDeleteProc *deleteProc; /* Function to cleanup idle event */
|
||||
ClientData clientData; /* Argument to pass to proc and deleteProc */
|
||||
int flags; /* Flags, OR-ed combination of flags/states
|
||||
* TCL_TMREV_PROMPT ... TCL_TMREV_DELETE */
|
||||
|
||||
Tcl_WideInt time; /* When timer is to fire (absolute/relative). */
|
||||
Tcl_TimerToken token; /* Identifies handler so it can be deleted. */
|
||||
|
||||
size_t generation; /* Used to distinguish older handlers from
|
||||
* recently-created ones. */
|
||||
size_t refCount; /* Used to preserve for deletion (nested exec
|
||||
* resp. prolongation). */
|
||||
struct TclTimerEvent *nextPtr;/* Next and prev event in idle queue, */
|
||||
struct TclTimerEvent *prevPtr;/* or NULL for end/start of the queue. */
|
||||
/* variable ExtraData */ /* If extraDataSize supplied to create event. */
|
||||
} TclTimerEvent;
|
||||
|
||||
/*
|
||||
* Macros to wrap ExtraData and TclTimerEvent (and vice versa)
|
||||
*/
|
||||
#define TclpTimerEvent2ExtraData(ptr) \
|
||||
( (ClientData)(((TclTimerEvent *)(ptr))+1) )
|
||||
#define TclpExtraData2TimerEvent(ptr) \
|
||||
( ((TclTimerEvent *)(ptr))-1 )
|
||||
|
||||
/*
|
||||
* The following procedures allow namespaces to be customized to support
|
||||
* special name resolution rules for commands/variables.
|
||||
@@ -1975,8 +2037,7 @@ typedef struct Interp {
|
||||
* reached. */
|
||||
int timeGranularity; /* Mod factor used to determine how often to
|
||||
* evaluate the limit check. */
|
||||
Tcl_TimerToken timeEvent;
|
||||
/* Handle for a timer callback that will occur
|
||||
TclTimerEvent *timeEvent;/* Handle for a timer callback that will occur
|
||||
* when the time-limit is exceeded. */
|
||||
|
||||
Tcl_HashTable callbacks;/* Mapping from (interp,type) pair to data
|
||||
@@ -2172,18 +2233,37 @@ typedef struct Interp {
|
||||
* existence of struct items 'prevPtr' and 'nextPtr'.
|
||||
*
|
||||
* a = element to add or remove.
|
||||
* b = list head.
|
||||
* b = list head (points to the first element).
|
||||
* e = list tail (points to the last element).
|
||||
*
|
||||
* TclSpliceIn adds to the head of the list.
|
||||
* TclSpliceTail adds to the tail of the list.
|
||||
*/
|
||||
|
||||
#define TclSpliceIn(a,b) \
|
||||
(a)->nextPtr = (b); \
|
||||
if ((b) != NULL) { \
|
||||
if (((a)->nextPtr = (b)) != NULL) { \
|
||||
(b)->prevPtr = (a); \
|
||||
} \
|
||||
(a)->prevPtr = NULL, (b) = (a);
|
||||
|
||||
#define TclSpliceInEx(a,b,e) \
|
||||
TclSpliceIn(a,b); \
|
||||
if ((e) == NULL) { \
|
||||
(e) = (a); \
|
||||
}
|
||||
|
||||
#define TclSpliceTail(a,e) \
|
||||
if (((a)->prevPtr = (e)) != NULL) { \
|
||||
(e)->nextPtr = (a); \
|
||||
} \
|
||||
(a)->nextPtr = NULL, (e) = (a);
|
||||
|
||||
#define TclSpliceTailEx(a,b,e) \
|
||||
TclSpliceTail(a,e); \
|
||||
if ((b) == NULL) { \
|
||||
(b) = (a); \
|
||||
}
|
||||
|
||||
#define TclSpliceOut(a,b) \
|
||||
if ((a)->prevPtr != NULL) { \
|
||||
(a)->prevPtr->nextPtr = (a)->nextPtr; \
|
||||
@@ -2194,6 +2274,11 @@ typedef struct Interp {
|
||||
(a)->nextPtr->prevPtr = (a)->prevPtr; \
|
||||
}
|
||||
|
||||
#define TclSpliceOutEx(a,b,e) \
|
||||
TclSpliceOut(a,b) else { \
|
||||
(e) = (e)->prevPtr; \
|
||||
}
|
||||
|
||||
/*
|
||||
* EvalFlag bits for Interp structures:
|
||||
*
|
||||
@@ -2689,6 +2774,7 @@ MODULE_SCOPE const Tcl_ObjType tclByteArrayType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclByteCodeType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclDoubleType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclEndOffsetType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclIndexType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclIntType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclListType;
|
||||
MODULE_SCOPE const Tcl_ObjType tclDictType;
|
||||
@@ -2848,6 +2934,12 @@ struct Tcl_LoadHandle_ {
|
||||
*----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
MODULE_SCOPE int TclObjIsIndexOfStruct(Tcl_Obj *objPtr,
|
||||
const void *tablePtr);
|
||||
#define TclObjIsIndexOfTable(objPtr, tablePtr) \
|
||||
((objPtr->typePtr == &tclIndexType) \
|
||||
&& TclObjIsIndexOfStruct(objPtr, tablePtr))
|
||||
|
||||
MODULE_SCOPE void TclAppendBytesToByteArray(Tcl_Obj *objPtr,
|
||||
const unsigned char *bytes, int len);
|
||||
MODULE_SCOPE int TclNREvalCmd(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
@@ -3213,9 +3305,70 @@ MODULE_SCOPE Tcl_WideInt TclpGetWideClicks(void);
|
||||
MODULE_SCOPE double TclpWideClickInMicrosec(void);
|
||||
# define TclpWideClicksToNanoseconds(clicks) \
|
||||
((double)(clicks) * TclpWideClickInMicrosec() * 1000)
|
||||
/* Tolerance (in percent), prevents entering busy wait, but has fewer accuracy
|
||||
* because can wait a bit shorter as wanted. Currently experimental value
|
||||
* (4.5% equivalent to 15600 / 15000 with small overhead) */
|
||||
# ifndef TMR_RES_TOLERANCE
|
||||
# define TMR_RES_TOLERANCE 4.5
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
MODULE_SCOPE Tcl_WideInt TclpGetMicroseconds(void);
|
||||
MODULE_SCOPE Tcl_WideInt TclpGetUTimeMonotonic(void);
|
||||
|
||||
MODULE_SCOPE int TclpGetUTimeFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr,
|
||||
Tcl_WideInt *timePtr, int factor);
|
||||
MODULE_SCOPE void TclpScaleUTime(Tcl_WideInt *usec);
|
||||
|
||||
MODULE_SCOPE void TclpUSleep(Tcl_WideInt usec);
|
||||
/*
|
||||
* Helper macros for working with times. TCL_TIME_BEFORE encodes how to write
|
||||
* the ordering relation on (normalized) times, and TCL_TIME_DIFF_MS resp.
|
||||
* TCL_TIME_DIFF_US compute the number of milliseconds or microseconds difference
|
||||
* between two times. Both macros use both of their arguments multiple times,
|
||||
* so make sure they are cheap and side-effect free.
|
||||
* Macro TCL_TIME_TO_USEC converts Tcl_Time to microseconds.
|
||||
* The "prototypes" for these macros are:
|
||||
*
|
||||
* static int TCL_TIME_BEFORE(Tcl_Time t1, Tcl_Time t2);
|
||||
* static Tcl_WideInt TCL_TIME_DIFF_MS(Tcl_Time t1, Tcl_Time t2);
|
||||
* static Tcl_WideInt TCL_TIME_DIFF_US(Tcl_Time t1, Tcl_Time t2);
|
||||
* static Tcl_WideInt TCL_TIME_TO_USEC(Tcl_Time t)
|
||||
*/
|
||||
|
||||
#define TCL_TIME_BEFORE(t1, t2) \
|
||||
(((t1).sec<(t2).sec) || ((t1).sec==(t2).sec && (t1).usec<(t2).usec))
|
||||
|
||||
#define TCL_TIME_DIFF_MS(t1, t2) \
|
||||
(1000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
|
||||
((long)(t1).usec - (long)(t2).usec)/1000)
|
||||
#define TCL_TIME_DIFF_US(t1, t2) \
|
||||
(1000000*((Tcl_WideInt)(t1).sec - (Tcl_WideInt)(t2).sec) + \
|
||||
((long)(t1).usec - (long)(t2).usec))
|
||||
#define TCL_TIME_TO_USEC(t) \
|
||||
(((Tcl_WideInt)(t).sec)*1000000 + (t).usec)
|
||||
|
||||
static inline void
|
||||
TclTimeSetMilliseconds(
|
||||
register Tcl_Time *timePtr,
|
||||
register double ms
|
||||
) {
|
||||
timePtr->sec = (long)(ms / 1000);
|
||||
timePtr->usec = (((long)ms) % 1000) * 1000 + (((long)(ms*1000)) % 1000);
|
||||
}
|
||||
|
||||
static inline void
|
||||
TclTimeAddMilliseconds(
|
||||
register Tcl_Time *timePtr,
|
||||
register double ms
|
||||
) {
|
||||
timePtr->sec += (long)(ms / 1000);
|
||||
timePtr->usec += (((long)ms) % 1000) * 1000 + (((long)(ms*1000)) % 1000);
|
||||
if (timePtr->usec > 1000000) {
|
||||
timePtr->usec -= 1000000;
|
||||
timePtr->sec++;
|
||||
}
|
||||
}
|
||||
|
||||
MODULE_SCOPE int TclZlibInit(Tcl_Interp *interp);
|
||||
MODULE_SCOPE void * TclpThreadCreateKey(void);
|
||||
@@ -3278,9 +3431,53 @@ MODULE_SCOPE int Tcl_ConcatObjCmd(ClientData clientData,
|
||||
MODULE_SCOPE int Tcl_ContinueObjCmd(ClientData clientData,
|
||||
Tcl_Interp *interp, int objc,
|
||||
Tcl_Obj *const objv[]);
|
||||
MODULE_SCOPE void TclSetTimerEventMarker(int flags);
|
||||
MODULE_SCOPE int TclServiceTimerEvents(void);
|
||||
MODULE_SCOPE int TclServiceIdleEx(int flags, int count);
|
||||
MODULE_SCOPE void TclpCancelEvent(Tcl_Event *evPtr);
|
||||
static inline Tcl_Event*
|
||||
TclpQueueEventEx(
|
||||
Tcl_EventProc *proc, /* Event function to call if it servicing. */
|
||||
ClientData extraData, /* Event extra data to be included and its */
|
||||
size_t extraDataSize, /* extra size (to allocate and copy into). */
|
||||
Tcl_QueuePosition position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
|
||||
* TCL_QUEUE_MARK or TCL_QUEUE_RETARDED. */
|
||||
{
|
||||
Tcl_Event *evPtr = ckalloc(sizeof(Tcl_Event) + extraDataSize);
|
||||
evPtr->proc = proc;
|
||||
memcpy((evPtr+1), extraData, extraDataSize);
|
||||
Tcl_QueueEvent(evPtr, position);
|
||||
return evPtr;
|
||||
}
|
||||
static inline Tcl_Event*
|
||||
TclpQueueEventClientData(
|
||||
Tcl_EventProc *proc, /* Event function to call if it servicing. */
|
||||
ClientData clientData, /* Event extra data to be included. */
|
||||
Tcl_QueuePosition position) /* One of TCL_QUEUE_TAIL, TCL_QUEUE_HEAD,
|
||||
* TCL_QUEUE_MARK or TCL_QUEUE_RETARDED. */
|
||||
{
|
||||
Tcl_Event *evPtr = ckalloc(sizeof(Tcl_Event) + sizeof(clientData));
|
||||
evPtr->proc = proc;
|
||||
*(ClientData*)(evPtr+1) = clientData;
|
||||
Tcl_QueueEvent(evPtr, position);
|
||||
return evPtr;
|
||||
}
|
||||
MODULE_SCOPE TclTimerEvent* TclpCreateTimerEvent(Tcl_WideInt usec,
|
||||
Tcl_TimerProc *proc, Tcl_TimerDeleteProc *delProc,
|
||||
size_t extraDataSize, int flags);
|
||||
MODULE_SCOPE TclTimerEvent* TclpCreatePromptTimerEvent(
|
||||
Tcl_TimerProc *proc, Tcl_TimerDeleteProc *delProc,
|
||||
size_t extraDataSize, int flags);
|
||||
MODULE_SCOPE Tcl_TimerToken TclCreateTimerHandler(
|
||||
Tcl_Time *timePtr, Tcl_TimerProc *proc,
|
||||
ClientData clientData, int flags);
|
||||
MODULE_SCOPE Tcl_TimerToken TclCreateAbsoluteTimerHandler(
|
||||
Tcl_Time *timePtr, Tcl_TimerProc *proc,
|
||||
ClientData clientData);
|
||||
MODULE_SCOPE void TclpDeleteTimerEvent(TclTimerEvent *tmrEvent);
|
||||
MODULE_SCOPE TclTimerEvent* TclpProlongTimerEvent(TclTimerEvent *tmrEvent,
|
||||
Tcl_WideInt usec, int flags);
|
||||
MODULE_SCOPE int TclPeekEventQueued(int flags);
|
||||
MODULE_SCOPE int TclDefaultBgErrorHandlerObjCmd(
|
||||
ClientData clientData, Tcl_Interp *interp,
|
||||
int objc, Tcl_Obj *const objv[]);
|
||||
@@ -4781,6 +4978,17 @@ MODULE_SCOPE Tcl_PackageInitProc Procbodytest_SafeInit;
|
||||
|
||||
#define TclLimitExceeded(limit) ((limit).exceeded != 0)
|
||||
|
||||
static inline int
|
||||
TclInlLimitExceeded(
|
||||
register Tcl_Interp *interp)
|
||||
{
|
||||
return (((Interp *)interp)->limit.exceeded != 0);
|
||||
}
|
||||
#ifdef Tcl_LimitExceeded
|
||||
# undef Tcl_LimitExceeded
|
||||
#endif
|
||||
#define Tcl_LimitExceeded(interp) TclInlLimitExceeded(interp)
|
||||
|
||||
#define TclLimitReady(limit) \
|
||||
(((limit).active == 0) ? 0 : \
|
||||
(++(limit).granularityTicker, \
|
||||
|
||||
+55
-12
@@ -3276,6 +3276,8 @@ Tcl_MakeSafe(
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#undef Tcl_LimitExceeded
|
||||
|
||||
int
|
||||
Tcl_LimitExceeded(
|
||||
Tcl_Interp *interp)
|
||||
@@ -3747,7 +3749,7 @@ TclLimitRemoveAllHandlers(
|
||||
*/
|
||||
|
||||
if (iPtr->limit.timeEvent != NULL) {
|
||||
Tcl_DeleteTimerHandler(iPtr->limit.timeEvent);
|
||||
TclpDeleteTimerEvent(iPtr->limit.timeEvent);
|
||||
iPtr->limit.timeEvent = NULL;
|
||||
}
|
||||
}
|
||||
@@ -3917,15 +3919,26 @@ Tcl_LimitGetCommands(
|
||||
|
||||
return iPtr->limit.cmdCount;
|
||||
}
|
||||
|
||||
static void
|
||||
TimeLimitDeleteCallback(
|
||||
ClientData clientData)
|
||||
{
|
||||
Interp *iPtr = clientData;
|
||||
iPtr->limit.timeEvent = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_LimitSetTime --
|
||||
* Tcl_LimitSetTime --, TclpLimitSetTimeOffs --
|
||||
*
|
||||
* Set the time limit for an interpreter by copying it from the value
|
||||
* pointed to by the timeLimitPtr argument.
|
||||
*
|
||||
* TclpLimitSetTimeOffs opposite to Tcl_LimitSetTime set the limit as
|
||||
* relative time.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
@@ -3943,22 +3956,52 @@ Tcl_LimitSetTime(
|
||||
Tcl_Time *timeLimitPtr)
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
Tcl_Time nextMoment;
|
||||
Tcl_WideInt nextMoment;
|
||||
|
||||
memcpy(&iPtr->limit.time, timeLimitPtr, sizeof(Tcl_Time));
|
||||
nextMoment = TCL_TIME_TO_USEC(*timeLimitPtr) + 10;
|
||||
if (iPtr->limit.timeEvent != NULL) {
|
||||
Tcl_DeleteTimerHandler(iPtr->limit.timeEvent);
|
||||
iPtr->limit.timeEvent = TclpProlongTimerEvent(iPtr->limit.timeEvent,
|
||||
nextMoment, TCL_TMREV_AT);
|
||||
if (iPtr->limit.timeEvent) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
nextMoment.sec = timeLimitPtr->sec;
|
||||
nextMoment.usec = timeLimitPtr->usec+10;
|
||||
if (nextMoment.usec >= 1000000) {
|
||||
nextMoment.sec++;
|
||||
nextMoment.usec -= 1000000;
|
||||
}
|
||||
iPtr->limit.timeEvent = TclCreateAbsoluteTimerHandler(&nextMoment,
|
||||
TimeLimitCallback, interp);
|
||||
iPtr->limit.timeEvent = TclpCreateTimerEvent(nextMoment,
|
||||
TimeLimitCallback, TimeLimitDeleteCallback, 0, TCL_TMREV_AT);
|
||||
iPtr->limit.timeEvent->clientData = interp;
|
||||
iPtr->limit.exceeded &= ~TCL_LIMIT_TIME;
|
||||
}
|
||||
#if 0
|
||||
void
|
||||
TclpLimitSetTimeOffs(
|
||||
Tcl_Interp *interp,
|
||||
Tcl_WideInt timeOffs)
|
||||
{
|
||||
Interp *iPtr = (Interp *) interp;
|
||||
|
||||
Tcl_GetTime(&iPtr->limit.time);
|
||||
iPtr->limit.time.sec += timeOffs / 1000000;
|
||||
iPtr->limit.time.usec += timeOffs % 1000000;
|
||||
if (iPtr->limit.time.usec > 1000000) {
|
||||
iPtr->limit.time.usec -= 1000000;
|
||||
iPtr->limit.time.sec++;
|
||||
}
|
||||
timeOffs += 10;
|
||||
/* we should use relative time (because of the timeout meaning) */
|
||||
if (iPtr->limit.timeEvent != NULL) {
|
||||
iPtr->limit.timeEvent = TclpProlongTimerEvent(iPtr->limit.timeEvent,
|
||||
timeOffs, 0);
|
||||
if (iPtr->limit.timeEvent) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
iPtr->limit.timeEvent = TclpCreateTimerEvent(timeOffs,
|
||||
TimeLimitCallback, TimeLimitDeleteCallback, 0, 0);
|
||||
iPtr->limit.timeEvent->clientData = interp;
|
||||
iPtr->limit.exceeded &= ~TCL_LIMIT_TIME;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
|
||||
+768
-185
File diff suppressed because it is too large
Load Diff
+1235
-453
File diff suppressed because it is too large
Load Diff
+10
-14
@@ -1487,9 +1487,9 @@ OnOffWaitingList(
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_Sleep --
|
||||
* TclpUSleep --
|
||||
*
|
||||
* Delay execution for the specified number of milliseconds.
|
||||
* Delay execution for the specified time (in microseconds).
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
@@ -1501,24 +1501,20 @@ OnOffWaitingList(
|
||||
*/
|
||||
|
||||
void
|
||||
Tcl_Sleep(
|
||||
int ms) /* Number of milliseconds to sleep. */
|
||||
TclpUSleep(
|
||||
Tcl_WideInt usec) /* Time to sleep. */
|
||||
{
|
||||
Tcl_Time vdelay;
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
if (ms <= 0) {
|
||||
return;
|
||||
if (usec <= 0) { /* force one context switch */
|
||||
usec = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TIP #233: Scale from virtual time to real-time.
|
||||
*/
|
||||
|
||||
vdelay.sec = ms / 1000;
|
||||
vdelay.usec = (ms % 1000) * 1000;
|
||||
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
|
||||
|
||||
TclpScaleUTime(&usec);
|
||||
|
||||
if (tsdPtr->runLoop) {
|
||||
CFTimeInterval waitTime;
|
||||
@@ -1526,7 +1522,7 @@ Tcl_Sleep(
|
||||
CFAbsoluteTime nextTimerFire = 0, waitEnd, now;
|
||||
SInt32 runLoopStatus;
|
||||
|
||||
waitTime = vdelay.sec + 1.0e-6 * vdelay.usec;
|
||||
waitTime = (usec / 1000000) + 1.0e-6 * (usec % 1000000);
|
||||
now = CFAbsoluteTimeGetCurrent();
|
||||
waitEnd = now + waitTime;
|
||||
|
||||
@@ -1563,8 +1559,8 @@ Tcl_Sleep(
|
||||
} else {
|
||||
struct timespec waitTime;
|
||||
|
||||
waitTime.tv_sec = vdelay.sec;
|
||||
waitTime.tv_nsec = vdelay.usec * 1000;
|
||||
waitTime.tv_sec = (usec / 1000000);
|
||||
waitTime.tv_nsec = (usec % 1000000) * 1000;
|
||||
while (nanosleep(&waitTime, &waitTime));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,29 @@ proc test-exec {{reptime 1000}} {
|
||||
}
|
||||
}
|
||||
|
||||
proc test-nrt-capability {{reptime 1000}} {
|
||||
proc test-exec-new {{reptime 1000}} {
|
||||
_test_run $reptime {
|
||||
# conditional update pure idle only (without window):
|
||||
{update -idle}
|
||||
# conditional update without idle events:
|
||||
{update -noidle}
|
||||
# conditional update timers only:
|
||||
{update -timer}
|
||||
# conditional update AIO only:
|
||||
{update -async}
|
||||
|
||||
# conditional vwait with zero timeout: pure idle only (without window):
|
||||
{vwait -idle 0 x}
|
||||
# conditional vwait with zero timeout: without idle events:
|
||||
{vwait -noidle 0 x}
|
||||
# conditional vwait with zero timeout: timers only:
|
||||
{vwait -timer 0 x}
|
||||
# conditional vwait with zero timeout: AIO only:
|
||||
{vwait -async 0 x}
|
||||
}
|
||||
}
|
||||
|
||||
proc test-nrt-capability-old {{reptime 1000}} {
|
||||
_test_run $reptime {
|
||||
# comparison values:
|
||||
{after 0 {set a 5}; update}
|
||||
@@ -143,6 +165,43 @@ proc test-nrt-capability {{reptime 1000}} {
|
||||
}
|
||||
}
|
||||
|
||||
proc test-nrt-capability {{reptime 1000}} {
|
||||
_test_run $reptime {
|
||||
# comparison values:
|
||||
{after 0 {set a 5}; update}
|
||||
{after 0 {set a 5}; vwait a}
|
||||
|
||||
# conditional vwait with very brief wait-time:
|
||||
{vwait 1 a}
|
||||
{vwait 0.5 a}
|
||||
{vwait 0.2 a}
|
||||
{vwait 0.1 a}
|
||||
{vwait 0.05 a}
|
||||
{vwait 0.02 a}
|
||||
{vwait 0.01 a}
|
||||
{vwait 0.005 a}
|
||||
{vwait 0.001 a}
|
||||
|
||||
# NRT sleep / very brief delays (0.5 - 0.005):
|
||||
{after 0.5}
|
||||
{after 0.05}
|
||||
{after 0.005}
|
||||
# NRT sleep / very brief delays (0.1 - 0.001):
|
||||
{after 0.1}
|
||||
{after 0.01}
|
||||
{after 0.001}
|
||||
|
||||
# comparison of update's executing event:
|
||||
{after idle {set a 5}; update -idle -timer}
|
||||
{after 0 {set a 5}; update -idle -timer}
|
||||
{after idle {set a 5}; update -idle}
|
||||
# comparison of vwait's executing event:
|
||||
{after idle {set a 5}; vwait -idle -timer a}
|
||||
{after 0 {set a 5}; vwait -idle -timer a}
|
||||
{after idle {set a 5}; vwait -idle a}
|
||||
}
|
||||
}
|
||||
|
||||
proc test-long {{reptime 1000}} {
|
||||
_test_run $reptime {
|
||||
# in-between important event by amount of idle events:
|
||||
@@ -159,7 +218,12 @@ proc test {{reptime 1000}} {
|
||||
foreach howmuch {5000 50000} {
|
||||
test-access [list $reptime $howmuch]
|
||||
}
|
||||
test-nrt-capability $reptime
|
||||
if {![catch {update -noidle}]} {
|
||||
test-exec-new $reptime
|
||||
test-nrt-capability $reptime
|
||||
} else {
|
||||
test-nrt-capability-old $reptime
|
||||
}
|
||||
test-long $reptime
|
||||
|
||||
puts ""
|
||||
|
||||
+10
-9
@@ -1715,7 +1715,7 @@ test chan-io-14.9 {reuse of stdio special channels} -setup {
|
||||
# Added delay to give Windows time to stop the spawned process and clean
|
||||
# up its grip on the file test1. Added delete as proper test cleanup.
|
||||
# The failing tests were 18.1 and 18.2 as first re-users of file "test1".
|
||||
after [expr {[testConstraint win] ? 10000 : 500}]
|
||||
after [expr {[testConstraint win] ? 1000 : 500}]
|
||||
file delete $path(script)
|
||||
file delete $path(test1)
|
||||
} -result hello
|
||||
@@ -6969,17 +6969,17 @@ test chan-io-53.7 {CopyData: Flooding chan copy from pipe} -setup {
|
||||
set fcopyTestCount 0
|
||||
set f1 [open $path(pipe) w]
|
||||
chan puts $f1 {
|
||||
# Write 10 bytes / 10 msec
|
||||
# Write 10 bytes / 1 msec
|
||||
proc Write {count} {
|
||||
chan puts -nonewline "1234567890"
|
||||
if {[incr count -1]} {
|
||||
after 10 [list Write $count]
|
||||
after 1 [list Write $count]
|
||||
} else {
|
||||
set ::ready 1
|
||||
}
|
||||
}
|
||||
chan configure stdout -buffering none
|
||||
Write 345 ;# 3450 bytes ~3.45 sec
|
||||
Write 345 ;# 3450 bytes ~0.345 sec
|
||||
vwait ready
|
||||
exit 0
|
||||
}
|
||||
@@ -7089,11 +7089,11 @@ test chan-io-53.9 {CopyData: -size and event interaction, Bug 780533} -setup {
|
||||
chan puts $pipe {
|
||||
chan configure stdout -translation binary -buffering line
|
||||
chan puts stderr Waiting...
|
||||
after 1000
|
||||
after 100
|
||||
foreach x {a b c} {
|
||||
chan puts stderr Looping...
|
||||
chan puts $x
|
||||
after 500
|
||||
after 50
|
||||
}
|
||||
proc bye args {
|
||||
if {[chan gets stdin line]<0} {
|
||||
@@ -7221,7 +7221,10 @@ test chan-io-54.1 {Recursive channel events} {socket fileevent} {
|
||||
lappend result $next
|
||||
if {$next == 1} {
|
||||
chan event $s readable [namespace code [list readit $s 2]]
|
||||
vwait [namespace which -variable x]
|
||||
if {![vwait 2000 [namespace which -variable x]]} {
|
||||
set x failure
|
||||
error "timeout: too long wait"
|
||||
}
|
||||
}
|
||||
incr x
|
||||
}
|
||||
@@ -7250,9 +7253,7 @@ test chan-io-54.1 {Recursive channel events} {socket fileevent} {
|
||||
lappend result [chan gets $cs]
|
||||
chan configure $cs -blocking off
|
||||
chan event $cs readable [namespace code [list readit $cs 1]]
|
||||
set a [after 2000 [namespace code { set x failure }]]
|
||||
vwait [namespace which -variable x]
|
||||
after cancel $a
|
||||
chan close $as
|
||||
chan close $ss
|
||||
chan close $cs
|
||||
|
||||
+240
-6
@@ -423,6 +423,38 @@ foo
|
||||
("after" script)
|
||||
}
|
||||
|
||||
test event-7.10 {after at - absolute time} {
|
||||
set result {}
|
||||
# 1st test simple delay (and mix generation / recursive processing)
|
||||
set attm [expr {[clock milliseconds]/1000.0 + 0.150}]
|
||||
after 0 {lappend result 1}
|
||||
after 100 {
|
||||
update; # this don't catch event 3
|
||||
lappend result 2a
|
||||
after at $attm; # delay to 150ms from start
|
||||
update; # this still don't catch event 3 also
|
||||
lappend result 2b
|
||||
after at [expr {$attm + 0.100}]; # delay to 250ms from start
|
||||
update; # this should catch event 3
|
||||
lappend result 2c
|
||||
}
|
||||
after 200 {lappend result 3; set a done}
|
||||
vwait a
|
||||
# 2nd test events "at" (mix due-times between relative/absolute events)
|
||||
lappend result --
|
||||
set sttm [expr {[clock milliseconds]/1000.0}]
|
||||
after 200 {lappend result 4; set a done}
|
||||
after 120 {lappend result 5}
|
||||
after 40 {lappend result 6}
|
||||
after at [expr {$sttm+0.160}] {lappend result at-1}
|
||||
after at [expr {$sttm+0.080}] {lappend result at-2}
|
||||
after at [expr {$sttm+0.005}] {lappend result at-3}
|
||||
after 2000 {lappend result [set a timeout]}
|
||||
after 0 {lappend result 7}
|
||||
vwait a
|
||||
set result
|
||||
} {1 2a 2b 3 2c -- 7 at-3 6 at-2 5 at-1 4}
|
||||
|
||||
# someday : add a test checking that when there is no bgerror, an error msg
|
||||
# goes to stderr ideally one would use sub interp and transfer a fake stderr
|
||||
# to it, unfortunatly the current interp tcl API does not allow that. The
|
||||
@@ -509,10 +541,10 @@ test event-10.1 {Tcl_Exit procedure} {stdio} {
|
||||
|
||||
test event-11.1 {Tcl_VwaitCmd procedure} -returnCodes error -body {
|
||||
vwait
|
||||
} -result {wrong # args: should be "vwait name"}
|
||||
} -result {wrong # args: should be "vwait ?options? ?timeout? name"}
|
||||
test event-11.2 {Tcl_VwaitCmd procedure} -returnCodes error -body {
|
||||
vwait a b
|
||||
} -result {wrong # args: should be "vwait name"}
|
||||
} -result {bad option "a": must be -idle, -noidle, -timer, -notimer, -file, -nofile, -window, -nowindow, -async, -noasync, -nowait, -wait, or idletasks}
|
||||
test event-11.3 {Tcl_VwaitCmd procedure} -setup {
|
||||
catch {unset x}
|
||||
} -body {
|
||||
@@ -539,6 +571,155 @@ test event-11.4 {Tcl_VwaitCmd procedure} -setup {
|
||||
after cancel $i
|
||||
}
|
||||
} -result {{} x-done y-done before q-done}
|
||||
test event-11.4.0 {vwait - interp limit precedence} {} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set result {}
|
||||
set i [interp create]
|
||||
$i bgerror {lappend errors}; # prevent stdout background errors;
|
||||
|
||||
# limit should be exceeded (wait infinite):
|
||||
$i limit time -milliseconds 0
|
||||
lappend result 1. [catch {$i eval {vwait x}} msg] $msg
|
||||
|
||||
# no limit in between:
|
||||
$i limit time -seconds {} -milliseconds {}
|
||||
lappend result 2. [catch {$i eval {vwait 0 x}} msg] $msg
|
||||
|
||||
# limit should be exceeded: (wait infinite)
|
||||
$i limit time -milliseconds 0
|
||||
lappend result 3. [catch {$i eval {vwait x}} msg] $msg
|
||||
# limit should be exceeded (wait too long - 1000ms):
|
||||
$i limit time -milliseconds 0
|
||||
lappend result 4. [catch {$i eval {vwait 1000 x}} msg] $msg
|
||||
|
||||
set tout [clock seconds]; incr tout 10
|
||||
# wait timeout (before limit):
|
||||
$i limit time -seconds $tout
|
||||
lappend result 5. [catch {$i eval {vwait 0 x}} msg] $msg
|
||||
# wait timeout (before limit):
|
||||
$i limit time -seconds $tout
|
||||
lappend result 6. [catch {$i eval {vwait 10 x}} msg] $msg
|
||||
|
||||
# wait successful (before limit):
|
||||
$i limit time -seconds $tout
|
||||
lappend result 7. [catch {$i eval {after 0 {set x ""}; vwait 10 x}} msg] $msg
|
||||
|
||||
interp delete $i
|
||||
set result
|
||||
} [list \
|
||||
1. 1 {limit exceeded} \
|
||||
2. 0 0 \
|
||||
3. 1 {limit exceeded} \
|
||||
4. 1 {limit exceeded} \
|
||||
5. 0 0 \
|
||||
6. 0 0 \
|
||||
7. 0 1 \
|
||||
]
|
||||
|
||||
test event-11.4.0 {vwait conditional with timeout (bypass timer)} {} {
|
||||
set x {}
|
||||
after 1000 {lappend x "error-too-slow"}
|
||||
after 0 {lappend x 1-timer}
|
||||
after 1 {lappend x 2-timer}
|
||||
after idle {lappend x 3-idle}
|
||||
vwait -async 50 x; # ignore all except async (timer also)
|
||||
lappend x 4-async
|
||||
vwait -idle 50 x; # ignore all except idle (timer also)
|
||||
lappend x 5-idle
|
||||
after idle {lappend x 6-idle}
|
||||
vwait 100 x; # now we accept timer events
|
||||
lappend x 7-idle
|
||||
vwait 100 x;
|
||||
# cleanup:
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set x
|
||||
} {4-async 3-idle 5-idle 1-timer 2-timer 7-idle 6-idle}
|
||||
|
||||
test event-11.4.1 {vwait with timeout} {} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set z {}
|
||||
set x {}
|
||||
# success cases:
|
||||
after 0 {lappend z 0}
|
||||
after 50 {lappend x 1}
|
||||
after 50 {lappend x 2}
|
||||
after 250 {lappend x 3}
|
||||
after 1000 {lappend x "error-too-slow"}
|
||||
vwait 0 x; # no-wait
|
||||
lappend z $x; # 0 {} - (x still empty)
|
||||
vwait 200 x; # wait up-to 200ms
|
||||
lappend z $x; # 0 {} {1 2}
|
||||
vwait x; # infinite wait
|
||||
lappend z $x; # 0 {} {1 2} {1 2 3}
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set z
|
||||
} {0 {} {1 2} {1 2 3}}
|
||||
|
||||
test event-11.4.2 {cancel} {} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set x {}
|
||||
# success cases:
|
||||
after 10 {lappend x 1}
|
||||
after 10 {lappend x 2}
|
||||
after 10 {lappend x 3}
|
||||
# cancel via object representation (4-6) and searching by id (7-9):
|
||||
foreach i [list \
|
||||
[after 0 {lappend x 4-unexpected}] \
|
||||
[after 5 {lappend x 5-unexpected}] \
|
||||
[after 10 {lappend x 6-unexpected}] \
|
||||
[string trim " [after 0 {lappend x 7-unexpected}] "] \
|
||||
[string trim " [after 5 {lappend x 8-unexpected}] "] \
|
||||
[string trim " [after 10 {lappend x 9-unexpected}] "] \
|
||||
] {
|
||||
after cancel $i
|
||||
}
|
||||
after 20 {set y done}
|
||||
list [vwait y] $x $y
|
||||
} {{} {1 2 3} done}
|
||||
|
||||
test event-11.4.3 {cancel twice and info} {} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set x {}
|
||||
# success cases:
|
||||
after 10 {lappend x 1}
|
||||
after 10 {lappend x 2}
|
||||
after 10 {lappend x 3}
|
||||
# cancel via object representation (4-6) and searching by id (7-9):
|
||||
foreach i [list \
|
||||
[after 0 {lappend x 4-unexpected}] \
|
||||
[after 5 {lappend x 5-unexpected}] \
|
||||
[after 10 {lappend x 6-unexpected}] \
|
||||
[string trim " [after 0 {lappend x 7-unexpected}] "] \
|
||||
[string trim " [after 5 {lappend x 8-unexpected}] "] \
|
||||
[string trim " [after 10 {lappend x 9-unexpected}] "] \
|
||||
] {
|
||||
after cancel $i
|
||||
# just to test possible segfault:
|
||||
after cancel $i
|
||||
if {![catch {after info $i} i]} {; # unexpected (event doesn't exist)
|
||||
error "\"after info\" returns \"$i\" - should be an error"
|
||||
}
|
||||
}
|
||||
after 20 {set y done}
|
||||
list [vwait y] $x $y
|
||||
} {{} {1 2 3} done}
|
||||
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
|
||||
test event-11.5 {Tcl_VwaitCmd procedure: round robin scheduling, 2 sources} -setup {
|
||||
set test1file [makeFile "" test1]
|
||||
} -constraints {socket} -body {
|
||||
@@ -612,12 +793,9 @@ test event-11.8 {Bug 16828b3744} -setup {
|
||||
A destroy
|
||||
} -result {}
|
||||
|
||||
test event-12.1 {Tcl_UpdateCmd procedure} -returnCodes error -body {
|
||||
update a b
|
||||
} -result {wrong # args: should be "update ?idletasks?"}
|
||||
test event-12.2 {Tcl_UpdateCmd procedure} -returnCodes error -body {
|
||||
update bogus
|
||||
} -result {bad option "bogus": must be idletasks}
|
||||
} -result {bad option "bogus": must be -idle, -noidle, -timer, -notimer, -file, -nofile, -window, -nowindow, -async, -noasync, -nowait, -wait, or idletasks}
|
||||
test event-12.3 {Tcl_UpdateCmd procedure} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
@@ -657,6 +835,62 @@ test event-12.4 {Tcl_UpdateCmd procedure} -setup {
|
||||
}
|
||||
} -result {x-done before z-done}
|
||||
|
||||
test event-12.5 {update -idle, update -noidle} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set x {}
|
||||
after idle {lappend x idle}
|
||||
update -noidle
|
||||
after 0 {lappend x 0}
|
||||
update -noidle
|
||||
after 50 {lappend x 1}
|
||||
update -noidle
|
||||
lappend x 2
|
||||
update -idle
|
||||
lappend x 3
|
||||
after idle {lappend x idle}
|
||||
after 0 {lappend x 4}
|
||||
after 0 {lappend x 5}
|
||||
update -idle
|
||||
lappend x 6
|
||||
update
|
||||
lappend x res:[vwait 500 x]
|
||||
set x
|
||||
} {0 2 idle 3 idle 6 4 5 1 res:1}
|
||||
|
||||
test event-12.6 {update -timer, update -notimer} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
set x {}
|
||||
after idle {lappend x idle.0}
|
||||
update -timer
|
||||
after 0 {lappend x 0a}
|
||||
update -notimer
|
||||
after idle {
|
||||
lappend x idle.1a;
|
||||
after 0 {lappend x 0b};
|
||||
after idle {lappend x idle.1b}
|
||||
}
|
||||
after 50 {lappend x 1; after idle {lappend x idle.2}}
|
||||
update -timer
|
||||
lappend x 2
|
||||
update -timer -idle
|
||||
lappend x 3
|
||||
after idle {lappend x idle.3}
|
||||
after 0 {lappend x 4}
|
||||
after 0 {lappend x 5}
|
||||
update -timer -idle
|
||||
lappend x 6
|
||||
update
|
||||
lappend x res:[vwait 500 x]
|
||||
update -noidle
|
||||
lappend x 7
|
||||
update
|
||||
set x
|
||||
} {idle.0 0a 2 idle.1a 0b idle.1b 3 4 5 idle.3 6 1 res:1 7 idle.2}
|
||||
|
||||
test event-13.1 {Tcl_WaitForFile procedure, readable} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
|
||||
+16
-9
@@ -3590,24 +3590,31 @@ test interp-36.7 {SlaveBgerror sets error handler of slave [1999035]} -setup {
|
||||
interp create slave
|
||||
slave alias handler handler
|
||||
slave bgerror handler
|
||||
variable result {untouched}
|
||||
variable result {}
|
||||
proc handler {args} {
|
||||
variable result
|
||||
set result [lindex $args 0]
|
||||
variable result
|
||||
lappend result [lindex $args 0]
|
||||
}
|
||||
} -body {
|
||||
slave eval {
|
||||
variable done {}
|
||||
after 0 error foo
|
||||
after 10 [list ::set [namespace which -variable done] {}]
|
||||
vwait [namespace which -variable done]
|
||||
# because bgerror executed in background and it is idle-event, give enough
|
||||
# time to process it (resp. wait until last idle event is done).
|
||||
slave eval {; # via vwait
|
||||
after 0 error foo-1
|
||||
after 10 {after idle {set done {}}}
|
||||
vwait done
|
||||
}
|
||||
lappend result between
|
||||
slave eval {; # via update
|
||||
after 1 error foo-2
|
||||
after 10
|
||||
update
|
||||
}
|
||||
set result
|
||||
} -cleanup {
|
||||
variable result {}
|
||||
unset -nocomplain result
|
||||
interp delete slave
|
||||
} -result foo
|
||||
} -result {foo-1 between foo-2}
|
||||
|
||||
test interp-37.1 {safe interps and min() and max(): Bug 2895741} -setup {
|
||||
catch {interp delete a}
|
||||
|
||||
+15
-3
@@ -2905,7 +2905,8 @@ test io-29.33b {TIP#398, no implicit flush of nonblocking on exit} {exec} {
|
||||
close $ff
|
||||
expr {($t2-$t1)/2000 ? $t2-$t1 : 0}
|
||||
} 0
|
||||
test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMac fileevent} {
|
||||
|
||||
proc io-29.34 {wait} {
|
||||
variable c 0
|
||||
variable x running
|
||||
set l abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
|
||||
@@ -2934,14 +2935,25 @@ test io-29.34 {Tcl_Close, async flush on close, using sockets} {socket tempNotMa
|
||||
}
|
||||
set ss [socket -server [namespace code accept] -myaddr 127.0.0.1 0]
|
||||
set cs [socket 127.0.0.1 [lindex [fconfigure $ss -sockname] 2]]
|
||||
vwait [namespace which -variable x]
|
||||
{*}$wait [namespace which -variable x]
|
||||
if {$x ne "accepted"} {error "timeout, state: $x"}
|
||||
fconfigure $cs -blocking off
|
||||
writelots $cs $l
|
||||
close $cs
|
||||
close $ss
|
||||
vwait [namespace which -variable x]
|
||||
{*}$wait [namespace which -variable x]
|
||||
if {$x ne "done"} {error "timeout, state: $x"}
|
||||
set c
|
||||
}
|
||||
test io-29.34.1 {Tcl_Close, async flush on close, using sockets} {socket tempNotMac fileevent} {
|
||||
io-29.34 {vwait 5000}
|
||||
} 9000
|
||||
|
||||
test io-29.34.2 {same as io-29.34 / IO without timer events} {socket tempNotMac fileevent} {
|
||||
# this test will fail if IO uses timer event for scheduled execution.
|
||||
io-29.34 {vwait -notimer 5000}
|
||||
} 9000
|
||||
|
||||
test io-29.35 {Tcl_Close vs fileevent vs multiple interpreters} {socket tempNotMac fileevent} {
|
||||
# On Mac, this test screws up sockets such that subsequent tests using port 2828
|
||||
# either cause errors or panic().
|
||||
|
||||
+323
-142
@@ -17,23 +17,40 @@ if {[lsearch [namespace children] ::tcltest] == -1} {
|
||||
package require tcltest 2
|
||||
namespace import -force ::tcltest::*
|
||||
}
|
||||
# On some platforms the short tolerance (in percent to wait-time) used to avoid
|
||||
# busy waiting, so it may cause on the fast mashines, that waiting interupts a bit
|
||||
# earlier as expected ("rounded" to this tolerance boundary).
|
||||
#
|
||||
# Following routines guarantee the timer event always occured in such cases.
|
||||
variable tolerance 5
|
||||
proc tl-after {ms args} {
|
||||
variable tolerance
|
||||
uplevel [list after [expr {$ms + double($ms*$tolerance/100)}] {*}$args]
|
||||
}
|
||||
proc tl-vwait {args} {
|
||||
variable tolerance
|
||||
set ms [lindex $args end-1]
|
||||
set vn [lindex $args end]
|
||||
uplevel [list vwait [expr {$ms + double($ms*$tolerance/100)}] {*}[lrange $args 0 end-2] $vn]
|
||||
}
|
||||
|
||||
test timer-1.1 {Tcl_CreateTimerHandler procedure} -setup {
|
||||
proc clean-up-events {} {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
}
|
||||
|
||||
test timer-1.1 {Tcl_CreateTimerHandler procedure} -setup {
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x ""
|
||||
foreach i {100 200 1000 50 150} {
|
||||
after $i lappend x $i
|
||||
}
|
||||
after 200 set done 1
|
||||
vwait done
|
||||
tl-vwait 200 done
|
||||
return $x
|
||||
} -cleanup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -result {50 100 150 200}
|
||||
|
||||
test timer-2.1 {Tcl_DeleteTimerHandler procedure} -setup {
|
||||
@@ -47,8 +64,7 @@ test timer-2.1 {Tcl_DeleteTimerHandler procedure} -setup {
|
||||
}
|
||||
after cancel lappend x 150
|
||||
after cancel lappend x 50
|
||||
after 200 set done 1
|
||||
vwait done
|
||||
tl-vwait 200 done
|
||||
return $x
|
||||
} -result {100 200}
|
||||
|
||||
@@ -65,70 +81,60 @@ test timer-3.1 {TimerHandlerEventProc procedure: event masks} {
|
||||
lappend result $x
|
||||
} {start fired}
|
||||
test timer-3.2 {TimerHandlerEventProc procedure: multiple timers} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
foreach i {200 600 1000} {
|
||||
after $i lappend x $i
|
||||
}
|
||||
after 200
|
||||
tl-after 200
|
||||
set result ""
|
||||
set x ""
|
||||
update
|
||||
lappend result $x
|
||||
after 400
|
||||
tl-after 400
|
||||
update
|
||||
lappend result $x
|
||||
after 400
|
||||
tl-after 400
|
||||
update
|
||||
lappend result $x
|
||||
} -result {200 {200 600} {200 600 1000}}
|
||||
test timer-3.3 {TimerHandlerEventProc procedure: reentrant timer deletion} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x {}
|
||||
after 100 lappend x 100
|
||||
set i [after 300 lappend x 300]
|
||||
after 200 after cancel $i
|
||||
after 400
|
||||
tl-after 400
|
||||
update
|
||||
return $x
|
||||
} -result 100
|
||||
test timer-3.4 {TimerHandlerEventProc procedure: all expired timers fire} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x {}
|
||||
after 100 lappend x a
|
||||
after 200 lappend x b
|
||||
after 300 lappend x c
|
||||
after 300
|
||||
tl-after 300
|
||||
vwait x
|
||||
return $x
|
||||
} -result {a b c}
|
||||
test timer-3.5 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x {}
|
||||
after 100 {lappend x a; after 0 lappend x b}
|
||||
after 100
|
||||
after 10 {lappend x a; after 0 lappend x b}
|
||||
after 50
|
||||
vwait x
|
||||
return $x
|
||||
} -result a
|
||||
test timer-3.6 {TimerHandlerEventProc procedure: reentrantly added timers don't fire} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x {}
|
||||
after 100 {lappend x a; after 100 lappend x b; after 100}
|
||||
after 100
|
||||
tl-after 100
|
||||
vwait x
|
||||
set result $x
|
||||
vwait x
|
||||
@@ -139,9 +145,7 @@ test timer-3.6 {TimerHandlerEventProc procedure: reentrantly added timers don't
|
||||
# below.
|
||||
|
||||
test timer-4.1 {Tcl_CancelIdleCall procedure} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x before
|
||||
set y before
|
||||
@@ -154,9 +158,7 @@ test timer-4.1 {Tcl_CancelIdleCall procedure} -setup {
|
||||
list $x $y $z
|
||||
} -result {after1 before after3}
|
||||
test timer-4.2 {Tcl_CancelIdleCall procedure} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x before
|
||||
set y before
|
||||
@@ -170,9 +172,7 @@ test timer-4.2 {Tcl_CancelIdleCall procedure} -setup {
|
||||
} -result {before after2 after3}
|
||||
|
||||
test timer-5.1 {Tcl_ServiceIdle, self-rescheduling handlers} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x 1
|
||||
set y 23
|
||||
@@ -189,27 +189,34 @@ test timer-6.1 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
|
||||
} -result {wrong # args: should be "after option ?arg ...?"}
|
||||
test timer-6.2 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
|
||||
after 2x
|
||||
} -result {bad argument "2x": must be cancel, idle, info, or an integer}
|
||||
} -result {bad argument "2x": must be at, cancel, idle, info or a time}
|
||||
test timer-6.3 {Tcl_AfterCmd procedure, basics} -returnCodes error -body {
|
||||
after gorp
|
||||
} -result {bad argument "gorp": must be cancel, idle, info, or an integer}
|
||||
} -result {bad argument "gorp": must be at, cancel, idle, info or a time}
|
||||
test timer-6.4 {Tcl_AfterCmd procedure, ms argument} {
|
||||
set x before
|
||||
after 400 {set x after}
|
||||
# cover prompt events also (immediate handling differs now):
|
||||
after 0 {lappend x immediate}
|
||||
lappend x before-immediate
|
||||
update
|
||||
lappend x after-immediate
|
||||
after 100 {lappend x after}
|
||||
after 10
|
||||
update
|
||||
lappend x nothing
|
||||
after 200
|
||||
lappend x before-after
|
||||
update
|
||||
set y $x
|
||||
after 400
|
||||
update
|
||||
list $y $x
|
||||
} {before after}
|
||||
lappend x after-after
|
||||
set x
|
||||
} {before before-immediate immediate after-immediate nothing before-after after after-after}
|
||||
test timer-6.5 {Tcl_AfterCmd procedure, ms argument} {
|
||||
set x before
|
||||
after 400 set x after
|
||||
after 200
|
||||
after 100 set x after
|
||||
after 10
|
||||
update
|
||||
set y $x
|
||||
after 400
|
||||
after 200
|
||||
update
|
||||
list $y $x
|
||||
} {before after}
|
||||
@@ -223,50 +230,42 @@ test timer-6.8 {Tcl_AfterCmd procedure, cancel option} {
|
||||
after cancel {foo bar}
|
||||
} {}
|
||||
test timer-6.9 {Tcl_AfterCmd procedure, cancel option} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x before
|
||||
set y [after 100 set x after]
|
||||
set y [after 10 set x after]
|
||||
after cancel $y
|
||||
after 200
|
||||
after 100
|
||||
update
|
||||
return $x
|
||||
} -result {before}
|
||||
test timer-6.10 {Tcl_AfterCmd procedure, cancel option} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x before
|
||||
after 100 set x after
|
||||
after 10 set x after
|
||||
after cancel {set x after}
|
||||
after 200
|
||||
after 100
|
||||
update
|
||||
return $x
|
||||
} -result {before}
|
||||
test timer-6.11 {Tcl_AfterCmd procedure, cancel option} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x before
|
||||
after 100 set x after
|
||||
set id [after 300 set x after]
|
||||
after 10 set x after-10
|
||||
set id [after 30 set x after-30]
|
||||
after cancel $id
|
||||
after 200
|
||||
after 100
|
||||
update
|
||||
set y $x
|
||||
set x cleared
|
||||
after 200
|
||||
after 100
|
||||
update
|
||||
list $y $x
|
||||
} -result {after cleared}
|
||||
} -result {after-10 cleared}
|
||||
test timer-6.12 {Tcl_AfterCmd procedure, cancel option} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x first
|
||||
after idle lappend x second
|
||||
@@ -278,9 +277,7 @@ test timer-6.12 {Tcl_AfterCmd procedure, cancel option} -setup {
|
||||
return $x
|
||||
} -result {first third}
|
||||
test timer-6.13 {Tcl_AfterCmd procedure, cancel option, multiple arguments for command} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x first
|
||||
after idle lappend x second
|
||||
@@ -292,22 +289,19 @@ test timer-6.13 {Tcl_AfterCmd procedure, cancel option, multiple arguments for c
|
||||
return $x
|
||||
} -result {first third}
|
||||
test timer-6.14 {Tcl_AfterCmd procedure, cancel option, cancel during handler, used to dump core} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set id [
|
||||
after 100 {
|
||||
after 10 {
|
||||
set x done
|
||||
after cancel $id
|
||||
after idle {set y done}
|
||||
}
|
||||
]
|
||||
vwait x
|
||||
} -result {}
|
||||
list [tl-vwait 1000 x] [tl-vwait 100 y]
|
||||
} -result {1 1}
|
||||
test timer-6.15 {Tcl_AfterCmd procedure, cancel option, multiple interps} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
interp create x
|
||||
x eval {set a before; set b before; after idle {set a a-after};
|
||||
@@ -348,23 +342,47 @@ set childEvent [x eval {after idle event in child}]
|
||||
test timer-6.19 {Tcl_AfterCmd, info option} {
|
||||
lsort [after info]
|
||||
} [lsort "$event1 $event2"]
|
||||
test timer-6.19.1 {Tcl_AfterCmd, info option (all events in child)} {
|
||||
x eval {after info}
|
||||
} [list $childEvent]
|
||||
test timer-6.20 {Tcl_AfterCmd, info option} -returnCodes error -body {
|
||||
after info a b
|
||||
} -result {wrong # args: should be "after info ?id?"}
|
||||
test timer-6.21 {Tcl_AfterCmd, info option} -returnCodes error -body {
|
||||
after info $childEvent
|
||||
} -result "event \"$childEvent\" doesn't exist"
|
||||
test timer-6.21.1 {Tcl_AfterCmd, info option (internal representation)} {
|
||||
list [catch {x eval [list after info $childEvent]} msg] $msg
|
||||
} {0 {{event in child} idle}}
|
||||
test timer-6.21.1 {Tcl_AfterCmd, info option (internal representation)} {
|
||||
list [catch {x eval [list after info $childEvent]} msg] $msg
|
||||
} {0 {{event in child} idle}}
|
||||
test timer-6.21.2 {Tcl_AfterCmd, info option (search using string representation)} {
|
||||
list [catch {x eval [list after info [string trim " $childEvent "]]} msg] $msg
|
||||
} {0 {{event in child} idle}}
|
||||
test timer-6.22 {Tcl_AfterCmd, info option} {
|
||||
list [after info $event1] [after info $event2]
|
||||
} {{{event 1} idle} {{event 2} timer}}
|
||||
test timer-6.22.1 {Tcl_AfterCmd, cancel option (internal representation)} {
|
||||
after cancel $childEvent; # foreign event - does nothing
|
||||
# check still available:
|
||||
list [catch {x eval [list after info $childEvent]} msg] $msg
|
||||
} {0 {{event in child} idle}}
|
||||
test timer-6.22.2 {Tcl_AfterCmd, cancel option (search using string representation)} {
|
||||
after cancel [string trim " $childEvent "]; # foreign event - does nothing
|
||||
# check still available:
|
||||
set lst [list [catch {x eval [list after info $childEvent]} msg] $msg]
|
||||
# cancel again but in child:
|
||||
x eval [list after cancel [string trim " $childEvent "]]
|
||||
# check it was canceled:
|
||||
lappend lst {*}[list [catch {x eval [list after info $childEvent]} msg] $msg]
|
||||
} [list 0 {{event in child} idle} 1 "event \"$childEvent\" doesn't exist"]
|
||||
after cancel $event1
|
||||
after cancel $event2
|
||||
interp delete x
|
||||
|
||||
test timer-6.23 {Tcl_AfterCmd procedure, no option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
after 1 "set x ab\0cd"
|
||||
@@ -373,9 +391,7 @@ test timer-6.23 {Tcl_AfterCmd procedure, no option, script with NUL} -setup {
|
||||
string length $x
|
||||
} -result {5}
|
||||
test timer-6.24 {Tcl_AfterCmd procedure, no option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
after 1 set x ab\0cd
|
||||
@@ -384,37 +400,27 @@ test timer-6.24 {Tcl_AfterCmd procedure, no option, script with NUL} -setup {
|
||||
string length $x
|
||||
} -result {5}
|
||||
test timer-6.25 {Tcl_AfterCmd procedure, cancel option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
after 1 set x ab\0cd
|
||||
after cancel "set x ab\0ef"
|
||||
llength [after info]
|
||||
} -cleanup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -result {1}
|
||||
test timer-6.26 {Tcl_AfterCmd procedure, cancel option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
after 1 set x ab\0cd
|
||||
after cancel set x ab\0ef
|
||||
llength [after info]
|
||||
} -cleanup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -result {1}
|
||||
test timer-6.27 {Tcl_AfterCmd procedure, idle option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
after idle "set x ab\0cd"
|
||||
@@ -422,9 +428,7 @@ test timer-6.27 {Tcl_AfterCmd procedure, idle option, script with NUL} -setup {
|
||||
string length $x
|
||||
} -result {5}
|
||||
test timer-6.28 {Tcl_AfterCmd procedure, idle option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
after idle set x ab\0cd
|
||||
@@ -432,9 +436,7 @@ test timer-6.28 {Tcl_AfterCmd procedure, idle option, script with NUL} -setup {
|
||||
string length $x
|
||||
} -result {5}
|
||||
test timer-6.29 {Tcl_AfterCmd procedure, info option, script with NUL} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
set x "hello world"
|
||||
set id junk
|
||||
@@ -442,9 +444,7 @@ test timer-6.29 {Tcl_AfterCmd procedure, info option, script with NUL} -setup {
|
||||
update
|
||||
string length [lindex [lindex [after info $id] 0] 2]
|
||||
} -cleanup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -result 5
|
||||
|
||||
set event [after idle foo bar]
|
||||
@@ -473,8 +473,8 @@ test timer-8.1 {AfterProc procedure} {
|
||||
set x before
|
||||
proc foo {} {
|
||||
set x untouched
|
||||
after 100 {set x after}
|
||||
after 200
|
||||
after 10 {set x after}
|
||||
after 100
|
||||
update
|
||||
return $x
|
||||
}
|
||||
@@ -488,8 +488,8 @@ test timer-8.2 {AfterProc procedure} -setup {
|
||||
set handler [interp bgerror {}]
|
||||
interp bgerror {} [namespace which myHandler]
|
||||
} -body {
|
||||
after 100 {error "After error"}
|
||||
after 200
|
||||
after 10 {error "After error"}
|
||||
after 100
|
||||
set y $x
|
||||
update
|
||||
list $y $x
|
||||
@@ -500,9 +500,7 @@ test timer-8.2 {AfterProc procedure} -setup {
|
||||
"error "After error""
|
||||
("after" script)}}}
|
||||
test timer-8.3 {AfterProc procedure, deleting handler from itself} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
proc foo {} {
|
||||
global x
|
||||
@@ -513,14 +511,13 @@ test timer-8.3 {AfterProc procedure, deleting handler from itself} -setup {
|
||||
after cancel foo
|
||||
}
|
||||
after idle foo
|
||||
after 1000 {error "I shouldn't ever have executed"}
|
||||
after 0 {error "I shouldn't ever have executed"}
|
||||
update idletasks
|
||||
clean-up-events
|
||||
return $x
|
||||
} -result {{{error "I shouldn't ever have executed"} timer}}
|
||||
test timer-8.4 {AfterProc procedure, deleting handler from itself} -setup {
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
} -body {
|
||||
proc foo {} {
|
||||
global x
|
||||
@@ -530,15 +527,14 @@ test timer-8.4 {AfterProc procedure, deleting handler from itself} -setup {
|
||||
}
|
||||
after cancel foo
|
||||
}
|
||||
after 1000 {error "I shouldn't ever have executed"}
|
||||
after 0 {error "I shouldn't ever have executed"}
|
||||
after 1 {error "I also shouldn't ever have executed"}
|
||||
after idle foo
|
||||
update idletasks
|
||||
return $x
|
||||
} -result {{{error "I shouldn't ever have executed"} timer}}
|
||||
lsort $x
|
||||
} -result [lsort {{{error "I shouldn't ever have executed"} timer} {{error "I also shouldn't ever have executed"} timer}}]
|
||||
|
||||
foreach i [after info] {
|
||||
after cancel $i
|
||||
}
|
||||
clean-up-events
|
||||
|
||||
# No test for FreeAfterPtr, since it is already tested above.
|
||||
|
||||
@@ -546,23 +542,23 @@ test timer-9.1 {AfterCleanupProc procedure} -setup {
|
||||
catch {interp delete x}
|
||||
} -body {
|
||||
interp create x
|
||||
x eval {after 200 {
|
||||
x eval {after 10 {
|
||||
lappend x after
|
||||
puts "part 1: this message should not appear"
|
||||
}}
|
||||
after 200 {lappend x after2}
|
||||
x eval {after 200 {
|
||||
after 10 {lappend x after2}
|
||||
x eval {after 10 {
|
||||
lappend x after3
|
||||
puts "part 2: this message should not appear"
|
||||
}}
|
||||
after 200 {lappend x after4}
|
||||
x eval {after 200 {
|
||||
after 10 {lappend x after4}
|
||||
x eval {after 10 {
|
||||
lappend x after5
|
||||
puts "part 3: this message should not appear"
|
||||
}}
|
||||
interp delete x
|
||||
set x before
|
||||
after 300
|
||||
after 100
|
||||
update
|
||||
return $x
|
||||
} -result {before after2 after4}
|
||||
@@ -579,15 +575,15 @@ test timer-10.1 {Bug 1016167: [after] overwrites imports} -setup {
|
||||
interp delete slave
|
||||
} -result ::after
|
||||
|
||||
test timer-11.1 {Bug 1350291: [after] overflowing 32-bit field} -body {
|
||||
test timer-11.1 {Bug 1350291: [after] overflowing 32-bit field} -setup {
|
||||
clean-up-events
|
||||
} -body {
|
||||
set b ok
|
||||
set a [after 0x100000001 {set b "after fired early"}]
|
||||
after 100 set done 1
|
||||
vwait done
|
||||
return $b
|
||||
list [vwait 100 b] [set b]
|
||||
} -cleanup {
|
||||
catch {after cancel $a}
|
||||
} -result ok
|
||||
} -result {0 ok}
|
||||
test timer-11.2 {Bug 1350293: [after] negative argument} -body {
|
||||
set l {}
|
||||
after 100 {lappend l 100; set done 1}
|
||||
@@ -595,6 +591,191 @@ test timer-11.2 {Bug 1350293: [after] negative argument} -body {
|
||||
vwait done
|
||||
return $l
|
||||
} -result {-1 100}
|
||||
test timer-11.3 {[after] correct timer ordering (insert ahead)} -setup {
|
||||
clean-up-events
|
||||
} -body {
|
||||
after 10 {set done 1}
|
||||
foreach l {1 0.75 0.5 0.25 0.1 0} {
|
||||
after $l [list lappend l "ev:$l"]
|
||||
}
|
||||
set l {}
|
||||
vwait done
|
||||
set l
|
||||
} -result {ev:0 ev:0.1 ev:0.25 ev:0.5 ev:0.75 ev:1}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# timer-20.x --
|
||||
#
|
||||
# Following test-cases cover event-driven functionality during time-jump's
|
||||
#
|
||||
# Note: on some platforms it is only possible if the user has corresponding
|
||||
# privileges to change system date and time.
|
||||
#
|
||||
# Ex.: sudo LD_LIBRARY_PATH=. ./tclsh ../tests/timer.test -match timer-20.*
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
proc timejump {args} {
|
||||
set tnow [clock clicks]
|
||||
set tm [clock format [clock add [clock seconds] {*}$args] -format %H:%M:%S]
|
||||
#puts -nonewline "***[format \[%04X\] [pid]]*** jump to $tm ($args) "
|
||||
if {$::tcl_platform(platform) eq "windows"} {
|
||||
exec $::env(COMSPEC) /c time $tm
|
||||
} else {
|
||||
exec date +%T -s $tm
|
||||
}
|
||||
#puts "***[format \[%04X\] [pid]]*** [clock format [clock seconds] -format {%Y-%m-%d %H:%M:%S}] =="
|
||||
}
|
||||
|
||||
testConstraint ChangeTimePrivilege [expr {![catch { timejump 0 minutes }]}]
|
||||
testConstraint NewVWaitAfter [expr {![catch { vwait 0 nothing }]}]
|
||||
|
||||
# provide monotonic command, if "clock monotonic" not available (old core):
|
||||
if {![catch {::tcl::clock::monotonic}]} {
|
||||
namespace inscope ::tcl::clock {namespace export monotonic}
|
||||
namespace import ::tcl::clock::monotonic
|
||||
} else {
|
||||
proc monotonic {} {
|
||||
variable tickFactor
|
||||
# warming-up:
|
||||
clock clicks; clock microseconds
|
||||
# calc tick2usec factor:
|
||||
set tick [::tcl::clock::clicks]; set usec [::tcl::clock::microseconds]
|
||||
after 100
|
||||
set tickFactor [expr {double([::tcl::clock::clicks] - $tick) / ([::tcl::clock::microseconds] - $usec)}]
|
||||
proc monotonic {} {
|
||||
variable tickFactor
|
||||
expr {wide([::tcl::clock::clicks] / $tickFactor)}
|
||||
}
|
||||
monotonic
|
||||
}
|
||||
}
|
||||
# asynchronous function doing 3 time jumps (+1 min, +1 min, -2 minutes) in 250-ms:
|
||||
proc delayedtimejump {delay {async 1} {startms {}}} {
|
||||
# async code (executed in separate process):
|
||||
if {$async} {
|
||||
set code ""
|
||||
foreach pr {timejump delayedtimejump} {
|
||||
append code [list proc $pr [info args $pr] [info body $pr]] \n
|
||||
}
|
||||
append code "delayedtimejump $delay 0 [::tcl::clock::milliseconds]"
|
||||
exec [info nameofexecutable] << $code &
|
||||
return
|
||||
}
|
||||
# time-jumps (1st in 250-ms, 2nd and 3rd in given delay):
|
||||
set delay1 250
|
||||
if {$startms ne {}} {
|
||||
set delay1 [expr {250 - ([::tcl::clock::milliseconds] - $startms)}]
|
||||
if {$delay1 < 0} { set delay1 0 }
|
||||
}
|
||||
after $delay1; timejump +1 minutes
|
||||
after $delay; timejump +1 minutes
|
||||
after $delay; timejump -2 minutes
|
||||
}
|
||||
|
||||
proc test-timer-with-jump {code maxCount expMT {maxOffs 100}} {
|
||||
set mitm [set sttm [clock seconds]]
|
||||
set stmt [monotonic]
|
||||
set expMT [expr {$expMT * 1000}]
|
||||
set maxOffs [expr {$maxOffs * 1000}]
|
||||
set res {}
|
||||
set jumped 0
|
||||
for {set i 0} {$i < $maxCount} {incr i} {
|
||||
set rt [::tcl::clock::microseconds]
|
||||
set mt [monotonic]
|
||||
# execute:
|
||||
if 1 $code
|
||||
# verify monotonic time:
|
||||
set mt [expr {[monotonic] - $mt}]
|
||||
set rt [expr {[::tcl::clock::microseconds] - $rt}]
|
||||
# give +/- 100-ms for some slow or busy systems:
|
||||
if {$mt < $expMT - $maxOffs || $mt > $expMT + $maxOffs} {
|
||||
lappend res "$i. too large discrepancy mt: $mt ~ $expMT (rt: $rt)"
|
||||
} else {
|
||||
#lappend res "$i. debug, # mt: $mt, rt: $rt"
|
||||
}
|
||||
# be sure we are in the future and then comming back:
|
||||
if {$jumped > 2} break; # we are already back
|
||||
if {[clock seconds] - $mitm > 30 || [clock seconds] - $mitm < -30} {
|
||||
set mitm [clock seconds]
|
||||
incr jumped
|
||||
}
|
||||
}
|
||||
# wait for time-jump back (from the future):
|
||||
set future [clock add $sttm +30 seconds]
|
||||
set aftto [after 10000 {set tout 1}]
|
||||
while {[clock seconds] >= $future} {
|
||||
if {[vwait 100 tout]} {
|
||||
error "unexpected case: too long wait for time-reset."
|
||||
}
|
||||
}
|
||||
after cancel $aftto
|
||||
after 10
|
||||
# result:
|
||||
if {[llength $res]} {
|
||||
return [join $res \n]
|
||||
}
|
||||
return $jumped
|
||||
}
|
||||
|
||||
test timer-20.1 {time jump: after relative} {ChangeTimePrivilege} {
|
||||
delayedtimejump 250; # delayed time jump in 250-ms
|
||||
test-timer-with-jump {
|
||||
after 150 {set x 1}; vwait x
|
||||
} 20 150
|
||||
} 3
|
||||
|
||||
test timer-20.2 {time jump: vwait timeout} {ChangeTimePrivilege NewVWaitAfter} {
|
||||
delayedtimejump 250; # delayed time jump in 250-ms
|
||||
test-timer-with-jump {
|
||||
vwait -timer 150 nothing; # we want listen timer only
|
||||
} 20 150
|
||||
} 3
|
||||
|
||||
test timer-20.3 {time jump: simple sleep} {ChangeTimePrivilege} {
|
||||
delayedtimejump 250; # delayed time jump in 250-ms
|
||||
test-timer-with-jump {
|
||||
after 150
|
||||
} 20 150
|
||||
} 3
|
||||
|
||||
|
||||
# Increase delay between time-jumps (1.5s) for possible retarded reaction of
|
||||
# the notifier by absolute timers (retarded recognition of the time-jump so
|
||||
# the time can jump again (also backwards) without recognition.
|
||||
# Note also we cannot test absolute timers by the backwards time-jump.
|
||||
|
||||
test timer-20.4 {time jump: after absolute time - "after at real-time code"} {ChangeTimePrivilege NewVWaitAfter} {
|
||||
set sttm [clock seconds]
|
||||
set i 0
|
||||
foreach tm [list \
|
||||
[clock add $sttm +1 minute -2 second] \
|
||||
[clock add $sttm +2 minute -2 second] \
|
||||
] {
|
||||
after at $tm [list set x$i 1]
|
||||
incr i
|
||||
}
|
||||
delayedtimejump 1500; # delayed time jump in 1.5s
|
||||
test-timer-with-jump {
|
||||
# we want listen timer only:
|
||||
if {![vwait -timer 10000 x$i]} {
|
||||
error "too long wait for \"x$i\" (should be maximal 1 second)"
|
||||
}
|
||||
} 2 250 3000; # max 3 seconds difference (compared to 1 minute)
|
||||
} 2
|
||||
|
||||
test timer-20.5 {time jump: sleep to absolute time - "after at real-time"} {ChangeTimePrivilege NewVWaitAfter} {
|
||||
set sttm [clock seconds]
|
||||
set offsLst [list \
|
||||
[clock add $sttm +1 minute] \
|
||||
[clock add $sttm +2 minute] \
|
||||
]
|
||||
delayedtimejump 1500; # delayed time jump in 1.5s
|
||||
test-timer-with-jump {
|
||||
upvar offsLst offsLst
|
||||
after at [lindex $offsLst $i]
|
||||
} 2 250 3000; # max 3 seconds difference (compared to 1 minute)
|
||||
} 2
|
||||
|
||||
# cleanup
|
||||
::tcltest::cleanupTests
|
||||
|
||||
@@ -1,920 +0,0 @@
|
||||
#! /bin/bash
|
||||
# Generated by configure.
|
||||
# Run this file to recreate the current configuration.
|
||||
# Compiler output produced by configure, useful for debugging
|
||||
# configure, is in config.log if it exists.
|
||||
|
||||
debug=false
|
||||
ac_cs_recheck=false
|
||||
ac_cs_silent=false
|
||||
SHELL=${CONFIG_SHELL-/bin/bash}
|
||||
## --------------------- ##
|
||||
## M4sh Initialization. ##
|
||||
## --------------------- ##
|
||||
|
||||
# Be Bourne compatible
|
||||
if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
|
||||
emulate sh
|
||||
NULLCMD=:
|
||||
# Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
|
||||
# is contrary to our usage. Disable this feature.
|
||||
alias -g '${1+"$@"}'='"$@"'
|
||||
elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
|
||||
set -o posix
|
||||
fi
|
||||
DUALCASE=1; export DUALCASE # for MKS sh
|
||||
|
||||
# Support unset when possible.
|
||||
if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
|
||||
as_unset=unset
|
||||
else
|
||||
as_unset=false
|
||||
fi
|
||||
|
||||
|
||||
# Work around bugs in pre-3.0 UWIN ksh.
|
||||
$as_unset ENV MAIL MAILPATH
|
||||
PS1='$ '
|
||||
PS2='> '
|
||||
PS4='+ '
|
||||
|
||||
# NLS nuisances.
|
||||
for as_var in \
|
||||
LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \
|
||||
LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \
|
||||
LC_TELEPHONE LC_TIME
|
||||
do
|
||||
if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then
|
||||
eval $as_var=C; export $as_var
|
||||
else
|
||||
$as_unset $as_var
|
||||
fi
|
||||
done
|
||||
|
||||
# Required to use basename.
|
||||
if expr a : '\(a\)' >/dev/null 2>&1; then
|
||||
as_expr=expr
|
||||
else
|
||||
as_expr=false
|
||||
fi
|
||||
|
||||
if (basename /) >/dev/null 2>&1 && test "X`basename / 2>&1`" = "X/"; then
|
||||
as_basename=basename
|
||||
else
|
||||
as_basename=false
|
||||
fi
|
||||
|
||||
|
||||
# Name of the executable.
|
||||
as_me=`$as_basename "$0" ||
|
||||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
|
||||
X"$0" : 'X\(//\)$' \| \
|
||||
X"$0" : 'X\(/\)$' \| \
|
||||
. : '\(.\)' 2>/dev/null ||
|
||||
echo X/"$0" |
|
||||
sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
|
||||
/^X\/\(\/\/\)$/{ s//\1/; q; }
|
||||
/^X\/\(\/\).*/{ s//\1/; q; }
|
||||
s/.*/./; q'`
|
||||
|
||||
|
||||
# PATH needs CR, and LINENO needs CR and PATH.
|
||||
# Avoid depending upon Character Ranges.
|
||||
as_cr_letters='abcdefghijklmnopqrstuvwxyz'
|
||||
as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
|
||||
as_cr_Letters=$as_cr_letters$as_cr_LETTERS
|
||||
as_cr_digits='0123456789'
|
||||
as_cr_alnum=$as_cr_Letters$as_cr_digits
|
||||
|
||||
# The user is always right.
|
||||
if test "${PATH_SEPARATOR+set}" != set; then
|
||||
echo "#! /bin/sh" >conf$$.sh
|
||||
echo "exit 0" >>conf$$.sh
|
||||
chmod +x conf$$.sh
|
||||
if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
|
||||
PATH_SEPARATOR=';'
|
||||
else
|
||||
PATH_SEPARATOR=:
|
||||
fi
|
||||
rm -f conf$$.sh
|
||||
fi
|
||||
|
||||
|
||||
as_lineno_1=103
|
||||
as_lineno_2=104
|
||||
as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
|
||||
test "x$as_lineno_1" != "x$as_lineno_2" &&
|
||||
test "x$as_lineno_3" = "x$as_lineno_2" || {
|
||||
# Find who we are. Look in the path if we contain no path at all
|
||||
# relative or not.
|
||||
case $0 in
|
||||
*[\\/]* ) as_myself=$0 ;;
|
||||
*) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in $PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
|
||||
done
|
||||
|
||||
;;
|
||||
esac
|
||||
# We did not find ourselves, most probably we were run as `sh COMMAND'
|
||||
# in which case we are not to be found in the path.
|
||||
if test "x$as_myself" = x; then
|
||||
as_myself=$0
|
||||
fi
|
||||
if test ! -f "$as_myself"; then
|
||||
{ { echo "$as_me:128: error: cannot find myself; rerun with an absolute path" >&5
|
||||
echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi
|
||||
case $CONFIG_SHELL in
|
||||
'')
|
||||
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
|
||||
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
|
||||
do
|
||||
IFS=$as_save_IFS
|
||||
test -z "$as_dir" && as_dir=.
|
||||
for as_base in sh bash ksh sh5; do
|
||||
case $as_dir in
|
||||
/*)
|
||||
if ("$as_dir/$as_base" -c '
|
||||
as_lineno_1=143
|
||||
as_lineno_2=144
|
||||
as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
|
||||
test "x$as_lineno_1" != "x$as_lineno_2" &&
|
||||
test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
|
||||
$as_unset BASH_ENV || test "${BASH_ENV+set}" != set || { BASH_ENV=; export BASH_ENV; }
|
||||
$as_unset ENV || test "${ENV+set}" != set || { ENV=; export ENV; }
|
||||
CONFIG_SHELL=$as_dir/$as_base
|
||||
export CONFIG_SHELL
|
||||
exec "$CONFIG_SHELL" "$0" ${1+"$@"}
|
||||
fi;;
|
||||
esac
|
||||
done
|
||||
done
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create $as_me.lineno as a copy of $as_myself, but with 160
|
||||
# uniformly replaced by the line number. The first 'sed' inserts a
|
||||
# line-number line before each line; the second 'sed' does the real
|
||||
# work. The second script uses 'N' to pair each line-number line
|
||||
# with the numbered line, and appends trailing '-' during
|
||||
# substitution so that 165 is not a special case at line end.
|
||||
# (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
|
||||
# second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
|
||||
sed '=' <$as_myself |
|
||||
sed '
|
||||
N
|
||||
s,$,-,
|
||||
: loop
|
||||
s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
|
||||
t loop
|
||||
s,-$,,
|
||||
s,^['$as_cr_digits']*\n,,
|
||||
' >$as_me.lineno &&
|
||||
chmod +x $as_me.lineno ||
|
||||
{ { echo "$as_me:179: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
|
||||
echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
|
||||
# Don't try to exec as it changes $[0], causing all sort of problems
|
||||
# (the dirname of $[0] is not the place where we might find the
|
||||
# original and so on. Autoconf is especially sensible to this).
|
||||
. ./$as_me.lineno
|
||||
# Exit status is that of the last command.
|
||||
exit
|
||||
}
|
||||
|
||||
|
||||
case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
|
||||
*c*,-n*) ECHO_N= ECHO_C='
|
||||
' ECHO_T=' ' ;;
|
||||
*c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
|
||||
*) ECHO_N= ECHO_C='\c' ECHO_T= ;;
|
||||
esac
|
||||
|
||||
if expr a : '\(a\)' >/dev/null 2>&1; then
|
||||
as_expr=expr
|
||||
else
|
||||
as_expr=false
|
||||
fi
|
||||
|
||||
rm -f conf$$ conf$$.exe conf$$.file
|
||||
echo >conf$$.file
|
||||
if ln -s conf$$.file conf$$ 2>/dev/null; then
|
||||
# We could just check for DJGPP; but this test a) works b) is more generic
|
||||
# and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
|
||||
if test -f conf$$.exe; then
|
||||
# Don't use ln at all; we don't have any links
|
||||
as_ln_s='cp -p'
|
||||
else
|
||||
as_ln_s='ln -s'
|
||||
fi
|
||||
elif ln conf$$.file conf$$ 2>/dev/null; then
|
||||
as_ln_s=ln
|
||||
else
|
||||
as_ln_s='cp -p'
|
||||
fi
|
||||
rm -f conf$$ conf$$.exe conf$$.file
|
||||
|
||||
if mkdir -p . 2>/dev/null; then
|
||||
as_mkdir_p=:
|
||||
else
|
||||
test -d ./-p && rmdir ./-p
|
||||
as_mkdir_p=false
|
||||
fi
|
||||
|
||||
as_executable_p="test -f"
|
||||
|
||||
# Sed expression to map a string onto a valid CPP name.
|
||||
as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
|
||||
|
||||
# Sed expression to map a string onto a valid variable name.
|
||||
as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
|
||||
|
||||
|
||||
# IFS
|
||||
# We need space, tab and new line, in precisely that order.
|
||||
as_nl='
|
||||
'
|
||||
IFS=" $as_nl"
|
||||
|
||||
# CDPATH.
|
||||
$as_unset CDPATH
|
||||
|
||||
exec 6>&1
|
||||
|
||||
# Open the log real soon, to keep \$[0] and so on meaningful, and to
|
||||
# report actual input values of CONFIG_FILES etc. instead of their
|
||||
# values after options handling. Logging --version etc. is OK.
|
||||
exec 5>>config.log
|
||||
{
|
||||
echo
|
||||
sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
|
||||
## Running $as_me. ##
|
||||
_ASBOX
|
||||
} >&5
|
||||
cat >&5 <<_CSEOF
|
||||
|
||||
This file was extended by tcl $as_me 8.6, which was
|
||||
generated by GNU Autoconf 2.59. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
CONFIG_HEADERS = $CONFIG_HEADERS
|
||||
CONFIG_LINKS = $CONFIG_LINKS
|
||||
CONFIG_COMMANDS = $CONFIG_COMMANDS
|
||||
$ $0 $@
|
||||
|
||||
_CSEOF
|
||||
echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
|
||||
echo >&5
|
||||
config_files=" Makefile:../unix/Makefile.in dltest/Makefile:../unix/dltest/Makefile.in tclConfig.sh:../unix/tclConfig.sh.in tcl.pc:../unix/tcl.pc.in"
|
||||
|
||||
ac_cs_usage="\
|
||||
\`$as_me' instantiates files from templates according to the
|
||||
current configuration.
|
||||
|
||||
Usage: $0 [OPTIONS] [FILE]...
|
||||
|
||||
-h, --help print this help, then exit
|
||||
-V, --version print version number, then exit
|
||||
-q, --quiet do not print progress messages
|
||||
-d, --debug don't remove temporary files
|
||||
--recheck update $as_me by reconfiguring in the same conditions
|
||||
--file=FILE[:TEMPLATE]
|
||||
instantiate the configuration file FILE
|
||||
|
||||
Configuration files:
|
||||
$config_files
|
||||
|
||||
Configuration commands:
|
||||
$config_commands
|
||||
|
||||
Report bugs to <bug-autoconf@gnu.org>."
|
||||
ac_cs_version="\
|
||||
tcl config.status 8.6
|
||||
configured by ./configure, generated by GNU Autoconf 2.59,
|
||||
with options \"'--prefix=/home/jima/space/ins/lin64/dynamic/main'\"
|
||||
|
||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
||||
This config.status script is free software; the Free Software Foundation
|
||||
gives unlimited permission to copy, distribute and modify it."
|
||||
srcdir=/home/jima/space/bui/lin64/dynamic/main/tcl/unix
|
||||
# If no file are specified by the user, then we need to provide default
|
||||
# value. By we need to know if files were specified by the user.
|
||||
ac_need_defaults=:
|
||||
while test $# != 0
|
||||
do
|
||||
case $1 in
|
||||
--*=*)
|
||||
ac_option=`expr "x$1" : 'x\([^=]*\)='`
|
||||
ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
|
||||
ac_shift=:
|
||||
;;
|
||||
-*)
|
||||
ac_option=$1
|
||||
ac_optarg=$2
|
||||
ac_shift=shift
|
||||
;;
|
||||
*) # This is not an option, so the user has probably given explicit
|
||||
# arguments.
|
||||
ac_option=$1
|
||||
ac_need_defaults=false;;
|
||||
esac
|
||||
|
||||
case $ac_option in
|
||||
# Handling of the options.
|
||||
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
|
||||
ac_cs_recheck=: ;;
|
||||
--version | --vers* | -V )
|
||||
echo "$ac_cs_version"; exit 0 ;;
|
||||
--he | --h)
|
||||
# Conflict between --help and --header
|
||||
{ { echo "$as_me:336: error: ambiguous option: $1
|
||||
Try \`$0 --help' for more information." >&5
|
||||
echo "$as_me: error: ambiguous option: $1
|
||||
Try \`$0 --help' for more information." >&2;}
|
||||
{ (exit 1); exit 1; }; };;
|
||||
--help | --hel | -h )
|
||||
echo "$ac_cs_usage"; exit 0 ;;
|
||||
--debug | --d* | -d )
|
||||
debug=: ;;
|
||||
--file | --fil | --fi | --f )
|
||||
$ac_shift
|
||||
CONFIG_FILES="$CONFIG_FILES $ac_optarg"
|
||||
ac_need_defaults=false;;
|
||||
--header | --heade | --head | --hea )
|
||||
$ac_shift
|
||||
CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg"
|
||||
ac_need_defaults=false;;
|
||||
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
|
||||
| -silent | --silent | --silen | --sile | --sil | --si | --s)
|
||||
ac_cs_silent=: ;;
|
||||
|
||||
# This is an error.
|
||||
-*) { { echo "$as_me:358: error: unrecognized option: $1
|
||||
Try \`$0 --help' for more information." >&5
|
||||
echo "$as_me: error: unrecognized option: $1
|
||||
Try \`$0 --help' for more information." >&2;}
|
||||
{ (exit 1); exit 1; }; } ;;
|
||||
|
||||
*) ac_config_targets="$ac_config_targets $1" ;;
|
||||
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
ac_configure_extra_args=
|
||||
|
||||
if $ac_cs_silent; then
|
||||
exec 6>/dev/null
|
||||
ac_configure_extra_args="$ac_configure_extra_args --silent"
|
||||
fi
|
||||
|
||||
if $ac_cs_recheck; then
|
||||
echo "running /bin/bash ./configure " '--prefix=/home/jima/space/ins/lin64/dynamic/main' $ac_configure_extra_args " --no-create --no-recursion" >&6
|
||||
exec /bin/bash ./configure '--prefix=/home/jima/space/ins/lin64/dynamic/main' $ac_configure_extra_args --no-create --no-recursion
|
||||
fi
|
||||
|
||||
#
|
||||
# INIT-COMMANDS section.
|
||||
#
|
||||
|
||||
VERSION=8.6
|
||||
|
||||
for ac_config_target in $ac_config_targets
|
||||
do
|
||||
case "$ac_config_target" in
|
||||
# Handling of arguments.
|
||||
"Tcl-Info.plist" ) CONFIG_FILES="$CONFIG_FILES Tcl-Info.plist:../macosx/Tcl-Info.plist.in" ;;
|
||||
"Tclsh-Info.plist" ) CONFIG_FILES="$CONFIG_FILES Tclsh-Info.plist:../macosx/Tclsh-Info.plist.in" ;;
|
||||
"Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile:../unix/Makefile.in" ;;
|
||||
"dltest/Makefile" ) CONFIG_FILES="$CONFIG_FILES dltest/Makefile:../unix/dltest/Makefile.in" ;;
|
||||
"tclConfig.sh" ) CONFIG_FILES="$CONFIG_FILES tclConfig.sh:../unix/tclConfig.sh.in" ;;
|
||||
"tcl.pc" ) CONFIG_FILES="$CONFIG_FILES tcl.pc:../unix/tcl.pc.in" ;;
|
||||
"Tcl.framework" ) CONFIG_COMMANDS="$CONFIG_COMMANDS Tcl.framework" ;;
|
||||
*) { { echo "$as_me:399: error: invalid argument: $ac_config_target" >&5
|
||||
echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
|
||||
{ (exit 1); exit 1; }; };;
|
||||
esac
|
||||
done
|
||||
|
||||
# If the user did not use the arguments to specify the items to instantiate,
|
||||
# then the envvar interface is used. Set only those that are not.
|
||||
# We use the long form for the default assignment because of an extremely
|
||||
# bizarre bug on SunOS 4.1.3.
|
||||
if $ac_need_defaults; then
|
||||
test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
|
||||
test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
|
||||
fi
|
||||
|
||||
# Have a temporary directory for convenience. Make it in the build tree
|
||||
# simply because there is no reason to put it here, and in addition,
|
||||
# creating and moving files from /tmp can sometimes cause problems.
|
||||
# Create a temporary directory, and hook for its removal unless debugging.
|
||||
$debug ||
|
||||
{
|
||||
trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
|
||||
trap '{ (exit 1); exit 1; }' 1 2 13 15
|
||||
}
|
||||
|
||||
# Create a (secure) tmp directory for tmp files.
|
||||
|
||||
{
|
||||
tmp=`(umask 077 && mktemp -d -q "./confstatXXXXXX") 2>/dev/null` &&
|
||||
test -n "$tmp" && test -d "$tmp"
|
||||
} ||
|
||||
{
|
||||
tmp=./confstat$$-$RANDOM
|
||||
(umask 077 && mkdir $tmp)
|
||||
} ||
|
||||
{
|
||||
echo "$me: cannot create a temporary directory in ." >&2
|
||||
{ (exit 1); exit 1; }
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# CONFIG_FILES section.
|
||||
#
|
||||
|
||||
# No need to generate the scripts if there are no CONFIG_FILES.
|
||||
# This happens for instance when ./config.status config.h
|
||||
if test -n "$CONFIG_FILES"; then
|
||||
# Protect against being on the right side of a sed subst in config.status.
|
||||
sed 's/,@/@@/; s/@,/@@/; s/,;t t$/@;t t/; /@;t t$/s/[\\&,]/\\&/g;
|
||||
s/@@/,@/; s/@@/@,/; s/@;t t$/,;t t/' >$tmp/subs.sed <<\CEOF
|
||||
s,@SHELL@,/bin/bash,;t t
|
||||
s,@PATH_SEPARATOR@,:,;t t
|
||||
s,@PACKAGE_NAME@,tcl,;t t
|
||||
s,@PACKAGE_TARNAME@,tcl,;t t
|
||||
s,@PACKAGE_VERSION@,8.6,;t t
|
||||
s,@PACKAGE_STRING@,tcl 8.6,;t t
|
||||
s,@PACKAGE_BUGREPORT@,,;t t
|
||||
s,@exec_prefix@,/home/jima/space/ins/lin64/dynamic/main,;t t
|
||||
s,@prefix@,/home/jima/space/ins/lin64/dynamic/main,;t t
|
||||
s,@program_transform_name@,s,x,x,,;t t
|
||||
s,@bindir@,${exec_prefix}/bin,;t t
|
||||
s,@sbindir@,${exec_prefix}/sbin,;t t
|
||||
s,@libexecdir@,${exec_prefix}/libexec,;t t
|
||||
s,@datadir@,${prefix}/share,;t t
|
||||
s,@sysconfdir@,${prefix}/etc,;t t
|
||||
s,@sharedstatedir@,${prefix}/com,;t t
|
||||
s,@localstatedir@,${prefix}/var,;t t
|
||||
s,@libdir@,/home/jima/space/ins/lin64/dynamic/main/lib,;t t
|
||||
s,@includedir@,${prefix}/include,;t t
|
||||
s,@oldincludedir@,/usr/include,;t t
|
||||
s,@infodir@,${prefix}/info,;t t
|
||||
s,@mandir@,${prefix}/man,;t t
|
||||
s,@build_alias@,,;t t
|
||||
s,@host_alias@,,;t t
|
||||
s,@target_alias@,,;t t
|
||||
s,@DEFS@,-DPACKAGE_NAME=\"tcl\" -DPACKAGE_TARNAME=\"tcl\" -DPACKAGE_VERSION=\"8.6\" -DPACKAGE_STRING=\"tcl\ 8.6\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DHAVE_PTHREAD_ATTR_SETSTACKSIZE=1 -DHAVE_PTHREAD_ATFORK=1 -DTCL_THREADS=1 -DTCL_CFGVAL_ENCODING=\"iso8859-1\" -DHAVE_ZLIB=1 -DMODULE_SCOPE=extern\ __attribute__\(\(__visibility__\(\"hidden\"\)\)\) -DHAVE_HIDDEN=1 -DHAVE_CAST_TO_UNION=1 -DTCL_SHLIB_EXT=\".so\" -DNDEBUG=1 -DTCL_CFG_OPTIMIZED=1 -DTCL_TOMMATH=1 -DMP_PREC=4 -D_LARGEFILE64_SOURCE=1 -DTCL_WIDE_INT_IS_LONG=1 -DHAVE_GETCWD=1 -DHAVE_MKSTEMP=1 -DHAVE_OPENDIR=1 -DHAVE_STRTOL=1 -DHAVE_WAITPID=1 -DHAVE_GETNAMEINFO=1 -DHAVE_GETADDRINFO=1 -DHAVE_FREEADDRINFO=1 -DHAVE_GAI_STRERROR=1 -DHAVE_STRUCT_ADDRINFO=1 -DHAVE_STRUCT_IN6_ADDR=1 -DHAVE_STRUCT_SOCKADDR_IN6=1 -DHAVE_STRUCT_SOCKADDR_STORAGE=1 -DHAVE_GETPWUID_R_5=1 -DHAVE_GETPWUID_R=1 -DHAVE_GETPWNAM_R_5=1 -DHAVE_GETPWNAM_R=1 -DHAVE_GETGRGID_R_5=1 -DHAVE_GETGRGID_R=1 -DHAVE_GETGRNAM_R_5=1 -DHAVE_GETGRNAM_R=1 -DHAVE_GETHOSTBYNAME_R_6=1 -DHAVE_GETHOSTBYNAME_R=1 -DHAVE_GETHOSTBYADDR_R_8=1 -DHAVE_GETHOSTBYADDR_R=1 -DHAVE_TERMIOS_H=1 -DHAVE_SYS_IOCTL_H=1 -DHAVE_SYS_TIME_H=1 -DTIME_WITH_SYS_TIME=1 -DHAVE_GMTIME_R=1 -DHAVE_LOCALTIME_R=1 -DHAVE_MKTIME=1 -DHAVE_TM_GMTOFF=1 -DHAVE_TIMEZONE_VAR=1 -DHAVE_STRUCT_STAT_ST_BLOCKS=1 -DHAVE_STRUCT_STAT_ST_BLKSIZE=1 -DHAVE_BLKCNT_T=1 -DHAVE_INTPTR_T=1 -DHAVE_UINTPTR_T=1 -DNO_UNION_WAIT=1 -DHAVE_SIGNED_CHAR=1 -DHAVE_LANGINFO=1 -DHAVE_MKSTEMPS=1 -DHAVE_FTS=1 -DHAVE_SYS_IOCTL_H=1 -DTCL_UNLOAD_DLLS=1 -DHAVE_CPUID=1 ,;t t
|
||||
s,@ECHO_C@,,;t t
|
||||
s,@ECHO_N@,-n,;t t
|
||||
s,@ECHO_T@,,;t t
|
||||
s,@LIBS@,-lz -lpthread,;t t
|
||||
s,@MAN_FLAGS@,,;t t
|
||||
s,@CC@,gcc,;t t
|
||||
s,@CFLAGS@, -pipe ,;t t
|
||||
s,@LDFLAGS@, -Wl,--export-dynamic ,;t t
|
||||
s,@CPPFLAGS@,,;t t
|
||||
s,@ac_ct_CC@,gcc,;t t
|
||||
s,@EXEEXT@,,;t t
|
||||
s,@OBJEXT@,o,;t t
|
||||
s,@CPP@,gcc -E,;t t
|
||||
s,@EGREP@,grep -E,;t t
|
||||
s,@TCL_THREADS@,1,;t t
|
||||
s,@TCLSH_PROG@,/home/jima/space/ins/lin64/dynamic/main/bin/tclsh8.6,;t t
|
||||
s,@ZLIB_OBJS@,,;t t
|
||||
s,@ZLIB_SRCS@,,;t t
|
||||
s,@ZLIB_INCLUDE@,,;t t
|
||||
s,@RANLIB@,ranlib,;t t
|
||||
s,@ac_ct_RANLIB@,ranlib,;t t
|
||||
s,@AR@,ar,;t t
|
||||
s,@ac_ct_AR@,ar,;t t
|
||||
s,@LIBOBJS@,,;t t
|
||||
s,@TCL_LIBS@,-ldl -lz -lpthread -lieee -lm,;t t
|
||||
s,@DL_LIBS@,-ldl,;t t
|
||||
s,@DL_OBJS@,tclLoadDl.o,;t t
|
||||
s,@PLAT_OBJS@,,;t t
|
||||
s,@PLAT_SRCS@,,;t t
|
||||
s,@LDAIX_SRC@,,;t t
|
||||
s,@CFLAGS_DEBUG@,-g,;t t
|
||||
s,@CFLAGS_OPTIMIZE@,-O2,;t t
|
||||
s,@CFLAGS_WARNING@,-Wall,;t t
|
||||
s,@LDFLAGS_DEBUG@,,;t t
|
||||
s,@LDFLAGS_OPTIMIZE@,,;t t
|
||||
s,@CC_SEARCH_FLAGS@,-Wl,-rpath,${LIB_RUNTIME_DIR},;t t
|
||||
s,@LD_SEARCH_FLAGS@,-Wl,-rpath,${LIB_RUNTIME_DIR},;t t
|
||||
s,@STLIB_LD@,${AR} cr,;t t
|
||||
s,@SHLIB_LD@,${CC} ${CFLAGS} ${LDFLAGS} -shared,;t t
|
||||
s,@TCL_SHLIB_LD_EXTRAS@,,;t t
|
||||
s,@TK_SHLIB_LD_EXTRAS@,,;t t
|
||||
s,@SHLIB_LD_LIBS@,${LIBS},;t t
|
||||
s,@SHLIB_CFLAGS@,-fPIC,;t t
|
||||
s,@SHLIB_SUFFIX@,.so,;t t
|
||||
s,@MAKE_LIB@,${SHLIB_LD} -o $@ ${OBJS} ${SHLIB_LD_LIBS} ${TCL_SHLIB_LD_EXTRAS} ${TK_SHLIB_LD_EXTRAS} ${LD_SEARCH_FLAGS},;t t
|
||||
s,@MAKE_STUB_LIB@,${STLIB_LD} $@ ${STUB_LIB_OBJS} ; ${RANLIB} $@,;t t
|
||||
s,@INSTALL_LIB@,$(INSTALL_LIBRARY) $(LIB_FILE) "$(LIB_INSTALL_DIR)/$(LIB_FILE)",;t t
|
||||
s,@DLL_INSTALL_DIR@,$(LIB_INSTALL_DIR),;t t
|
||||
s,@INSTALL_STUB_LIB@,$(INSTALL_LIBRARY) $(STUB_LIB_FILE) "$(LIB_INSTALL_DIR)/$(STUB_LIB_FILE)",;t t
|
||||
s,@CFLAGS_DEFAULT@,$(CFLAGS_OPTIMIZE),;t t
|
||||
s,@LDFLAGS_DEFAULT@,$(LDFLAGS_OPTIMIZE),;t t
|
||||
s,@DTRACE@,,;t t
|
||||
s,@TCL_VERSION@,8.6,;t t
|
||||
s,@TCL_MAJOR_VERSION@,8,;t t
|
||||
s,@TCL_MINOR_VERSION@,6,;t t
|
||||
s,@TCL_PATCH_LEVEL@,.8,;t t
|
||||
s,@TCL_YEAR@,,;t t
|
||||
s,@PKG_CFG_ARGS@,'--prefix=/home/jima/space/ins/lin64/dynamic/main' ,;t t
|
||||
s,@TCL_LIB_FILE@,libtcl8.6.so,;t t
|
||||
s,@TCL_LIB_FLAG@,-ltcl8.6,;t t
|
||||
s,@TCL_LIB_SPEC@,-L/home/jima/space/ins/lin64/dynamic/main/lib -ltcl8.6,;t t
|
||||
s,@TCL_STUB_LIB_FILE@,libtclstub8.6.a,;t t
|
||||
s,@TCL_STUB_LIB_FLAG@,-ltclstub8.6,;t t
|
||||
s,@TCL_STUB_LIB_SPEC@,-L/home/jima/space/ins/lin64/dynamic/main/lib -ltclstub8.6,;t t
|
||||
s,@TCL_STUB_LIB_PATH@,/home/jima/space/ins/lin64/dynamic/main/lib/libtclstub8.6.a,;t t
|
||||
s,@TCL_INCLUDE_SPEC@,-I/home/jima/space/ins/lin64/dynamic/main/include,;t t
|
||||
s,@TCL_BUILD_STUB_LIB_SPEC@,-L/home/jima/space/bui/lin64/dynamic/main/tcl/unix -ltclstub8.6,;t t
|
||||
s,@TCL_BUILD_STUB_LIB_PATH@,/home/jima/space/bui/lin64/dynamic/main/tcl/unix/libtclstub8.6.a,;t t
|
||||
s,@TCL_SRC_DIR@,/home/jima/space/bui/lin64/dynamic/main/tcl,;t t
|
||||
s,@CFG_TCL_SHARED_LIB_SUFFIX@,${VERSION}.so,;t t
|
||||
s,@CFG_TCL_UNSHARED_LIB_SUFFIX@,${VERSION}.a,;t t
|
||||
s,@TCL_SHARED_BUILD@,1,;t t
|
||||
s,@LD_LIBRARY_PATH_VAR@,LD_LIBRARY_PATH,;t t
|
||||
s,@TCL_BUILD_LIB_SPEC@,-L/home/jima/space/bui/lin64/dynamic/main/tcl/unix -ltcl8.6,;t t
|
||||
s,@TCL_LIB_VERSIONS_OK@,ok,;t t
|
||||
s,@TCL_SHARED_LIB_SUFFIX@,${VERSION}${SHLIB_SUFFIX},;t t
|
||||
s,@TCL_UNSHARED_LIB_SUFFIX@,${VERSION}.a,;t t
|
||||
s,@TCL_HAS_LONGLONG@,,;t t
|
||||
s,@INSTALL_TZDATA@,,;t t
|
||||
s,@DTRACE_SRC@,,;t t
|
||||
s,@DTRACE_HDR@,,;t t
|
||||
s,@DTRACE_OBJ@,,;t t
|
||||
s,@MAKEFILE_SHELL@,/bin/sh,;t t
|
||||
s,@BUILD_DLTEST@,$(DLTEST_TARGETS),;t t
|
||||
s,@TCL_PACKAGE_PATH@,/home/jima/space/ins/lin64/dynamic/main/lib ,;t t
|
||||
s,@TCL_MODULE_PATH@,,;t t
|
||||
s,@TCL_LIBRARY@,$(prefix)/lib/tcl$(VERSION),;t t
|
||||
s,@PRIVATE_INCLUDE_DIR@,$(includedir),;t t
|
||||
s,@HTML_DIR@,$(DISTDIR)/html,;t t
|
||||
s,@PACKAGE_DIR@,/home/jima/space/ins/lin64/dynamic/main/lib,;t t
|
||||
s,@EXTRA_CC_SWITCHES@,,;t t
|
||||
s,@EXTRA_APP_CC_SWITCHES@,,;t t
|
||||
s,@EXTRA_INSTALL@,,;t t
|
||||
s,@EXTRA_INSTALL_BINARIES@,@:,;t t
|
||||
s,@EXTRA_BUILD_HTML@,@:,;t t
|
||||
s,@EXTRA_TCLSH_LIBS@,,;t t
|
||||
s,@DLTEST_LD@,${SHLIB_LD},;t t
|
||||
s,@DLTEST_SUFFIX@,,;t t
|
||||
CEOF
|
||||
|
||||
# Split the substitutions into bite-sized pieces for seds with
|
||||
# small command number limits, like on Digital OSF/1 and HP-UX.
|
||||
ac_max_sed_lines=48
|
||||
ac_sed_frag=1 # Number of current file.
|
||||
ac_beg=1 # First line for current file.
|
||||
ac_end=$ac_max_sed_lines # Line after last line for current file.
|
||||
ac_more_lines=:
|
||||
ac_sed_cmds=
|
||||
while $ac_more_lines; do
|
||||
if test $ac_beg -gt 1; then
|
||||
sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
|
||||
else
|
||||
sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
|
||||
fi
|
||||
if test ! -s $tmp/subs.frag; then
|
||||
ac_more_lines=false
|
||||
else
|
||||
# The purpose of the label and of the branching condition is to
|
||||
# speed up the sed processing (if there are no `@' at all, there
|
||||
# is no need to browse any of the substitutions).
|
||||
# These are the two extra sed commands mentioned above.
|
||||
(echo ':t
|
||||
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
|
||||
if test -z "$ac_sed_cmds"; then
|
||||
ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
|
||||
else
|
||||
ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
|
||||
fi
|
||||
ac_sed_frag=`expr $ac_sed_frag + 1`
|
||||
ac_beg=$ac_end
|
||||
ac_end=`expr $ac_end + $ac_max_sed_lines`
|
||||
fi
|
||||
done
|
||||
if test -z "$ac_sed_cmds"; then
|
||||
ac_sed_cmds=cat
|
||||
fi
|
||||
fi # test -n "$CONFIG_FILES"
|
||||
|
||||
for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
|
||||
# Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
|
||||
case $ac_file in
|
||||
- | *:- | *:-:* ) # input from stdin
|
||||
cat >$tmp/stdin
|
||||
ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
|
||||
ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
|
||||
*:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
|
||||
ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
|
||||
* ) ac_file_in=$ac_file.in ;;
|
||||
esac
|
||||
|
||||
# Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
|
||||
ac_dir=`(dirname "$ac_file") 2>/dev/null ||
|
||||
$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$ac_file" : 'X\(//\)[^/]' \| \
|
||||
X"$ac_file" : 'X\(//\)$' \| \
|
||||
X"$ac_file" : 'X\(/\)' \| \
|
||||
. : '\(.\)' 2>/dev/null ||
|
||||
echo X"$ac_file" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
|
||||
/^X\(\/\/\)[^/].*/{ s//\1/; q; }
|
||||
/^X\(\/\/\)$/{ s//\1/; q; }
|
||||
/^X\(\/\).*/{ s//\1/; q; }
|
||||
s/.*/./; q'`
|
||||
{ if $as_mkdir_p; then
|
||||
mkdir -p "$ac_dir"
|
||||
else
|
||||
as_dir="$ac_dir"
|
||||
as_dirs=
|
||||
while test ! -d "$as_dir"; do
|
||||
as_dirs="$as_dir $as_dirs"
|
||||
as_dir=`(dirname "$as_dir") 2>/dev/null ||
|
||||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$as_dir" : 'X\(//\)[^/]' \| \
|
||||
X"$as_dir" : 'X\(//\)$' \| \
|
||||
X"$as_dir" : 'X\(/\)' \| \
|
||||
. : '\(.\)' 2>/dev/null ||
|
||||
echo X"$as_dir" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
|
||||
/^X\(\/\/\)[^/].*/{ s//\1/; q; }
|
||||
/^X\(\/\/\)$/{ s//\1/; q; }
|
||||
/^X\(\/\).*/{ s//\1/; q; }
|
||||
s/.*/./; q'`
|
||||
done
|
||||
test ! -n "$as_dirs" || mkdir $as_dirs
|
||||
fi || { { echo "$as_me:660: error: cannot create directory \"$ac_dir\"" >&5
|
||||
echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
|
||||
{ (exit 1); exit 1; }; }; }
|
||||
|
||||
ac_builddir=.
|
||||
|
||||
if test "$ac_dir" != .; then
|
||||
ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
|
||||
# A "../" for each directory in $ac_dir_suffix.
|
||||
ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
|
||||
else
|
||||
ac_dir_suffix= ac_top_builddir=
|
||||
fi
|
||||
|
||||
case $srcdir in
|
||||
.) # No --srcdir option. We are building in place.
|
||||
ac_srcdir=.
|
||||
if test -z "$ac_top_builddir"; then
|
||||
ac_top_srcdir=.
|
||||
else
|
||||
ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
|
||||
fi ;;
|
||||
[\\/]* | ?:[\\/]* ) # Absolute path.
|
||||
ac_srcdir=$srcdir$ac_dir_suffix;
|
||||
ac_top_srcdir=$srcdir ;;
|
||||
*) # Relative path.
|
||||
ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
|
||||
ac_top_srcdir=$ac_top_builddir$srcdir ;;
|
||||
esac
|
||||
|
||||
# Do not use `cd foo && pwd` to compute absolute paths, because
|
||||
# the directories may not exist.
|
||||
case `pwd` in
|
||||
.) ac_abs_builddir="$ac_dir";;
|
||||
*)
|
||||
case "$ac_dir" in
|
||||
.) ac_abs_builddir=`pwd`;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
|
||||
*) ac_abs_builddir=`pwd`/"$ac_dir";;
|
||||
esac;;
|
||||
esac
|
||||
case $ac_abs_builddir in
|
||||
.) ac_abs_top_builddir=${ac_top_builddir}.;;
|
||||
*)
|
||||
case ${ac_top_builddir}. in
|
||||
.) ac_abs_top_builddir=$ac_abs_builddir;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
|
||||
*) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
|
||||
esac;;
|
||||
esac
|
||||
case $ac_abs_builddir in
|
||||
.) ac_abs_srcdir=$ac_srcdir;;
|
||||
*)
|
||||
case $ac_srcdir in
|
||||
.) ac_abs_srcdir=$ac_abs_builddir;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
|
||||
*) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
|
||||
esac;;
|
||||
esac
|
||||
case $ac_abs_builddir in
|
||||
.) ac_abs_top_srcdir=$ac_top_srcdir;;
|
||||
*)
|
||||
case $ac_top_srcdir in
|
||||
.) ac_abs_top_srcdir=$ac_abs_builddir;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
|
||||
*) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
if test x"$ac_file" != x-; then
|
||||
{ echo "$as_me:732: creating $ac_file" >&5
|
||||
echo "$as_me: creating $ac_file" >&6;}
|
||||
rm -f "$ac_file"
|
||||
fi
|
||||
# Let's still pretend it is `configure' which instantiates (i.e., don't
|
||||
# use $as_me), people would be surprised to read:
|
||||
# /* config.h. Generated by config.status. */
|
||||
if test x"$ac_file" = x-; then
|
||||
configure_input=
|
||||
else
|
||||
configure_input="$ac_file. "
|
||||
fi
|
||||
configure_input=$configure_input"Generated from `echo $ac_file_in |
|
||||
sed 's,.*/,,'` by configure."
|
||||
|
||||
# First look for the input files in the build tree, otherwise in the
|
||||
# src tree.
|
||||
ac_file_inputs=`IFS=:
|
||||
for f in $ac_file_in; do
|
||||
case $f in
|
||||
-) echo $tmp/stdin ;;
|
||||
[\\/$]*)
|
||||
# Absolute (can't be DOS-style, as IFS=:)
|
||||
test -f "$f" || { { echo "$as_me:755: error: cannot find input file: $f" >&5
|
||||
echo "$as_me: error: cannot find input file: $f" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
echo "$f";;
|
||||
*) # Relative
|
||||
if test -f "$f"; then
|
||||
# Build tree
|
||||
echo "$f"
|
||||
elif test -f "$srcdir/$f"; then
|
||||
# Source tree
|
||||
echo "$srcdir/$f"
|
||||
else
|
||||
# /dev/null tree
|
||||
{ { echo "$as_me:768: error: cannot find input file: $f" >&5
|
||||
echo "$as_me: error: cannot find input file: $f" >&2;}
|
||||
{ (exit 1); exit 1; }; }
|
||||
fi;;
|
||||
esac
|
||||
done` || { (exit 1); exit 1; }
|
||||
sed "
|
||||
|
||||
:t
|
||||
/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
|
||||
s,@configure_input@,$configure_input,;t t
|
||||
s,@srcdir@,$ac_srcdir,;t t
|
||||
s,@abs_srcdir@,$ac_abs_srcdir,;t t
|
||||
s,@top_srcdir@,$ac_top_srcdir,;t t
|
||||
s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
|
||||
s,@builddir@,$ac_builddir,;t t
|
||||
s,@abs_builddir@,$ac_abs_builddir,;t t
|
||||
s,@top_builddir@,$ac_top_builddir,;t t
|
||||
s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
|
||||
" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
|
||||
rm -f $tmp/stdin
|
||||
if test x"$ac_file" != x-; then
|
||||
mv $tmp/out $ac_file
|
||||
else
|
||||
cat $tmp/out
|
||||
rm -f $tmp/out
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
#
|
||||
# CONFIG_COMMANDS section.
|
||||
#
|
||||
for ac_file in : $CONFIG_COMMANDS; do test "x$ac_file" = x: && continue
|
||||
ac_dest=`echo "$ac_file" | sed 's,:.*,,'`
|
||||
ac_source=`echo "$ac_file" | sed 's,[^:]*:,,'`
|
||||
ac_dir=`(dirname "$ac_dest") 2>/dev/null ||
|
||||
$as_expr X"$ac_dest" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$ac_dest" : 'X\(//\)[^/]' \| \
|
||||
X"$ac_dest" : 'X\(//\)$' \| \
|
||||
X"$ac_dest" : 'X\(/\)' \| \
|
||||
. : '\(.\)' 2>/dev/null ||
|
||||
echo X"$ac_dest" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
|
||||
/^X\(\/\/\)[^/].*/{ s//\1/; q; }
|
||||
/^X\(\/\/\)$/{ s//\1/; q; }
|
||||
/^X\(\/\).*/{ s//\1/; q; }
|
||||
s/.*/./; q'`
|
||||
{ if $as_mkdir_p; then
|
||||
mkdir -p "$ac_dir"
|
||||
else
|
||||
as_dir="$ac_dir"
|
||||
as_dirs=
|
||||
while test ! -d "$as_dir"; do
|
||||
as_dirs="$as_dir $as_dirs"
|
||||
as_dir=`(dirname "$as_dir") 2>/dev/null ||
|
||||
$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
|
||||
X"$as_dir" : 'X\(//\)[^/]' \| \
|
||||
X"$as_dir" : 'X\(//\)$' \| \
|
||||
X"$as_dir" : 'X\(/\)' \| \
|
||||
. : '\(.\)' 2>/dev/null ||
|
||||
echo X"$as_dir" |
|
||||
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
|
||||
/^X\(\/\/\)[^/].*/{ s//\1/; q; }
|
||||
/^X\(\/\/\)$/{ s//\1/; q; }
|
||||
/^X\(\/\).*/{ s//\1/; q; }
|
||||
s/.*/./; q'`
|
||||
done
|
||||
test ! -n "$as_dirs" || mkdir $as_dirs
|
||||
fi || { { echo "$as_me:837: error: cannot create directory \"$ac_dir\"" >&5
|
||||
echo "$as_me: error: cannot create directory \"$ac_dir\"" >&2;}
|
||||
{ (exit 1); exit 1; }; }; }
|
||||
|
||||
ac_builddir=.
|
||||
|
||||
if test "$ac_dir" != .; then
|
||||
ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
|
||||
# A "../" for each directory in $ac_dir_suffix.
|
||||
ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
|
||||
else
|
||||
ac_dir_suffix= ac_top_builddir=
|
||||
fi
|
||||
|
||||
case $srcdir in
|
||||
.) # No --srcdir option. We are building in place.
|
||||
ac_srcdir=.
|
||||
if test -z "$ac_top_builddir"; then
|
||||
ac_top_srcdir=.
|
||||
else
|
||||
ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
|
||||
fi ;;
|
||||
[\\/]* | ?:[\\/]* ) # Absolute path.
|
||||
ac_srcdir=$srcdir$ac_dir_suffix;
|
||||
ac_top_srcdir=$srcdir ;;
|
||||
*) # Relative path.
|
||||
ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
|
||||
ac_top_srcdir=$ac_top_builddir$srcdir ;;
|
||||
esac
|
||||
|
||||
# Do not use `cd foo && pwd` to compute absolute paths, because
|
||||
# the directories may not exist.
|
||||
case `pwd` in
|
||||
.) ac_abs_builddir="$ac_dir";;
|
||||
*)
|
||||
case "$ac_dir" in
|
||||
.) ac_abs_builddir=`pwd`;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_builddir="$ac_dir";;
|
||||
*) ac_abs_builddir=`pwd`/"$ac_dir";;
|
||||
esac;;
|
||||
esac
|
||||
case $ac_abs_builddir in
|
||||
.) ac_abs_top_builddir=${ac_top_builddir}.;;
|
||||
*)
|
||||
case ${ac_top_builddir}. in
|
||||
.) ac_abs_top_builddir=$ac_abs_builddir;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_top_builddir=${ac_top_builddir}.;;
|
||||
*) ac_abs_top_builddir=$ac_abs_builddir/${ac_top_builddir}.;;
|
||||
esac;;
|
||||
esac
|
||||
case $ac_abs_builddir in
|
||||
.) ac_abs_srcdir=$ac_srcdir;;
|
||||
*)
|
||||
case $ac_srcdir in
|
||||
.) ac_abs_srcdir=$ac_abs_builddir;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_srcdir=$ac_srcdir;;
|
||||
*) ac_abs_srcdir=$ac_abs_builddir/$ac_srcdir;;
|
||||
esac;;
|
||||
esac
|
||||
case $ac_abs_builddir in
|
||||
.) ac_abs_top_srcdir=$ac_top_srcdir;;
|
||||
*)
|
||||
case $ac_top_srcdir in
|
||||
.) ac_abs_top_srcdir=$ac_abs_builddir;;
|
||||
[\\/]* | ?:[\\/]* ) ac_abs_top_srcdir=$ac_top_srcdir;;
|
||||
*) ac_abs_top_srcdir=$ac_abs_builddir/$ac_top_srcdir;;
|
||||
esac;;
|
||||
esac
|
||||
|
||||
|
||||
{ echo "$as_me:907: executing $ac_dest commands" >&5
|
||||
echo "$as_me: executing $ac_dest commands" >&6;}
|
||||
case $ac_dest in
|
||||
Tcl.framework ) n=Tcl &&
|
||||
f=$n.framework && v=Versions/$VERSION &&
|
||||
rm -rf $f && mkdir -p $f/$v/Resources &&
|
||||
ln -s $v/$n $v/Resources $f && ln -s ../../../$n $f/$v &&
|
||||
ln -s ../../../../$n-Info.plist $f/$v/Resources/Info.plist &&
|
||||
unset n f v
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
{ (exit 0); exit 0; }
|
||||
Vendored
+8
-5
@@ -17384,11 +17384,6 @@ cat >>confdefs.h <<\_ACEOF
|
||||
_ACEOF
|
||||
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define TCL_WIDE_CLICKS 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
for ac_header in AvailabilityMacros.h
|
||||
do
|
||||
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||
@@ -17694,6 +17689,14 @@ else
|
||||
DLTEST_SUFFIX=""
|
||||
fi
|
||||
|
||||
# Completelly supports on unix (linux/darwin)
|
||||
|
||||
cat >>confdefs.h <<\_ACEOF
|
||||
#define TCL_WIDE_CLICKS 1
|
||||
_ACEOF
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check for support of fts functions (readdir replacement)
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
+5
-2
@@ -565,8 +565,6 @@ if test "`uname -s`" = "Darwin" ; then
|
||||
[Are we to override what our default encoding is?])
|
||||
AC_DEFINE(TCL_LOAD_FROM_MEMORY, 1,
|
||||
[Can this platform load code from memory?])
|
||||
AC_DEFINE(TCL_WIDE_CLICKS, 1,
|
||||
[Does this platform have wide high-resolution clicks?])
|
||||
AC_CHECK_HEADERS(AvailabilityMacros.h)
|
||||
if test "$ac_cv_header_AvailabilityMacros_h" = yes; then
|
||||
AC_CACHE_CHECK([if weak import is available], tcl_cv_cc_weak_import, [
|
||||
@@ -614,6 +612,11 @@ else
|
||||
DLTEST_SUFFIX=""
|
||||
fi
|
||||
|
||||
# Completelly supports on unix (linux/darwin)
|
||||
AC_DEFINE(TCL_WIDE_CLICKS, 1,
|
||||
[Does this platform have wide high-resolution clicks?])
|
||||
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
# Check for support of fts functions (readdir replacement)
|
||||
#--------------------------------------------------------------------
|
||||
|
||||
@@ -12,79 +12,7 @@
|
||||
#include "tclInt.h"
|
||||
#ifndef HAVE_COREFOUNDATION /* Darwin/Mac OS X CoreFoundation notifier is
|
||||
* in tclMacOSXNotify.c */
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_Sleep --
|
||||
*
|
||||
* Delay execution for the specified number of milliseconds.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Time passes.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
Tcl_Sleep(
|
||||
int ms) /* Number of milliseconds to sleep. */
|
||||
{
|
||||
struct timeval delay;
|
||||
Tcl_Time before, after, vdelay;
|
||||
|
||||
/*
|
||||
* The only trick here is that select appears to return early under some
|
||||
* conditions, so we have to check to make sure that the right amount of
|
||||
* time really has elapsed. If it's too early, go back to sleep again.
|
||||
*/
|
||||
|
||||
Tcl_GetTime(&before);
|
||||
after = before;
|
||||
after.sec += ms/1000;
|
||||
after.usec += (ms%1000)*1000;
|
||||
if (after.usec > 1000000) {
|
||||
after.usec -= 1000000;
|
||||
after.sec += 1;
|
||||
}
|
||||
while (1) {
|
||||
/*
|
||||
* TIP #233: Scale from virtual time to real-time for select.
|
||||
*/
|
||||
|
||||
vdelay.sec = after.sec - before.sec;
|
||||
vdelay.usec = after.usec - before.usec;
|
||||
|
||||
if (vdelay.usec < 0) {
|
||||
vdelay.usec += 1000000;
|
||||
vdelay.sec -= 1;
|
||||
}
|
||||
|
||||
if ((vdelay.sec != 0) || (vdelay.usec != 0)) {
|
||||
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
|
||||
}
|
||||
|
||||
delay.tv_sec = vdelay.sec;
|
||||
delay.tv_usec = vdelay.usec;
|
||||
|
||||
/*
|
||||
* Special note: must convert delay.tv_sec to int before comparing to
|
||||
* zero, since delay.tv_usec is unsigned on some platforms.
|
||||
*/
|
||||
|
||||
if ((((int) delay.tv_sec) < 0)
|
||||
|| ((delay.tv_usec == 0) && (delay.tv_sec == 0))) {
|
||||
break;
|
||||
}
|
||||
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
|
||||
(SELECT_MASK *) 0, &delay);
|
||||
Tcl_GetTime(&before);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_COREFOUNDATION */
|
||||
/*
|
||||
* Local Variables:
|
||||
|
||||
+480
-283
@@ -102,9 +102,10 @@ typedef struct ThreadSpecificData {
|
||||
pthread_cond_t waitCV; /* Any other thread alerts a notifier that an
|
||||
* event is ready to be processed by signaling
|
||||
* this condition variable. */
|
||||
int waitCVMono; /* Mark wait monotonic based */
|
||||
#endif /* __CYGWIN__ */
|
||||
int waitCVinitialized; /* Variable to flag initialization of the structure */
|
||||
int eventReady; /* True if an event is ready to be processed.
|
||||
int eventReady; /* > 0 if an event is ready to be processed.
|
||||
* Used as condition flag together with waitCV
|
||||
* above. */
|
||||
#endif /* TCL_THREADS */
|
||||
@@ -324,68 +325,76 @@ StartNotifierThread(const char *proc)
|
||||
ClientData
|
||||
Tcl_InitNotifier(void)
|
||||
{
|
||||
if (tclNotifierHooks.initNotifierProc) {
|
||||
return tclNotifierHooks.initNotifierProc();
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
if (tclNotifierHooks.initNotifierProc) {
|
||||
return tclNotifierHooks.initNotifierProc();
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
pthread_condattr_t wcvAttr, *wcvAttrPtr = NULL;
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
tsdPtr->eventReady = 0;
|
||||
tsdPtr->eventReady = 0;
|
||||
|
||||
/*
|
||||
* Initialize thread specific condition variable for this thread.
|
||||
*/
|
||||
if (tsdPtr->waitCVinitialized == 0) {
|
||||
/*
|
||||
* Initialize thread specific condition variable for this thread.
|
||||
*/
|
||||
if (tsdPtr->waitCVinitialized == 0) {
|
||||
#ifdef __CYGWIN__
|
||||
WNDCLASS class;
|
||||
WNDCLASS class;
|
||||
|
||||
class.style = 0;
|
||||
class.cbClsExtra = 0;
|
||||
class.cbWndExtra = 0;
|
||||
class.hInstance = TclWinGetTclInstance();
|
||||
class.hbrBackground = NULL;
|
||||
class.lpszMenuName = NULL;
|
||||
class.lpszClassName = NotfyClassName;
|
||||
class.lpfnWndProc = NotifierProc;
|
||||
class.hIcon = NULL;
|
||||
class.hCursor = NULL;
|
||||
class.style = 0;
|
||||
class.cbClsExtra = 0;
|
||||
class.cbWndExtra = 0;
|
||||
class.hInstance = TclWinGetTclInstance();
|
||||
class.hbrBackground = NULL;
|
||||
class.lpszMenuName = NULL;
|
||||
class.lpszClassName = NotfyClassName;
|
||||
class.lpfnWndProc = NotifierProc;
|
||||
class.hIcon = NULL;
|
||||
class.hCursor = NULL;
|
||||
|
||||
RegisterClassW(&class);
|
||||
tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName,
|
||||
class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
|
||||
TclWinGetTclInstance(), NULL);
|
||||
tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
|
||||
0 /* !signaled */, NULL);
|
||||
#else
|
||||
pthread_cond_init(&tsdPtr->waitCV, NULL);
|
||||
#endif /* __CYGWIN__ */
|
||||
tsdPtr->waitCVinitialized = 1;
|
||||
RegisterClassW(&class);
|
||||
tsdPtr->hwnd = CreateWindowExW(NULL, class.lpszClassName,
|
||||
class.lpszClassName, 0, 0, 0, 0, 0, NULL, NULL,
|
||||
TclWinGetTclInstance(), NULL);
|
||||
tsdPtr->event = CreateEventW(NULL, 1 /* manual */,
|
||||
0 /* !signaled */, NULL);
|
||||
#else /* !__CYGWIN__ */
|
||||
pthread_condattr_init(&wcvAttr);
|
||||
if (pthread_condattr_setclock(&wcvAttr, CLOCK_MONOTONIC) == 0) {
|
||||
/* we can use conditional wait monotonic based */
|
||||
wcvAttrPtr = &wcvAttr;
|
||||
tsdPtr->waitCVMono = 1;
|
||||
}
|
||||
pthread_cond_init(&tsdPtr->waitCV, wcvAttrPtr);
|
||||
(void)pthread_condattr_destroy(&wcvAttr);
|
||||
#endif /* !__CYGWIN__ */
|
||||
tsdPtr->waitCVinitialized = 1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(¬ifierInitMutex);
|
||||
pthread_mutex_lock(¬ifierInitMutex);
|
||||
#if defined(HAVE_PTHREAD_ATFORK)
|
||||
/*
|
||||
* Install pthread_atfork handlers to clean up the notifier in the
|
||||
* child of a fork.
|
||||
*/
|
||||
/*
|
||||
* Install pthread_atfork handlers to clean up the notifier in the
|
||||
* child of a fork.
|
||||
*/
|
||||
|
||||
if (!atForkInit) {
|
||||
int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild);
|
||||
if (!atForkInit) {
|
||||
int result = pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild);
|
||||
|
||||
if (result) {
|
||||
Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
|
||||
}
|
||||
atForkInit = 1;
|
||||
if (result) {
|
||||
Tcl_Panic("Tcl_InitNotifier: pthread_atfork failed");
|
||||
}
|
||||
atForkInit = 1;
|
||||
}
|
||||
#endif /* HAVE_PTHREAD_ATFORK */
|
||||
|
||||
notifierCount++;
|
||||
notifierCount++;
|
||||
|
||||
pthread_mutex_unlock(¬ifierInitMutex);
|
||||
pthread_mutex_unlock(¬ifierInitMutex);
|
||||
|
||||
#endif /* TCL_THREADS */
|
||||
return tsdPtr;
|
||||
}
|
||||
return tsdPtr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -498,13 +507,13 @@ Tcl_AlertNotifier(
|
||||
ThreadSpecificData *tsdPtr = clientData;
|
||||
|
||||
pthread_mutex_lock(¬ifierMutex);
|
||||
tsdPtr->eventReady = 1;
|
||||
tsdPtr->eventReady++;
|
||||
|
||||
# ifdef __CYGWIN__
|
||||
PostMessageW(tsdPtr->hwnd, 1024, 0, 0);
|
||||
# else
|
||||
# else /* !__CYGWIN__ */
|
||||
pthread_cond_broadcast(&tsdPtr->waitCV);
|
||||
# endif /* __CYGWIN__ */
|
||||
# endif /* !__CYGWIN__ */
|
||||
pthread_mutex_unlock(¬ifierMutex);
|
||||
#endif /* TCL_THREADS */
|
||||
}
|
||||
@@ -832,12 +841,125 @@ NotifierProc(
|
||||
* Process all of the runnable events.
|
||||
*/
|
||||
|
||||
tsdPtr->eventReady = 1;
|
||||
tsdPtr->eventReady++;
|
||||
Tcl_ServiceAll();
|
||||
return 0;
|
||||
}
|
||||
#endif /* TCL_THREADS && __CYGWIN__ */
|
||||
|
||||
|
||||
/*
|
||||
* Several minimal sleep and wait values, corresponding unix timer resolution
|
||||
*
|
||||
* Note: Adjusting of this values may increase NRT-capability, but also may
|
||||
* increase CPU load (resp. busy waits on brief intervals).
|
||||
*/
|
||||
|
||||
#ifndef TCL_TMR_MIN_DELAY
|
||||
# define TCL_TMR_MIN_DELAY 100
|
||||
# define TCL_TMR_MIN_USLEEP 50
|
||||
# define TCL_TMR_MIN_NSLEEP 1
|
||||
# define TCL_TMR_OVERHEAD 50
|
||||
#endif
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclpUSleep --
|
||||
*
|
||||
* Delay execution for the specified time (in microseconds).
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Time passes.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static unsigned int tclMinDelay = TCL_TMR_MIN_DELAY;
|
||||
static unsigned int tclMinUSleep = TCL_TMR_MIN_USLEEP;
|
||||
static unsigned int tclMinNSleep = TCL_TMR_MIN_NSLEEP;
|
||||
|
||||
void
|
||||
TclpUSleep(
|
||||
Tcl_WideInt usec) /* Time to sleep. */
|
||||
{
|
||||
Tcl_WideInt now, desired;
|
||||
unsigned int *calibValue;
|
||||
|
||||
if (usec < 0) {
|
||||
usec = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* TIP #233: Scale from virtual time to real-time for select/usleep.
|
||||
*/
|
||||
TclpScaleUTime(&usec);
|
||||
|
||||
/*
|
||||
* The only trick here is that select appears to return early under some
|
||||
* conditions, so we have to check to make sure that the right amount of
|
||||
* time really has elapsed. If it's too early, go back to sleep again.
|
||||
*
|
||||
* Note the time can be switched (time-jump), so use monotonic time here.
|
||||
*/
|
||||
|
||||
now = TclpGetUTimeMonotonic();
|
||||
if ((desired = (now + usec)) < now) { /* overflow */
|
||||
desired = 0x7FFFFFFFFFFFFFFFL;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
||||
if (usec >= tclMinDelay) {
|
||||
|
||||
struct timeval delay;
|
||||
|
||||
calibValue = &tclMinDelay;
|
||||
usec -= (usec % tclMinDelay);
|
||||
delay.tv_sec = usec / 1000000;
|
||||
delay.tv_usec = usec % 1000000;
|
||||
|
||||
(void) select(0, (SELECT_MASK *) 0, (SELECT_MASK *) 0,
|
||||
(SELECT_MASK *) 0, &delay);
|
||||
|
||||
} else if (usec >= tclMinUSleep) {
|
||||
calibValue = &tclMinUSleep;
|
||||
usec -= (usec % tclMinUSleep);
|
||||
usleep((useconds_t)usec);
|
||||
} else if (usec >= tclMinNSleep) {
|
||||
struct timespec delay;
|
||||
|
||||
calibValue = &tclMinNSleep;
|
||||
usec -= (usec % tclMinNSleep);
|
||||
delay.tv_sec = usec / 1000000;
|
||||
delay.tv_nsec = (usec % 1000000) * 1000; /* usec to nsec */
|
||||
|
||||
nanosleep(&delay, NULL);
|
||||
} else {
|
||||
calibValue = NULL;
|
||||
#ifdef _POSIX_PRIORITY_SCHEDULING
|
||||
sched_yield(); /* yield the processor (force context switch). */
|
||||
#endif
|
||||
}
|
||||
|
||||
now = TclpGetUTimeMonotonic();
|
||||
|
||||
if ((usec = (desired - now)) <= 0 /* or tolerance */) {
|
||||
/*
|
||||
* Self calibration - sleep was too long, so adjust related value.
|
||||
*/
|
||||
if (calibValue && (unsigned int)-usec > *calibValue) {
|
||||
*calibValue = (*calibValue + (unsigned int)-usec) / 2;
|
||||
}
|
||||
/* end of sleep */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -860,262 +982,337 @@ int
|
||||
Tcl_WaitForEvent(
|
||||
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
|
||||
{
|
||||
if (tclNotifierHooks.waitForEventProc) {
|
||||
return tclNotifierHooks.waitForEventProc(timePtr);
|
||||
} else {
|
||||
FileHandler *filePtr;
|
||||
int mask;
|
||||
Tcl_Time vTime;
|
||||
if (tclNotifierHooks.waitForEventProc) {
|
||||
return tclNotifierHooks.waitForEventProc(timePtr);
|
||||
} else {
|
||||
FileHandler *filePtr;
|
||||
int mask, canWait = 1;
|
||||
Tcl_WideInt endTime = 0, waitTime = 0;
|
||||
#ifdef TCL_THREADS
|
||||
int waitForFiles;
|
||||
# ifdef __CYGWIN__
|
||||
MSG msg;
|
||||
# endif /* __CYGWIN__ */
|
||||
int waitForFiles = 0;
|
||||
# ifdef __CYGWIN__
|
||||
MSG msg;
|
||||
# endif /* __CYGWIN__ */
|
||||
#else
|
||||
/*
|
||||
* Impl. notes: timeout & timeoutPtr are used if, and only if threads
|
||||
* are not enabled. They are the arguments for the regular select()
|
||||
* used when the core is not thread-enabled.
|
||||
*/
|
||||
/*
|
||||
* Impl. notes: timeout & timeoutPtr are used if, and only if threads
|
||||
* are not enabled. They are the arguments for the regular select()
|
||||
* used when the core is not thread-enabled.
|
||||
*/
|
||||
|
||||
struct timeval timeout, *timeoutPtr;
|
||||
int numFound;
|
||||
struct timeval timeout, *timeoutPtr;
|
||||
int numFound;
|
||||
#endif /* TCL_THREADS */
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
ThreadSpecificData *tsdPtr;
|
||||
|
||||
tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
|
||||
/*
|
||||
* Set up the timeout structure. Note that if there are no events to
|
||||
* check for, we return with a negative result rather than blocking
|
||||
* forever.
|
||||
*/
|
||||
|
||||
if (timePtr != NULL) {
|
||||
|
||||
waitTime = TCL_TIME_TO_USEC(*timePtr);
|
||||
/* TIP #233: Scale from virtual time to real-time */
|
||||
TclpScaleUTime(&waitTime);
|
||||
/*
|
||||
* Set up the timeout structure. Note that if there are no events to
|
||||
* check for, we return with a negative result rather than blocking
|
||||
* forever.
|
||||
* Note the time can be switched (time-jump), so use monotonic time here.
|
||||
*/
|
||||
endTime = TclpGetUTimeMonotonic() + waitTime;
|
||||
|
||||
/*
|
||||
* If short wait or no wait at all, just process events already available
|
||||
* right now, avoid waiting too long somewhere (NRT-capability fix).
|
||||
*/
|
||||
if (!timePtr->sec && timePtr->usec < TCL_TMR_MIN_DELAY) {
|
||||
|
||||
canWait = 0;
|
||||
}
|
||||
|
||||
#ifndef TCL_THREADS
|
||||
timeout.tv_sec = timePtr->sec;
|
||||
timeout.tv_usec = timePtr->usec;
|
||||
timeoutPtr = &timeout;
|
||||
} else if (tsdPtr->numFdBits == 0) {
|
||||
/*
|
||||
* If there are no threads, no timeout, and no fds registered,
|
||||
* then there are no events possible and we must avoid deadlock.
|
||||
* Note that this is not entirely correct because there might be a
|
||||
* signal that could interrupt the select call, but we don't
|
||||
* handle that case if we aren't using threads.
|
||||
*/
|
||||
|
||||
if (timePtr != NULL) {
|
||||
/*
|
||||
* TIP #233 (Virtualized Time). Is virtual time in effect? And do
|
||||
* we actually have something to scale? If yes to both then we
|
||||
* call the handler to do this scaling.
|
||||
*/
|
||||
|
||||
if (timePtr->sec != 0 || timePtr->usec != 0) {
|
||||
vTime = *timePtr;
|
||||
tclScaleTimeProcPtr(&vTime, tclTimeClientData);
|
||||
timePtr = &vTime;
|
||||
}
|
||||
#ifndef TCL_THREADS
|
||||
timeout.tv_sec = timePtr->sec;
|
||||
timeout.tv_usec = timePtr->usec;
|
||||
timeoutPtr = &timeout;
|
||||
} else if (tsdPtr->numFdBits == 0) {
|
||||
/*
|
||||
* If there are no threads, no timeout, and no fds registered,
|
||||
* then there are no events possible and we must avoid deadlock.
|
||||
* Note that this is not entirely correct because there might be a
|
||||
* signal that could interrupt the select call, but we don't
|
||||
* handle that case if we aren't using threads.
|
||||
*/
|
||||
|
||||
return -1;
|
||||
} else {
|
||||
timeoutPtr = NULL;
|
||||
return -1;
|
||||
} else {
|
||||
timeoutPtr = NULL;
|
||||
#endif /* !TCL_THREADS */
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
/*
|
||||
* Start notifier thread and place this thread on the list of
|
||||
* interested threads, signal the notifier thread, and wait for a
|
||||
* response or a timeout.
|
||||
*/
|
||||
StartNotifierThread("Tcl_WaitForEvent");
|
||||
|
||||
pthread_mutex_lock(¬ifierMutex);
|
||||
|
||||
waitForFiles = (tsdPtr->numFdBits > 0);
|
||||
|
||||
/* if cannot wait (but not really necessary to wait), bypass triggering pipe */
|
||||
if (!canWait && (!waitForFiles || tsdPtr->eventReady)) {
|
||||
goto nowait;
|
||||
}
|
||||
|
||||
if (!canWait) {
|
||||
/*
|
||||
* Start notifier thread and place this thread on the list of
|
||||
* interested threads, signal the notifier thread, and wait for a
|
||||
* response or a timeout.
|
||||
* Cannot emulate a polling select with a polling condition
|
||||
* variable. Instead, pretend to wait for files and tell the
|
||||
* notifier thread what we are doing. The notifier thread makes
|
||||
* sure it goes through select with its select mask in the same
|
||||
* state as ours currently is. We block until that happens.
|
||||
*/
|
||||
StartNotifierThread("Tcl_WaitForEvent");
|
||||
|
||||
pthread_mutex_lock(¬ifierMutex);
|
||||
|
||||
if (timePtr != NULL && timePtr->sec == 0 && (timePtr->usec == 0
|
||||
#if defined(__APPLE__) && defined(__LP64__)
|
||||
/*
|
||||
* On 64-bit Darwin, pthread_cond_timedwait() appears to have
|
||||
* a bug that causes it to wait forever when passed an
|
||||
* absolute time which has already been exceeded by the system
|
||||
* time; as a workaround, when given a very brief timeout,
|
||||
* just do a poll. [Bug 1457797]
|
||||
*/
|
||||
|| timePtr->usec < 10
|
||||
#endif /* __APPLE__ && __LP64__ */
|
||||
)) {
|
||||
/*
|
||||
* Cannot emulate a polling select with a polling condition
|
||||
* variable. Instead, pretend to wait for files and tell the
|
||||
* notifier thread what we are doing. The notifier thread makes
|
||||
* sure it goes through select with its select mask in the same
|
||||
* state as ours currently is. We block until that happens.
|
||||
*/
|
||||
|
||||
waitForFiles = 1;
|
||||
tsdPtr->pollState = POLL_WANT;
|
||||
timePtr = NULL;
|
||||
} else {
|
||||
waitForFiles = (tsdPtr->numFdBits > 0);
|
||||
tsdPtr->pollState = 0;
|
||||
}
|
||||
|
||||
if (waitForFiles) {
|
||||
/*
|
||||
* Add the ThreadSpecificData structure of this thread to the list
|
||||
* of ThreadSpecificData structures of all threads that are
|
||||
* waiting on file events.
|
||||
*/
|
||||
tsdPtr->pollState = POLL_WANT;
|
||||
canWait = 1;
|
||||
}
|
||||
} else {
|
||||
tsdPtr->pollState = 0;
|
||||
}
|
||||
|
||||
tsdPtr->nextPtr = waitingListPtr;
|
||||
if (waitingListPtr) {
|
||||
waitingListPtr->prevPtr = tsdPtr;
|
||||
if (waitForFiles) {
|
||||
/*
|
||||
* Add the ThreadSpecificData structure of this thread to the list
|
||||
* of ThreadSpecificData structures of all threads that are
|
||||
* waiting on file events.
|
||||
*/
|
||||
|
||||
tsdPtr->nextPtr = waitingListPtr;
|
||||
if (waitingListPtr) {
|
||||
waitingListPtr->prevPtr = tsdPtr;
|
||||
}
|
||||
tsdPtr->prevPtr = 0;
|
||||
waitingListPtr = tsdPtr;
|
||||
tsdPtr->onList = 1;
|
||||
|
||||
if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
|
||||
Tcl_Panic("Tcl_WaitForEvent: %s",
|
||||
"unable to write to triggerPipe");
|
||||
}
|
||||
}
|
||||
|
||||
nowait:
|
||||
|
||||
FD_ZERO(&tsdPtr->readyMasks.readable);
|
||||
FD_ZERO(&tsdPtr->readyMasks.writable);
|
||||
FD_ZERO(&tsdPtr->readyMasks.exception);
|
||||
|
||||
while (!tsdPtr->eventReady) {
|
||||
|
||||
if (canWait && timePtr) {
|
||||
|
||||
waitTime = endTime - TclpGetUTimeMonotonic();
|
||||
|
||||
/* Note: we should wait at least once if waitForFiles set */
|
||||
if (waitTime <= 0) {
|
||||
if (!waitForFiles) {
|
||||
break; /* end of wait */
|
||||
}
|
||||
waitForFiles = 0;
|
||||
waitTime = 0;
|
||||
}
|
||||
tsdPtr->prevPtr = 0;
|
||||
waitingListPtr = tsdPtr;
|
||||
tsdPtr->onList = 1;
|
||||
|
||||
if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
|
||||
Tcl_Panic("Tcl_WaitForEvent: %s",
|
||||
"unable to write to triggerPipe");
|
||||
else
|
||||
if (waitTime <= TCL_TMR_OVERHEAD) {
|
||||
if (!waitForFiles) {
|
||||
canWait = 0;
|
||||
}
|
||||
waitForFiles = 0;
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef __CYGWIN__
|
||||
if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
|
||||
DWORD timeout;
|
||||
|
||||
if (timePtr) {
|
||||
timeout = waitTime / 1000;
|
||||
} else {
|
||||
timeout = 0xFFFFFFFF;
|
||||
}
|
||||
pthread_mutex_unlock(¬ifierMutex);
|
||||
MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
|
||||
pthread_mutex_lock(¬ifierMutex);
|
||||
}
|
||||
# else
|
||||
/* prevent too long waiting (NRT-capability) */
|
||||
if ( !canWait ) {
|
||||
/* short sleep */
|
||||
if (waitTime) {
|
||||
TclpUSleep(waitTime);
|
||||
}
|
||||
break; /* end of wait */
|
||||
}
|
||||
else
|
||||
if (timePtr) {
|
||||
struct timespec ptime;
|
||||
|
||||
clock_gettime(tsdPtr->waitCVMono ?
|
||||
CLOCK_MONOTONIC : CLOCK_REALTIME, &ptime);
|
||||
ptime.tv_sec += waitTime / 1000000;
|
||||
ptime.tv_nsec += (waitTime % 1000000) * 1000;
|
||||
if (ptime.tv_nsec > 1000000*1000) {
|
||||
ptime.tv_nsec -= 1000000*1000;
|
||||
ptime.tv_sec++;
|
||||
}
|
||||
|
||||
# if defined(__APPLE__) && defined(__LP64__)
|
||||
/*
|
||||
* On 64-bit Darwin, pthread_cond_timedwait() appears to have
|
||||
* a bug that causes it to wait forever when passed an
|
||||
* absolute time which has already been exceeded by the system
|
||||
* time; as a workaround, when given a very brief timeout,
|
||||
* just increment a bit the waiting-time from now. [Bug 1457797]
|
||||
*/
|
||||
if (waitTime <= 0) {
|
||||
ptime.tv_sec = now.sec;
|
||||
ptime.tv_nsec = 1000 * now.usec + 10; /* + 10 nanosecond */
|
||||
}
|
||||
# else
|
||||
/* remove overhead in nsec */
|
||||
if (ptime.tv_nsec < TCL_TMR_OVERHEAD * 1000) {
|
||||
ptime.tv_nsec += 1000000*1000;
|
||||
ptime.tv_sec--;
|
||||
}
|
||||
ptime.tv_nsec -= TCL_TMR_OVERHEAD * 1000;
|
||||
|
||||
# endif /* __APPLE__ && __LP64__ */
|
||||
|
||||
if (ptime.tv_nsec > 1000000*1000) {
|
||||
ptime.tv_nsec -= 1000000*1000;
|
||||
ptime.tv_sec++;
|
||||
}
|
||||
if (pthread_cond_timedwait(&tsdPtr->waitCV, ¬ifierMutex,
|
||||
&ptime) == ETIMEDOUT) {
|
||||
continue; /* repeat wait (if not yet real timeout) */
|
||||
};
|
||||
} else {
|
||||
pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex);
|
||||
}
|
||||
# endif /* __CYGWIN__ */
|
||||
|
||||
break; /* end of wait */
|
||||
}
|
||||
if (tsdPtr->eventReady > 0) {
|
||||
tsdPtr->eventReady--;
|
||||
}
|
||||
|
||||
# ifdef __CYGWIN__
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
|
||||
/*
|
||||
* Retrieve and dispatch the message.
|
||||
*/
|
||||
|
||||
DWORD result = GetMessageW(&msg, NULL, 0, 0);
|
||||
|
||||
if (result == 0) {
|
||||
PostQuitMessage(msg.wParam);
|
||||
/* What to do here? */
|
||||
} else if (result != (DWORD) -1) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
ResetEvent(tsdPtr->event);
|
||||
# endif /* __CYGWIN__ */
|
||||
|
||||
if (tsdPtr->onList) {
|
||||
/*
|
||||
* Remove the ThreadSpecificData structure of this thread from the
|
||||
* waiting list. Alert the notifier thread to recompute its select
|
||||
* masks - skipping this caused a hang when trying to close a pipe
|
||||
* which the notifier thread was still doing a select on.
|
||||
*/
|
||||
|
||||
if (tsdPtr->prevPtr) {
|
||||
tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
|
||||
} else {
|
||||
waitingListPtr = tsdPtr->nextPtr;
|
||||
}
|
||||
if (tsdPtr->nextPtr) {
|
||||
tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
|
||||
}
|
||||
tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
|
||||
tsdPtr->onList = 0;
|
||||
if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
|
||||
Tcl_Panic("Tcl_WaitForEvent: %s",
|
||||
"unable to write to triggerPipe");
|
||||
}
|
||||
}
|
||||
|
||||
#else /* !TCL_THREADS */
|
||||
tsdPtr->readyMasks = tsdPtr->checkMasks;
|
||||
numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
|
||||
&tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
|
||||
timeoutPtr);
|
||||
|
||||
/*
|
||||
* Some systems don't clear the masks after an error, so we have to do
|
||||
* it here.
|
||||
*/
|
||||
|
||||
if (numFound == -1) {
|
||||
FD_ZERO(&tsdPtr->readyMasks.readable);
|
||||
FD_ZERO(&tsdPtr->readyMasks.writable);
|
||||
FD_ZERO(&tsdPtr->readyMasks.exception);
|
||||
|
||||
if (!tsdPtr->eventReady) {
|
||||
#ifdef __CYGWIN__
|
||||
if (!PeekMessageW(&msg, NULL, 0, 0, 0)) {
|
||||
DWORD timeout;
|
||||
|
||||
if (timePtr) {
|
||||
timeout = timePtr->sec * 1000 + timePtr->usec / 1000;
|
||||
} else {
|
||||
timeout = 0xFFFFFFFF;
|
||||
}
|
||||
pthread_mutex_unlock(¬ifierMutex);
|
||||
MsgWaitForMultipleObjects(1, &tsdPtr->event, 0, timeout, 1279);
|
||||
pthread_mutex_lock(¬ifierMutex);
|
||||
}
|
||||
#else
|
||||
if (timePtr != NULL) {
|
||||
Tcl_Time now;
|
||||
struct timespec ptime;
|
||||
|
||||
Tcl_GetTime(&now);
|
||||
ptime.tv_sec = timePtr->sec + now.sec + (timePtr->usec + now.usec) / 1000000;
|
||||
ptime.tv_nsec = 1000 * ((timePtr->usec + now.usec) % 1000000);
|
||||
|
||||
pthread_cond_timedwait(&tsdPtr->waitCV, ¬ifierMutex, &ptime);
|
||||
} else {
|
||||
pthread_cond_wait(&tsdPtr->waitCV, ¬ifierMutex);
|
||||
}
|
||||
#endif /* __CYGWIN__ */
|
||||
}
|
||||
tsdPtr->eventReady = 0;
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
while (PeekMessageW(&msg, NULL, 0, 0, 0)) {
|
||||
/*
|
||||
* Retrieve and dispatch the message.
|
||||
*/
|
||||
|
||||
DWORD result = GetMessageW(&msg, NULL, 0, 0);
|
||||
|
||||
if (result == 0) {
|
||||
PostQuitMessage(msg.wParam);
|
||||
/* What to do here? */
|
||||
} else if (result != (DWORD) -1) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
ResetEvent(tsdPtr->event);
|
||||
#endif /* __CYGWIN__ */
|
||||
|
||||
if (waitForFiles && tsdPtr->onList) {
|
||||
/*
|
||||
* Remove the ThreadSpecificData structure of this thread from the
|
||||
* waiting list. Alert the notifier thread to recompute its select
|
||||
* masks - skipping this caused a hang when trying to close a pipe
|
||||
* which the notifier thread was still doing a select on.
|
||||
*/
|
||||
|
||||
if (tsdPtr->prevPtr) {
|
||||
tsdPtr->prevPtr->nextPtr = tsdPtr->nextPtr;
|
||||
} else {
|
||||
waitingListPtr = tsdPtr->nextPtr;
|
||||
}
|
||||
if (tsdPtr->nextPtr) {
|
||||
tsdPtr->nextPtr->prevPtr = tsdPtr->prevPtr;
|
||||
}
|
||||
tsdPtr->nextPtr = tsdPtr->prevPtr = NULL;
|
||||
tsdPtr->onList = 0;
|
||||
if ((write(triggerPipe, "", 1) == -1) && (errno != EAGAIN)) {
|
||||
Tcl_Panic("Tcl_WaitForEvent: %s",
|
||||
"unable to write to triggerPipe");
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
tsdPtr->readyMasks = tsdPtr->checkMasks;
|
||||
numFound = select(tsdPtr->numFdBits, &tsdPtr->readyMasks.readable,
|
||||
&tsdPtr->readyMasks.writable, &tsdPtr->readyMasks.exception,
|
||||
timeoutPtr);
|
||||
|
||||
/*
|
||||
* Some systems don't clear the masks after an error, so we have to do
|
||||
* it here.
|
||||
*/
|
||||
|
||||
if (numFound == -1) {
|
||||
FD_ZERO(&tsdPtr->readyMasks.readable);
|
||||
FD_ZERO(&tsdPtr->readyMasks.writable);
|
||||
FD_ZERO(&tsdPtr->readyMasks.exception);
|
||||
}
|
||||
#endif /* TCL_THREADS */
|
||||
|
||||
/*
|
||||
* Queue all detected file events before returning.
|
||||
*/
|
||||
|
||||
for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
|
||||
filePtr = filePtr->nextPtr) {
|
||||
mask = 0;
|
||||
if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) {
|
||||
mask |= TCL_READABLE;
|
||||
}
|
||||
if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) {
|
||||
mask |= TCL_WRITABLE;
|
||||
}
|
||||
if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) {
|
||||
mask |= TCL_EXCEPTION;
|
||||
}
|
||||
|
||||
if (!mask) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't bother to queue an event if the mask was previously
|
||||
* non-zero since an event must still be on the queue.
|
||||
*/
|
||||
|
||||
if (filePtr->readyMask == 0) {
|
||||
FileHandlerEvent *fileEvPtr =
|
||||
ckalloc(sizeof(FileHandlerEvent));
|
||||
|
||||
fileEvPtr->header.proc = FileHandlerEventProc;
|
||||
fileEvPtr->fd = filePtr->fd;
|
||||
Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
|
||||
}
|
||||
filePtr->readyMask = mask;
|
||||
}
|
||||
#ifdef TCL_THREADS
|
||||
pthread_mutex_unlock(¬ifierMutex);
|
||||
#endif /* TCL_THREADS */
|
||||
return 0;
|
||||
}
|
||||
#endif /* !TCL_THREADS */
|
||||
|
||||
/*
|
||||
* Queue all detected file events before returning.
|
||||
*/
|
||||
|
||||
for (filePtr = tsdPtr->firstFileHandlerPtr; (filePtr != NULL);
|
||||
filePtr = filePtr->nextPtr) {
|
||||
mask = 0;
|
||||
if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.readable)) {
|
||||
mask |= TCL_READABLE;
|
||||
}
|
||||
if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.writable)) {
|
||||
mask |= TCL_WRITABLE;
|
||||
}
|
||||
if (FD_ISSET(filePtr->fd, &tsdPtr->readyMasks.exception)) {
|
||||
mask |= TCL_EXCEPTION;
|
||||
}
|
||||
|
||||
if (!mask) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't bother to queue an event if the mask was previously
|
||||
* non-zero since an event must still be on the queue.
|
||||
*/
|
||||
|
||||
if (filePtr->readyMask == 0) {
|
||||
FileHandlerEvent *fileEvPtr =
|
||||
ckalloc(sizeof(FileHandlerEvent));
|
||||
|
||||
fileEvPtr->header.proc = FileHandlerEventProc;
|
||||
fileEvPtr->fd = filePtr->fd;
|
||||
Tcl_QueueEvent((Tcl_Event *) fileEvPtr, TCL_QUEUE_TAIL);
|
||||
}
|
||||
filePtr->readyMask = mask;
|
||||
}
|
||||
#ifdef TCL_THREADS
|
||||
pthread_mutex_unlock(¬ifierMutex);
|
||||
#endif /* TCL_THREADS */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TCL_THREADS
|
||||
@@ -1282,7 +1479,7 @@ NotifierThreadProc(
|
||||
}
|
||||
|
||||
if (found || (tsdPtr->pollState & POLL_DONE)) {
|
||||
tsdPtr->eventReady = 1;
|
||||
tsdPtr->eventReady++;
|
||||
if (tsdPtr->onList) {
|
||||
/*
|
||||
* Remove the ThreadSpecificData structure of this thread
|
||||
|
||||
+154
-47
@@ -101,10 +101,93 @@ TclpGetSeconds(void)
|
||||
Tcl_WideInt
|
||||
TclpGetMicroseconds(void)
|
||||
{
|
||||
Tcl_Time time;
|
||||
if (tclGetTimeProcPtr == NativeGetTime) {
|
||||
struct timeval tv;
|
||||
|
||||
tclGetTimeProcPtr(&time, tclTimeClientData);
|
||||
return ((Tcl_WideInt)time.sec)*1000000 + time.usec;
|
||||
(void) gettimeofday(&tv, NULL);
|
||||
return ((Tcl_WideInt)tv.tv_sec)*1000000 + tv.tv_usec;
|
||||
} else {
|
||||
Tcl_Time time;
|
||||
|
||||
tclGetTimeProcPtr(&time, tclTimeClientData);
|
||||
return ((Tcl_WideInt)time.sec)*1000000 + time.usec;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclpGetUTimeMonotonic --
|
||||
*
|
||||
* This procedure returns the number of microseconds from some unspecified
|
||||
* starting point.
|
||||
* This time is monotonic (not affected by the time-jumps), so can be used
|
||||
* for relative wait purposes and relative time calculation.
|
||||
*
|
||||
* Results:
|
||||
* Monotonic time in microseconds.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
Tcl_WideInt
|
||||
TclpGetUTimeMonotonic(void)
|
||||
{
|
||||
if (tclGetTimeProcPtr == NativeGetTime) {
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
/* monotonic time available on this platform */
|
||||
struct timespec mntv;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &mntv) != 0) {
|
||||
/* fallback to non-monotonic real-time. */
|
||||
return TclpGetMicroseconds();
|
||||
}
|
||||
/* monotonic time since some starting point in microseconds */
|
||||
return ((Tcl_WideInt)mntv.tv_sec)*1000000 + mntv.tv_nsec / 1000;
|
||||
#elif defined(MAC_OSX_TCL)
|
||||
/* absolute time related (tb.numer / tb.denom / 1000) microseconds */
|
||||
static mach_timebase_info_data_t tb;
|
||||
static uint64_t maxClicksForUInt64;
|
||||
uint64_t clicks = mach_absolute_time();
|
||||
|
||||
if (!tb.denom) {
|
||||
mach_timebase_info(&tb);
|
||||
maxClicksForUInt64 = UINT64_MAX / tb.numer;
|
||||
}
|
||||
if ((uint64_t) clicks < maxClicksForUInt64) {
|
||||
return (Tcl_WideInt)(((uint64_t) clicks) * tb.numer / 1000 / tb.denom);
|
||||
} else {
|
||||
return (Tcl_WideInt)(((uint64_t) clicks) / 1000 * tb.numer / tb.denom);
|
||||
}
|
||||
|
||||
#else /* no MAC_OSX_TCL and no monotonic time (xcode etc) */
|
||||
|
||||
/* fallback to non-monotonic real-time (microseconds) */
|
||||
return TclpGetMicroseconds();
|
||||
/*
|
||||
* TODO: may be the seconds could be obtained over the uptime (since last boot),
|
||||
* like here (https://stackoverflow.com/questions/20817311/ios-real-monotonic-clock-other-than-mach-absolute-time):
|
||||
int mib[2] = {CTL_KERN, KERN_BOOTTIME};
|
||||
size_t size = sizeof(boottime);
|
||||
time_t now;
|
||||
time_t uptime = -1;
|
||||
(void)time(&now);
|
||||
if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && boottime.tv_sec != 0)
|
||||
{
|
||||
uptime = now - (boottime.tv_sec);
|
||||
}
|
||||
* but I don't think this could provide even micro- or milliseconds granularity,
|
||||
* so a not back-drifting (monotonic) mix-in would be necessary.
|
||||
*/
|
||||
#endif
|
||||
} else {
|
||||
Tcl_Time time;
|
||||
|
||||
tclGetTimeProcPtr(&time, tclTimeClientData);
|
||||
return ((Tcl_WideInt)time.sec)*1000000 + time.usec;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -129,30 +212,8 @@ TclpGetMicroseconds(void)
|
||||
unsigned long
|
||||
TclpGetClicks(void)
|
||||
{
|
||||
unsigned long now;
|
||||
|
||||
#ifdef NO_GETTOD
|
||||
if (tclGetTimeProcPtr != NativeGetTime) {
|
||||
Tcl_Time time;
|
||||
|
||||
tclGetTimeProcPtr(&time, tclTimeClientData);
|
||||
now = time.sec*1000000 + time.usec;
|
||||
} else {
|
||||
/*
|
||||
* A semi-NativeGetTime, specialized to clicks.
|
||||
*/
|
||||
struct tms dummy;
|
||||
|
||||
now = (unsigned long) times(&dummy);
|
||||
}
|
||||
#else
|
||||
Tcl_Time time;
|
||||
|
||||
tclGetTimeProcPtr(&time, tclTimeClientData);
|
||||
now = time.sec*1000000 + time.usec;
|
||||
#endif
|
||||
|
||||
return now;
|
||||
/* clicks should provide monotonic intervals */
|
||||
return (unsigned long) TclpGetUTimeMonotonic();
|
||||
}
|
||||
#ifdef TCL_WIDE_CLICKS
|
||||
|
||||
@@ -180,17 +241,26 @@ TclpGetWideClicks(void)
|
||||
{
|
||||
Tcl_WideInt now;
|
||||
|
||||
if (tclGetTimeProcPtr != NativeGetTime) {
|
||||
if (tclGetTimeProcPtr == NativeGetTime) {
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
/* 1 wide click == 0.001 microseconds (1 nanosecond) */
|
||||
struct timespec mntv;
|
||||
|
||||
(void)clock_gettime(CLOCK_MONOTONIC, &mntv);
|
||||
return ((Tcl_WideInt)mntv.tv_sec)*1000000*1000 + mntv.tv_nsec;
|
||||
#elif defined(MAC_OSX_TCL)
|
||||
/* 1 wide click == (tb.numer / tb.denom / 1000) microseconds */
|
||||
return (Tcl_WideInt) (mach_absolute_time() & INT64_MAX);
|
||||
#else /* no MAC_OSX_TCL and no monotonic time (xcode etc) */
|
||||
/* 1 wide click == 1 microsecond (1000 nanoseconds) */
|
||||
return TclpGetMicroseconds();
|
||||
#endif
|
||||
} else {
|
||||
/* 1 wide click == 1 microsecond (1000 nanoseconds) */
|
||||
Tcl_Time time;
|
||||
|
||||
tclGetTimeProcPtr(&time, tclTimeClientData);
|
||||
now = ((Tcl_WideInt)time.sec)*1000000 + time.usec;
|
||||
} else {
|
||||
#ifdef MAC_OSX_TCL
|
||||
now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX);
|
||||
#else
|
||||
#error Wide high-resolution clicks not implemented on this platform
|
||||
#endif
|
||||
}
|
||||
|
||||
return now;
|
||||
@@ -219,10 +289,12 @@ TclpWideClicksToNanoseconds(
|
||||
{
|
||||
double nsec;
|
||||
|
||||
if (tclGetTimeProcPtr != NativeGetTime) {
|
||||
nsec = clicks * 1000;
|
||||
} else {
|
||||
#ifdef MAC_OSX_TCL
|
||||
if (tclGetTimeProcPtr == NativeGetTime) {
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
/* 1 wide click == 0.001 microseconds (1 nanosecond) */
|
||||
return clicks;
|
||||
#elif defined(MAC_OSX_TCL)
|
||||
/* 1 wide click == (tb.numer / tb.denom) nanoseconds */
|
||||
static mach_timebase_info_data_t tb;
|
||||
static uint64_t maxClicksForUInt64;
|
||||
|
||||
@@ -235,9 +307,13 @@ TclpWideClicksToNanoseconds(
|
||||
} else {
|
||||
nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom;
|
||||
}
|
||||
#else
|
||||
#error Wide high-resolution clicks not implemented on this platform
|
||||
#else /* no MAC_OSX_TCL and no monotonic time (xcode etc) */
|
||||
/* 1 wide click == 1 microsecond (1000 nanoseconds) */
|
||||
return clicks * 1000;
|
||||
#endif
|
||||
} else {
|
||||
/* 1 wide click == 1 microsecond (1000 nanoseconds) */
|
||||
nsec = clicks * 1000;
|
||||
}
|
||||
|
||||
return nsec;
|
||||
@@ -248,7 +324,7 @@ TclpWideClicksToNanoseconds(
|
||||
*
|
||||
* TclpWideClickInMicrosec --
|
||||
*
|
||||
* This procedure return scale to convert click values from the
|
||||
* This procedure return scale to convert click values from the
|
||||
* TclpGetWideClicks native resolution to microsecond resolution
|
||||
* and back.
|
||||
*
|
||||
@@ -264,10 +340,12 @@ TclpWideClicksToNanoseconds(
|
||||
double
|
||||
TclpWideClickInMicrosec(void)
|
||||
{
|
||||
if (tclGetTimeProcPtr != NativeGetTime) {
|
||||
return 1.0;
|
||||
} else {
|
||||
#ifdef MAC_OSX_TCL
|
||||
if (tclGetTimeProcPtr == NativeGetTime) {
|
||||
#ifndef MAC_OSX_TCL
|
||||
/* 1 wide click == 0.001 microseconds (1 nanosecond) */
|
||||
return 0.001;
|
||||
#else /* MAC_OSX_TCL: */
|
||||
/* 1 wide click == (tb.numer / tb.denom / 1000) microseconds */
|
||||
static int initialized = 0;
|
||||
static double scale = 0.0;
|
||||
|
||||
@@ -282,9 +360,10 @@ TclpWideClickInMicrosec(void)
|
||||
initialized = 1;
|
||||
return scale;
|
||||
}
|
||||
#else
|
||||
#error Wide high-resolution clicks not implemented on this platform
|
||||
#endif
|
||||
} else {
|
||||
/* 1 wide click == 1 microsecond (1000 nanoseconds) */
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
#endif /* TCL_WIDE_CLICKS */
|
||||
@@ -510,6 +589,34 @@ NativeScaleTime(
|
||||
/* Native scale is 1:1. Nothing is done */
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclpScaleUTime --
|
||||
*
|
||||
* This procedure scales number of microseconds if expected.
|
||||
*
|
||||
* Results:
|
||||
* Number of microseconds scaled using tclScaleTimeProcPtr.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
void
|
||||
TclpScaleUTime(
|
||||
Tcl_WideInt *usec)
|
||||
{
|
||||
/* Native scale is 1:1. */
|
||||
if (tclScaleTimeProcPtr == NativeScaleTime) {
|
||||
return;
|
||||
} else {
|
||||
Tcl_Time scTime;
|
||||
scTime.sec = *usec / 1000000;
|
||||
scTime.usec = *usec % 1000000;
|
||||
tclScaleTimeProcPtr(&scTime, tclTimeClientData);
|
||||
*usec = ((Tcl_WideInt)scTime.sec) * 1000000 + scTime.usec;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
|
||||
+484
-144
@@ -21,6 +21,7 @@
|
||||
|
||||
#define WM_WAKEUP WM_USER /* Message that is send by
|
||||
* Tcl_AlertNotifier. */
|
||||
|
||||
/*
|
||||
* The following static structure contains the state information for the
|
||||
* Windows implementation of the Tcl notifier. One of these structures is
|
||||
@@ -79,49 +80,49 @@ static LRESULT CALLBACK NotifierProc(HWND hwnd, UINT message,
|
||||
ClientData
|
||||
Tcl_InitNotifier(void)
|
||||
{
|
||||
if (tclNotifierHooks.initNotifierProc) {
|
||||
return tclNotifierHooks.initNotifierProc();
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
WNDCLASS class;
|
||||
if (tclNotifierHooks.initNotifierProc) {
|
||||
return tclNotifierHooks.initNotifierProc();
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
WNDCLASS class;
|
||||
|
||||
/*
|
||||
* Register Notifier window class if this is the first thread to use
|
||||
* this module.
|
||||
*/
|
||||
/*
|
||||
* Register Notifier window class if this is the first thread to use this
|
||||
* module.
|
||||
*/
|
||||
|
||||
Tcl_MutexLock(¬ifierMutex);
|
||||
if (notifierCount == 0) {
|
||||
class.style = 0;
|
||||
class.cbClsExtra = 0;
|
||||
class.cbWndExtra = 0;
|
||||
class.hInstance = TclWinGetTclInstance();
|
||||
class.hbrBackground = NULL;
|
||||
class.lpszMenuName = NULL;
|
||||
class.lpszClassName = classname;
|
||||
class.lpfnWndProc = NotifierProc;
|
||||
class.hIcon = NULL;
|
||||
class.hCursor = NULL;
|
||||
Tcl_MutexLock(¬ifierMutex);
|
||||
if (notifierCount == 0) {
|
||||
class.style = 0;
|
||||
class.cbClsExtra = 0;
|
||||
class.cbWndExtra = 0;
|
||||
class.hInstance = TclWinGetTclInstance();
|
||||
class.hbrBackground = NULL;
|
||||
class.lpszMenuName = NULL;
|
||||
class.lpszClassName = classname;
|
||||
class.lpfnWndProc = NotifierProc;
|
||||
class.hIcon = NULL;
|
||||
class.hCursor = NULL;
|
||||
|
||||
if (!RegisterClass(&class)) {
|
||||
Tcl_Panic("Unable to register TclNotifier window class");
|
||||
}
|
||||
if (!RegisterClass(&class)) {
|
||||
Tcl_Panic("Unable to register TclNotifier window class");
|
||||
}
|
||||
notifierCount++;
|
||||
Tcl_MutexUnlock(¬ifierMutex);
|
||||
|
||||
tsdPtr->pending = 0;
|
||||
tsdPtr->timerActive = 0;
|
||||
|
||||
InitializeCriticalSection(&tsdPtr->crit);
|
||||
|
||||
tsdPtr->hwnd = NULL;
|
||||
tsdPtr->thread = GetCurrentThreadId();
|
||||
tsdPtr->event = CreateEvent(NULL, TRUE /* manual */,
|
||||
FALSE /* !signaled */, NULL);
|
||||
|
||||
return tsdPtr;
|
||||
}
|
||||
notifierCount++;
|
||||
Tcl_MutexUnlock(¬ifierMutex);
|
||||
|
||||
tsdPtr->pending = 0;
|
||||
tsdPtr->timerActive = 0;
|
||||
|
||||
InitializeCriticalSection(&tsdPtr->crit);
|
||||
|
||||
tsdPtr->hwnd = NULL;
|
||||
tsdPtr->thread = GetCurrentThreadId();
|
||||
tsdPtr->event = CreateEvent(NULL, FALSE /* !manual */,
|
||||
FALSE /* !signaled */, NULL);
|
||||
|
||||
return tsdPtr;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -409,6 +410,216 @@ NotifierProc(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer resolution primitives
|
||||
*/
|
||||
|
||||
typedef int (CALLBACK* LPFN_NtQueryTimerResolution)(PULONG,PULONG,PULONG);
|
||||
typedef int (CALLBACK* LPFN_NtSetTimerResolution)(ULONG,BOOLEAN,PULONG);
|
||||
|
||||
static LPFN_NtQueryTimerResolution NtQueryTimerResolution = NULL;
|
||||
static LPFN_NtSetTimerResolution NtSetTimerResolution = NULL;
|
||||
|
||||
#define TMR_RES_MICROSEC (1000 / 100)
|
||||
|
||||
static struct {
|
||||
int available; /* Availability of timer resolution functions */
|
||||
ULONG minRes; /* Lowest possible resolution (in 100-ns) */
|
||||
ULONG maxRes; /* Highest possible resolution (in 100-ns) */
|
||||
ULONG curRes; /* Current resolution (in 100-ns units). */
|
||||
ULONG resRes; /* Resolution to be restored (delayed restore) */
|
||||
LONG minDelay; /* Lowest delay by max resolution (in microsecs) */
|
||||
LONG maxDelay; /* Highest delay by min resolution (in microsecs) */
|
||||
size_t count; /* Waiter count (used to restore the resolution) */
|
||||
Tcl_WideInt timeToReset; /* Time to reset resolution (typically now + 5s) */
|
||||
CRITICAL_SECTION cs; /* Mutex guarding this structure. */
|
||||
} timerResolution = {
|
||||
-1,
|
||||
15600 * TMR_RES_MICROSEC, 500 * TMR_RES_MICROSEC,
|
||||
15600 * TMR_RES_MICROSEC, 0,
|
||||
500, 15600,
|
||||
0,
|
||||
(Tcl_WideInt)0x7FFFFFFFFFFFFFFFL
|
||||
};
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* InitTimerResolution --
|
||||
*
|
||||
* This function initializes the timer resolution functionality.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
InitTimerResolution(void)
|
||||
{
|
||||
if (timerResolution.available == -1) {
|
||||
TclpInitLock();
|
||||
if (timerResolution.available == -1) {
|
||||
HMODULE hLib = GetModuleHandle(TEXT("NTDLL"));
|
||||
if (hLib) {
|
||||
NtQueryTimerResolution =
|
||||
(LPFN_NtQueryTimerResolution)GetProcAddress(hLib,
|
||||
"NtQueryTimerResolution");
|
||||
NtSetTimerResolution =
|
||||
(LPFN_NtSetTimerResolution)GetProcAddress(hLib,
|
||||
"NtSetTimerResolution");
|
||||
|
||||
if ( NtSetTimerResolution && NtQueryTimerResolution
|
||||
&& NtQueryTimerResolution(&timerResolution.minRes,
|
||||
&timerResolution.maxRes, &timerResolution.curRes) == 0
|
||||
) {
|
||||
InitializeCriticalSection(&timerResolution.cs);
|
||||
timerResolution.resRes = timerResolution.curRes;
|
||||
timerResolution.minRes -= (timerResolution.minRes % TMR_RES_MICROSEC);
|
||||
timerResolution.minDelay = timerResolution.maxRes / TMR_RES_MICROSEC;
|
||||
timerResolution.maxDelay = timerResolution.minRes / TMR_RES_MICROSEC;
|
||||
if (timerResolution.maxRes <= 1000 * TMR_RES_MICROSEC) {
|
||||
timerResolution.available = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (timerResolution.available <= 0) {
|
||||
/* not available, set min/max to typical values on windows */
|
||||
timerResolution.minRes = 15600 * TMR_RES_MICROSEC;
|
||||
timerResolution.maxRes = 500 * TMR_RES_MICROSEC;
|
||||
timerResolution.minDelay = timerResolution.maxRes / TMR_RES_MICROSEC;
|
||||
timerResolution.maxDelay = timerResolution.minRes / TMR_RES_MICROSEC;
|
||||
timerResolution.available = 0;
|
||||
}
|
||||
}
|
||||
TclpInitUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* SetTimerResolution --
|
||||
*
|
||||
* This is called by Tcl_WaitForEvent to increase timer resolution if wait
|
||||
* for events with time smaller as the typical windows value (ca. 15ms).
|
||||
*
|
||||
* Results:
|
||||
* Returns previous value of timer resolution, used for restoring with
|
||||
* RestoreTimerResolution.
|
||||
*
|
||||
* Side effects:
|
||||
* Note that timer resolution takes affect for the whole process (accross
|
||||
* all threads).
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static unsigned long
|
||||
SetTimerResolution(
|
||||
unsigned long newResolution,
|
||||
unsigned long actualResolution
|
||||
) {
|
||||
/* if available */
|
||||
if (timerResolution.available > 0)
|
||||
{
|
||||
if (newResolution < timerResolution.maxRes) {
|
||||
newResolution = timerResolution.maxRes;
|
||||
}
|
||||
EnterCriticalSection(&timerResolution.cs);
|
||||
if (!actualResolution) {
|
||||
timerResolution.count++;
|
||||
actualResolution = timerResolution.curRes;
|
||||
}
|
||||
if (newResolution < timerResolution.curRes) {
|
||||
ULONG curRes;
|
||||
if (NtSetTimerResolution(newResolution, TRUE, &curRes) == 0) {
|
||||
timerResolution.curRes = curRes;
|
||||
}
|
||||
}
|
||||
LeaveCriticalSection(&timerResolution.cs);
|
||||
return actualResolution;
|
||||
}
|
||||
|
||||
/* resolution unchanged (and counter not increased) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* RestoreTimerResolution --
|
||||
*
|
||||
* This is called by Tcl_WaitForEvent to restore timer resolution to
|
||||
* previous value.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* Because timer resolution takes affect for the whole process, it can
|
||||
* remain max resolution after execution of this function (if some thread
|
||||
* still waits with the highest timer resolution).
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static void
|
||||
RestoreTimerResolution(
|
||||
unsigned long newResolution
|
||||
) {
|
||||
/* if available */
|
||||
if (timerResolution.available > 0 && newResolution) {
|
||||
EnterCriticalSection(&timerResolution.cs);
|
||||
if (timerResolution.count-- <= 1) {
|
||||
timerResolution.resRes = newResolution;
|
||||
/* prolong time to reset resolution */
|
||||
timerResolution.timeToReset = TclpGetMicroseconds() + 1000000;
|
||||
}
|
||||
LeaveCriticalSection(&timerResolution.cs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* TclWinResetTimerResolution --
|
||||
*
|
||||
* This is called to delayed reset (after 1 second) of the timer resolution
|
||||
* to original value, if no more waiting workers using precise resolution.
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
*
|
||||
* Side effects:
|
||||
* None.
|
||||
*
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void
|
||||
TclWinResetTimerResolution(void)
|
||||
{
|
||||
if ( timerResolution.available > 0
|
||||
&& timerResolution.count == 0 && timerResolution.resRes > timerResolution.curRes
|
||||
&& TclpGetMicroseconds() >= timerResolution.timeToReset
|
||||
) {
|
||||
EnterCriticalSection(&timerResolution.cs);
|
||||
if (timerResolution.count == 0 && timerResolution.resRes > timerResolution.curRes) {
|
||||
ULONG curRes;
|
||||
if (NtSetTimerResolution(timerResolution.resRes, TRUE, &curRes) == 0) {
|
||||
timerResolution.curRes = curRes;
|
||||
};
|
||||
timerResolution.timeToReset = 0x7FFFFFFFFFFFFFFFL;
|
||||
}
|
||||
LeaveCriticalSection(&timerResolution.cs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
@@ -432,108 +643,189 @@ int
|
||||
Tcl_WaitForEvent(
|
||||
const Tcl_Time *timePtr) /* Maximum block time, or NULL. */
|
||||
{
|
||||
if (tclNotifierHooks.waitForEventProc) {
|
||||
return tclNotifierHooks.waitForEventProc(timePtr);
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
MSG msg;
|
||||
DWORD timeout, result;
|
||||
int status;
|
||||
if (tclNotifierHooks.waitForEventProc) {
|
||||
return tclNotifierHooks.waitForEventProc(timePtr);
|
||||
} else {
|
||||
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
|
||||
MSG msg;
|
||||
DWORD timeout = INFINITE, result = WAIT_TIMEOUT;
|
||||
int status = 0;
|
||||
Tcl_WideInt waitTime = 0;
|
||||
Tcl_WideInt endTime = 0;
|
||||
long tolerance = 0;
|
||||
unsigned long actualResolution = 0;
|
||||
|
||||
/*
|
||||
* Compute the timeout in milliseconds.
|
||||
*/
|
||||
/*
|
||||
* Compute the timeout in milliseconds.
|
||||
*/
|
||||
|
||||
if (timePtr) {
|
||||
/*
|
||||
* TIP #233 (Virtualized Time). Convert virtual domain delay to
|
||||
* real-time.
|
||||
*/
|
||||
if (timePtr) {
|
||||
|
||||
Tcl_Time myTime;
|
||||
waitTime = TCL_TIME_TO_USEC(*timePtr);
|
||||
|
||||
myTime.sec = timePtr->sec;
|
||||
myTime.usec = timePtr->usec;
|
||||
|
||||
if (myTime.sec != 0 || myTime.usec != 0) {
|
||||
tclScaleTimeProcPtr(&myTime, tclTimeClientData);
|
||||
}
|
||||
|
||||
timeout = myTime.sec * 1000 + myTime.usec / 1000;
|
||||
} else {
|
||||
timeout = INFINITE;
|
||||
/* if no wait */
|
||||
if (waitTime <= 0) {
|
||||
result = 0;
|
||||
goto peek;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if there are any messages in the queue before waiting
|
||||
* because MsgWaitForMultipleObjects will not wake up if there are
|
||||
* events currently sitting in the queue.
|
||||
* TIP #233 (Virtualized Time). Convert virtual domain delay to
|
||||
* real-time.
|
||||
*/
|
||||
|
||||
if (!PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
/*
|
||||
* Wait for something to happen (a signal from another thread, a
|
||||
* message, or timeout) or loop servicing asynchronous procedure
|
||||
* calls queued to this thread.
|
||||
*/
|
||||
|
||||
again:
|
||||
result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
|
||||
QS_ALLINPUT, MWMO_ALERTABLE);
|
||||
if (result == WAIT_IO_COMPLETION) {
|
||||
goto again;
|
||||
} else if (result == WAIT_FAILED) {
|
||||
status = -1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
TclpScaleUTime(&waitTime);
|
||||
|
||||
/*
|
||||
* Check to see if there are any messages to process.
|
||||
* Note the time can be switched (time-jump), so use monotonic time here.
|
||||
*/
|
||||
endTime = TclpGetUTimeMonotonic() + waitTime;
|
||||
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
/*
|
||||
* Retrieve and dispatch the first message.
|
||||
*/
|
||||
if (timerResolution.available == -1) {
|
||||
InitTimerResolution();
|
||||
}
|
||||
|
||||
#ifdef TMR_RES_TOLERANCE
|
||||
/* calculate possible maximal tolerance (in usec) of original wait-time */
|
||||
tolerance = ((waitTime <= 1000000) ? waitTime : 1000000) *
|
||||
TMR_RES_TOLERANCE / 100;
|
||||
if (tolerance > timerResolution.maxDelay) {
|
||||
tolerance = timerResolution.maxDelay;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = GetMessage(&msg, NULL, 0, 0);
|
||||
if (result == 0) {
|
||||
/*
|
||||
* We received a request to exit this thread (WM_QUIT), so
|
||||
* propagate the quit message and start unwinding.
|
||||
*/
|
||||
repeat:
|
||||
|
||||
PostQuitMessage((int) msg.wParam);
|
||||
status = -1;
|
||||
} else if (result == (DWORD)-1) {
|
||||
/*
|
||||
* We got an error from the system. I have no idea why this
|
||||
* would happen, so we'll just unwind.
|
||||
*/
|
||||
|
||||
status = -1;
|
||||
/* No wait if timeout too small (because windows may wait too long) */
|
||||
if (waitTime < (long)timerResolution.minDelay) {
|
||||
timeout = 0;
|
||||
/* prevent busy wait */
|
||||
if (waitTime >= 10) {
|
||||
goto wait;
|
||||
}
|
||||
Sleep(0);
|
||||
goto peek;
|
||||
}
|
||||
|
||||
if (timerResolution.available) {
|
||||
long overhead = (tolerance < 100 ? tolerance/2 : 50);
|
||||
Tcl_WideInt waitTimeWithOverhead = waitTime + overhead;
|
||||
if (waitTimeWithOverhead > timerResolution.maxDelay) {
|
||||
/* floor (truncate) using max delay as base (follow timeout better) */
|
||||
timeout = (waitTimeWithOverhead
|
||||
/ timerResolution.maxDelay)
|
||||
* timerResolution.maxDelay / 1000;
|
||||
} else {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
status = 1;
|
||||
/* calculate resolution up to 1000 microseconds
|
||||
* (don't use highest, because of too large CPU load) */
|
||||
ULONG res;
|
||||
if (waitTimeWithOverhead >= 10000) {
|
||||
res = 10000 * TMR_RES_MICROSEC;
|
||||
} else {
|
||||
res = 1000 * TMR_RES_MICROSEC;
|
||||
}
|
||||
timeout = waitTimeWithOverhead / 1000;
|
||||
/* set more precise timer resolution for minimal delay */
|
||||
if (!actualResolution || res < timerResolution.curRes) {
|
||||
actualResolution = SetTimerResolution(
|
||||
res, actualResolution);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
status = 0;
|
||||
timeout = waitTime / 1000;
|
||||
}
|
||||
|
||||
end:
|
||||
ResetEvent(tsdPtr->event);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if there are any messages in the queue before waiting
|
||||
* because MsgWaitForMultipleObjects will not wake up if there are events
|
||||
* currently sitting in the queue.
|
||||
*/
|
||||
wait:
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
goto get;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for something to happen (a signal from another thread, a
|
||||
* message, or timeout) or loop servicing asynchronous procedure calls
|
||||
* queued to this thread.
|
||||
*/
|
||||
|
||||
again:
|
||||
result = MsgWaitForMultipleObjectsEx(1, &tsdPtr->event, timeout,
|
||||
QS_ALLINPUT, MWMO_ALERTABLE);
|
||||
if (result == WAIT_IO_COMPLETION) {
|
||||
goto again;
|
||||
}
|
||||
if (result == WAIT_FAILED) {
|
||||
status = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to see if there are any messages to process.
|
||||
*/
|
||||
peek:
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
||||
/*
|
||||
* Retrieve and dispatch the first message.
|
||||
*/
|
||||
|
||||
get:
|
||||
result = GetMessage(&msg, NULL, 0, 0);
|
||||
if (result == 0) {
|
||||
/*
|
||||
* We received a request to exit this thread (WM_QUIT), so
|
||||
* propagate the quit message and start unwinding.
|
||||
*/
|
||||
|
||||
PostQuitMessage((int) msg.wParam);
|
||||
status = -1;
|
||||
} else if (result == (DWORD)-1) {
|
||||
/*
|
||||
* We got an error from the system. I have no idea why this would
|
||||
* happen, so we'll just unwind.
|
||||
*/
|
||||
|
||||
status = -1;
|
||||
} else {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
status = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (result == WAIT_TIMEOUT && timeout != INFINITE) {
|
||||
/* Check the wait should be repeated, and correct time for wait */
|
||||
|
||||
waitTime = endTime - TclpGetUTimeMonotonic();
|
||||
if (waitTime <= tolerance) {
|
||||
goto end;
|
||||
}
|
||||
/* Repeat wait with more precise timer resolution (or using sleep) */
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
/* restore timer resolution */
|
||||
if (actualResolution) {
|
||||
RestoreTimerResolution(actualResolution);
|
||||
}
|
||||
/* todo: move it to the service-thread (if available at some point) */
|
||||
TclWinResetTimerResolution();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
*
|
||||
* Tcl_Sleep --
|
||||
* TclpUSleep --
|
||||
*
|
||||
* Delay execution for the specified number of milliseconds.
|
||||
* Delay execution for the specified number of microseconds.
|
||||
*
|
||||
* TclpUSleep in contrast to Tcl_Sleep is more precise (microseconds).
|
||||
*
|
||||
* Results:
|
||||
* None.
|
||||
@@ -545,8 +837,8 @@ Tcl_WaitForEvent(
|
||||
*/
|
||||
|
||||
void
|
||||
Tcl_Sleep(
|
||||
int ms) /* Number of milliseconds to sleep. */
|
||||
TclpUSleep(
|
||||
Tcl_WideInt usec) /* Number of microseconds to sleep. */
|
||||
{
|
||||
/*
|
||||
* Simply calling 'Sleep' for the requisite number of milliseconds can
|
||||
@@ -558,45 +850,93 @@ Tcl_Sleep(
|
||||
* requisite amount.
|
||||
*/
|
||||
|
||||
Tcl_Time now; /* Current wall clock time. */
|
||||
Tcl_Time desired; /* Desired wakeup time. */
|
||||
Tcl_Time vdelay; /* Time to sleep, for scaling virtual ->
|
||||
* real. */
|
||||
Tcl_WideInt desired; /* Desired wakeup time. */
|
||||
DWORD sleepTime; /* Time to sleep, real-time */
|
||||
|
||||
vdelay.sec = ms / 1000;
|
||||
vdelay.usec = (ms % 1000) * 1000;
|
||||
|
||||
Tcl_GetTime(&now);
|
||||
desired.sec = now.sec + vdelay.sec;
|
||||
desired.usec = now.usec + vdelay.usec;
|
||||
if (desired.usec > 1000000) {
|
||||
++desired.sec;
|
||||
desired.usec -= 1000000;
|
||||
}
|
||||
long tolerance = 0;
|
||||
unsigned long actualResolution = 0;
|
||||
|
||||
/*
|
||||
* TIP #233: Scale delay from virtual to real-time.
|
||||
*/
|
||||
TclpScaleUTime(&usec);
|
||||
|
||||
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
|
||||
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
|
||||
if (usec <= 9) { /* too short to start whole sleep process */
|
||||
do {
|
||||
/* causes context switch only (shortest waiting) */
|
||||
SleepEx(0, TRUE);
|
||||
} while (--usec > 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (timerResolution.available == -1) {
|
||||
InitTimerResolution();
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the time can be switched (time-jump), so use monotonic time here.
|
||||
*/
|
||||
desired = TclpGetUTimeMonotonic() + usec;
|
||||
|
||||
#ifdef TMR_RES_TOLERANCE
|
||||
/* calculate possible maximal tolerance (in usec) of original wait-time */
|
||||
tolerance = ((usec <= 1000000) ? usec : 1000000) *
|
||||
TMR_RES_TOLERANCE / 100;
|
||||
if (tolerance > timerResolution.maxDelay) {
|
||||
tolerance = timerResolution.maxDelay;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
SleepEx(sleepTime, TRUE);
|
||||
Tcl_GetTime(&now);
|
||||
if (now.sec > desired.sec) {
|
||||
break;
|
||||
} else if ((now.sec == desired.sec) && (now.usec >= desired.usec)) {
|
||||
break;
|
||||
|
||||
/* No wait if sleep time too small (because windows may wait too long) */
|
||||
if (usec < (long)timerResolution.minDelay) {
|
||||
sleepTime = 0;
|
||||
goto wait;
|
||||
}
|
||||
|
||||
vdelay.sec = desired.sec - now.sec;
|
||||
vdelay.usec = desired.usec - now.usec;
|
||||
if (timerResolution.available) {
|
||||
if (usec > timerResolution.maxDelay) {
|
||||
/* floor (truncate) using max delay as base (follow timeout better) */
|
||||
sleepTime = (usec
|
||||
/ timerResolution.maxDelay)
|
||||
* timerResolution.maxDelay / 1000;
|
||||
} else {
|
||||
/* calculate resolution up to 1000 microseconds
|
||||
* (don't use highest, because of too large CPU load) */
|
||||
ULONG res;
|
||||
if (usec >= 10000) {
|
||||
res = 10000 * TMR_RES_MICROSEC;
|
||||
} else {
|
||||
res = 1000 * TMR_RES_MICROSEC;
|
||||
}
|
||||
sleepTime = usec / 1000;
|
||||
/* set more precise timer resolution for minimal delay */
|
||||
if (!actualResolution || res < timerResolution.curRes) {
|
||||
actualResolution = SetTimerResolution(
|
||||
res, actualResolution);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sleepTime = usec / 1000;
|
||||
}
|
||||
|
||||
tclScaleTimeProcPtr(&vdelay, tclTimeClientData);
|
||||
sleepTime = vdelay.sec * 1000 + vdelay.usec / 1000;
|
||||
wait:
|
||||
SleepEx(sleepTime, TRUE);
|
||||
|
||||
/* new difference to now (monotonic base) */
|
||||
usec = desired - TclpGetUTimeMonotonic();
|
||||
|
||||
if (usec <= tolerance) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* restore timer resolution */
|
||||
if (actualResolution) {
|
||||
RestoreTimerResolution(actualResolution);
|
||||
}
|
||||
/* todo: move it to the service-thread (if available at some point) */
|
||||
TclWinResetTimerResolution();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+445
-622
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user