aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libtle_glue/poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libtle_glue/poll.c')
-rw-r--r--lib/libtle_glue/poll.c138
1 files changed, 138 insertions, 0 deletions
diff --git a/lib/libtle_glue/poll.c b/lib/libtle_glue/poll.c
new file mode 100644
index 0000000..ebc0110
--- /dev/null
+++ b/lib/libtle_glue/poll.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2018 Ant Financial Services Group.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <signal.h>
+#include <poll.h>
+
+#include "fd.h"
+#include "ctx.h"
+#include "sym.h"
+#include "log.h"
+#include "util.h"
+#include "internal.h"
+#include "tle_glue.h"
+
+int
+PRE(poll)(struct pollfd *fds, nfds_t nfds, int timeout)
+{
+ int efd;
+ int total = 0, j;
+ int tmp_ev;
+ uint32_t i;
+ uint32_t k_n = 0;
+ int k_fds[nfds];
+ struct sock *so;
+ struct glue_ctx *ctx;
+ struct epoll_event k_ev;
+ struct epoll_event events[nfds];
+
+ for (i = 0; i < nfds; ++i) {
+ if (is_kernel_fd(fds[i].fd)) {
+ k_fds[k_n++] = i;
+ continue;
+ }
+
+ so = fd2sock(fds[i].fd);
+ if (!so->valid)
+ continue;
+
+ fds[i].revents = fd_ready(fds[i].fd, fds[i].events);
+ if (fds[i].revents) {
+ total++;
+ continue;
+ }
+
+ /* We fill sock->event here as we need this when
+ * we filter events in poll_common(). But it was
+ * originally set by epoll_ctl(). Now we have to
+ * assume that there are no application which
+ * uses epoll and poll at the same time.
+ */
+ so->event.events = fds[i].events;
+ so->event.data.u32 = i; /* store idx */
+ }
+
+ if (k_n == nfds)
+ return k_poll(fds, nfds, timeout);
+
+ if (total > 0)
+ return total;
+
+ /* thread <> context binding happens here */
+ if (RTE_PER_LCORE(glue_ctx) == NULL) {
+ ctx = &ctx_array[glue_ctx_alloc()];
+ RTE_PER_LCORE(glue_ctx) = ctx;
+ } else
+ ctx = RTE_PER_LCORE(glue_ctx);
+
+ total = poll_common(ctx, events, nfds, 0, -1);
+
+ /* We assume kernel I/O events are not as important as user ones */
+ if (total > 0)
+ goto format;
+
+ efd = k_epoll_create(1);
+ if (efd < 0)
+ rte_panic("k_epoll_create failed %d", errno);
+
+ for (i = 0; i < k_n; ++i) {
+ k_ev.events = fds[k_fds[i]].events;
+ k_ev.data.u32 = k_fds[i]; /* store idx */
+ k_epoll_ctl(efd, EPOLL_CTL_ADD, fds[k_fds[i]].fd, &k_ev);
+ }
+
+ total = poll_common(ctx, events, nfds, timeout, efd);
+ k_close(efd);
+format:
+ for (j = 0; j < total; ++j) {
+ tmp_ev = events[j].events;
+ if (tmp_ev == POLLHUP) {
+ tmp_ev |= POLLERR | (fds[events[j].data.u32].events &
+ (POLLIN | POLLOUT));
+ }
+ fds[events[j].data.u32].revents = tmp_ev;
+ }
+
+ return total;
+}
+
+int
+PRE(ppoll)(struct pollfd *fds, nfds_t nfds,
+ const struct timespec *tmo_p, const sigset_t *sigmask)
+{
+ int timeout;
+
+ if (sigmask != NULL)
+ rte_panic("ppoll with signal is not supported");
+
+ if (tmo_p == NULL)
+ timeout = -1;
+ else
+ timeout = tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000;
+
+ return poll(fds, nfds, timeout);
+}
+
+extern int __poll_chk(struct pollfd *fds, nfds_t nfds, int timeout,
+ __SIZE_TYPE__ fdslen);
+int
+__poll_chk(struct pollfd *fds, nfds_t nfds, int timeout,
+ __SIZE_TYPE__ fdslen __rte_unused)
+{
+ return poll(fds, nfds, timeout);
+}