Browse Source

CommandQueueMT: Make re-entrant again + Fix multiple flushers case

Pedro J. Estébanez 6 days ago
parent
commit
824287eefb

+ 19 - 15
core/templates/command_queue_mt.h

@@ -107,7 +107,8 @@ class CommandQueueMT {
 
 	static const uint32_t DEFAULT_COMMAND_MEM_SIZE_KB = 64;
 
-	bool unique_flusher = false;
+	inline static thread_local bool flushing = false;
+
 	BinaryMutex mutex;
 	LocalVector<uint8_t> command_mem;
 	ConditionVariable sync_cond_var;
@@ -157,10 +158,20 @@ class CommandQueueMT {
 	}
 
 	void _flush() {
+		// Safeguard against trying to re-lock the binary mutex.
+		if (flushing) {
+			return;
+		}
+
+		flushing = true;
+
 		MutexLock lock(mutex);
 
 		if (unlikely(flush_read_ptr)) {
-			// Re-entrant call.
+			// Another thread is flushing.
+			lock.temp_unlock(); // Not really temp.
+			sync();
+			flushing = false;
 			return;
 		}
 
@@ -177,17 +188,9 @@ class CommandQueueMT {
 			CommandBase *cmd_local = reinterpret_cast<CommandBase *>(cmd_local_mem);
 			memcpy(cmd_local_mem, (char *)cmd_original, size);
 
-			if (unique_flusher) {
-				// A single thread will pump; the lock is only needed for the command queue itself.
-				lock.temp_unlock();
-				cmd_local->call();
-				lock.temp_relock();
-			} else {
-				// At least we can unlock during WTP operations.
-				uint32_t allowance_id = WorkerThreadPool::thread_enter_unlock_allowance_zone(lock);
-				cmd_local->call();
-				WorkerThreadPool::thread_exit_unlock_allowance_zone(allowance_id);
-			}
+			lock.temp_unlock();
+			cmd_local->call();
+			lock.temp_relock();
 
 			if (unlikely(cmd_local->sync)) {
 				sync_head++;
@@ -206,6 +209,8 @@ class CommandQueueMT {
 		flush_read_ptr = 0;
 
 		_prevent_sync_wraparound();
+
+		flushing = false;
 	}
 
 	_FORCE_INLINE_ void _wait_for_sync(MutexLock<BinaryMutex> &p_lock) {
@@ -270,8 +275,7 @@ public:
 		pump_task_id = p_task_id;
 	}
 
-	CommandQueueMT(bool p_unique_flusher = false) :
-			unique_flusher(p_unique_flusher) {
+	CommandQueueMT() {
 		command_mem.reserve(DEFAULT_COMMAND_MEM_SIZE_KB * 1024);
 	}
 };

+ 1 - 1
modules/betsy/image_compress_betsy.h

@@ -103,7 +103,7 @@ Error _betsy_compress_s3tc(Image *r_img, Image::UsedChannels p_channels);
 class BetsyCompressor : public Object {
 	GDSOFTCLASS(BetsyCompressor, Object);
 
-	mutable CommandQueueMT command_queue = CommandQueueMT(true);
+	mutable CommandQueueMT command_queue;
 	bool exit = false;
 	WorkerThreadPool::TaskID task_id = WorkerThreadPool::INVALID_TASK_ID;
 

+ 1 - 1
servers/rendering/rendering_server_default.h

@@ -74,7 +74,7 @@ class RenderingServerDefault : public RenderingServer {
 	uint64_t print_frame_profile_ticks_from = 0;
 	uint32_t print_frame_profile_frame_count = 0;
 
-	mutable CommandQueueMT command_queue = CommandQueueMT(true);
+	mutable CommandQueueMT command_queue;
 
 	Thread::ID server_thread = Thread::MAIN_ID;
 	WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID;