/* ================================================== */
-/* Variables to handle the capability to dispatch on particular file
- handles becoming readable */
-
-/* Each bit set in this fd set corresponds to a read descriptor that
- we are watching and with which we have a handler associated in the
- file_handlers array */
-static fd_set read_fds;
-
-/* This is the number of bits that we have set in read_fds */
-static unsigned int n_read_fds;
-
/* One more than the highest file descriptor that is registered */
static unsigned int one_highest_fd;
typedef struct {
SCH_FileHandler handler;
SCH_ArbitraryArgument arg;
+ int events;
} FileHandlerEntry;
static ARR_Instance file_handlers;
void
SCH_Initialise(void)
{
- FD_ZERO(&read_fds);
- n_read_fds = 0;
-
file_handlers = ARR_CreateInstance(sizeof (FileHandlerEntry));
n_timer_queue_entries = 0;
if (fd >= FD_SETSIZE)
LOG_FATAL(LOGF_Scheduler, "Too many file descriptors");
+ /* Resize the array if the descriptor is highest so far */
+ while (ARR_GetSize(file_handlers) <= fd) {
+ ptr = ARR_GetNewElement(file_handlers);
+ ptr->handler = NULL;
+ ptr->arg = NULL;
+ ptr->events = 0;
+ }
+
+ ptr = ARR_GetElement(file_handlers, fd);
+
/* Don't want to allow the same fd to register a handler more than
once without deleting a previous association - this suggests
a bug somewhere else in the program. */
- if (FD_ISSET(fd, &read_fds))
- assert(0);
-
- ++n_read_fds;
-
- if (ARR_GetSize(file_handlers) < fd + 1)
- ARR_SetSize(file_handlers, fd + 1);
+ assert(!ptr->handler);
- ptr = (FileHandlerEntry *)ARR_GetElement(file_handlers, fd);
ptr->handler = handler;
ptr->arg = arg;
+ ptr->events = events;
- FD_SET(fd, &read_fds);
-
- if ((fd + 1) > one_highest_fd) {
+ if (one_highest_fd < fd + 1)
one_highest_fd = fd + 1;
- }
}
void
SCH_RemoveFileHandler(int fd)
{
- int fds_left, fd_to_check;
+ FileHandlerEntry *ptr;
assert(initialised);
- /* Check that a handler was registered for the fd in question */
- if (!FD_ISSET(fd, &read_fds))
- assert(0);
+ ptr = ARR_GetElement(file_handlers, fd);
- --n_read_fds;
+ /* Check that a handler was registered for the fd in question */
+ assert(ptr->handler);
- FD_CLR(fd, &read_fds);
+ ptr->handler = NULL;
+ ptr->arg = NULL;
+ ptr->events = 0;
/* Find new highest file descriptor */
- fds_left = n_read_fds;
- fd_to_check = 0;
- while (fds_left > 0) {
- if (FD_ISSET(fd_to_check, &read_fds)) {
- --fds_left;
- }
- ++fd_to_check;
+ while (one_highest_fd > 0) {
+ ptr = ARR_GetElement(file_handlers, one_highest_fd - 1);
+ if (ptr->handler)
+ break;
+ one_highest_fd--;
}
-
- one_highest_fd = fd_to_check;
}
/* ================================================== */
/* ================================================== */
+static void
+fill_fd_sets(fd_set **read_fds)
+{
+ FileHandlerEntry *handlers;
+ fd_set *rd;
+ int i, n, events;
+
+ n = ARR_GetSize(file_handlers);
+ handlers = ARR_GetElements(file_handlers);
+ rd = NULL;
+
+ for (i = 0; i < n; i++) {
+ events = handlers[i].events;
+
+ if (!events)
+ continue;
+
+ if (events & SCH_FILE_INPUT) {
+ if (!rd) {
+ rd = *read_fds;
+ FD_ZERO(rd);
+ }
+ FD_SET(i, rd);
+ }
+ }
+
+ if (!rd)
+ *read_fds = NULL;
+}
+
+/* ================================================== */
+
#define JUMP_DETECT_THRESHOLD 10
static int
void
SCH_MainLoop(void)
{
- fd_set rd;
+ fd_set read_fds, *p_read_fds;
int status, errsv;
struct timeval tv, saved_tv, *ptv;
struct timeval now, saved_now, cooked;
saved_tv.tv_sec = 0;
}
+ p_read_fds = &read_fds;
+ fill_fd_sets(&p_read_fds);
+
/* if there are no file descriptors being waited on and no
timeout set, this is clearly ridiculous, so stop the run */
- if (!ptv && !n_read_fds) {
+ if (!ptv && !p_read_fds)
LOG_FATAL(LOGF_Scheduler, "Nothing to do");
- }
-
- /* Copy current set of read file descriptors */
- memcpy((void *) &rd, (void *) &read_fds, sizeof(fd_set));
- status = select(one_highest_fd, &rd, NULL, NULL, ptv);
+ status = select(one_highest_fd, p_read_fds, NULL, NULL, ptv);
errsv = errno;
LCL_ReadRawTime(&now);
} else if (status > 0) {
/* A file descriptor is ready to read */
- dispatch_filehandlers(status, &rd);
+ dispatch_filehandlers(status, &read_fds);
} else {
/* No descriptors readable, timeout must have elapsed.