From a6c4f29f835a9c768f217cb1fbf70d385dce3569 Mon Sep 17 00:00:00 2001
From: Recolic Keghart <root@recolic.net>
Date: Sun, 29 Dec 2019 23:28:13 +0800
Subject: [PATCH] async device update

---
 nemu/Makefile             |  2 +-
 nemu/src/device/device.cc | 26 +++++++++++++++++++-------
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/nemu/Makefile b/nemu/Makefile
index 57860b6..d47a0af 100644
--- a/nemu/Makefile
+++ b/nemu/Makefile
@@ -53,7 +53,7 @@ NEMU_EXEC := $(BINARY) $(ARGS)
 $(BINARY): $(OBJS)
 	$(call git_commit, "compile")
 	@echo + LD $@
-	@$(LD) -O2 -rdynamic $(SO_LDLAGS) -o $@ $^ -lSDL2 -lreadline -ldl
+	@$(LD) -O2 -rdynamic $(SO_LDLAGS) -o $@ $^ -lSDL2 -lreadline -ldl -pthread
 
 run: $(BINARY)
 	$(call git_commit, "run")
diff --git a/nemu/src/device/device.cc b/nemu/src/device/device.cc
index 560d1b0..b36ae40 100644
--- a/nemu/src/device/device.cc
+++ b/nemu/src/device/device.cc
@@ -6,13 +6,16 @@
 #include <signal.h>
 #include <SDL2/SDL.h>
 
+#include <thread>
+#include <atomic>
+
 #define TIMER_HZ 100
 #define VGA_HZ 50
 
 static uint64_t jiffy = 0;
 static struct itimerval it;
-static int device_update_flag = false;
-static int update_screen_flag = false;
+static std::atomic<bool> device_update_flag(false);
+static std::atomic<bool> update_screen_flag(false);
 
 void init_serial();
 void init_timer();
@@ -37,12 +40,9 @@ static void timer_sig_handler(int signum) {
   Assert(ret == 0, "Can not set timer");
 }
 
-void device_update() {
-  if (!device_update_flag) {
-    return;
-  }
-  device_update_flag = false;
+void device_update() {} // Now an independent thread will do it.
 
+void device_update_impl() {
   if (update_screen_flag) {
     update_screen();
     update_screen_flag = false;
@@ -72,6 +72,16 @@ void device_update() {
   }
 }
 
+static void device_update_thread_daemon() {
+  while(true) {
+    if(device_update_flag.exchange(false)) {
+      device_update_impl();
+    }
+    // At most, 1000FPS
+    std::this_thread::sleep_for(std::chrono::milliseconds(1));
+  }
+}
+
 void sdl_clear_event_queue() {
   SDL_Event event;
   while (SDL_PollEvent(&event));
@@ -93,6 +103,8 @@ void init_device() {
   it.it_value.tv_usec = 1000000 / TIMER_HZ;
   ret = setitimer(ITIMER_VIRTUAL, &it, NULL);
   Assert(ret == 0, "Can not set timer");
+
+  std::thread(device_update_thread_daemon).detach();
 }
 #else
 
-- 
GitLab