X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Futils-upoll.c;h=b9b8de471f90b93bd3d6861159f1d42b48e5caa4;hb=84d141ab55dbc409aed542fe5163f1ed16353beb;hp=d72a0e8bedd92173809a3fd8b76701adcf57fa5d;hpb=68a8eaafe5f43480f29308bfd2ec12ad54da43f1;p=src%2Fapp-framework-binder.git diff --git a/src/utils-upoll.c b/src/utils-upoll.c index d72a0e8b..b9b8de47 100644 --- a/src/utils-upoll.c +++ b/src/utils-upoll.c @@ -24,31 +24,58 @@ #include "utils-upoll.h" - struct upollfd; +/* + * Structure describing one opened client + */ struct upoll { - struct upollfd *fd; - void (*read)(void *); - void (*write)(void *); - void (*hangup)(void *); - void *closure; - struct upoll *next; + struct upollfd *fd; /* structure handling the file descriptor */ + void (*read)(void *); /* callback for handling on_readable */ + void (*write)(void *); /* callback for handling on_writable */ + void (*hangup)(void *); /* callback for handling on_hangup */ + void *closure; /* closure for callbacks */ + struct upoll *next; /* next client of the same file descriptor */ }; +/* + * Structure describing a watched file descriptor + */ struct upollfd { - int fd; - uint32_t events; - struct upollfd *next; - struct upoll *head; + int fd; /* watch file descriptor */ + uint32_t events; /* watched events */ + struct upollfd *next; /* next watched file descriptor */ + struct upoll *head; /* first client watching the file descriptor */ +}; + +/* + * Structure describing a upoll group + */ +struct upollgrp +{ + int pollfd; + struct upollfd *head; + struct upoll *current; + pthread_mutex_t mutex; +}; + +static struct upollgrp global = { + .pollfd = 0, + .head = NULL, + .current = NULL, + .mutex = PTHREAD_MUTEX_INITIALIZER }; static int pollfd = 0; static struct upollfd *head = NULL; +static struct upoll *current = NULL; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +/* + * + */ static int update(struct upollfd *ufd) { int rc; @@ -94,6 +121,42 @@ static int update(struct upollfd *ufd) return rc; } +/* + * Compute the events for the set of clients + */ +static int update_flags(struct upollfd *ufd) +{ + int rc; + struct upoll *u; + struct epoll_event e; + uint32_t events; + struct upollfd **prv; + + /* compute expected events */ + events = 0; + pthread_mutex_lock(&mutex); + u = ufd->head; + assert (u != NULL); + while (u != NULL) { + if (u->read != NULL) + events |= EPOLLIN; + if (u->write != NULL) + events |= EPOLLOUT; + u = u->next; + } + if (ufd->events == events) + rc = 0; + else { + e.events = events; + e.data.ptr = ufd; + rc = epoll_ctl(pollfd, EPOLL_CTL_MOD, ufd->fd, &e); + if (rc == 0) + ufd->events = events; + } + pthread_mutex_unlock(&mutex); + return rc; +} + static struct upollfd *get_fd(int fd) { struct epoll_event e; @@ -226,6 +289,8 @@ void upoll_close(struct upoll *upoll) ufd = upoll->fd; pthread_mutex_lock(&mutex); + if (current == upoll) + current = NULL; it = &ufd->head; while (*it != upoll) it = &(*it)->next; @@ -240,7 +305,6 @@ int upoll_wait(int timeout) int rc; struct epoll_event e; struct upollfd *ufd; - struct upoll *u; if (pollfd == 0) { errno = ECANCELED; @@ -252,21 +316,25 @@ int upoll_wait(int timeout) } while (rc < 0 && errno == EINTR); if (rc == 1) { ufd = e.data.ptr; - u = ufd->head; - while (u != NULL) { - if ((e.events & EPOLLIN) && u->read) { - u->read(u->closure); - break; + current = ufd->head; + e.events &= EPOLLIN | EPOLLOUT | EPOLLHUP; + while (current != NULL && e.events != 0) { + if ((e.events & EPOLLIN) && current->read) { + current->read(current->closure); + e.events &= (uint32_t)~EPOLLIN; + continue; } - if ((e.events & EPOLLOUT) && u->write) { - u->write(u->closure); - break; + if ((e.events & EPOLLOUT) && current->write) { + current->write(current->closure); + e.events &= (uint32_t)~EPOLLOUT; + continue; } - if ((e.events & EPOLLHUP) && u->hangup) { - u->hangup(u->closure); - break; + if ((e.events & EPOLLHUP) && current->hangup) { + current->hangup(current->closure); + if (current == NULL) + break; } - u = u->next; + current = current->next; } } return rc < 0 ? rc : 0;