sched: don't keep prepared fd_set

Instead of copying a prepared fd_set to the fd_set used by select(),
fill it from scratch according to the array of file handlers before each
select() call. This should make the code simpler and save some memory
when other events are supported.
This commit is contained in:
Miroslav Lichvar 2016-06-22 14:21:33 +02:00
parent 0a10545314
commit d8d096aa54

114
sched.c
View file

@ -44,17 +44,6 @@ static int initialised = 0;
/* ================================================== */
/* 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;
@ -67,6 +56,7 @@ static unsigned int one_highest_fd;
typedef struct {
SCH_FileHandler handler;
SCH_ArbitraryArgument arg;
int events;
} FileHandlerEntry;
static ARR_Instance file_handlers;
@ -132,9 +122,6 @@ handle_slew(struct timeval *raw,
void
SCH_Initialise(void)
{
FD_ZERO(&read_fds);
n_read_fds = 0;
file_handlers = ARR_CreateInstance(sizeof (FileHandlerEntry));
n_timer_queue_entries = 0;
@ -178,26 +165,27 @@ SCH_AddFileHandler
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);
assert(!ptr->handler);
++n_read_fds;
if (ARR_GetSize(file_handlers) < fd + 1)
ARR_SetSize(file_handlers, fd + 1);
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;
}
}
@ -206,29 +194,26 @@ SCH_AddFileHandler
void
SCH_RemoveFileHandler(int fd)
{
int fds_left, fd_to_check;
FileHandlerEntry *ptr;
assert(initialised);
ptr = ARR_GetElement(file_handlers, fd);
/* Check that a handler was registered for the fd in question */
if (!FD_ISSET(fd, &read_fds))
assert(0);
assert(ptr->handler);
--n_read_fds;
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;
}
/* ================================================== */
@ -595,6 +580,38 @@ handle_slew(struct timeval *raw,
/* ================================================== */
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
@ -650,7 +667,7 @@ check_current_time(struct timeval *prev_raw, struct timeval *raw, int timeout,
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;
@ -681,16 +698,15 @@ SCH_MainLoop(void)
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);
@ -713,7 +729,7 @@ SCH_MainLoop(void)
} 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.