diff --git a/src/iomux_select.c b/src/iomux_select.c index f680d60..fb1517a 100644 --- a/src/iomux_select.c +++ b/src/iomux_select.c @@ -14,54 +14,28 @@ struct IOMuxSelect { fd_set master_read_set; fd_set master_write_set; - struct IOMuxFD **descriptors; // array of pointers to the user IOMuxFD's + struct IOMuxFD *descriptors[FD_SETSIZE]; // array of pointers to the user IOMuxFD's size_t alloc_descriptors; //allocated descriptors in 'descriptors' size_t num_descriptors; //number of descriptors we're watching - size_t deleted_cnt; //used to rebuild the descriptors array + int recalc_max; int max_fd; //keeps track of the max fd for select() }; static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd); -//grows the descriptor array. We never shrink it. -static int iomux_select_grow(struct IOMuxSelect *mux) -{ - void *tmp = realloc(mux->descriptors, (mux->num_descriptors + IOMUX_GROW_CHUNK) * sizeof *mux->descriptors); - assert(tmp != NULL); - if (tmp == NULL) - return ENOMEM; - mux->alloc_descriptors += IOMUX_GROW_CHUNK; - mux->descriptors = tmp; - - return 0; -} - -static void iomux_select_remove(struct IOMuxSelect *mux, size_t idx) -{ - if (mux->num_descriptors > 1) { - //move last element into the empty slot - size_t last_idx = mux->num_descriptors - 1; - mux->descriptors[idx] = mux->descriptors[last_idx]; - mux->descriptors[last_idx] = NULL; - } - - mux->num_descriptors--; -} - -static void iomux_select_rebuild(struct IOMuxSelect *mux) +static void iomux_select_recalc_max(struct IOMuxSelect *mux) { size_t i; - mux->max_fd = -1; + for (i = 0; i < mux->num_descriptors; ) { - if (mux->descriptors[i] == NULL) { - iomux_select_remove(mux, i); - //a deleted fd slot needs to be rechecked, no i++ here - } else { + if (mux->descriptors[i] != NULL) { mux->max_fd = UC_MAX(mux->descriptors[i]->fd, mux->max_fd); i++; } + + assert(i < FD_SETSIZE); } } @@ -70,6 +44,10 @@ static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd) { struct IOMuxSelect *mux = mux_->instance; + if (fd->fd < 0 || fd->fd >= FD_SETSIZE) { + return EINVAL; + } + if (fd->what & MUX_EV_READ) FD_SET(fd->fd, &mux->master_read_set); else @@ -86,18 +64,19 @@ static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd) static int iomux_select_register_fd(struct IOMux *mux_, struct IOMuxFD *fd) { struct IOMuxSelect *mux = mux_->instance; - if (fd->what == 0 || fd->callback == NULL) + int rc; + + if ((fd->what & MUX_EV_MASK) == 0 || fd->callback == NULL) return EINVAL; - if (mux->num_descriptors == mux->alloc_descriptors) { - if (iomux_select_grow(mux) != 0) - return ENOMEM; + rc = iomux_select_update_events(mux_, fd); + if (rc != 0) { + return ENFILE; } - mux->descriptors[mux->num_descriptors] = fd; + mux->descriptors[fd->fd] = fd; mux->num_descriptors++; - iomux_select_update_events(mux_, fd); mux->max_fd = UC_MAX(fd->fd, mux->max_fd); @@ -109,18 +88,21 @@ static int iomux_select_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd) struct IOMuxSelect *mux = mux_->instance; int rc = ENOENT; - size_t i; - for (i = 0; i < mux->num_descriptors; i++) { - if (fd == mux->descriptors[i]) { - unsigned int what = fd->what; //make sure we don't alter 'what' as seen from the user - fd->what &= ~MUX_EV_MASK; - iomux_select_update_events(mux_, fd); - mux->descriptors[i] = NULL; //set the slot to NULL, the event loop needs to rebuild it. - mux->deleted_cnt++; - fd->what = what; - rc = 0; - break; - } + if (fd->fd < 0 || fd->fd >= FD_SETSIZE) { + return ENFILE; + } + + if (mux->descriptors[fd->fd] != NULL) { + unsigned int what = fd->what; //make sure we don't alter 'what' as seen from the user + + fd->what = 0; + iomux_select_update_events(mux_, fd); + mux->descriptors[fd->fd] = NULL; + mux->recalc_max = 1; + fd->what = what; + + rc = 0; + mux->num_descriptors--; } return rc; @@ -136,9 +118,9 @@ static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout) fd_set read_set; fd_set write_set; - if (mux->deleted_cnt) { - iomux_select_rebuild(mux); - mux->deleted_cnt = 0; + if (mux->recalc_max) { + iomux_select_recalc_max(mux); + mux->recalc_max = 0; } if (mux->max_fd == -1 && timeout == NULL) @@ -161,8 +143,8 @@ static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout) if (rc == 0) //no fd's were ready, no more work to do return event_cnt; - for (i = 0; rc > 0 && i < mux->num_descriptors; i++) { - unsigned int events = 0; + for (i = 0; rc > 0 && i < FD_SETSIZE; i++) { + int had_event = 0; //deliver only one event at a time , to simplify application //programming @@ -171,7 +153,7 @@ static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout) rc--; assert(mux->descriptors[i]->callback != NULL); mux->descriptors[i]->callback(mux_, mux->descriptors[i], MUX_EV_READ); - events = 1; + had_event = 1; } //need to re-check in case the callback deleted the IOMuxFD @@ -180,10 +162,11 @@ static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout) rc--; assert(mux->descriptors[i]->callback != NULL); mux->descriptors[i]->callback(mux_, mux->descriptors[i], MUX_EV_WRITE); - events = 1; + had_event = 1; } - event_cnt += events; + event_cnt += had_event; + } return event_cnt; @@ -193,8 +176,6 @@ static void iomux_select_delete(struct IOMux *mux) { if (mux != NULL && mux->instance != NULL) { struct IOMuxSelect *mux_select = mux->instance; - free(mux_select->descriptors); - mux_select->descriptors = NULL; free(mux_select); mux->instance = NULL; }