Пример #1
0
static void JimAioDelProc(Jim_Interp *interp, void *privData)
{
    AioFile *af = privData;
    JIM_NOTUSED(interp);

    if (!(af->OpenFlags & AIO_KEEPOPEN))
        fclose(af->fp);
    if (!af->OpenFlags == AIO_FDOPEN) // fp = fdopen(fd) !!
        close(af->fd);
    if (af->rEvent) { // remove existing EventHandlers
	fprintf(stderr,"deleting ReadEvent\n");
	Jim_DeleteFileHandler(interp,af->fp);
	Jim_DecrRefCount(interp,af->rEvent);
    }
    if (af->wEvent) {
	fprintf(stderr,"deleting WriteEvent\n");
	Jim_DeleteFileHandler(interp,af->fp);
    	Jim_DecrRefCount(interp,af->wEvent);
    }
    if (af->eEvent) {
	fprintf(stderr,"deleting ExceptionEvent\n");
	Jim_DeleteFileHandler(interp,af->fp);
    	Jim_DecrRefCount(interp,af->eEvent);
    }
    Jim_Free(af);
}
Пример #2
0
static void JimAioDelProc(Jim_Interp *interp, void *privData)
{
    AioFile *af = privData;

    JIM_NOTUSED(interp);

    if (!(af->OpenFlags & AIO_KEEPOPEN)) {
        fclose(af->fp);
    }

    Jim_DecrRefCount(interp, af->filename);

#ifdef jim_ext_eventloop
    /* remove existing EventHandlers */
    if (af->rEvent) {
        Jim_DeleteFileHandler(interp, af->fp);
    }
    if (af->wEvent) {
        Jim_DeleteFileHandler(interp, af->fp);
    }
    if (af->eEvent) {
        Jim_DeleteFileHandler(interp, af->fp);
    }
#endif
    Jim_Free(af);
}
Пример #3
0
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
    int argc, Jim_Obj * const *argv)
{
    int scriptlen = 0;

    if (argc == 0) {
        /* Return current script */
        if (*scriptHandlerObj) {
            Jim_SetResult(interp, *scriptHandlerObj);
        }
        return JIM_OK;
    }

    if (*scriptHandlerObj) {
        /* Delete old handler */
        Jim_DeleteFileHandler(interp, af->fp);
        *scriptHandlerObj = NULL;
    }

    /* Now possibly add the new script(s) */
    Jim_GetString(argv[0], &scriptlen);
    if (scriptlen == 0) {
        /* Empty script, so done */
        return JIM_OK;
    }

    /* A new script to add */
    Jim_IncrRefCount(argv[0]);
    *scriptHandlerObj = argv[0];

    Jim_CreateFileHandler(interp, af->fp, mask,
        JimAioFileEventHandler, *scriptHandlerObj, JimAioFileEventFinalizer);

    return JIM_OK;
}
Пример #4
0
/* Calls to [aio.file] create commands that are implemented by this
 * C command. */
