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) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> | ||||||
|  |  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> | ||||||
|  * |  * | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
|  | @ -8,24 +9,33 @@ | ||||||
| #include <LibThreading/BackgroundAction.h> | #include <LibThreading/BackgroundAction.h> | ||||||
| #include <LibThreading/Lock.h> | #include <LibThreading/Lock.h> | ||||||
| #include <LibThreading/Thread.h> | #include <LibThreading/Thread.h> | ||||||
|  | #include <unistd.h> | ||||||
| 
 | 
 | ||||||
| static Threading::Lockable<Queue<Function<void()>>>* s_all_actions; | static Threading::Lockable<Queue<Function<void()>>>* s_all_actions; | ||||||
| static Threading::Thread* s_background_thread; | static Threading::Thread* s_background_thread; | ||||||
|  | static int s_notify_pipe_fds[2]; | ||||||
| 
 | 
 | ||||||
| static intptr_t background_thread_func() | static intptr_t background_thread_func() | ||||||
| { | { | ||||||
|     while (true) { |     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()); |             Threading::Locker locker(s_all_actions->lock()); | ||||||
| 
 | 
 | ||||||
|             if (!s_all_actions->resource().is_empty()) |             while (!s_all_actions->resource().is_empty()) { | ||||||
|                 work_item = s_all_actions->resource().dequeue(); |                 work_items.append(s_all_actions->resource().dequeue()); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         if (work_item) | 
 | ||||||
|  |         for (auto& work_item : work_items) | ||||||
|             work_item(); |             work_item(); | ||||||
|         else |  | ||||||
|             sleep(1); |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     VERIFY_NOT_REACHED(); |     VERIFY_NOT_REACHED(); | ||||||
|  | @ -33,22 +43,32 @@ static intptr_t background_thread_func() | ||||||
| 
 | 
 | ||||||
| static void init() | static void init() | ||||||
| { | { | ||||||
|  |     if (pipe(s_notify_pipe_fds) < 0) { | ||||||
|  |         perror("pipe"); | ||||||
|  |         _exit(1); | ||||||
|  |     } | ||||||
|     s_all_actions = new Threading::Lockable<Queue<Function<void()>>>(); |     s_all_actions = new Threading::Lockable<Queue<Function<void()>>>(); | ||||||
|     s_background_thread = &Threading::Thread::construct(background_thread_func).leak_ref(); |     s_background_thread = &Threading::Thread::construct(background_thread_func).leak_ref(); | ||||||
|     s_background_thread->set_name("Background thread"); |     s_background_thread->set_name("Background thread"); | ||||||
|     s_background_thread->start(); |     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() | Threading::Thread& Threading::BackgroundActionBase::background_thread() | ||||||
| { | { | ||||||
|     if (s_background_thread == nullptr) |     if (s_background_thread == nullptr) | ||||||
|         init(); |         init(); | ||||||
|     return *s_background_thread; |     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) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org> | ||||||
|  |  * Copyright (c) 2021, Andreas Kling <kling@serenityos.org> | ||||||
|  * |  * | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
|  | @ -13,7 +14,6 @@ | ||||||
| #include <LibCore/Event.h> | #include <LibCore/Event.h> | ||||||
| #include <LibCore/EventLoop.h> | #include <LibCore/EventLoop.h> | ||||||
| #include <LibCore/Object.h> | #include <LibCore/Object.h> | ||||||
| #include <LibThreading/Lock.h> |  | ||||||
| #include <LibThreading/Thread.h> | #include <LibThreading/Thread.h> | ||||||
| 
 | 
 | ||||||
| namespace Threading { | namespace Threading { | ||||||
|  | @ -28,7 +28,7 @@ class BackgroundActionBase { | ||||||
| private: | private: | ||||||
|     BackgroundActionBase() { } |     BackgroundActionBase() { } | ||||||
| 
 | 
 | ||||||
|     static Lockable<Queue<Function<void()>>>& all_actions(); |     static void enqueue_work(Function<void()>); | ||||||
|     static Thread& background_thread(); |     static Thread& background_thread(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -63,9 +63,7 @@ private: | ||||||
|         , m_action(move(action)) |         , m_action(move(action)) | ||||||
|         , m_on_complete(move(on_complete)) |         , m_on_complete(move(on_complete)) | ||||||
|     { |     { | ||||||
|         Locker locker(all_actions().lock()); |         enqueue_work([this] { | ||||||
| 
 |  | ||||||
|         all_actions().resource().enqueue([this] { |  | ||||||
|             m_result = m_action(*this); |             m_result = m_action(*this); | ||||||
|             if (m_on_complete) { |             if (m_on_complete) { | ||||||
|                 Core::EventLoop::current().post_event(*this, make<Core::DeferredInvocationEvent>([this](auto&) { |                 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