aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2011-02-15 18:35:05 +0000
committerRiku Voipio <riku.voipio@nokia.com>2011-02-17 11:46:34 +0200
commit3b6edd1611e25099a1df20771ce3f88939a0e93a (patch)
tree510c84632687df90f0f47d7159c5eb8e9ab7e8aa
parentd2ee72a5b17d95fe0e57e496f1b2ddb2464b5c08 (diff)
linux-user: Support the epoll syscalls
Support the epoll family of syscalls: epoll_create(), epoll_create1(), epoll_ctl(), epoll_wait() and epoll_pwait(). Note that epoll_create1() and epoll_pwait() are later additions, so we have to test separately in configure for their presence. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Riku Voipio <riku.voipio@nokia.com>
-rwxr-xr-xconfigure54
-rw-r--r--linux-user/syscall.c107
-rw-r--r--linux-user/syscall_defs.h13
3 files changed, 174 insertions, 0 deletions
diff --git a/configure b/configure
index a3f53456f4..cb72ced129 100755
--- a/configure
+++ b/configure
@@ -2142,6 +2142,51 @@ if compile_prog "" "" ; then
dup3=yes
fi
+# check for epoll support
+epoll=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+ epoll_create(0);
+ return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+ epoll=yes
+fi
+
+# epoll_create1 and epoll_pwait are later additions
+# so we must check separately for their presence
+epoll_create1=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+ epoll_create1(0);
+ return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+ epoll_create1=yes
+fi
+
+epoll_pwait=no
+cat > $TMPC << EOF
+#include <sys/epoll.h>
+
+int main(void)
+{
+ epoll_pwait(0, 0, 0, 0, 0);
+ return 0;
+}
+EOF
+if compile_prog "$ARCH_CFLAGS" "" ; then
+ epoll_pwait=yes
+fi
+
# Check if tools are available to build documentation.
if test "$docs" != "no" ; then
if has makeinfo && has pod2man; then
@@ -2674,6 +2719,15 @@ fi
if test "$dup3" = "yes" ; then
echo "CONFIG_DUP3=y" >> $config_host_mak
fi
+if test "$epoll" = "yes" ; then
+ echo "CONFIG_EPOLL=y" >> $config_host_mak
+fi
+if test "$epoll_create1" = "yes" ; then
+ echo "CONFIG_EPOLL_CREATE1=y" >> $config_host_mak
+fi
+if test "$epoll_pwait" = "yes" ; then
+ echo "CONFIG_EPOLL_PWAIT=y" >> $config_host_mak
+fi
if test "$inotify" = "yes" ; then
echo "CONFIG_INOTIFY=y" >> $config_host_mak
fi
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 4412a9b143..cf8a4c3876 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -66,6 +66,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#ifdef CONFIG_EVENTFD
#include <sys/eventfd.h>
#endif
+#ifdef CONFIG_EPOLL
+#include <sys/epoll.h>
+#endif
#define termios host_termios
#define winsize host_winsize
@@ -7612,6 +7615,110 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
break;
#endif
#endif
+#if defined(CONFIG_EPOLL)
+#if defined(TARGET_NR_epoll_create)
+ case TARGET_NR_epoll_create:
+ ret = get_errno(epoll_create(arg1));
+ break;
+#endif
+#if defined(TARGET_NR_epoll_create1) && defined(CONFIG_EPOLL_CREATE1)
+ case TARGET_NR_epoll_create1:
+ ret = get_errno(epoll_create1(arg1));
+ break;
+#endif
+#if defined(TARGET_NR_epoll_ctl)
+ case TARGET_NR_epoll_ctl:
+ {
+ struct epoll_event ep;
+ struct epoll_event *epp = 0;
+ if (arg4) {
+ struct target_epoll_event *target_ep;
+ if (!lock_user_struct(VERIFY_READ, target_ep, arg4, 1)) {
+ goto efault;
+ }
+ ep.events = tswap32(target_ep->events);
+ /* The epoll_data_t union is just opaque data to the kernel,
+ * so we transfer all 64 bits across and need not worry what
+ * actual data type it is.
+ */
+ ep.data.u64 = tswap64(target_ep->data.u64);
+ unlock_user_struct(target_ep, arg4, 0);
+ epp = &ep;
+ }
+ ret = get_errno(epoll_ctl(arg1, arg2, arg3, epp));
+ break;
+ }
+#endif
+
+#if defined(TARGET_NR_epoll_pwait) && defined(CONFIG_EPOLL_PWAIT)
+#define IMPLEMENT_EPOLL_PWAIT
+#endif
+#if defined(TARGET_NR_epoll_wait) || defined(IMPLEMENT_EPOLL_PWAIT)
+#if defined(TARGET_NR_epoll_wait)
+ case TARGET_NR_epoll_wait:
+#endif
+#if defined(IMPLEMENT_EPOLL_PWAIT)
+ case TARGET_NR_epoll_pwait:
+#endif
+ {
+ struct target_epoll_event *target_ep;
+ struct epoll_event *ep;
+ int epfd = arg1;
+ int maxevents = arg3;
+ int timeout = arg4;
+
+ target_ep = lock_user(VERIFY_WRITE, arg2,
+ maxevents * sizeof(struct target_epoll_event), 1);
+ if (!target_ep) {
+ goto efault;
+ }
+
+ ep = alloca(maxevents * sizeof(struct epoll_event));
+
+ switch (num) {
+#if defined(IMPLEMENT_EPOLL_PWAIT)
+ case TARGET_NR_epoll_pwait:
+ {
+ target_sigset_t *target_set;
+ sigset_t _set, *set = &_set;
+
+ if (arg5) {
+ target_set = lock_user(VERIFY_READ, arg5,
+ sizeof(target_sigset_t), 1);
+ if (!target_set) {
+ unlock_user(target_ep, arg2, 0);
+ goto efault;
+ }
+ target_to_host_sigset(set, target_set);
+ unlock_user(target_set, arg5, 0);
+ } else {
+ set = NULL;
+ }
+
+ ret = get_errno(epoll_pwait(epfd, ep, maxevents, timeout, set));
+ break;
+ }
+#endif
+#if defined(TARGET_NR_epoll_wait)
+ case TARGET_NR_epoll_wait:
+ ret = get_errno(epoll_wait(epfd, ep, maxevents, timeout));
+ break;
+#endif
+ default:
+ ret = -TARGET_ENOSYS;
+ }
+ if (!is_error(ret)) {
+ int i;
+ for (i = 0; i < ret; i++) {
+ target_ep[i].events = tswap32(ep[i].events);
+ target_ep[i].data.u64 = tswap64(ep[i].data.u64);
+ }
+ }
+ unlock_user(target_ep, arg2, ret * sizeof(struct target_epoll_event));
+ break;
+ }
+#endif
+#endif
default:
unimplemented:
gemu_log("qemu: Unsupported syscall: %d\n", num);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 4742ac0272..702652cb9e 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -2206,3 +2206,16 @@ struct target_mq_attr {
#define FUTEX_CLOCK_REALTIME 256
#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME)
+#ifdef CONFIG_EPOLL
+typedef union target_epoll_data {
+ abi_ulong ptr;
+ abi_ulong fd;
+ uint32_t u32;
+ uint64_t u64;
+} target_epoll_data_t;
+
+struct target_epoll_event {
+ uint32_t events;
+ target_epoll_data_t data;
+};
+#endif