From a383fd43f12dcde80b70cf33157bc7f55d1c4632 Mon Sep 17 00:00:00 2001
From: Florian Schmaus <flow@cs.fau.de>
Date: Thu, 5 Nov 2020 10:29:10 +0100
Subject: [PATCH] [static analysis] Add "Include What You Use" (iwyu)

---
 Makefile                                    |  2 +
 apps/Main.cpp                               | 25 ++++----
 apps/WorkerSleepExample.cpp                 | 27 ++++----
 emper/BinaryPrivateSemaphore.cpp            |  7 +-
 emper/BinaryPrivateSemaphore.hpp            |  8 +--
 emper/Common.cpp                            |  2 -
 emper/Common.hpp                            |  2 -
 emper/Context.hpp                           | 15 ++---
 emper/ContextManager.cpp                    | 11 ++--
 emper/ContextManager.hpp                    |  9 ++-
 emper/CountingPrivateSemaphore.cpp          |  4 +-
 emper/CountingPrivateSemaphore.hpp          |  6 +-
 emper/Debug.cpp                             |  8 +--
 emper/Debug.hpp                             |  9 ++-
 emper/Dispatcher.cpp                        |  6 +-
 emper/Dispatcher.hpp                        | 11 +++-
 emper/Fiber.cpp                             |  3 +-
 emper/Fiber.hpp                             | 27 ++++----
 emper/FiberManager.cpp                      |  6 +-
 emper/FiberManager.hpp                      |  7 +-
 emper/PrivateSemaphore.hpp                  |  1 +
 emper/Runtime.cpp                           | 34 ++++++----
 emper/Runtime.hpp                           | 29 ++++++---
 emper/Scheduler.hpp                         |  8 +--
 emper/Semaphore.cpp                         |  4 ++
 emper/c_emper.cpp                           | 13 ++--
 emper/strategies/laws/LawsDispatcher.cpp    |  4 +-
 emper/strategies/laws/LawsDispatcher.hpp    |  3 +-
 emper/strategies/laws/LawsScheduler.cpp     |  2 +-
 emper/strategies/laws/LawsScheduler.hpp     |  7 +-
 emper/strategies/laws/LawsStrategy.cpp      |  4 ++
 emper/strategies/laws/LawsStrategy.hpp      | 10 +--
 emper/strategies/laws/LawsStrategyStats.cpp |  1 +
 emper/strategies/ws/WsDispatcher.cpp        |  7 +-
 emper/strategies/ws/WsDispatcher.hpp        |  2 +
 emper/strategies/ws/WsScheduler.cpp         |  4 ++
 emper/strategies/ws/WsScheduler.hpp         | 12 ++--
 emper/strategies/ws/WsStrategy.cpp          |  4 ++
 emper/strategies/ws/WsStrategy.hpp          |  5 +-
 emper/strategies/ws/WsStrategyStats.cpp     |  1 +
 eval/Locality.cpp                           | 35 ++++++----
 eval/SpawnALot.cpp                          | 19 ++++--
 eval/TimeToSpawn.cpp                        | 15 +++--
 iwyu-mappings.imp                           |  4 ++
 meson.build                                 |  3 +
 tests/CppApiTest.cpp                        | 10 ++-
 tests/SimpleActorTest.cpp                   | 23 ++++---
 tests/SimpleFibTest.cpp                     | 21 +++---
 tests/SimplestFibTest.cpp                   | 24 ++++---
 tools/check-iwyu                            | 71 +++++++++++++++++++++
 50 files changed, 366 insertions(+), 209 deletions(-)
 create mode 100644 iwyu-mappings.imp
 create mode 100755 tools/check-iwyu

diff --git a/Makefile b/Makefile
index 00aac72a..b37b1526 100644
--- a/Makefile
+++ b/Makefile
@@ -23,9 +23,11 @@ debug:
 	rm -f build
 	$(MAKE) build BUILDTYPE=$@
 
+SMOKE_TEST_NINJA_TARGETS += iwyu
 
 smoke-test: all check-format
 	cd build && meson test --suite smoke
+	$(NINJA) -C build $(SMOKE_TEST_NINJA_TARGETS)
 
 
 TEST_NINJA_TARGETS += test
