[PATCH v2 1/4] dm: support iothread


Conghui Chen
 

Supply a decidate thread, which can moniter a set of fds with epoll,
when the data is ready, call the corresponding callback.

This iothread will be created automatically with the first successful
call to iothread_add, and will be destroyed in iothread_deinit if it
was created.

Note, currenlty only support one iothread.

v1->v2: add mtx and fix tiny bugs.

Signed-off-by: Conghui <conghui.chen@...>
---
devicemodel/Makefile | 1 +
devicemodel/core/iothread.c | 158 +++++++++++++++++++++++++++++++++
devicemodel/core/main.c | 10 +++
devicemodel/include/iothread.h | 19 ++++
4 files changed, 188 insertions(+)
create mode 100644 devicemodel/core/iothread.c
create mode 100644 devicemodel/include/iothread.h

diff --git a/devicemodel/Makefile b/devicemodel/Makefile
index 1b0b27384..823265e27 100644
--- a/devicemodel/Makefile
+++ b/devicemodel/Makefile
@@ -170,6 +170,7 @@ SRCS += core/sw_load_vsbl.c
SRCS += core/sw_load_ovmf.c
SRCS += core/sw_load_elf.c
SRCS += core/mevent.c
+SRCS += core/iothread.c
SRCS += core/pm.c
SRCS += core/pm_vuart.c
SRCS += core/console.c
diff --git a/devicemodel/core/iothread.c b/devicemodel/core/iothread.c
new file mode 100644
index 000000000..4584ea1cd
--- /dev/null
+++ b/devicemodel/core/iothread.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2022 Intel Corporation.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+*/
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/queue.h>
+#include <pthread.h>
+#include <signal.h>
+
+#include "iothread.h"
+#include "log.h"
+#include "mevent.h"
+
+
+#define MEVENT_MAX 64
+struct iothread_ctx {
+ pthread_t tid;
+ int epfd;
+ bool started;
+ pthread_mutex_t mtx;
+};
+static struct iothread_ctx ioctx;
+
+static void *
+io_thread(void *arg)
+{
+ struct epoll_event eventlist[MEVENT_MAX];
+ struct iothread_mevent *aevp;
+ int i, n;
+
+ while(ioctx.started) {
+ n = epoll_wait(ioctx.epfd, eventlist, MEVENT_MAX, -1);
+ if (n < 0) {
+ if (errno == EINTR)
+ pr_info("%s: exit from epoll_wait\n", __func__);
+ else
+ pr_err("%s: return from epoll wait with errno %d\r\n", __func__, errno);
+ break;
+ }
+ for (i = 0; i < n; i++) {
+ aevp = eventlist[i].data.ptr;
+ if (aevp && aevp->run)
+ (*aevp->run)(aevp->arg);
+ }
+ }
+
+ return NULL;
+}
+
+static int
+iothread_start(void)
+{
+ pthread_mutex_lock(&ioctx.mtx);
+
+ if (ioctx.started) {
+ pthread_mutex_unlock(&ioctx.mtx);
+ return 0;
+ }
+
+ if (pthread_create(&ioctx.tid, NULL, io_thread, NULL) != 0) {
+ pthread_mutex_unlock(&ioctx.mtx);
+ pr_err("%s", "iothread create failed\r\n");
+ return -1;
+ }
+ ioctx.started = true;
+ pthread_setname_np(ioctx.tid, "iothread");
+ pthread_mutex_unlock(&ioctx.mtx);
+ pr_info("iothread started\n");
+ return 0;
+}
+
+int
+iothread_add(int fd, struct iothread_mevent *aevt)
+{
+ struct epoll_event ee;
+ int ret;
+ /* Create a epoll instance before the first fd is added.*/
+ ee.events = EPOLLIN;
+ ee.data.ptr = aevt;
+ ret = epoll_ctl(ioctx.epfd, EPOLL_CTL_ADD, fd, &ee);
+ if (ret < 0) {
+ pr_err("%s: failed to add fd, error is %d\n",
+ __func__, errno);
+ return ret;
+ }
+
+ /* Start the iothread after the first fd is added.*/
+ ret = iothread_start();
+ if (ret < 0) {
+ pr_err("%s: failed to start iothread thread\n",
+ __func__);
+ }
+ return ret;
+}
+
+int
+iothread_del(int fd)
+{
+ int ret = 0;
+
+ if (ioctx.epfd) {
+ ret = epoll_ctl(ioctx.epfd, EPOLL_CTL_DEL, fd, NULL);
+ if (ret < 0)
+ pr_err("%s: failed to delete fd from epoll fd, error is %d\n",
+ __func__, errno);
+ }
+ return ret;
+}
+
+void
+iothread_deinit(void)
+{
+ void *jval;
+
+ if (ioctx.tid > 0) {
+ pthread_mutex_lock(&ioctx.mtx);
+ ioctx.started = false;
+ pthread_mutex_unlock(&ioctx.mtx);
+ pthread_kill(ioctx.tid, SIGCONT);
+ pthread_join(ioctx.tid, &jval);
+ }
+ if (ioctx.epfd > 0) {
+ close(ioctx.epfd);
+ ioctx.epfd = -1;
+ }
+ pthread_mutex_destroy(&ioctx.mtx);
+ pr_info("iothread stop\n");
+}
+
+int
+iothread_init(void)
+{
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&ioctx.mtx, &attr);
+ pthread_mutexattr_destroy(&attr);
+
+ ioctx.tid = -1;
+ ioctx.started = false;
+ ioctx.epfd = epoll_create1(0);
+
+ if (ioctx.epfd < 0) {
+ pr_err("%s: failed to create epoll fd, error is %d\r\n",
+ __func__, errno);
+ return -1;
+ }
+ return 0;
+}
diff --git a/devicemodel/core/main.c b/devicemodel/core/main.c
index 924a6b5d6..f2acb0b15 100644
--- a/devicemodel/core/main.c
+++ b/devicemodel/core/main.c
@@ -70,6 +70,7 @@
#include "vssram.h"
#include "cmd_monitor.h"
#include "vdisplay.h"
+#include "iothread.h"

