select: Externalize fd_set filling and dispatch

To integrate with an external event loop (in this case glib) we
need to allow an application to get a filled out fd_set and then
dispatch it. osmo_fds and maxfds are static and I decided to keep
it that way and instead create two routines to fill the fdset and
then one to dispatch the result.

The public header file does not include sys/select.h and we can
compile the library without select, so I didn't want to require
having to include this file, and used void * for the parameter.

Mark the routines as inline to avoid a call from the select
function. I have confirmed that inlining has an effect on x86
using Debian's gcc-4.9.2-10 compiler
This commit is contained in:
Holger Hans Peter Freyther 2016-03-21 09:55:05 +01:00
parent fb348eeff2
commit 61f28880d5
2 changed files with 57 additions and 32 deletions

View File

@ -41,4 +41,10 @@ int osmo_select_main(int polling);
struct osmo_fd *osmo_fd_get_by_fd(int fd); struct osmo_fd *osmo_fd_get_by_fd(int fd);
/*
* foreign event loop integration
*/
int osmo_fd_fill_fds(void *readset, void *writeset, void *exceptset);
int osmo_fd_disp_fds(void *readset, void *writeset, void *exceptset);
/*! @} */ /*! @} */

View File

@ -98,62 +98,49 @@ void osmo_fd_unregister(struct osmo_fd *fd)
llist_del(&fd->list); llist_del(&fd->list);
} }
/*! \brief select main loop integration inline int osmo_fd_fill_fds(void *_rset, void *_wset, void *_eset)
* \param[in] polling should we pollonly (1) or block on select (0)
*/
int osmo_select_main(int polling)
{ {
struct osmo_fd *ufd, *tmp; fd_set *readset = _rset, *writeset = _wset, *exceptset = _eset;
fd_set readset, writeset, exceptset; struct osmo_fd *ufd;
int work = 0, rc;
struct timeval no_time = {0, 0};
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
/* prepare read and write fdsets */
llist_for_each_entry(ufd, &osmo_fds, list) { llist_for_each_entry(ufd, &osmo_fds, list) {
if (ufd->when & BSC_FD_READ) if (ufd->when & BSC_FD_READ)
FD_SET(ufd->fd, &readset); FD_SET(ufd->fd, readset);
if (ufd->when & BSC_FD_WRITE) if (ufd->when & BSC_FD_WRITE)
FD_SET(ufd->fd, &writeset); FD_SET(ufd->fd, writeset);
if (ufd->when & BSC_FD_EXCEPT) if (ufd->when & BSC_FD_EXCEPT)
FD_SET(ufd->fd, &exceptset); FD_SET(ufd->fd, exceptset);
} }
osmo_timers_check(); return maxfd;
}
if (!polling) inline int osmo_fd_disp_fds(void *_rset, void *_wset, void *_eset)
osmo_timers_prepare(); {
rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest()); struct osmo_fd *ufd, *tmp;
if (rc < 0) int work = 0;
return 0; fd_set *readset = _rset, *writeset = _wset, *exceptset = _eset;
/* fire timers */
osmo_timers_update();
/* call registered callback functions */
restart: restart:
unregistered_count = 0; unregistered_count = 0;
llist_for_each_entry_safe(ufd, tmp, &osmo_fds, list) { llist_for_each_entry_safe(ufd, tmp, &osmo_fds, list) {
int flags = 0; int flags = 0;
if (FD_ISSET(ufd->fd, &readset)) { if (FD_ISSET(ufd->fd, readset)) {
flags |= BSC_FD_READ; flags |= BSC_FD_READ;
FD_CLR(ufd->fd, &readset); FD_CLR(ufd->fd, readset);
} }
if (FD_ISSET(ufd->fd, &writeset)) { if (FD_ISSET(ufd->fd, writeset)) {
flags |= BSC_FD_WRITE; flags |= BSC_FD_WRITE;
FD_CLR(ufd->fd, &writeset); FD_CLR(ufd->fd, writeset);
} }
if (FD_ISSET(ufd->fd, &exceptset)) { if (FD_ISSET(ufd->fd, exceptset)) {
flags |= BSC_FD_EXCEPT; flags |= BSC_FD_EXCEPT;
FD_CLR(ufd->fd, &exceptset); FD_CLR(ufd->fd, exceptset);
} }
if (flags) { if (flags) {
@ -167,9 +154,41 @@ restart:
if (unregistered_count >= 1) if (unregistered_count >= 1)
goto restart; goto restart;
} }
return work; return work;
} }
/*! \brief select main loop integration
* \param[in] polling should we pollonly (1) or block on select (0)
*/
int osmo_select_main(int polling)
{
fd_set readset, writeset, exceptset;
int rc;
struct timeval no_time = {0, 0};
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_ZERO(&exceptset);
/* prepare read and write fdsets */
osmo_fd_fill_fds(&readset, &writeset, &exceptset);
osmo_timers_check();
if (!polling)
osmo_timers_prepare();
rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : osmo_timers_nearest());
if (rc < 0)
return 0;
/* fire timers */
osmo_timers_update();
/* call registered callback functions */
return osmo_fd_disp_fds(&readset, &writeset, &exceptset);
}
/*! \brief find an osmo_fd based on the integer fd */ /*! \brief find an osmo_fd based on the integer fd */
struct osmo_fd *osmo_fd_get_by_fd(int fd) struct osmo_fd *osmo_fd_get_by_fd(int fd)
{ {