|
@@ -0,0 +1,186 @@
|
|
|
+/* Copyright (C) 2019 Intel Corporation
|
|
|
+ This file is part of Graphene Library OS.
|
|
|
+
|
|
|
+ Graphene Library OS is free software: you can redistribute it and/or
|
|
|
+ modify it under the terms of the GNU Lesser General Public License
|
|
|
+ as published by the Free Software Foundation, either version 3 of the
|
|
|
+ License, or (at your option) any later version.
|
|
|
+
|
|
|
+ Graphene Library OS is distributed in the hope that it will be useful,
|
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ GNU Lesser General Public License for more details.
|
|
|
+
|
|
|
+ You should have received a copy of the GNU Lesser General Public License
|
|
|
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
+
|
|
|
+/*
|
|
|
+ * db_eventfd.c
|
|
|
+ *
|
|
|
+ * This file contains operations to handle streams with URIs that have
|
|
|
+ * "eventfd:".
|
|
|
+ */
|
|
|
+
|
|
|
+#include <asm/fcntl.h>
|
|
|
+#include <asm/poll.h>
|
|
|
+#include <linux/un.h>
|
|
|
+#include <linux/time.h>
|
|
|
+#include <linux/types.h>
|
|
|
+#include <sys/eventfd.h>
|
|
|
+
|
|
|
+#include "api.h"
|
|
|
+#include "pal_defs.h"
|
|
|
+#include "pal_linux_defs.h"
|
|
|
+#include "pal.h"
|
|
|
+#include "pal_internal.h"
|
|
|
+#include "pal_linux.h"
|
|
|
+#include "pal_linux_error.h"
|
|
|
+#include "pal_error.h"
|
|
|
+#include "pal_security.h"
|
|
|
+#include "pal_debug.h"
|
|
|
+
|
|
|
+static inline int eventfd_type(int options) {
|
|
|
+ int type = 0;
|
|
|
+ if (options & PAL_OPTION_NONBLOCK)
|
|
|
+ type |= EFD_NONBLOCK;
|
|
|
+
|
|
|
+ if (options & PAL_OPTION_CLOEXEC)
|
|
|
+ type |= EFD_CLOEXEC;
|
|
|
+
|
|
|
+ if (options & PAL_OPTION_EFD_SEMAPHORE)
|
|
|
+ type |= EFD_SEMAPHORE;
|
|
|
+
|
|
|
+ return type;
|
|
|
+}
|
|
|
+
|
|
|
+/* `type` must be eventfd, `uri` & `access` & `share` are unused,
|
|
|
+ * `create` holds eventfd's initval, `options` holds eventfd's flags */
|
|
|
+static int eventfd_pal_open(PAL_HANDLE* handle, const char* type, const char* uri, int access,
|
|
|
+ int share, int create, int options) {
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ __UNUSED(access);
|
|
|
+ __UNUSED(share);
|
|
|
+
|
|
|
+ if ((strcmp_static(type, "eventfd") != 0) || (*uri != '\0')) {
|
|
|
+ return -PAL_ERROR_INVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Using create arg as a work-around (note: initval is uint32 but create is int32).*/
|
|
|
+ ret = INLINE_SYSCALL(eventfd2, 2, create, eventfd_type(options));
|
|
|
+
|
|
|
+ if (IS_ERR(ret))
|
|
|
+ return unix_to_pal_error(ERRNO(ret));
|
|
|
+
|
|
|
+ PAL_HANDLE hdl = malloc(HANDLE_SIZE(eventfd));
|
|
|
+ SET_HANDLE_TYPE(hdl, eventfd);
|
|
|
+
|
|
|
+ /* Note: using index 0, given that there is only 1 eventfd FD per pal-handle. */
|
|
|
+ HANDLE_HDR(hdl)->flags = RFD(0) | WFD(0) | WRITABLE(0);
|
|
|
+
|
|
|
+ hdl->eventfd.fd = ret;
|
|
|
+ hdl->eventfd.nonblocking = (options & PAL_OPTION_NONBLOCK) ? PAL_TRUE : PAL_FALSE;
|
|
|
+ *handle = hdl;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static int64_t eventfd_pal_read(PAL_HANDLE handle, uint64_t offset, uint64_t len, void* buffer) {
|
|
|
+ if (offset)
|
|
|
+ return -PAL_ERROR_INVAL;
|
|
|
+
|
|
|
+ if (!IS_HANDLE_TYPE(handle, eventfd))
|
|
|
+ return -PAL_ERROR_NOTCONNECTION;
|
|
|
+
|
|
|
+ if (len < sizeof(uint64_t))
|
|
|
+ return -PAL_ERROR_INVAL;
|
|
|
+
|
|
|
+ int bytes = INLINE_SYSCALL(read, 3, handle->eventfd.fd, buffer, len);
|
|
|
+
|
|
|
+ if (IS_ERR(bytes))
|
|
|
+ return unix_to_pal_error(ERRNO(bytes));
|
|
|
+
|
|
|
+ if (!bytes)
|
|
|
+ return -PAL_ERROR_ENDOFSTREAM;
|
|
|
+
|
|
|
+ return bytes;
|
|
|
+}
|
|
|
+
|
|
|
+static int64_t eventfd_pal_write(PAL_HANDLE handle, uint64_t offset, uint64_t len,
|
|
|
+ const void* buffer) {
|
|
|
+ if (offset)
|
|
|
+ return -PAL_ERROR_INVAL;
|
|
|
+
|
|
|
+ if (!IS_HANDLE_TYPE(handle, eventfd))
|
|
|
+ return -PAL_ERROR_NOTCONNECTION;
|
|
|
+
|
|
|
+ if (len < sizeof(uint64_t))
|
|
|
+ return -PAL_ERROR_INVAL;
|
|
|
+
|
|
|
+ int bytes = INLINE_SYSCALL(write, 3, handle->eventfd.fd, buffer, len);
|
|
|
+ PAL_FLG writable = WRITABLE(0);
|
|
|
+
|
|
|
+ if (IS_ERR(bytes)) {
|
|
|
+ if (ERRNO(bytes) == EAGAIN)
|
|
|
+ HANDLE_HDR(handle)->flags &= ~writable;
|
|
|
+ return unix_to_pal_error(ERRNO(bytes));
|
|
|
+ }
|
|
|
+
|
|
|
+ /* whether fd is writable or not, gets updated here,
|
|
|
+ * to optimize polling logic in _DkObjectsWaitAny */
|
|
|
+ if ((uint64_t) bytes == sizeof(uint64_t))
|
|
|
+ HANDLE_HDR(handle)->flags |= writable;
|
|
|
+ else
|
|
|
+ HANDLE_HDR(handle)->flags &= ~writable;
|
|
|
+
|
|
|
+ return bytes;
|
|
|
+}
|
|
|
+
|
|
|
+/* invoked during poll operation on eventfd from LibOS. */
|
|
|
+static int eventfd_pal_attrquerybyhdl(PAL_HANDLE handle, PAL_STREAM_ATTR* attr) {
|
|
|
+ if (handle->generic.fds[0] == PAL_IDX_POISON)
|
|
|
+ return -PAL_ERROR_BADHANDLE;
|
|
|
+
|
|
|
+ attr->handle_type = PAL_GET_TYPE(handle);
|
|
|
+ int efd = handle->eventfd.fd;
|
|
|
+ int flags = HANDLE_HDR(handle)->flags;
|
|
|
+
|
|
|
+ struct pollfd pfd = { .fd = efd, .events = POLLIN, .revents = 0 };
|
|
|
+ struct timespec tp = {0, 0};
|
|
|
+ int ret = INLINE_SYSCALL(ppoll, 5, &pfd, 1, &tp, NULL, 0);
|
|
|
+
|
|
|
+ if (IS_ERR(ret))
|
|
|
+ return unix_to_pal_error(ERRNO(ret));
|
|
|
+
|
|
|
+ attr->readable = (ret == 1 && pfd.revents == POLLIN);
|
|
|
+ attr->disconnected = flags & ERROR(0);
|
|
|
+ attr->nonblocking = handle->eventfd.nonblocking;
|
|
|
+
|
|
|
+ /* For future use, so that Linux host kernel can send notifications to user-space apps.
|
|
|
+ * App receives virtual FD from LibOS, but the Linux-host eventfd is memorized
|
|
|
+ * here, such that this Linux-host eventfd can be retrieved (by LibOS) during app's ioctl(). */
|
|
|
+ attr->no_of_fds = 1;
|
|
|
+ attr->fds[0] = efd;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int eventfd_pal_close(PAL_HANDLE handle) {
|
|
|
+ if (IS_HANDLE_TYPE(handle, eventfd)) {
|
|
|
+ if (handle->eventfd.fd != PAL_IDX_POISON) {
|
|
|
+ INLINE_SYSCALL(close, 1, handle->eventfd.fd);
|
|
|
+ handle->eventfd.fd = PAL_IDX_POISON;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+struct handle_ops eventfd_ops = {
|
|
|
+ .open = &eventfd_pal_open,
|
|
|
+ .read = &eventfd_pal_read,
|
|
|
+ .write = &eventfd_pal_write,
|
|
|
+ .close = &eventfd_pal_close,
|
|
|
+ .attrquerybyhdl = &eventfd_pal_attrquerybyhdl,
|
|
|
+};
|