From 21425705a687706faa642e8b99a9c549d7bcaab6 Mon Sep 17 00:00:00 2001
From: yangchen <yangchen145@huawei.com>
Date: Thu, 2 Nov 2023 16:10:04 +0800
Subject: [PATCH] wrap: support select

---
 src/lstack/api/lstack_epoll.c           | 88 +++++++++++++++++++++++++
 src/lstack/api/lstack_rtc_api.c         |  7 ++
 src/lstack/api/lstack_rtw_api.c         |  5 ++
 src/lstack/api/lstack_wrap.c            | 19 ++++++
 src/lstack/include/lstack_rtc_api.h     |  2 +
 src/lstack/include/lstack_rtw_api.h     |  3 +
 src/lstack/include/posix/lstack_epoll.h |  1 +
 7 files changed, 125 insertions(+)

diff --git a/src/lstack/api/lstack_epoll.c b/src/lstack/api/lstack_epoll.c
index a711ae3..f2c4a8b 100644
--- a/src/lstack/api/lstack_epoll.c
+++ b/src/lstack/api/lstack_epoll.c
@@ -13,6 +13,7 @@
 #include <string.h>
 #include <securec.h>
 #include <sys/epoll.h>
+#include <sys/select.h>
 #include <time.h>
 #include <poll.h>
 #include <stdatomic.h>
@@ -870,3 +871,90 @@ int32_t lstack_poll(struct pollfd *fds, nfds_t nfds, int32_t timeout)
     __atomic_store_n(&wakeup->in_wait, false, __ATOMIC_RELEASE);
     return lwip_num + kernel_num;
 }
+
+static void select_set_revent_fdset(struct pollfd *fds, nfds_t nfds, fd_set *eventfds, uint32_t event)
+{
+    FD_ZERO(eventfds);
+
+    /* Set the fd_set parameter based on the actual revents. */
+    for (int i = 0; i < nfds; i++) {
+        if (fds[i].revents & event) {
+            FD_SET(fds[i].fd, eventfds);
+        }
+    }
+}
+
+static void fds_poll2select(struct pollfd *fds, nfds_t nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds)
+{
+    if (fds == NULL || nfds == 0) {
+        return;
+    }
+    
+    if (readfds) {
+        select_set_revent_fdset(fds, nfds, readfds, EPOLLIN);
+    }
+    if (writefds) {
+        select_set_revent_fdset(fds, nfds, writefds, EPOLLOUT);
+    }
+    if (exceptfds) {
+        select_set_revent_fdset(fds, nfds, exceptfds, EPOLLERR);
+    }
+}
+
+static inline int timeval_to_ms(struct timeval *timeval)
+{
+    if (timeval == NULL) {
+        return -1;
+    }
+
+    return (timeval->tv_sec * 1000 + timeval->tv_usec / 1000);
+}
+
+static nfds_t fds_select2poll(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct pollfd **fds)
+{
+    struct pollfd pollfds[FD_SETSIZE] = { 0 };
+    nfds_t nfds = 0;
+
+    for (int i = 0; i < maxfd; i++) {
+        if (readfds && FD_ISSET(i, readfds)) {
+            pollfds[nfds].events = POLLIN;
+        }
+        if (writefds && FD_ISSET(i, writefds)) {
+            pollfds[nfds].events |= POLLOUT;
+        }
+        if (exceptfds && FD_ISSET(i, exceptfds)) {
+            pollfds[nfds].events |= POLLERR;
+        }
+        if (pollfds[nfds].events > 0) {
+            pollfds[nfds].fd = i;
+            nfds++;
+        }
+    }
+
+    *fds = pollfds;
+    return nfds;
+}
+
+int lstack_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeval)
+{
+    if (maxfd == 0) {
+        return 0;
+    }
+
+    if (maxfd < 0 || maxfd > FD_SETSIZE || (readfds == NULL && writefds == NULL && exceptfds == NULL)) {
+        GAZELLE_RETURN(EINVAL);
+    }
+    
+    /* Convert the select parameter to the poll parameter. */
+    struct pollfd *fds = NULL;
+    nfds_t nfds = fds_select2poll(maxfd, readfds, writefds, exceptfds, &fds);
+    int timeout = timeval_to_ms(timeval);
+
+    int event_num = lstack_poll(fds, nfds, timeout);
+    
+    /* After poll, set select fd_set by fds.revents. */
+    fds_poll2select(fds, nfds, readfds, writefds, exceptfds);
+
+    return event_num;
+}
+
diff --git a/src/lstack/api/lstack_rtc_api.c b/src/lstack/api/lstack_rtc_api.c
index 059b518..5fad3e8 100644
--- a/src/lstack/api/lstack_rtc_api.c
+++ b/src/lstack/api/lstack_rtc_api.c
@@ -24,6 +24,13 @@
 
 int rtc_poll(struct pollfd *fds, nfds_t nfds, int timeout)
 {
+    LSTACK_LOG(ERR, LSTACK, "rtc_poll: rtc currently does not support poll\n");
+    return -1;
+}
+
+int rtc_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+    LSTACK_LOG(ERR, LSTACK, "rtc_select: rtc currently does not support select\n");
     return -1;
 }
 