diff --git a/apps/Main.cpp b/apps/Main.cpp
index 42d1e102..0d568608 100644
--- a/apps/Main.cpp
+++ b/apps/Main.cpp
@@ -1,17 +1,14 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <iostream>
-#include <list>
-#include <string>
-#include <thread>
-
-#include "BinaryPrivateSemaphore.hpp"
-#include "Common.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "Debug.hpp"
-#include "PrivateSemaphore.hpp"
-#include "Runtime.hpp"
+#include <stdlib.h>	 // for exit, EXIT_SUCCESS
+
+#include <iostream>	 // for basic_ostream::operator<<
+
+#include "BinaryPrivateSemaphore.hpp"		 // for BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Debug.hpp"										 // for WDBG
+#include "Fiber.hpp"										 // for Fiber
+#include "PrivateSemaphore.hpp"					 // for PS
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG
 
 typedef struct {
 	int n;
diff --git a/apps/WorkerSleepExample.cpp b/apps/WorkerSleepExample.cpp
index 093ac184..b6e2e0d3 100644
--- a/apps/WorkerSleepExample.cpp
+++ b/apps/WorkerSleepExample.cpp
@@ -1,18 +1,15 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <iostream>
-#include <list>
-#include <string>
-
-#include "BinaryPrivateSemaphore.hpp"
-#include "Common.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "Debug.hpp"
-#include "PrivateSemaphore.hpp"
-#include "Runtime.hpp"
-#include "emper-version.h"
-#include "emper.hpp"
+#include <stdlib.h>	 // for exit, EXIT_SUCCESS
+
+#include <chrono>		 // for milliseconds, operator+, hig...
+#include <iostream>	 // for operator<<, basic_ostream, endl
+#include <ratio>		 // for ratio
+
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Fiber.hpp"										 // for Fiber
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG, workerid_t
+#include "emper-version.h"							 // for EMPER_FULL_VERSION
+#include "emper.hpp"										 // for spawn
 
 static unsigned int ITERATIONS = 10;
 
diff --git a/emper/BinaryPrivateSemaphore.cpp b/emper/BinaryPrivateSemaphore.cpp
index 491e9e28..c20e0ea3 100644
--- a/emper/BinaryPrivateSemaphore.cpp
+++ b/emper/BinaryPrivateSemaphore.cpp
@@ -1,9 +1,10 @@
 #include "BinaryPrivateSemaphore.hpp"
 
-#include <cassert>
+#include <cassert>	// for assert
 
-#include "Common.hpp"
-#include "Debug.hpp"
+#include "Common.hpp"		// for unlikely
+#include "Context.hpp"	// for Context
+#include "Debug.hpp"		// for LOGDD
 
 void BinaryPrivateSemaphore::wait() {
 	State state = bpsState.load();
diff --git a/emper/BinaryPrivateSemaphore.hpp b/emper/BinaryPrivateSemaphore.hpp
index 1da3ee81..7e308335 100644
--- a/emper/BinaryPrivateSemaphore.hpp
+++ b/emper/BinaryPrivateSemaphore.hpp
@@ -1,10 +1,10 @@
 #pragma once
 
-#include <atomic>
+#include <atomic>	 // for atomic
 
-#include "Debug.hpp"
-#include "Dispatcher.hpp"
-#include "PrivateSemaphore.hpp"
+#include "PrivateSemaphore.hpp"	 // for PrivateSemaphore
+
+class Context;
 
 class BinaryPrivateSemaphore : public PrivateSemaphore {
  private:
diff --git a/emper/Common.cpp b/emper/Common.cpp
index 3655e119..99cda074 100644
--- a/emper/Common.cpp
+++ b/emper/Common.cpp
@@ -1,7 +1,5 @@
 #include "Common.hpp"
 
-#include <stdio.h>
-
 #include <cstdio>
 #include <cstdlib>
 #include <iostream>
diff --git a/emper/Common.hpp b/emper/Common.hpp
index 1407b979..43b611fb 100644
--- a/emper/Common.hpp
+++ b/emper/Common.hpp
@@ -2,8 +2,6 @@
 
 #include <functional>
 
-#include "emper-common.h"
-
 typedef std::function<void(void)> func_t;
 
 #define STRINGIFY(x) #x
diff --git a/emper/Context.hpp b/emper/Context.hpp
index 28169b47..312d60d3 100644
--- a/emper/Context.hpp
+++ b/emper/Context.hpp
@@ -1,15 +1,14 @@
 #pragma once
 
-#include <valgrind/valgrind.h>
+#include <stdint.h>	 // for uintptr_t
 
-#include <cassert>
-#include <cstring>
-#include <functional>
+#include <cassert>		 // for assert
+#include <cstring>		 // for memset
+#include <functional>	 // for function
+#include <iosfwd>			 // for ostream
 
-#include "Common.hpp"
-#include "Debug.hpp"
-
-class Context;
+#include "Common.hpp"	 // for func_t, DIE, ALIGN_TO_CACHE_LINE
+#include "Debug.hpp"	 // for LOGD, LogSubsystem, LogSubsystem::C, Logger
 
 extern "C" [[noreturn]] void switch_and_load_context(void** toTos);
 // *Not* marked as 'noreturn' because save_and_switch_context does
diff --git a/emper/ContextManager.cpp b/emper/ContextManager.cpp
index 90627f00..ea000a87 100644
--- a/emper/ContextManager.cpp
+++ b/emper/ContextManager.cpp
@@ -1,10 +1,13 @@
 #include "ContextManager.hpp"
 
-#include <ostream>
+#include <assert.h>	 // for assert
 
-#include "Context.hpp"
-#include "Debug.hpp"
-#include "Runtime.hpp"
+#include <new>	// for operator new, operator delete
+
+#include "Context.hpp"		 // for Context
+#include "Debug.hpp"			 // for LOGD
+#include "Dispatcher.hpp"	 // for Dispatcher
+#include "Runtime.hpp"		 // for Runtime
 
 ContextManager::ContextManager(Runtime& runtime) : MemoryManager(runtime), runtime(runtime) {
 	auto newWorkerHook = [this]() {
diff --git a/emper/ContextManager.hpp b/emper/ContextManager.hpp
index 529bdb66..2037b00c 100644
--- a/emper/ContextManager.hpp
+++ b/emper/ContextManager.hpp
@@ -1,12 +1,11 @@
 #pragma once
 
-#include "Common.hpp"
-#include "Context.hpp"
-#include "MemoryManager.hpp"
-#include "Runtime.hpp"
-#include "lib/adt/WsClQueue.hpp"
+#include "Common.hpp"					// for func_t
+#include "Debug.hpp"					// for LogSubsystem, LogSubsystem::CM, Logger
+#include "MemoryManager.hpp"	// for MemoryManager
 
 class Context;
+class Runtime;
 
 #define CONTEXT_MANAGER_FIRST_LAYER_QUEUE_SIZE 64
 
diff --git a/emper/CountingPrivateSemaphore.cpp b/emper/CountingPrivateSemaphore.cpp
index e1e3fae6..cae315d9 100644
--- a/emper/CountingPrivateSemaphore.cpp
+++ b/emper/CountingPrivateSemaphore.cpp
@@ -1,6 +1,8 @@
 #include "CountingPrivateSemaphore.hpp"
 
-#include <cassert>
+#include <cassert>	// for assert
+
+#include "Context.hpp"	// for Context
 
 CountingPrivateSemaphore::CountingPrivateSemaphore() : CountingPrivateSemaphore(0) {}
 
diff --git a/emper/CountingPrivateSemaphore.hpp b/emper/CountingPrivateSemaphore.hpp
index ee90f8a0..58627593 100644
--- a/emper/CountingPrivateSemaphore.hpp
+++ b/emper/CountingPrivateSemaphore.hpp
@@ -1,8 +1,10 @@
 #pragma once
 
-#include <atomic>
+#include <atomic>	 // for atomic_uint, atomic
 
-#include "PrivateSemaphore.hpp"
+#include "PrivateSemaphore.hpp"	 // for PrivateSemaphore
+
+class Context;
 
 /**
  * A counting private semaphore.
diff --git a/emper/Debug.cpp b/emper/Debug.cpp
index 2d34fe58..e833074f 100644
--- a/emper/Debug.cpp
+++ b/emper/Debug.cpp
@@ -1,10 +1,10 @@
 #include "Debug.hpp"
 
-#include <iostream>
-#include <mutex>
+#include <iostream>	 // for operator<<, cerr, ostream, basic_ostream
+#include <mutex>		 // for mutex, unique_lock
 
-#include "Common.hpp"
-#include "Runtime.hpp"
+#include "Runtime.hpp"		 // for Runtime
+#include "emper-common.h"	 // for workerid_t
 
 static std::mutex worker_log_mutex;
 
diff --git a/emper/Debug.hpp b/emper/Debug.hpp
index 0d5a5db3..0fed216b 100644
--- a/emper/Debug.hpp
+++ b/emper/Debug.hpp
@@ -1,9 +1,7 @@
 #pragma once
 
-#include <cstdlib>
-#include <iostream>
-#include <map>
-#include <sstream>
+#include <map>		 // for allocator, map
+#include <string>	 // for string, operator<<
 
 #ifdef NDEBUG
 
@@ -14,7 +12,8 @@
 
 #else
 
-#include <sstream>
+#include <iostream>	 // IWYU pragma: keep
+#include <sstream>	 // IWYU pragma: keep
 
 #define DBG(x)                   \
 	do {                           \
diff --git a/emper/Dispatcher.cpp b/emper/Dispatcher.cpp
index d789db77..cc98a092 100644
--- a/emper/Dispatcher.cpp
+++ b/emper/Dispatcher.cpp
@@ -1,10 +1,8 @@
 #include "Dispatcher.hpp"
 
-//#include <pthread.h>
-#include <functional>
+#include <functional>	 // for _Bind_helper<>::type, bind
 
-#include "Debug.hpp"
-#include "Runtime.hpp"
+#include "Runtime.hpp"	// for Runtime
 
 thread_local const Fiber* Dispatcher::currentFiber;
 
diff --git a/emper/Dispatcher.hpp b/emper/Dispatcher.hpp
index 2ab0e971..30e6d52d 100644
--- a/emper/Dispatcher.hpp
+++ b/emper/Dispatcher.hpp
@@ -1,8 +1,13 @@
 #pragma once
 
-#include "Common.hpp"
-#include "Debug.hpp"
-#include "Fiber.hpp"
+#include <assert.h>	 // for assert
+
+#include <new>	// for operator delete
+
+#include "Common.hpp"			 // for func_t
+#include "Debug.hpp"			 // for LOGD, LogSubsystem, LogSubsystem::DISP
+#include "Fiber.hpp"			 // for Fiber
+#include "emper-common.h"	 // for workeraffinity_t
 
 class Runtime;
 class ContextManager;
diff --git a/emper/Fiber.cpp b/emper/Fiber.cpp
index 32109563..caa61837 100644
--- a/emper/Fiber.cpp
+++ b/emper/Fiber.cpp
@@ -1,6 +1,7 @@
 #include "Fiber.hpp"
 
-#include <ostream>
+#include <iostream>	 // for operator<<, basic_ostream, ostream, basic_ostrea...
+#include <typeinfo>	 // for type_info
 
 void Fiber::run() const {
 	LOGD("run() calling " << function.target<FIBER_FUN_TEMPLATE_ARG>() << " ("
diff --git a/emper/Fiber.hpp b/emper/Fiber.hpp
index 8132274d..e3fa62c0 100644
--- a/emper/Fiber.hpp
+++ b/emper/Fiber.hpp
@@ -1,21 +1,24 @@
 #pragma once
 
-#include <atomic>
-#include <cassert>
-#include <climits>
-#include <functional>
-
-#include "Common.hpp"
-#include "Debug.hpp"
-#include "lib/adt/MpscQueue.hpp"
+#include <atomic>			 // for atomic_uint, atomic, __atomic_base, memory...
+#include <cassert>		 // for assert
+#include <climits>		 // for UINT_MAX
+#include <functional>	 // for function
+#include <iosfwd>			 // for ostream
+#include <new>				 // for operator new
+
+#include "Common.hpp"			 // for ALIGN_TO_CACHE_LINE
+#include "Debug.hpp"			 // for LogSubsystem, LogSubsystem::F, Logger
+#include "emper-common.h"	 // for workeraffinity_t, UNUSED_ARG
+
+namespace adt {
+template <typename T>
+class MpscQueue;
+}
 
 #define FIBER_FUN_TEMPLATE_ARG void(void*)
 #define FIBER_FUN0_TEMPLATE_ARG void(void)
 
-class Scheduler;
-class Dispatcher;
-class LawsScheduler;
-
 class ALIGN_TO_CACHE_LINE Fiber : public Logger<LogSubsystem::F> {
  public:
 	typedef std::function<FIBER_FUN_TEMPLATE_ARG> fiber_fun_t;
diff --git a/emper/FiberManager.cpp b/emper/FiberManager.cpp
index 01efdc3b..3979bfaf 100644
--- a/emper/FiberManager.cpp
+++ b/emper/FiberManager.cpp
@@ -1,6 +1,10 @@
 #include "FiberManager.hpp"
 
-#include <cstdlib>
+#include <cstdlib>	// for abort, free, posix_memalign
+
+#include "Fiber.hpp"	// for Fiber
+
+class Runtime;
 
 FiberManager::FiberManager(Runtime& runtime) : MemoryManager(runtime) {}
 
diff --git a/emper/FiberManager.hpp b/emper/FiberManager.hpp
index ae745e18..d9234bd3 100644
--- a/emper/FiberManager.hpp
+++ b/emper/FiberManager.hpp
@@ -1,8 +1,9 @@
 #pragma once
 
-#include "Fiber.hpp"
-#include "MemoryManager.hpp"
-#include "Runtime.hpp"
+#include "MemoryManager.hpp"	// for MemoryManager
+
+class Fiber;
+class Runtime;
 
 class FiberManager : protected MemoryManager<Fiber, 128, 64> {
  private:
diff --git a/emper/PrivateSemaphore.hpp b/emper/PrivateSemaphore.hpp
index 4c9b4ce0..ae435ae6 100644
--- a/emper/PrivateSemaphore.hpp
+++ b/emper/PrivateSemaphore.hpp
@@ -4,6 +4,7 @@
 #include "Context.hpp"
 #include "ContextManager.hpp"
 #include "Debug.hpp"
+#include "Dispatcher.hpp"
 #include "Fiber.hpp"
 #include "Runtime.hpp"
 
diff --git a/emper/Runtime.cpp b/emper/Runtime.cpp
index 273e6936..0eae91fb 100644
--- a/emper/Runtime.cpp
+++ b/emper/Runtime.cpp
@@ -1,20 +1,26 @@
 #include "Runtime.hpp"
 
-#include <pthread.h>
-#include <sys/syscall.h>
-#include <sys/sysinfo.h>
-#include <unistd.h>
-
-#include <cstdlib>
-#include <ctime>
-
+#include <errno.h>		// for errno
+#include <pthread.h>	// for pthread_t, pthread_attr_init
 // Non portable.
-#include <sched.h>
-
-#include "Common.hpp"
-#include "ContextManager.hpp"
-#include "Debug.hpp"
-#include "emper-config.h"
+#include <sched.h>				// for cpu_set_t, CPU_SET, CPU_ZERO
+#include <sys/sysinfo.h>	// for get_nprocs
+#include <syscall.h>			// for SYS_gettid
+#include <unistd.h>				// for syscall
+
+#include <cstdlib>	// for rand, srand, abort
+#include <ctime>		// for time
+#include <memory>		// for __shared_ptr_access, shared_ptr
+#include <ostream>	// for operator<<, basic_ostream<>:...
+
+#include "Common.hpp"										 // for DIE_MSG_ERRNO, DIE, DIE_MSG
+#include "ContextManager.hpp"						 // for ContextManager
+#include "Debug.hpp"										 // for DBG, ABORT, LOGD, LOGE
+#include "Dispatcher.hpp"								 // for Dispatcher
+#include "Fiber.hpp"										 // for Fiber
+#include "RuntimeStrategy.hpp"					 // for RuntimeStrategy
+#include "RuntimeStrategyStats.hpp"			 // for RuntimeStrategyStats
+#include "strategies/ws/WsStrategy.hpp"	 // for WsStrategy, WsStrategy::INST...
 
 std::mutex Runtime::currentRuntimeMutex;
 Runtime* Runtime::currentRuntime;
diff --git a/emper/Runtime.hpp b/emper/Runtime.hpp
index c446473e..e1a29071 100644
--- a/emper/Runtime.hpp
+++ b/emper/Runtime.hpp
@@ -1,17 +1,26 @@
 #pragma once
 
-#include <thread>
-#include <vector>
-
-#include "Common.hpp"
-#include "Debug.hpp"
-#include "Dispatcher.hpp"
-#include "RuntimeStrategy.hpp"
-#include "Scheduler.hpp"
-#include "lib/sync/Latch.hpp"
-#include "strategies/ws/WsStrategy.hpp"
+#include <pthread.h>	// for pthread_t
+#include <stddef.h>		// for size_t
+#include <stdint.h>		// for intptr_t
+
+#include <atomic>							 // for atomic, memory_order_relaxed
+#include <condition_variable>	 // for condition_variable
+#include <functional>					 // for function
+#include <mutex>							 // for mutex, lock_guard, unique_lock
+#include <thread>							 // for thread
+#include <vector>							 // for vector
+
+#include "Common.hpp"					 // for ALIGN_TO_CACHE_LINE
+#include "Debug.hpp"					 // for LogSubsystem, LogSubsystem::RUNTI, Logger
+#include "Scheduler.hpp"			 // for Scheduler
+#include "emper-common.h"			 // for workerid_t
+#include "lib/sync/Latch.hpp"	 // for Latch
 
 class ContextManager;
+class Dispatcher;
+class Fiber;
+class RuntimeStrategy;
 
 class Runtime : public Logger<LogSubsystem::RUNTI> {
  private:
diff --git a/emper/Scheduler.hpp b/emper/Scheduler.hpp
index a14b7a06..9c13b5f0 100644
--- a/emper/Scheduler.hpp
+++ b/emper/Scheduler.hpp
@@ -1,10 +1,10 @@
 #pragma once
 
-#include <functional>
+#include <functional>	 // for function
 
-#include "Common.hpp"
-#include "Debug.hpp"
-#include "Fiber.hpp"
+#include "Debug.hpp"			 // for LogSubsystem, LogSubsystem::SCHED, Logger
+#include "Fiber.hpp"			 // for Fiber
+#include "emper-common.h"	 // for workeraffinity_t
 
 class Runtime;
 
diff --git a/emper/Semaphore.cpp b/emper/Semaphore.cpp
index 91c92144..00df3cab 100644
--- a/emper/Semaphore.cpp
+++ b/emper/Semaphore.cpp
@@ -1,5 +1,9 @@
 #include "Semaphore.hpp"
 
+#include <iostream>	 // for operator<<, basic_ostream, basic_o...
+
+#include "lib/sync/Semaphore.hpp"	 // for emper
+
 using namespace emper;
 
 void Semaphore::print() {
diff --git a/emper/c_emper.cpp b/emper/c_emper.cpp
index 6b8a9211..dc2bb845 100644
--- a/emper/c_emper.cpp
+++ b/emper/c_emper.cpp
@@ -1,8 +1,11 @@
-#include "BinaryPrivateSemaphore.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "Fiber.hpp"
-#include "Runtime.hpp"
-#include "emper.h"
+#include <new>	// for operator new
+
+#include "BinaryPrivateSemaphore.hpp"		 // for BinaryPrivateSemaphore, BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CountingPrivateSemaphore, CPS
+#include "Fiber.hpp"										 // for Fiber, Fiber::NOT_AFFINE
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for workeraffinity_t
+#include "emper.h"											 // for fiber, cps, bps, runtime
 
 runtime* init_runtime(void) {
 	Runtime* r = new Runtime();
diff --git a/emper/strategies/laws/LawsDispatcher.cpp b/emper/strategies/laws/LawsDispatcher.cpp
index 06a8566a..fa6c27bf 100644
--- a/emper/strategies/laws/LawsDispatcher.cpp
+++ b/emper/strategies/laws/LawsDispatcher.cpp
@@ -1,9 +1,11 @@
 #include "LawsDispatcher.hpp"
 
-#include "LawsStrategy.hpp"
+#include "LawsStrategy.hpp"	 // IWYU pragma: keep
 #include "Runtime.hpp"
 #include "emper-config.h"
 
+class Fiber;
+
 void LawsDispatcher::dispatchLoop() {
 	while (true) {
 		Fiber* const fiber = runtime.nextFiber();
diff --git a/emper/strategies/laws/LawsDispatcher.hpp b/emper/strategies/laws/LawsDispatcher.hpp
index f45b6dce..80446a12 100644
--- a/emper/strategies/laws/LawsDispatcher.hpp
+++ b/emper/strategies/laws/LawsDispatcher.hpp
@@ -1,9 +1,10 @@
 #pragma once
 
 #include "Dispatcher.hpp"
-#include "emper-config.h"
+#include "emper-common.h"
 
 class LawsStrategy;
+class Runtime;
 
 class LawsDispatcher : public Dispatcher {
  private:
diff --git a/emper/strategies/laws/LawsScheduler.cpp b/emper/strategies/laws/LawsScheduler.cpp
index a9fea701..c29f36c7 100644
--- a/emper/strategies/laws/LawsScheduler.cpp
+++ b/emper/strategies/laws/LawsScheduler.cpp
@@ -2,7 +2,7 @@
 
 #include "Common.hpp"
 #include "Debug.hpp"
-#include "LawsStrategy.hpp"
+#include "LawsStrategy.hpp"	 // IWYU pragma: keep
 #include "Runtime.hpp"
 #include "emper-config.h"
 
diff --git a/emper/strategies/laws/LawsScheduler.hpp b/emper/strategies/laws/LawsScheduler.hpp
index 5a8e1131..07b4f3d3 100644
--- a/emper/strategies/laws/LawsScheduler.hpp
+++ b/emper/strategies/laws/LawsScheduler.hpp
@@ -1,14 +1,15 @@
 #pragma once
 
+#include <stddef.h>
+
 #include "Fiber.hpp"
 #include "Scheduler.hpp"
-#include "emper-config.h"
-#include "lib/adt/LockedQueue.hpp"
-#include "lib/adt/LockedUnboundedQueue.hpp"
+#include "emper-common.h"
 #include "lib/adt/MpscQueue.hpp"
 #include "lib/adt/WsClQueue.hpp"
 
 class LawsStrategy;
+class Runtime;
 
 class LawsScheduler : public Scheduler {
 	template <size_t SIZE>
diff --git a/emper/strategies/laws/LawsStrategy.cpp b/emper/strategies/laws/LawsStrategy.cpp
index 9e8c5a6f..c5fc5f64 100644
--- a/emper/strategies/laws/LawsStrategy.cpp
+++ b/emper/strategies/laws/LawsStrategy.cpp
@@ -1,5 +1,9 @@
 #include "LawsStrategy.hpp"
 
+#include "strategies/laws/LawsDispatcher.hpp"			// for LawsDispatcher
+#include "strategies/laws/LawsScheduler.hpp"			// for LawsScheduler
+#include "strategies/laws/LawsStrategyStats.hpp"	// for LawsStrategyStats
+
 LawsStrategy LawsStrategy::INSTANCE;
 
 Scheduler& LawsStrategy::getScheduler(Runtime& runtime) {
diff --git a/emper/strategies/laws/LawsStrategy.hpp b/emper/strategies/laws/LawsStrategy.hpp
index 3b692dcf..4d6a6b13 100644
--- a/emper/strategies/laws/LawsStrategy.hpp
+++ b/emper/strategies/laws/LawsStrategy.hpp
@@ -4,13 +4,15 @@
 #include <cstdint>
 #include <memory>
 
-#include "LawsDispatcher.hpp"
-#include "LawsScheduler.hpp"
-#include "LawsStrategyStats.hpp"
 #include "RuntimeStrategy.hpp"
 
+class Dispatcher;
+class LawsDispatcher;
 class LawsScheduler;
-class LawsDispater;
+class LawsStrategyStats;
+class Runtime;
+class RuntimeStrategyStats;
+class Scheduler;
 
 class LawsStrategy : public RuntimeStrategy {
  private:
diff --git a/emper/strategies/laws/LawsStrategyStats.cpp b/emper/strategies/laws/LawsStrategyStats.cpp
index 81584dac..5d736548 100644
--- a/emper/strategies/laws/LawsStrategyStats.cpp
+++ b/emper/strategies/laws/LawsStrategyStats.cpp
@@ -1,5 +1,6 @@
 #include "LawsStrategyStats.hpp"
 
+#include <atomic>
 #include <iostream>
 
 #include "LawsStrategy.hpp"
diff --git a/emper/strategies/ws/WsDispatcher.cpp b/emper/strategies/ws/WsDispatcher.cpp
index 5f070d6e..80de76fb 100644
--- a/emper/strategies/ws/WsDispatcher.cpp
+++ b/emper/strategies/ws/WsDispatcher.cpp
@@ -1,8 +1,9 @@
 #include "WsDispatcher.hpp"
 
-#include "Debug.hpp"
-#include "Runtime.hpp"
-#include "emper-config.h"
+#include "Runtime.hpp"		 // for Runtime
+#include "emper-config.h"	 // for EMPER_WORKER_SLEEP
+
+class Fiber;
 
 void WsDispatcher::dispatchLoop() {
 	while (true) {
diff --git a/emper/strategies/ws/WsDispatcher.hpp b/emper/strategies/ws/WsDispatcher.hpp
index c3d70015..b754d672 100644
--- a/emper/strategies/ws/WsDispatcher.hpp
+++ b/emper/strategies/ws/WsDispatcher.hpp
@@ -2,6 +2,8 @@
 
 #include "Dispatcher.hpp"
 
+class Runtime;
+
 class WsDispatcher : public Dispatcher {
  public:
 	WsDispatcher(Runtime& runtime) : Dispatcher(runtime){};
diff --git a/emper/strategies/ws/WsScheduler.cpp b/emper/strategies/ws/WsScheduler.cpp
index eec4cfa6..2083376f 100644
--- a/emper/strategies/ws/WsScheduler.cpp
+++ b/emper/strategies/ws/WsScheduler.cpp
@@ -1,10 +1,14 @@
 #include "WsScheduler.hpp"
 
+#include <ostream>
+
 #include "Common.hpp"
 #include "Debug.hpp"
 #include "Runtime.hpp"
 #include "emper-config.h"
 
+class Fiber;
+
 thread_local WsScheduler::WsQueue<WsScheduler::QUEUE_SIZE> WsScheduler::queue;
 
 WsScheduler::WsScheduler(Runtime& runtime, WsStrategy& wsStrategy)
diff --git a/emper/strategies/ws/WsScheduler.hpp b/emper/strategies/ws/WsScheduler.hpp
index 9d1c3454..3286f6da 100644
--- a/emper/strategies/ws/WsScheduler.hpp
+++ b/emper/strategies/ws/WsScheduler.hpp
@@ -1,11 +1,13 @@
 #pragma once
 
-#include "Scheduler.hpp"
-#include "emper-common.h"
-#include "emper-config.h"
-#include "lib/adt/LockedQueue.hpp"
-#include "lib/adt/WsClQueue.hpp"
+#include <stddef.h>	 // for size_t
 
+#include "Scheduler.hpp"					// for Scheduler
+#include "emper-common.h"					// for ATTR_UNUSED
+#include "lib/adt/WsClQueue.hpp"	// for WsClQueue
+
+class Fiber;
+class Runtime;
 class WsStrategy;
 
 class WsScheduler : public Scheduler {
diff --git a/emper/strategies/ws/WsStrategy.cpp b/emper/strategies/ws/WsStrategy.cpp
index b9b78d91..3162da16 100644
--- a/emper/strategies/ws/WsStrategy.cpp
+++ b/emper/strategies/ws/WsStrategy.cpp
@@ -2,6 +2,10 @@
 
 #include "WsDispatcher.hpp"
 #include "WsScheduler.hpp"
+#include "strategies/ws/WsStrategyStats.hpp"	// for WsStrategyStats
+
+class Runtime;
+class RuntimeStrategyStats;
 
 WsStrategy WsStrategy::INSTANCE;
 
diff --git a/emper/strategies/ws/WsStrategy.hpp b/emper/strategies/ws/WsStrategy.hpp
index 269e93f6..8386b5a2 100644
--- a/emper/strategies/ws/WsStrategy.hpp
+++ b/emper/strategies/ws/WsStrategy.hpp
@@ -5,13 +5,14 @@
 #include <memory>
 
 #include "RuntimeStrategy.hpp"
-#include "WsStrategyStats.hpp"
 
 class Scheduler;
 class Dispatcher;
-
+class Runtime;
+class RuntimeStrategyStats;
 class WsScheduler;
 class WsDispatcher;
+class WsStrategyStats;
 
 class WsStrategy : public RuntimeStrategy {
  private:
diff --git a/emper/strategies/ws/WsStrategyStats.cpp b/emper/strategies/ws/WsStrategyStats.cpp
index d3925dfc..e5a50e88 100644
--- a/emper/strategies/ws/WsStrategyStats.cpp
+++ b/emper/strategies/ws/WsStrategyStats.cpp
@@ -1,5 +1,6 @@
 #include "WsStrategyStats.hpp"
 
+#include <atomic>
 #include <iostream>
 
 #include "WsStrategy.hpp"
diff --git a/eval/Locality.cpp b/eval/Locality.cpp
index 7d1f7ded..625e7d97 100644
--- a/eval/Locality.cpp
+++ b/eval/Locality.cpp
@@ -1,17 +1,24 @@
-#include <unistd.h>
-
-#include <algorithm>
-#include <cstdint>
-#include <random>
-#include <thread>
-
-#include "CountingPrivateSemaphore.hpp"
-#include "Dispatcher.hpp"
-#include "Fiber.hpp"
-#include "PrivateSemaphore.hpp"
-#include "Runtime.hpp"
-#include "lib/DebugUtil.hpp"
-#include "strategies/laws/LawsStrategy.hpp"
+// SPDX-License-Identifier: LGPL-3.0-or-later
+// Copyright © 2020 Florian Schmaus
+#include <stdlib.h>	 // for abort, exit, EXIT_SUCCESS
+#include <unistd.h>	 // for getopt, optarg
+
+#include <algorithm>	// for generate
+#include <chrono>			// for microseconds, high_resol...
+#include <cstdint>		// for uint8_t, UINT8_MAX
+#include <iostream>		// for operator<<, basic_ostream
+#include <new>				// for operator new
+#include <random>			// for mt19937, uniform_int_dis...
+#include <string>			// for string, operator<<, oper...
+
+#include "CountingPrivateSemaphore.hpp"			 // for CPS
+#include "Debug.hpp"												 // for DBG
+#include "Fiber.hpp"												 // for Fiber, Fiber::NOT_AFFINE
+#include "PrivateSemaphore.hpp"							 // for PS
+#include "Runtime.hpp"											 // for Runtime
+#include "emper-common.h"										 // for workeraffinity_t, UNUSED...
+#include "lib/DebugUtil.hpp"								 // for enableStacktraceOnAborts
+#include "strategies/laws/LawsStrategy.hpp"	 // for LawsStrategy, LawsStrate...
 
 #define L1_CACHE_LINE_SIZE 64	 // 64 Bytes
 
diff --git a/eval/SpawnALot.cpp b/eval/SpawnALot.cpp
index 9b99d72e..eff5cf35 100644
--- a/eval/SpawnALot.cpp
+++ b/eval/SpawnALot.cpp
@@ -1,8 +1,17 @@
-#include "BinaryPrivateSemaphore.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "PrivateSemaphore.hpp"
-#include "Runtime.hpp"
-#include "lib/DebugUtil.hpp"
+#include <stdint.h>	 // for uint8_t, uint64_t
+#include <stdlib.h>	 // for EXIT_SUCCESS
+
+#include <chrono>		 // for nanoseconds, time_point, dur...
+#include <iostream>	 // for operator<<, basic_ostream
+#include <thread>		 // for thread
+
+#include "BinaryPrivateSemaphore.hpp"		 // for BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Fiber.hpp"										 // for Fiber
+#include "PrivateSemaphore.hpp"					 // for PS
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG
+#include "lib/DebugUtil.hpp"						 // for enableStacktraceOnAborts
 
 #define CACHE_LINE_SIZE 64
 
diff --git a/eval/TimeToSpawn.cpp b/eval/TimeToSpawn.cpp
index 9be3ee43..488c1e30 100644
--- a/eval/TimeToSpawn.cpp
+++ b/eval/TimeToSpawn.cpp
@@ -1,9 +1,12 @@
-#include <chrono>
-#include <mutex>
-#include <thread>
-
-#include "BinaryPrivateSemaphore.hpp"
-#include "Runtime.hpp"
+#include <chrono>		 // for nanoseconds, duration_cast
+#include <iostream>	 // for operator<<, basic_ostream, endl
+#include <mutex>		 // for mutex
+#include <thread>		 // for thread
+
+#include "BinaryPrivateSemaphore.hpp"	 // for BPS
+#include "Fiber.hpp"									 // for Fiber
+#include "Runtime.hpp"								 // for Runtime
+#include "emper-common.h"							 // for UNUSED_ARG
 
 static std::chrono::nanoseconds threadTimeToSpawn() {
 	std::chrono::time_point<std::chrono::high_resolution_clock> end;
diff --git a/iwyu-mappings.imp b/iwyu-mappings.imp
new file mode 100644
index 00000000..8a64523b
--- /dev/null
+++ b/iwyu-mappings.imp
@@ -0,0 +1,4 @@
+[
+	{ include: ["<bits/getopt_core.h>", "private", "<unistd.h>", "public"] },
+	{ include: ["@<gtest/.*>", "private", "<gtest/gtest.h>", "public"] },
+]
diff --git a/meson.build b/meson.build
index 0733d8e9..325105c8 100644
--- a/meson.build
+++ b/meson.build
@@ -14,6 +14,9 @@ add_project_arguments('-Wno-non-virtual-dtor', language: 'cpp')
 thread_dep = dependency('threads')
 emper_dependencies = [thread_dep]
 
+run_target('iwyu',
+		   command: 'tools/check-iwyu')
+
 conf_data = configuration_data()
 conf_data.set('EMPER_WORKER_SLEEP', get_option('worker_sleep'))
 conf_data.set('EMPER_LOCKED_WS_QUEUE', get_option('locked_ws_queue'))
diff --git a/tests/CppApiTest.cpp b/tests/CppApiTest.cpp
index 6308da48..954ad76c 100644
--- a/tests/CppApiTest.cpp
+++ b/tests/CppApiTest.cpp
@@ -1,7 +1,11 @@
-#include <atomic>
+#include <stdlib.h>	 // for exit, EXIT_FAILURE, EXIT_SUC...
 
-#include "CountingPrivateSemaphore.hpp"
-#include "emper.hpp"
+#include <atomic>	 // for atomic_uint, __atomic_base
+
+#include "CountingPrivateSemaphore.hpp"	 // for CountingPrivateSemaphore
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG
+#include "emper.hpp"										 // for async, spawn
 
 static std::atomic_uint counter;
 
diff --git a/tests/SimpleActorTest.cpp b/tests/SimpleActorTest.cpp
index d0fd44f4..d00480a6 100644
--- a/tests/SimpleActorTest.cpp
+++ b/tests/SimpleActorTest.cpp
@@ -1,12 +1,17 @@
-#include <atomic>
-#include <mutex>
-
-#include "Actor.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "Debug.hpp"
-#include "Dispatcher.hpp"
-#include "Runtime.hpp"
-#include "emper.hpp"
+#include <stdlib.h>	 // for exit, EXIT_FAILURE, EXIT_SUC...
+
+#include <atomic>		 // for atomic_thread_fence, memory_...
+#include <cstdint>	 // for uint64_t
+#include <iostream>	 // for operator<<, basic_ostream
+
+#include "Actor.hpp"										 // for Actor
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Debug.hpp"										 // for WDBG
+#include "Dispatcher.hpp"								 // for Dispatcher
+#include "Fiber.hpp"										 // for Fiber
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG
+#include "emper.hpp"										 // for spawn
 
 class SumActor : public Actor<uint64_t> {
  private:
diff --git a/tests/SimpleFibTest.cpp b/tests/SimpleFibTest.cpp
index cd29790a..1ac4a786 100644
--- a/tests/SimpleFibTest.cpp
+++ b/tests/SimpleFibTest.cpp
@@ -1,16 +1,11 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <iostream>
-#include <list>
-#include <string>
-
-#include "BinaryPrivateSemaphore.hpp"
-#include "Common.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "Debug.hpp"
-#include "PrivateSemaphore.hpp"
-#include "Runtime.hpp"
+#include <stdlib.h>	 // for exit, EXIT_FAILURE, EXIT_SUC...
+
+#include "BinaryPrivateSemaphore.hpp"		 // for BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Fiber.hpp"										 // for Fiber
+#include "PrivateSemaphore.hpp"					 // for PS
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG
 
 typedef struct {
 	int n;
diff --git a/tests/SimplestFibTest.cpp b/tests/SimplestFibTest.cpp
index 753b26f6..3f5a5a95 100644
--- a/tests/SimplestFibTest.cpp
+++ b/tests/SimplestFibTest.cpp
@@ -1,16 +1,14 @@
-#include <cstdlib>
-#include <iostream>
-#include <list>
-#include <string>
-#include <thread>
-
-#include "BinaryPrivateSemaphore.hpp"
-#include "Common.hpp"
-#include "CountingPrivateSemaphore.hpp"
-#include "Debug.hpp"
-#include "PrivateSemaphore.hpp"
-#include "Runtime.hpp"
-#include "emper.hpp"
+#include <cstdlib>	 // for abort, exit, EXIT_SUCCESS
+#include <iostream>	 // for operator<<, basic_ostream::o...
+
+#include "BinaryPrivateSemaphore.hpp"		 // for BPS
+#include "CountingPrivateSemaphore.hpp"	 // for CPS
+#include "Debug.hpp"										 // for WDBG
+#include "Fiber.hpp"										 // for Fiber
+#include "PrivateSemaphore.hpp"					 // for PS
+#include "Runtime.hpp"									 // for Runtime
+#include "emper-common.h"								 // for UNUSED_ARG
+#include "emper.hpp"										 // for async
 
 typedef struct {
 	int n;
diff --git a/tools/check-iwyu b/tools/check-iwyu
new file mode 100755
index 00000000..24f74423
--- /dev/null
+++ b/tools/check-iwyu
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+# Meson issue regarding iwyu integration: https://github.com/mesonbuild/meson/issues/2637
+
+# Pretty fancy method to get reliable the absolute path of a shell
+# script, *even if it is sourced*. Credits go to GreenFox on
+# stackoverflow: http://stackoverflow.com/a/12197518/194894
+pushd . > /dev/null
+SCRIPTDIR="${BASH_SOURCE[0]}";
+while([ -h "${SCRIPTDIR}" ]); do
+    cd "`dirname "${SCRIPTDIR}"`"
+    SCRIPTDIR="$(readlink "`basename "${SCRIPTDIR}"`")";
+done
+cd "`dirname "${SCRIPTDIR}"`" > /dev/null
+SCRIPTDIR="`pwd`";
+popd  > /dev/null
+
+set +u
+if [[ -n "${MESON_BUILD_ROOT}" ]]; then
+	MESON_BUILD_ROOT_SET=true
+else
+	MESON_BUILD_ROOT_SET=false
+fi
+set -u
+
+if ! ${MESON_BUILD_ROOT_SET}; then
+	ROOTDIR=$(readlink -f "${SCRIPTDIR}/..")
+	make -C "${ROOTDIR}"
+	MESON_BUILD_ROOT="${ROOTDIR}/build"
+	exec ninja -C "${MESON_BUILD_ROOT}" iwyu
+fi
+
+readonly IWYU_LOG="${MESON_BUILD_ROOT}/iwyu.log"
+
+NPROC=$(nproc)
+
+for POSSIBLE_CMD in iwyu_tool iwyu-tool iwyu_tool.py; do
+	if command -v ${POSSIBLE_CMD} >/dev/null; then
+		IWYU_TOOL=${POSSIBLE_CMD}
+		break
+	fi
+done
+
+if [[ -z "${IWYU_TOOL}" ]]; then
+	echo "iwyu_tool not found"
+	exit 1
+fi
+
+${IWYU_TOOL} -p "${MESON_BUILD_ROOT}" --jobs "${NPROC}" -- \
+			 -Xiwyu --mapping_file="${MESON_SOURCE_ROOT}/iwyu-mappings.imp" \
+			 > "${IWYU_LOG}"
+
+# Sadly, iwyu_tool.py does not (yet) return an non-zero exit value if
+# there are include issues, so we have to check the output manually.
+# See https://github.com/include-what-you-use/include-what-you-use/issues/790
+# Also note that the output contains "error: nos uch file or
+# directory: 'cc'" if ccache is used (which meson does by default if
+# ccache is available).
+# See https://github.com/include-what-you-use/include-what-you-use/issues/789
+ERROR_STRINGS=()
+ERROR_STRINGS+=("should add these lines:")
+ERROR_STRINGS+=("fatal error:")
+
+for ERROR_STRING in "${ERROR_STRINGS[@]}"; do
+	if grep -q "${ERROR_STRING}" "${IWYU_LOG}"; then
+		echo "IWYU found errors!"  
+		cat "${IWYU_LOG}"		   
+		exit 1
+	fi
+done
-- 
GitLab