#define VM_MAXCPU 16 /* maximum virtual cpus */

@@ -1105,6 +1106,12 @@ main(int argc, char *argv[])
goto mevent_fail;
}

+ error = iothread_init();
+ if (error) {
+ pr_err("Unable to initialize iothread (%d)\n", errno);
+ goto iothread_fail;
+ }
+
pr_notice("vm_init_vdevs\n");
if (vm_init_vdevs(ctx) < 0) {
pr_err("Unable to init vdev (%d)\n", errno);
@@ -1167,6 +1174,7 @@ main(int argc, char *argv[])

vm_deinit_vdevs(ctx);
mevent_deinit();
+ iothread_deinit();
vm_unsetup_memory(ctx);
vm_destroy(ctx);
_ctx = 0;
@@ -1181,6 +1189,8 @@ vm_fail:
clean_vssram_configs();

dev_fail:
+ iothread_deinit();
+iothread_fail:
mevent_deinit();
mevent_fail:
vm_unsetup_memory(ctx);
diff --git a/devicemodel/include/iothread.h b/devicemodel/include/iothread.h
new file mode 100644
index 000000000..6a3cc7167
--- /dev/null
+++ b/devicemodel/include/iothread.h
@@ -0,0 +1,19 @@
+/* Copyright (C) 2022 Intel Corporation.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#ifndef _iothread_CTX_H_
+#define _iothread_CTX_H_
+
+struct iothread_mevent {
+ void (*run)(void *);
+ void *arg;
+};
+int iothread_add(int fd, struct iothread_mevent *aevt);
+int iothread_del(int fd);
+int iothread_init(void);
+void iothread_deinit(void);
+
+#endif
--
2.25.1

Join acrn-dev@lists.projectacrn.org to automatically receive all group messages.