aboutsummaryrefslogtreecommitdiff
path: root/jim-eventloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'jim-eventloop.c')
-rw-r--r--jim-eventloop.c312
1 files changed, 252 insertions, 60 deletions
diff --git a/jim-eventloop.c b/jim-eventloop.c
index 0f34dd3..992b607 100644
--- a/jim-eventloop.c
+++ b/jim-eventloop.c
@@ -4,7 +4,7 @@
* Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
* Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
* Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
- * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
* Copyright 2008 Andrew Lunn <andrew@lunn.ch>
* Copyright 2008 Duane Ellis <openocd@duaneellis.com>
* Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
@@ -91,8 +91,49 @@ typedef struct Jim_EventLoop
jim_wide timeEventNextId;
Jim_FileEvent *fileEventHead;
Jim_TimeEvent *timeEventHead;
+ int suppress_bgerror; /* bgerror returned break, so don't call it again */
} Jim_EventLoop;
+static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData);
+static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData);
+
+int Jim_EvalObjBackground(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+ Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+ Jim_CallFrame *savedFramePtr;
+ int retval;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_EvalObj(interp, scriptObjPtr);
+ interp->framePtr = savedFramePtr;
+ /* Try to report the error (if any) via the bgerror proc */
+ if (retval != JIM_OK && !eventLoop->suppress_bgerror) {
+ Jim_Obj *objv[2];
+ int rc = JIM_ERR;
+
+ objv[0] = Jim_NewStringObj(interp, "bgerror", -1);
+ objv[1] = Jim_GetResult(interp);
+ Jim_IncrRefCount(objv[0]);
+ Jim_IncrRefCount(objv[1]);
+ if (Jim_GetCommand(interp, objv[0], JIM_NONE) == NULL || (rc = Jim_EvalObjVector(interp, 2, objv)) != JIM_OK) {
+ if (rc == JIM_BREAK) {
+ /* No more bgerror calls */
+ eventLoop->suppress_bgerror++;
+ }
+ else {
+ /* Report the error to stderr. */
+ fprintf(stderr, "Background error:" JIM_NL);
+ Jim_PrintErrorMessage(interp);
+ }
+ }
+ Jim_DecrRefCount(interp, objv[0]);
+ Jim_DecrRefCount(interp, objv[1]);
+ }
+ return retval;
+}
+
+
void Jim_CreateFileHandler(Jim_Interp *interp, FILE * handle, int mask,
Jim_FileProc * proc, void *clientData, Jim_EventFinalizerProc * finalizerProc)
{
@@ -147,7 +188,7 @@ jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide milliseconds,
{
Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
jim_wide id = eventLoop->timeEventNextId++;
- Jim_TimeEvent *te;
+ Jim_TimeEvent *te, *e, *prev;
long cur_sec, cur_ms;
JimGetTime(&cur_sec, &cur_ms);
@@ -165,61 +206,117 @@ jim_wide Jim_CreateTimeHandler(Jim_Interp *interp, jim_wide milliseconds,
te->timeProc = proc;
te->finalizerProc = finalizerProc;
te->clientData = clientData;
+
+ /* Add to the appropriate place in the list */
+ if (eventLoop->timeEventHead) {
+ prev = NULL;
+ for (e = eventLoop->timeEventHead; e; e = e->next) {
+ if (te->when_sec < e->when_sec || (te->when_sec == e->when_sec && te->when_ms < e->when_ms)) {
+ break;
+ }
+ prev = e;
+ }
+ if (prev) {
+ te->next = prev->next;
+ prev->next = te;
+ return id;
+ }
+ }
+
te->next = eventLoop->timeEventHead;
eventLoop->timeEventHead = te;
+
return id;
}
-jim_wide Jim_DeleteTimeHandler(Jim_Interp *interp, jim_wide id)
+static jim_wide JimParseAfterId(Jim_Obj *idObj)
{
- Jim_TimeEvent *te, *prev = NULL;
- Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
- long cur_sec, cur_ms;
- jim_wide remain;
+ int len;
+ const char *tok = Jim_GetString(idObj, &len);
+ jim_wide id;
- JimGetTime(&cur_sec, &cur_ms);
+ if (strncmp(tok, "after#", 6) == 0 && Jim_StringToWide(tok + 6, &id, 10) == JIM_OK) {
+ /* Got an event by id */
+ return id;
+ }
+ return -1;
+}
- te = eventLoop->timeEventHead;
- if (id >= eventLoop->timeEventNextId) {
- return -2; /* wrong event ID */
+static jim_wide JimFindAfterByScript(Jim_EventLoop *eventLoop, Jim_Obj *scriptObj)
+{
+ Jim_TimeEvent *te;
+
+ for (te = eventLoop->timeEventHead; te; te = te->next) {
+ /* Is this an 'after' event? */
+ if (te->timeProc == JimAfterTimeHandler) {
+ if (Jim_StringCompareObj(scriptObj, te->clientData, 0) == 0) {
+ return te->id;
+ }
+ }
}
- while (te) {
+ return -1; /* NO event with the specified ID found */
+}
+
+static Jim_TimeEvent *JimFindTimeHandlerById(Jim_EventLoop *eventLoop, jim_wide id)
+{
+ Jim_TimeEvent *te;
+
+ for (te = eventLoop->timeEventHead; te; te = te->next) {
if (te->id == id) {
- remain = (te->when_sec - cur_sec) * 1000;
- remain += (te->when_ms - cur_ms);
- remain = (remain < 0) ? 0 : remain;
+ return te;
+ }
+ }
+ return NULL;
+}
+
+static Jim_TimeEvent *Jim_RemoveTimeHandler(Jim_EventLoop *eventLoop, jim_wide id)
+{
+ Jim_TimeEvent *te, *prev = NULL;
+ for (te = eventLoop->timeEventHead; te; te = te->next) {
+ if (te->id == id) {
if (prev == NULL)
eventLoop->timeEventHead = te->next;
else
prev->next = te->next;
- if (te->finalizerProc)
- te->finalizerProc(interp, te->clientData);
- Jim_Free(te);
- return remain;
+ return te;
}
prev = te;
- te = te->next;
}
- return -1; /* NO event with the specified ID found */
+ return NULL;
}
-/* Search the first timer to fire.
- * This operation is useful to know how many time the select can be
- * put in sleep without to delay any event.
- * If there are no timers NULL is returned. */
-static Jim_TimeEvent *JimSearchNearestTimer(Jim_EventLoop * eventLoop)
+static void Jim_FreeTimeHandler(Jim_Interp *interp, Jim_TimeEvent *te)
{
- Jim_TimeEvent *te = eventLoop->timeEventHead;
- Jim_TimeEvent *nearest = NULL;
+ if (te->finalizerProc)
+ te->finalizerProc(interp, te->clientData);
+ Jim_Free(te);
+}
- while (te) {
- if (!nearest || te->when_sec < nearest->when_sec ||
- (te->when_sec == nearest->when_sec && te->when_ms < nearest->when_ms))
- nearest = te;
- te = te->next;
+jim_wide Jim_DeleteTimeHandler(Jim_Interp *interp, jim_wide id)
+{
+ Jim_TimeEvent *te;
+ Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
+
+ if (id >= eventLoop->timeEventNextId) {
+ return -2; /* wrong event ID */
}
- return nearest;
+
+ te = Jim_RemoveTimeHandler(eventLoop, id);
+ if (te) {
+ jim_wide remain;
+ long cur_sec, cur_ms;
+
+ JimGetTime(&cur_sec, &cur_ms);
+
+ remain = (te->when_sec - cur_sec) * 1000;
+ remain += (te->when_ms - cur_ms);
+ remain = (remain < 0) ? 0 : remain;
+
+ Jim_FreeTimeHandler(interp, te);
+ return remain;
+ }
+ return -1; /* NO event with the specified ID found */
}
/* --- POSIX version of Jim_ProcessEvents, for now the only available --- */
@@ -282,12 +379,18 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags)
* to fire. */
if (numfd || ((flags & JIM_TIME_EVENTS) && !(flags & JIM_DONT_WAIT))) {
int retval;
- Jim_TimeEvent *shortest;
struct timeval tv, *tvp;
jim_wide dt;
- shortest = JimSearchNearestTimer(eventLoop);
- if (shortest) {
+ if (flags & JIM_DONT_WAIT) {
+ /* Wait no time */
+ tvp = &tv;
+ tvp->tv_sec = 0;
+ tvp->tv_usec = 0;
+ }
+ /* The nearest timer is always at the head of the list */
+ else if (eventLoop->timeEventHead) {
+ Jim_TimeEvent *shortest = eventLoop->timeEventHead;
long now_sec, now_ms;
/* Calculate the time missing for the nearest
@@ -364,6 +467,8 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags)
JimGetTime(&now_sec, &now_ms);
if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) {
id = te->id;
+ /* Remove from the list before executing */
+ Jim_RemoveTimeHandler(eventLoop, id);
te->timeProc(interp, te->clientData);
/* After an event is processed our time event list may
* no longer be the same, so we restart from head.
@@ -371,8 +476,10 @@ int Jim_ProcessEvents(Jim_Interp *interp, int flags)
* by event handlers itself in order to don't loop forever
* even in case an [after 0] that continuously register
* itself. To do so we saved the max ID we want to handle. */
- Jim_DeleteTimeHandler(interp, id);
+ Jim_FreeTimeHandler(interp, te);
+
te = eventLoop->timeEventHead;
+ processed++;
}
else {
te = te->next;
@@ -413,6 +520,7 @@ void JimELAssocDataDeleProc(Jim_Interp *interp, void *data)
static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
+ Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
Jim_Obj *oldValue;
if (argc != 2) {
@@ -420,8 +528,6 @@ static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
- interp->suppress_bgerror = 0;
-
oldValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE);
if (oldValue) {
Jim_IncrRefCount(oldValue);
@@ -434,6 +540,9 @@ static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
}
+
+ eventLoop->suppress_bgerror = 0;
+
while (1) {
Jim_Obj *currValue;
@@ -456,14 +565,40 @@ static int JimELVwaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_OK;
}
-void JimAfterTimeHandler(Jim_Interp *interp, void *clientData)
+static int JimELUpdateCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+ static const char *options[] = {
+ "idletasks", NULL
+ };
+ enum { UPDATE_IDLE, UPDATE_NONE };
+ int option = UPDATE_NONE;
+ int flags = JIM_TIME_EVENTS;
+
+ if (argc == 1) {
+ flags = JIM_ALL_EVENTS;
+ }
+ else if (argc > 2 || Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ Jim_WrongNumArgs(interp, 1, argv, "?idletasks?");
+ return JIM_ERR;
+ }
+
+ eventLoop->suppress_bgerror = 0;
+
+ while (Jim_ProcessEvents(interp, flags | JIM_DONT_WAIT) > 0) {
+ }
+
+ return JIM_OK;
+}
+
+static void JimAfterTimeHandler(Jim_Interp *interp, void *clientData)
{
Jim_Obj *objPtr = clientData;
Jim_EvalObjBackground(interp, objPtr);
}
-void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData)
+static void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData)
{
Jim_Obj *objPtr = clientData;
@@ -472,23 +607,25 @@ void JimAfterTimeEventFinalizer(Jim_Interp *interp, void *clientData)
static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- jim_wide ms, id;
+ Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp);
+ jim_wide ms = 0, id;
Jim_Obj *objPtr, *idObjPtr;
const char *options[] = {
- "cancel", NULL
+ "cancel", "info", "idle", NULL
};
enum
- { AFTER_CANCEL, AFTER_INFO, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE };
+ { AFTER_CANCEL, AFTER_INFO, AFTER_IDLE, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE };
int option = AFTER_CREATE;
if (argc < 2) {
- Jim_WrongNumArgs(interp, 1, argv, "<after milliseconds> ?script|cancel <id>?");
+ Jim_WrongNumArgs(interp, 1, argv, "option ?arg ...?");
return JIM_ERR;
}
if (Jim_GetWide(interp, argv[1], &ms) != JIM_OK) {
- if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ if (Jim_GetEnum(interp, argv[1], options, &option, "argument", JIM_ERRMSG) != JIM_OK) {
return JIM_ERR;
}
+ Jim_SetEmptyResult(interp);
}
else if (argc == 2) {
/* Simply a sleep */
@@ -496,10 +633,18 @@ static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
usleep((ms % 1000) * 1000);
return JIM_OK;
}
+
switch (option) {
- case AFTER_CREATE:
- Jim_IncrRefCount(argv[2]);
- id = Jim_CreateTimeHandler(interp, ms, JimAfterTimeHandler, argv[2],
+ case AFTER_IDLE:
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "script ?script ...?");
+ return JIM_ERR;
+ }
+ /* fall through */
+ case AFTER_CREATE: {
+ Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2);
+ Jim_IncrRefCount(scriptObj);
+ id = Jim_CreateTimeHandler(interp, ms, JimAfterTimeHandler, scriptObj,
JimAfterTimeEventFinalizer);
objPtr = Jim_NewStringObj(interp, NULL, 0);
Jim_AppendString(interp, objPtr, "after#", -1);
@@ -509,21 +654,66 @@ static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Jim_DecrRefCount(interp, idObjPtr);
Jim_SetResult(interp, objPtr);
return JIM_OK;
- case AFTER_CANCEL:{
- int tlen;
+ }
+ case AFTER_CANCEL:
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "id|command");
+ return JIM_ERR;
+ }
+ else {
jim_wide remain = 0;
- const char *tok = Jim_GetString(argv[2], &tlen);
- if (strncmp(tok, "after#", 6) == 0 && Jim_StringToWide(tok + 6, &id, 10) == JIM_OK) {
- remain = Jim_DeleteTimeHandler(interp, id);
- if (remain > -2) {
- Jim_SetResult(interp, Jim_NewIntObj(interp, remain));
+ id = JimParseAfterId(argv[2]);
+ if (id < 0) {
+ /* Not an event id, so search by script */
+ Jim_Obj *scriptObj = Jim_ConcatObj(interp, argc - 2, argv + 2);
+ id = JimFindAfterByScript(eventLoop, scriptObj);
+ Jim_FreeNewObj(interp, scriptObj);
+ if (id < 0) {
+ /* Not found */
+ break;
+ }
+ }
+ remain = Jim_DeleteTimeHandler(interp, id);
+ if (remain >= 0) {
+ Jim_SetResultInt(interp, remain);
+ }
+ }
+ break;
+
+ case AFTER_INFO:
+ if (argc == 2) {
+ Jim_TimeEvent *te = eventLoop->timeEventHead;
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ char buf[30];
+
+ while (te) {
+ snprintf(buf, sizeof(buf), "after#%" JIM_WIDE_MODIFIER, te->id);
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, buf, -1));
+ te = te->next;
+ }
+ Jim_SetResult(interp, listObj);
+ }
+ else if (argc == 3) {
+ jim_wide id = JimParseAfterId(argv[2]);
+ if (id >= 0) {
+ Jim_TimeEvent *e = JimFindTimeHandlerById(eventLoop, id);
+ if (e && e->timeProc == JimAfterTimeHandler) {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, listObj, e->clientData);
+ Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, e->initialms ? "timer" : "idle", -1));
+ Jim_SetResult(interp, listObj);
return JIM_OK;
}
}
- Jim_SetResultString(interp, "invalid event", -1);
+ Jim_SetResultFormatted(interp, "event \"%#s\" doesn't exist", argv[2]);
return JIM_ERR;
}
+ else {
+ Jim_WrongNumArgs(interp, 2, argv, "?id?");
+ return JIM_ERR;
+ }
+ break;
}
return JIM_OK;
}
@@ -536,10 +726,12 @@ int Jim_eventloopInit(Jim_Interp *interp)
eventLoop->fileEventHead = NULL;
eventLoop->timeEventHead = NULL;
eventLoop->timeEventNextId = 1;
+ eventLoop->suppress_bgerror = 0;
Jim_SetAssocData(interp, "eventloop", JimELAssocDataDeleProc, eventLoop);
- Jim_CreateCommand(interp, "vwait", JimELVwaitCommand, NULL, NULL);
- Jim_CreateCommand(interp, "after", JimELAfterCommand, NULL, NULL);
+ Jim_CreateCommand(interp, "vwait", JimELVwaitCommand, eventLoop, NULL);
+ Jim_CreateCommand(interp, "update", JimELUpdateCommand, eventLoop, NULL);
+ Jim_CreateCommand(interp, "after", JimELAfterCommand, eventLoop, NULL);
return JIM_OK;
}