static int JimAioHandlerCommand(Jim_Interp *interp, int argc,
        Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);
    int option;
    const char *options[] = {
        "close", 
	"seek", "tell", 
	"gets", "read", "puts", 
	"flush", "eof", 
	"ndelay", 
	"readable", "writable", "onexception",
	"accept",
	NULL
    };
    enum {OPT_CLOSE, 
	  OPT_SEEK, OPT_TELL, 
	  OPT_GETS, OPT_READ, OPT_PUTS,
          OPT_FLUSH, OPT_EOF, 
	  OPT_NDELAY,
	  OPT_READABLE, OPT_WRITABLE, OPT_EXCEPTION,
	  OPT_ACCEPT
    };

    if (argc < 2) {
        Jim_WrongNumArgs(interp, 1, argv, "method ?args ...?");
        return JIM_ERR;
    }
    if (Jim_GetEnum(interp, argv[1], options, &option, "AIO method",
                JIM_ERRMSG) != JIM_OK)
        return JIM_ERR;
    /* CLOSE */
    if (option == OPT_CLOSE) {
        if (argc != 2) {
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
        Jim_DeleteCommand(interp, Jim_GetString(argv[0], NULL));
        return JIM_OK;
    } else if (option == OPT_SEEK) {
    /* SEEK */
        int orig = SEEK_SET;
        long offset;

        if (argc != 3 && argc != 4) {
            Jim_WrongNumArgs(interp, 2, argv, "offset ?origin?");
            return JIM_ERR;
        }
        if (argc == 4) {
            if (Jim_CompareStringImmediate(interp, argv[3], "start"))
                orig = SEEK_SET;
            else if (Jim_CompareStringImmediate(interp, argv[3], "current"))
                orig = SEEK_CUR;
            else if (Jim_CompareStringImmediate(interp, argv[3], "end"))
                orig = SEEK_END;
            else {
                Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                Jim_AppendStrings(interp, Jim_GetResult(interp),
                        "bad origin \"", Jim_GetString(argv[3], NULL),
                        "\" must be: start, current, or end", NULL);
                return JIM_ERR;
            }
        }
        if (Jim_GetLong(interp, argv[2], &offset) != JIM_OK)
            return JIM_ERR;
        if (fseek(af->fp, offset, orig) == -1) {
            JimAioSetError(interp);
            return JIM_ERR;
        }
        return JIM_OK;
    } else if (option == OPT_TELL) {
    /* TELL */
        long position;

        if (argc != 2) {
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
        position = ftell(af->fp);
        Jim_SetResult(interp, Jim_NewIntObj(interp, position));
        return JIM_OK;
    } else if (option == OPT_GETS) {
    /* GETS */
        char buf[AIO_BUF_LEN];
        Jim_Obj *objPtr;

        if (argc != 2 && argc != 3) {
            Jim_WrongNumArgs(interp, 2, argv, "?varName?");
            return JIM_ERR;
        }
        objPtr = Jim_NewStringObj(interp, NULL, 0);
        while (1) {
            int more = 0;
            buf[AIO_BUF_LEN-1] = '_';
            if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
                break;
            if (buf[AIO_BUF_LEN-1] == '\0' && buf[AIO_BUF_LEN-2] != '\n')
                more = 1;
            if (more) {
                Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN-1);
            } else {
                /* strip "\n" */
                Jim_AppendString(interp, objPtr, buf, strlen(buf)-1);
            }
            if (!more)
                break;
        }
        if (ferror(af->fp) && (errno != EAGAIN)) {
            /* I/O error */
            Jim_IncrRefCount(objPtr);
            Jim_DecrRefCount(interp, objPtr);
            JimAioSetError(interp);
            return JIM_ERR;
        }
        /* On EOF returns -1 if varName was specified, or the empty string. */
        if (feof(af->fp) && Jim_Length(objPtr) == 0) {
            Jim_IncrRefCount(objPtr);
            Jim_DecrRefCount(interp, objPtr);
            if (argc == 3)
                Jim_SetResult(interp, Jim_NewIntObj(interp, -1));
            return JIM_OK;
        }
        if (argc == 3) {
            int totLen;

            Jim_GetString(objPtr, &totLen);
            if (Jim_SetVariable(interp, argv[2], objPtr) != JIM_OK) {
                Jim_IncrRefCount(objPtr);
                Jim_DecrRefCount(interp, objPtr);
                return JIM_ERR;
            }
            Jim_SetResult(interp, Jim_NewIntObj(interp, totLen));
        } else {
            Jim_SetResult(interp, objPtr);
        }
        return JIM_OK;
    } else if (option == OPT_READ) {
    /* READ */
        char buf[AIO_BUF_LEN];
        Jim_Obj *objPtr;
        int nonewline = 0;
        int neededLen = -1; /* -1 is "read as much as possible" */

        if (argc != 2 && argc != 3) {
            Jim_WrongNumArgs(interp, 2, argv, "?-nonewline? ?len?");
            return JIM_ERR;
        }
        if (argc == 3 &&
            Jim_CompareStringImmediate(interp, argv[2], "-nonewline"))
        {
            nonewline = 1;
            argv++;
            argc--;
        }
        if (argc == 3) {
            jim_wide wideValue;
            if (Jim_GetWide(interp, argv[2], &wideValue) != JIM_OK)
                return JIM_ERR;
            if (wideValue < 0) {
                Jim_SetResultString(interp, "invalid parameter: negative len",
                        -1);
                return JIM_ERR;
            }
            neededLen = (int) wideValue;
        }
        objPtr = Jim_NewStringObj(interp, NULL, 0);
        while (neededLen != 0) {
            int retval;
            int readlen;
           
            if (neededLen == -1) {
                readlen = AIO_BUF_LEN;
            } else {
                readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
            }
            retval = fread(buf, 1, readlen, af->fp);
            if (retval > 0) {
                Jim_AppendString(interp, objPtr, buf, retval);
                if (neededLen != -1) {
                    neededLen -= retval;
                }
            }
            if (retval != readlen) break;
        }
        /* Check for error conditions */
        if (ferror(af->fp)) {
            /* I/O error */
            Jim_FreeNewObj(interp, objPtr);
            JimAioSetError(interp);
            return JIM_ERR;
        }
        if (nonewline) {
            int len;
            const char *s = Jim_GetString(objPtr, &len);

            if (len > 0 && s[len-1] == '\n') {
                objPtr->length--;
                objPtr->bytes[objPtr->length] = '\0';
            }
        }
        Jim_SetResult(interp, objPtr);
        return JIM_OK;
    } else if (option == OPT_PUTS) {
    /* PUTS */
        int wlen;
        const char *wdata;

        if (argc != 3 && (argc != 4 || !Jim_CompareStringImmediate(
                        interp, argv[2], "-nonewline"))) {
            Jim_WrongNumArgs(interp, 2, argv, "?-nonewline? string");
            return JIM_ERR;
        }
        wdata = Jim_GetString(argv[2+(argc==4)], &wlen);
        if (fwrite(wdata, 1, wlen, af->fp) != (unsigned)wlen ||
            (argc == 3 && fwrite("\n", 1, 1, af->fp) != 1)) {
            JimAioSetError(interp);
            return JIM_ERR;
        }
        return JIM_OK;
    } else if (option  == OPT_FLUSH) {
    /* FLUSH */
        if (argc != 2) {
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
        if (fflush(af->fp) == EOF) {
            JimAioSetError(interp);
            return JIM_ERR;
        }
        return JIM_OK;
    } else if (option  == OPT_EOF) {
    /* EOF */
        if (argc != 2) {
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
        Jim_SetResult(interp, Jim_NewIntObj(interp, feof(af->fp)));
        return JIM_OK;
    } else if (option  == OPT_NDELAY) {
#ifdef O_NDELAY
    	int fmode = af->flags;

        if (argc == 3) {
		jim_wide wideValue;

		if (Jim_GetWide(interp, argv[2], &wideValue) != JIM_OK)
                return JIM_ERR;
		switch (wideValue) {
		case 0:
			fmode &= ~O_NDELAY; break ;
		case 1:
			fmode |=  O_NDELAY; break ;
		}
		fcntl(af->fd,F_SETFL,fmode);
		af->flags = fmode;
	}
        Jim_SetResult(interp, Jim_NewIntObj(interp, (fmode & O_NONBLOCK)?1:0));
        return JIM_OK;
#else
        return JIM_ERR;
#endif
    } else if   (  (option  == OPT_READABLE) 
		|| (option  == OPT_WRITABLE) 
		|| (option  == OPT_EXCEPTION) 
                ) {
	int mask = 0;
	Jim_Obj **scrListObjpp = NULL;
	Jim_Obj *listObj;
	const char *dummy = NULL;
	int scrlen = 0;

	if (!(Jim_CreateFileHandler && Jim_DeleteFileHandler)) {
		Jim_SetResultString(interp, "Eventloop not present ( or loaded too late ) !", -1);
        	return JIM_ERR;
	}
	switch (option) {
	case OPT_READABLE:  mask = JIM_EVENT_READABLE;  scrListObjpp = &af->rEvent; 
		if (argc == 4)  mask |= JIM_EVENT_FEOF ; 			  break;
	case OPT_WRITABLE:  mask = JIM_EVENT_WRITABLE;  scrListObjpp = &af->wEvent; break;
	case OPT_EXCEPTION: mask = JIM_EVENT_EXCEPTION; scrListObjpp = &af->eEvent; break;
	}
        switch (argc) {
	case 4:
	case 3:
		if (*scrListObjpp) {
			Jim_DeleteFileHandler(interp, af->fp); //,mask);
			Jim_DecrRefCount(interp, *scrListObjpp); 
			*scrListObjpp = NULL;
		}
		if ( dummy = Jim_GetString(argv[2],&scrlen),(scrlen == 0)) {
			break;
		} else {
			*scrListObjpp = Jim_NewListObj(interp, NULL, 0);
			Jim_IncrRefCount(*scrListObjpp);
			// fprintf(stderr,"0 %p \n",*scrListObjpp);
			listObj = argv[2];
			if (Jim_IsShared(listObj))
				listObj = Jim_DuplicateObj(interp, listObj);
			// Jim_IncrRefCount(listObj);
			// fprintf(stderr,"script:\"%s\" argp: %p objp1: %p\n", Jim_GetString(argv[2], NULL),argv[2],listObj);
			// fprintf(stderr,"1");
			Jim_ListAppendElement(interp,*scrListObjpp,listObj);
			// fprintf(stderr,"2");
			if (mask & JIM_EVENT_FEOF) {
				listObj = argv[3];
				if (Jim_IsShared(listObj))
					listObj = Jim_DuplicateObj(interp, listObj);
				// Jim_IncrRefCount(listObj);
				// fprintf(stderr,"script:\"%s\" argp: %p objp2: %p\n", Jim_GetString(argv[3], NULL),argv[3],listObj);
				// fprintf(stderr,"3");
				Jim_ListAppendElement(interp,*scrListObjpp,listObj);
				// fprintf(stderr,"4");
			}
			// fprintf(stderr,"event readable fd: %d, script:\"%s\" objp3: %p\n",af->fd, Jim_GetString(argv[2], NULL),argv[2]);
			Jim_IncrRefCount(*scrListObjpp);
			// fprintf(stderr,"6 %p \n",Jim_CreateFileHandler);
			Jim_CreateFileHandler(interp, af->fp, mask, 
				JimAioFileEventHandler,
				*scrListObjpp,
				JimAioFileEventFinalizer);
			// fprintf(stderr,"7");
		}
		break;
	case 2:
		if (*scrListObjpp)
			Jim_SetResult(interp,*scrListObjpp);
		return JIM_OK;
	default:
            Jim_WrongNumArgs(interp, 2, argv, "");
            return JIM_ERR;
        }
    } else if (option  == OPT_ACCEPT) {
	int ret;
	fprintf(stderr,"ACCEPT\n");
	ret = JimAioAcceptHelper(interp,af);
	fprintf(stderr,"ret %d\n",ret);
	return (ret);
    }
    return JIM_OK;
}
Пример #5
0
/* Process every pending time event, then every pending file event
 * (that may be registered by time event callbacks just processed).
 * The behaviour depends upon the setting of flags:
 *
 * If flags is 0, the function does nothing and returns.
 * if flags has JIM_ALL_EVENTS set, all event types 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 as soon as all
 * the events that are possible to process without waiting are processed.
 *
 * Returns the number of events processed or -1 if
 * there are no matching handlers, or -2 on error.
 */
int Jim_ProcessEvents(Jim_Interp *interp, int flags)
{
    jim_wide sleep_us = -1;
    int processed = 0;
    Jim_EventLoop *eventLoop = Jim_GetAssocData(interp, "eventloop");
    Jim_FileEvent *fe = eventLoop->fileEventHead;
    Jim_TimeEvent *te;
    jim_wide maxId;

    if ((flags & JIM_FILE_EVENTS) == 0 || fe == NULL) {
        /* No file events */
        if ((flags & JIM_TIME_EVENTS) == 0 || eventLoop->timeEventHead == NULL) {
            /* No time events */
            return -1;
        }
    }

    /* 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 (flags & JIM_DONT_WAIT) {
        /* Wait no time */
        sleep_us = 0;
    }
    else if (flags & JIM_TIME_EVENTS) {
        /* The nearest timer is always at the head of the list */
        if (eventLoop->timeEventHead) {
            Jim_TimeEvent *shortest = eventLoop->timeEventHead;

            /* Calculate the time missing for the nearest
             * timer to fire. */
            sleep_us = shortest->when - JimGetTimeUsec(eventLoop);
            if (sleep_us < 0) {
                sleep_us = 0;
            }
        }
        else {
            /* Wait forever */
            sleep_us = -1;
        }
    }

#ifdef HAVE_SELECT
    if (flags & JIM_FILE_EVENTS) {
        int retval;
        struct timeval tv, *tvp = NULL;
        fd_set rfds, wfds, efds;
        int maxfd = -1;

        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
        FD_ZERO(&efds);

        /* Check file events */
        while (fe != NULL) {
            if (fe->mask & JIM_EVENT_READABLE)
                FD_SET(fe->fd, &rfds);
            if (fe->mask & JIM_EVENT_WRITABLE)
                FD_SET(fe->fd, &wfds);
            if (fe->mask & JIM_EVENT_EXCEPTION)
                FD_SET(fe->fd, &efds);
            if (maxfd < fe->fd)
                maxfd = fe->fd;
            fe = fe->next;
        }

        if (sleep_us >= 0) {
            tvp = &tv;
            tvp->tv_sec = sleep_us / 1000000;
            tvp->tv_usec = sleep_us % 1000000;
        }

        retval = select(maxfd + 1, &rfds, &wfds, &efds, tvp);

        if (retval < 0) {
            if (errno == EINVAL) {
                /* This can happen on mingw32 if a non-socket filehandle is passed */
                Jim_SetResultString(interp, "non-waitable filehandle", -1);
                return -2;
            }
        }
        else if (retval > 0) {
            fe = eventLoop->fileEventHead;
            while (fe != NULL) {
                int mask = 0;
                int fd = fe->fd;

                if ((fe->mask & JIM_EVENT_READABLE) && FD_ISSET(fd, &rfds))
                    mask |= JIM_EVENT_READABLE;
                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 (mask) {
                    int ret = fe->fileProc(interp, fe->clientData, mask);
                    if (ret != JIM_OK && ret != JIM_RETURN) {
                        /* Remove the element on handler error */
                        Jim_DeleteFileHandler(interp, fd, mask);
                        /* At this point fe is no longer valid - it will be assigned below */
                    }
                    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. */
                    FD_CLR(fd, &rfds);
                    FD_CLR(fd, &wfds);
                    FD_CLR(fd, &efds);
                    fe = eventLoop->fileEventHead;
                }
                else {
                    fe = fe->next;
                }
            }
        }
    }
#else
    if (sleep_us > 0) {
        usleep(sleep_us);
    }
#endif

    /* Check time events */
    te = eventLoop->timeEventHead;
    maxId = eventLoop->timeEventNextId;
    while (te) {
        jim_wide id;

        if (te->id > maxId) {
            te = te->next;
            continue;
        }
        if (JimGetTimeUsec(eventLoop) >= te->when) {
            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.
             * 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_FreeTimeHandler(interp, te);

            te = eventLoop->timeEventHead;
            processed++;
        }
        else {
            te = te->next;
        }
    }

    return processed;
}
Пример #6
0
/* 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;
}