diff --git a/src/lstack/api/lstack_rtw_api.c b/src/lstack/api/lstack_rtw_api.c
index 7d14ffa..c524bf9 100644
--- a/src/lstack/api/lstack_rtw_api.c
+++ b/src/lstack/api/lstack_rtw_api.c
@@ -214,6 +214,11 @@ int rtw_poll(struct pollfd *fds, nfds_t nfds, int timeout)
     return lstack_poll(fds, nfds, timeout);
 }
 
+int rtw_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+    return lstack_select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
 int rtw_close(int s)
 {
     struct lwip_sock *sock = get_socket(s);
diff --git a/src/lstack/api/lstack_wrap.c b/src/lstack/api/lstack_wrap.c
index a808ee8..5bad513 100644
--- a/src/lstack/api/lstack_wrap.c
+++ b/src/lstack/api/lstack_wrap.c
@@ -76,6 +76,7 @@ void wrap_api_init(void)
         g_wrap_api->epoll_ctl_fn     = rtc_epoll_ctl;
         g_wrap_api->epoll_create1_fn = rtc_epoll_create1;
         g_wrap_api->epoll_create_fn  = rtc_epoll_create;
+        g_wrap_api->select_fn        = rtc_select;
     } else {
         g_wrap_api->socket_fn        = rtw_socket;
         g_wrap_api->accept_fn        = rtw_accept;
@@ -103,6 +104,7 @@ void wrap_api_init(void)
         g_wrap_api->epoll_ctl_fn     = rtw_epoll_ctl;
         g_wrap_api->epoll_create1_fn = rtw_epoll_create1;
         g_wrap_api->epoll_create_fn  = rtw_epoll_create;
+        g_wrap_api->select_fn        = rtw_select;
     }
 }
 
@@ -609,6 +611,15 @@ static int32_t do_sigaction(int32_t signum, const struct sigaction *act, struct
     return lstack_sigaction(signum, act, oldact);
 }
 
+static int32_t do_select(int32_t nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+    if (select_posix_path() == PATH_KERNEL) {
+        return posix_api->select_fn(nfds, readfds, writefds, exceptfds, timeout);
+    }
+
+    return g_wrap_api->select_fn(nfds, readfds, writefds, exceptfds, timeout);
+}
+
 #define WRAP_VA_PARAM(_fd, _cmd, _lwip_fcntl, _fcntl_fn) \
     do { \
         unsigned long val; \
@@ -769,6 +780,10 @@ pid_t fork(void)
 {
     return lstack_fork();
 }
+int32_t select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+    return do_select(nfds, readfds, writefds, exceptfds, timeout);
+}
 
 /*  --------------------------------------------------------
  *  -------  Compile mode replacement interface  -----------
@@ -898,3 +913,7 @@ pid_t __wrap_fork(void)
 {
     return lstack_fork();
 }
+int32_t __wrap_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
+{
+    return do_select(nfds, readfds, writefds, exceptfds, timeout);
+}
diff --git a/src/lstack/include/lstack_rtc_api.h b/src/lstack/include/lstack_rtc_api.h
index 0aff928..dd90e59 100644
--- a/src/lstack/include/lstack_rtc_api.h
+++ b/src/lstack/include/lstack_rtc_api.h
@@ -13,6 +13,7 @@
 #ifndef _LSTACK_RTC_API_H_
 #define _LSTACK_RTC_API_H_
 #include <sys/epoll.h>
+#include <sys/select.h>
 #include <sys/socket.h>
 
 /* don't include lwip/sockets.h, conflict with sys/socket.h */
@@ -51,5 +52,6 @@ int rtc_close(int s);
 int rtc_epoll_create(int flags);
 int rtc_epoll_create1(int flags);
 int rtc_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
+int rtc_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
 
 #endif /* __LSTACK_RTC_API_H_  */
diff --git a/src/lstack/include/lstack_rtw_api.h b/src/lstack/include/lstack_rtw_api.h
index facf4c0..d0f77b7 100644
--- a/src/lstack/include/lstack_rtw_api.h
+++ b/src/lstack/include/lstack_rtw_api.h
@@ -14,6 +14,7 @@
 #define _LSTACK_RTW_API_H_
 
 #include <sys/epoll.h>
+#include <sys/select.h>
 #include <sys/socket.h>
 
 int rtw_socket(int domain, int type, int protocol);
@@ -44,4 +45,6 @@ int rtw_close(int s);
 int rtw_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
 int rtw_epoll_create1(int flags);
 int rtw_epoll_create(int flags);
+int rtw_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
+
 #endif /* _LSTACK_RTW_API_H_ */
diff --git a/src/lstack/include/posix/lstack_epoll.h b/src/lstack/include/posix/lstack_epoll.h
index c42f3a5..9c34eb3 100644
--- a/src/lstack/include/posix/lstack_epoll.h
+++ b/src/lstack/include/posix/lstack_epoll.h
@@ -78,6 +78,7 @@ int32_t lstack_rtc_epoll_ctl(int32_t epfd, int32_t op, int32_t fd, struct epoll_
 int32_t lstack_rtw_epoll_wait(int32_t epfd, struct epoll_event *events, int32_t maxevents, int32_t timeout);
 int32_t lstack_rtc_epoll_wait(int32_t epfd, struct epoll_event* events, int32_t maxevents, int32_t timeout);
 int32_t lstack_poll(struct pollfd *fds, nfds_t nfds, int32_t timeout);
+int lstack_select(int maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeval);
 
 #ifdef __cplusplus
 }
-- 
2.27.0

