mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 22:02:44 +00:00 
			
		
		
		
	LibThreading: Wake up the background worker thread when there's work
The worker thread used for BackgroundAction was going to sleep for 1 second at a time (when there was nothing to do.) This made using background actions for anything interactive quite unresponsive since you had to wait up to 1 second before it even started on your task. We now use a simple Unix pipe to signal the worker thread that a new work item is available. This makes Assistant way more responsive when typing. :^)
This commit is contained in:
		
							parent
							
								
									d114ba4c4e
								
							
						
					
					
						commit
						e8579ed24a
					
				
					 2 changed files with 36 additions and 18 deletions
				
			
		|  | @ -1,5 +1,6 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> | ||||
|  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
|  | @ -8,24 +9,33 @@ | |||
| #include <LibThreading/BackgroundAction.h> | ||||
| #include <LibThreading/Lock.h> | ||||
| #include <LibThreading/Thread.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| static Threading::Lockable<Queue<Function<void()>>>* s_all_actions; | ||||
| static Threading::Thread* s_background_thread; | ||||
| static int s_notify_pipe_fds[2]; | ||||
| 
 | ||||
| static intptr_t background_thread_func() | ||||
| { | ||||
|     while (true) { | ||||
|         Function<void()> work_item; | ||||
|         char buffer[1]; | ||||
|         auto nread = read(s_notify_pipe_fds[0], buffer, sizeof(buffer)); | ||||
|         if (nread < 0) { | ||||
|             perror("read"); | ||||
|             _exit(1); | ||||
|         } | ||||
| 
 | ||||
|         Vector<Function<void()>> work_items; | ||||
|         { | ||||
|             Threading::Locker locker(s_all_actions->lock()); | ||||
| 
 | ||||
|             if (!s_all_actions->resource().is_empty()) | ||||
|                 work_item = s_all_actions->resource().dequeue(); | ||||
|             while (!s_all_actions->resource().is_empty()) { | ||||
|                 work_items.append(s_all_actions->resource().dequeue()); | ||||
|             } | ||||
|         if (work_item) | ||||
|         } | ||||
| 
 | ||||
|         for (auto& work_item : work_items) | ||||
|             work_item(); | ||||
|         else | ||||
|             sleep(1); | ||||
|     } | ||||
| 
 | ||||
|     VERIFY_NOT_REACHED(); | ||||
|  | @ -33,22 +43,32 @@ static intptr_t background_thread_func() | |||
| 
 | ||||
| static void init() | ||||
| { | ||||
|     if (pipe(s_notify_pipe_fds) < 0) { | ||||
|         perror("pipe"); | ||||
|         _exit(1); | ||||
|     } | ||||
|     s_all_actions = new Threading::Lockable<Queue<Function<void()>>>(); | ||||
|     s_background_thread = &Threading::Thread::construct(background_thread_func).leak_ref(); | ||||
|     s_background_thread->set_name("Background thread"); | ||||
|     s_background_thread->start(); | ||||
| } | ||||
| 
 | ||||
| Threading::Lockable<Queue<Function<void()>>>& Threading::BackgroundActionBase::all_actions() | ||||
| { | ||||
|     if (s_all_actions == nullptr) | ||||
|         init(); | ||||
|     return *s_all_actions; | ||||
| } | ||||
| 
 | ||||
| Threading::Thread& Threading::BackgroundActionBase::background_thread() | ||||
| { | ||||
|     if (s_background_thread == nullptr) | ||||
|         init(); | ||||
|     return *s_background_thread; | ||||
| } | ||||
| 
 | ||||
| void Threading::BackgroundActionBase::enqueue_work(Function<void()> work) | ||||
| { | ||||
|     if (s_all_actions == nullptr) | ||||
|         init(); | ||||
|     Locker locker(s_all_actions->lock()); | ||||
|     s_all_actions->resource().enqueue(move(work)); | ||||
|     char ch = 'x'; | ||||
|     if (write(s_notify_pipe_fds[1], &ch, sizeof(ch)) < 0) { | ||||
|         perror("write"); | ||||
|         _exit(1); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> | ||||
|  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> | ||||
|  * | ||||
|  * SPDX-License-Identifier: BSD-2-Clause | ||||
|  */ | ||||
|  | @ -13,7 +14,6 @@ | |||
| #include <LibCore/Event.h> | ||||
| #include <LibCore/EventLoop.h> | ||||
| #include <LibCore/Object.h> | ||||
| #include <LibThreading/Lock.h> | ||||
| #include <LibThreading/Thread.h> | ||||
| 
 | ||||
| namespace Threading { | ||||
|  | @ -28,7 +28,7 @@ class BackgroundActionBase { | |||
| private: | ||||
|     BackgroundActionBase() { } | ||||
| 
 | ||||
|     static Lockable<Queue<Function<void()>>>& all_actions(); | ||||
|     static void enqueue_work(Function<void()>); | ||||
|     static Thread& background_thread(); | ||||
| }; | ||||
| 
 | ||||
|  | @ -63,9 +63,7 @@ private: | |||
|         , m_action(move(action)) | ||||
|         , m_on_complete(move(on_complete)) | ||||
|     { | ||||
|         Locker locker(all_actions().lock()); | ||||
| 
 | ||||
|         all_actions().resource().enqueue([this] { | ||||
|         enqueue_work([this] { | ||||
|             m_result = m_action(*this); | ||||
|             if (m_on_complete) { | ||||
|                 Core::EventLoop::current().post_event(*this, make<Core::DeferredInvocationEvent>([this](auto&) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling