static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { jim_wide ms, id; Jim_Obj *objPtr, *idObjPtr; const char *options[] = { "info", "cancel", "restart", "expire", NULL }; enum {INFO, CANCEL, RESTART, EXPIRE, CREATE }; int option = CREATE ; if (argc < 3) { Jim_WrongNumArgs(interp, 1, argv, "<after milliseconds> script"); return JIM_ERR; } if (Jim_GetWide(interp, argv[1], &ms) != JIM_OK) if (Jim_GetEnum(interp, argv[1], options, &option, "after options", JIM_ERRMSG) != JIM_OK) return JIM_ERR; switch (option) { case CREATE: Jim_IncrRefCount(argv[2]); id = Jim_CreateTimeHandler(interp, ms, JimAfterTimeHandler, argv[2], JimAfterTimeEventFinalizer); objPtr = Jim_NewStringObj(interp, NULL, 0); Jim_AppendString(interp, objPtr, "after#", -1); idObjPtr = Jim_NewIntObj(interp, id); Jim_IncrRefCount(idObjPtr); Jim_AppendObj(interp, objPtr, idObjPtr); Jim_DecrRefCount(interp, idObjPtr); Jim_SetResult(interp, objPtr); return JIM_OK; case CANCEL: { int tlen ; jim_wide remain = 0; const char *tok = Jim_GetString(argv[2], &tlen); if ( sscanf(tok,"after#%lld",&id) == 1) { remain = Jim_DeleteTimeHandler(interp, id); if (remain > -2) { Jim_SetResult(interp, Jim_NewIntObj(interp, remain)); return JIM_OK; } } Jim_SetResultString(interp, "invalid event" , -1); return JIM_ERR; } default: fprintf(stderr,"unserviced option to after %d\n",option); } return JIM_OK; }
static int JimELAfterCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_EventLoop *eventLoop = Jim_CmdPrivData(interp); double ms = 0; jim_wide id; Jim_Obj *objPtr, *idObjPtr; static const char * const options[] = { "cancel", "info", "idle", NULL }; enum { AFTER_CANCEL, AFTER_INFO, AFTER_IDLE, AFTER_RESTART, AFTER_EXPIRE, AFTER_CREATE }; int option = AFTER_CREATE; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arg ...?"); return JIM_ERR; } if (Jim_GetDouble(interp, argv[1], &ms) != 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 */ usleep(ms * 1000); return JIM_OK; } switch (option) { 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, (jim_wide)(ms * 1000), JimAfterTimeHandler, scriptObj, JimAfterTimeEventFinalizer); objPtr = Jim_NewStringObj(interp, NULL, 0); Jim_AppendString(interp, objPtr, "after#", -1); idObjPtr = Jim_NewIntObj(interp, id); Jim_IncrRefCount(idObjPtr); Jim_AppendObj(interp, objPtr, idObjPtr); Jim_DecrRefCount(interp, idObjPtr); Jim_SetResult(interp, objPtr); return JIM_OK; } case AFTER_CANCEL: if (argc < 3) { Jim_WrongNumArgs(interp, 2, argv, "id|command"); return JIM_ERR; } else { jim_wide remain = 0; 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]; const char *fmt = "after#%" JIM_WIDE_MODIFIER; while (te) { snprintf(buf, sizeof(buf), fmt, te->id); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, buf, -1)); te = te->next; } Jim_SetResult(interp, listObj); } else if (argc == 3) { 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->initialus ? "timer" : "idle", -1)); Jim_SetResult(interp, listObj); return JIM_OK; } } 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; }
/* Process every pending time event, then every pending file event * (that may be registered by time event callbacks just processed). * Without special flags the function sleeps until some file event * fires, or when the next time event occurrs (if any). * * If flags is 0, the function does nothing and returns. * if flags has JIM_ALL_EVENTS set, all the kind of events are processed. * if flags has JIM_FILE_EVENTS set, file events are processed. * if flags has JIM_TIME_EVENTS set, time events are processed. * if flags has JIM_DONT_WAIT set the function returns ASAP until all * the events that's possible to process without to wait are processed. * * The function returns the number of events processed. */ int Jim_ProcessEvents(Jim_Interp *interp, int flags) { int maxfd = 0, numfd = 0, processed = 0; fd_set rfds, wfds, efds; Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop"); Jim_FileEvent *fe = eventLoop->fileEventHead; Jim_TimeEvent *te; jim_wide maxId; JIM_NOTUSED(flags); FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds); /* Check file events */ while (fe != NULL) { int fd = fileno((FILE*)fe->handle); if (fe->mask & JIM_EVENT_READABLE) FD_SET(fd, &rfds); if (fe->mask & JIM_EVENT_WRITABLE) FD_SET(fd, &wfds); if (fe->mask & JIM_EVENT_EXCEPTION) FD_SET(fd, &efds); if (maxfd < fd) maxfd = fd; numfd++; fe = fe->next; } /* Note that we want call select() even if there are no * file events to process as long as we want to process time * events, in order to sleep until the next time event is ready * 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) { long now_sec, now_ms; /* Calculate the time missing for the nearest * timer to fire. */ JimGetTime(&now_sec, &now_ms); tvp = &tv; dt = 1000 * (shortest->when_sec - now_sec); dt += ( shortest->when_ms - now_ms); if (dt < 0) { dt = 1; } tvp->tv_sec = dt / 1000; tvp->tv_usec = dt % 1000; // fprintf(stderr,"Next %d.% 8d\n",(int)tvp->tv_sec,(int)tvp->tv_usec); } else { tvp = NULL; /* wait forever */ // fprintf(stderr,"No Event\n"); } retval = select(maxfd+1, &rfds, &wfds, &efds, tvp); if (retval < 0) { switch (errno) { case EINTR: fprintf(stderr,"select EINTR\n"); break; case EINVAL: fprintf(stderr,"select EINVAL\n"); break; case ENOMEM: fprintf(stderr,"select ENOMEM\n"); break; } } else if (retval > 0) { fe = eventLoop->fileEventHead; while(fe != NULL) { int fd = fileno((FILE*)fe->handle); // fprintf(stderr,"fd: %d mask: %02x \n",fd,fe->mask); if ((fe->mask & JIM_EVENT_READABLE && FD_ISSET(fd, &rfds)) || (fe->mask & JIM_EVENT_WRITABLE && FD_ISSET(fd, &wfds)) || (fe->mask & JIM_EVENT_EXCEPTION && FD_ISSET(fd, &efds))) { int mask = 0; if (fe->mask & JIM_EVENT_READABLE && FD_ISSET(fd, &rfds)) { mask |= JIM_EVENT_READABLE; if ((fe->mask & JIM_EVENT_FEOF) && feof((FILE *)fe->handle)) mask |= JIM_EVENT_FEOF; } if (fe->mask & JIM_EVENT_WRITABLE && FD_ISSET(fd, &wfds)) mask |= JIM_EVENT_WRITABLE; if (fe->mask & JIM_EVENT_EXCEPTION && FD_ISSET(fd, &efds)) mask |= JIM_EVENT_EXCEPTION; if (fe->fileProc(interp, fe->clientData, mask) == JIM_ERR) { /* Remove the element on handler error */ Jim_DeleteFileHandler(interp, fe->handle); } processed++; /* After an event is processed our file event list * may no longer be the same, so what we do * is to clear the bit for this file descriptor and * restart again from the head. */ fe = eventLoop->fileEventHead; FD_CLR(fd, &rfds); FD_CLR(fd, &wfds); FD_CLR(fd, &efds); } else { fe = fe->next; } } } } /* Check time events */ te = eventLoop->timeEventHead; maxId = eventLoop->timeEventNextId-1; while(te) { long now_sec, now_ms; jim_wide id; if (te->id > maxId) { te = te->next; continue; } JimGetTime(&now_sec, &now_ms); if (now_sec > te->when_sec || (now_sec == te->when_sec && now_ms >= te->when_ms)) { id = te->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. * Still we make sure to don't process events registered * 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); te = eventLoop->timeEventHead; } else { te = te->next; } } return processed; }