/* * Update events with the current events object. */ static int update_current_events(struct lttng_poll_event *events) { int ret; struct compat_poll_event_array *current, *wait; assert(events); current = &events->current; wait = &events->wait; wait->nb_fd = current->nb_fd; if (current->alloc_size != wait->alloc_size) { ret = resize_poll_event(wait, current->alloc_size); if (ret < 0) { goto error; } } memcpy(wait->events, current->events, current->nb_fd * sizeof(*current->events)); /* Update is done. */ events->need_update = 0; return 0; error: return -1; }
/* * Wait on epoll set. This is a blocking call of timeout value. */ int compat_epoll_wait(struct lttng_poll_event *events, int timeout) { int ret; uint32_t new_size; if (events == NULL || events->events == NULL) { ERR("Wrong arguments in compat_epoll_wait"); goto error; } if (events->nb_fd == 0) { errno = EINVAL; return -1; } /* * Resize if needed before waiting. We could either expand the array or * shrink it down. It's important to note that after this step, we are * ensured that the events argument of the epoll_wait call will be large * enough to hold every possible returned events. */ new_size = 1U << utils_get_count_order_u32(events->nb_fd); if (new_size != events->alloc_size && new_size >= events->init_size) { ret = resize_poll_event(events, new_size); if (ret < 0) { /* ENOMEM problem at this point. */ goto error; } } do { ret = epoll_wait(events->epfd, events->events, events->nb_fd, timeout); } while (ret == -1 && errno == EINTR); if (ret < 0) { /* At this point, every error is fatal */ PERROR("epoll_wait"); goto error; } /* * Since the returned events are set sequentially in the "events" structure * we only need to return the epoll_wait value and iterate over it. */ return ret; error: return -1; }
/* * Add fd to pollfd data structure with requested events. */ int compat_poll_add(struct lttng_poll_event *events, int fd, uint32_t req_events) { int new_size, ret, i; struct compat_poll_event_array *current; if (events == NULL || events->current.events == NULL || fd < 0) { ERR("Bad compat poll add arguments"); goto error; } current = &events->current; /* Check if fd we are trying to add is already there. */ for (i = 0; i < current->nb_fd; i++) { if (current->events[i].fd == fd) { errno = EEXIST; goto error; } } /* Resize array if needed. */ new_size = 1U << utils_get_count_order_u32(current->nb_fd + 1); if (new_size != current->alloc_size && new_size >= current->init_size) { ret = resize_poll_event(current, new_size); if (ret < 0) { goto error; } } current->events[current->nb_fd].fd = fd; current->events[current->nb_fd].events = req_events; current->nb_fd++; events->need_update = 1; DBG("fd %d of %d added to pollfd", fd, current->nb_fd); return 0; error: return -1; }
/* * Remove a fd from the pollfd structure. */ int compat_poll_del(struct lttng_poll_event *events, int fd) { int new_size, i, count = 0, ret; struct compat_poll_event_array *current; if (events == NULL || events->current.events == NULL || fd < 0) { ERR("Wrong arguments for poll del"); goto error; } /* Ease our life a bit. */ current = &events->current; for (i = 0; i < current->nb_fd; i++) { /* Don't put back the fd we want to delete */ if (current->events[i].fd != fd) { current->events[count].fd = current->events[i].fd; current->events[count].events = current->events[i].events; count++; } } /* No fd duplicate should be ever added into array. */ assert(current->nb_fd - 1 == count); current->nb_fd = count; /* Resize array if needed. */ new_size = 1U << utils_get_count_order_u32(current->nb_fd); if (new_size != current->alloc_size && new_size >= current->init_size) { ret = resize_poll_event(current, new_size); if (ret < 0) { goto error; } } events->need_update = 1; return 0; error: return -1; }