libports: add poll() to libc

Implements poll() via select() for certain programs like OpenSSH
which need it.

(This implementation is actually based OpenSSHp's compat function.)
This commit is contained in:
Josef Söntgen 2012-07-18 16:01:30 +02:00 committed by Norman Feske
parent ced77c5403
commit a6917d982a
2 changed files with 131 additions and 1 deletions

View File

@ -14,7 +14,7 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.cc munmap.cc \
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.cc \
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
libc_mem_alloc.cc pread_pwrite.cc readv_writev.cc
libc_mem_alloc.cc pread_pwrite.cc readv_writev.cc poll.cc
#
# Files from string library that are not included in libc-raw_string because

View File

@ -0,0 +1,130 @@
/*
* \brief poll() implementation
* \author Josef Soentgen
* \date 2012-07-12
*
* this 'poll()' implementation is based on OpenSSHp's and
* uses our 'select()' function internally.
*/
/*
* Copyright (C) 2010-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/printf.h>
#include <os/timed_semaphore.h>
#include <libc-plugin/plugin_registry.h>
#include <libc-plugin/plugin.h>
#include <sys/select.h>
#include <sys/poll.h>
#include <stdlib.h>
using namespace Libc;
/**
* The poll function was taken from OpenSSH portable (bsd-poll.c) and adepted
* to better fit within Genode's libc.
*
* Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au).
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
extern "C" int
__attribute__((weak))
poll(struct pollfd fds[], nfds_t nfds, int timeout)
{
nfds_t i;
int saved_errno, ret, fd, maxfd = 0;
fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL;
size_t nmemb;
struct timeval tv, *tvp = NULL;
for (i = 0; i < nfds; i++) {
fd = fds[i].fd;
if (fd >= FD_SETSIZE) {
/*errno = EINVAL;*/
return -1;
}
maxfd = MAX(maxfd, fd);
}
nmemb = howmany(maxfd + 1 , NFDBITS);
if ((readfds = (fd_set *) calloc(nmemb, sizeof(fd_mask))) == NULL ||
(writefds = (fd_set *) calloc(nmemb, sizeof(fd_mask))) == NULL ||
(exceptfds = (fd_set *) calloc(nmemb, sizeof(fd_mask))) == NULL) {
/*saved_errno = ENOMEM;*/
ret = -1;
goto out;
}
/* populate event bit vectors for the events we're interested in */
for (i = 0; i < nfds; i++) {
fd = fds[i].fd;
if (fd == -1)
continue;
if (fds[i].events & POLLIN) {
FD_SET(fd, readfds);
FD_SET(fd, exceptfds);
}
if (fds[i].events & POLLOUT) {
FD_SET(fd, writefds);
FD_SET(fd, exceptfds);
}
}
/* poll timeout is msec, select is timeval (sec + usec) */
if (timeout >= 0) {
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
tvp = &tv;
}
ret = select(maxfd + 1, readfds, writefds, exceptfds, tvp);
/*saved_errno = errno;*/
/* scan through select results and set poll() flags */
for (i = 0; i < nfds; i++) {
fd = fds[i].fd;
fds[i].revents = 0;
if (fd == -1)
continue;
if (FD_ISSET(fd, readfds)) {
fds[i].revents |= POLLIN;
}
if (FD_ISSET(fd, writefds)) {
fds[i].revents |= POLLOUT;
}
if (FD_ISSET(fd, exceptfds)) {
fds[i].revents |= POLLERR;
}
}
out:
if (readfds != NULL)
free(readfds);
if (writefds != NULL)
free(writefds);
if (exceptfds != NULL)
free(exceptfds);
/*
if (ret == -1)
errno = saved_errno;
*/
return ret;
}