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