xref: /aosp_15_r20/external/cronet/base/task/thread_pool/worker_thread_waitable_event.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/task/thread_pool/worker_thread_waitable_event.h"
6 
7 #include "base/debug/alias.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/task/thread_pool/task_tracker.h"
10 #include "base/task/thread_pool/worker_thread_observer.h"
11 #include "base/time/time.h"
12 #include "base/trace_event/base_tracing.h"
13 
14 #if BUILDFLAG(IS_APPLE)
15 #include "base/apple/scoped_nsautorelease_pool.h"
16 #endif
17 
18 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && \
19     PA_CONFIG(THREAD_CACHE_SUPPORTED)
20 #include "partition_alloc/thread_cache.h"
21 #endif
22 
23 namespace base::internal {
24 
TimedWait(TimeDelta timeout)25 bool WorkerThreadWaitableEvent::Delegate::TimedWait(TimeDelta timeout) {
26   return wake_up_event_.TimedWait(timeout);
27 }
28 
WorkerThreadWaitableEvent(ThreadType thread_type_hint,std::unique_ptr<Delegate> delegate,TrackedRef<TaskTracker> task_tracker,size_t sequence_num,const CheckedLock * predecessor_lock)29 WorkerThreadWaitableEvent::WorkerThreadWaitableEvent(
30     ThreadType thread_type_hint,
31     std::unique_ptr<Delegate> delegate,
32     TrackedRef<TaskTracker> task_tracker,
33     size_t sequence_num,
34     const CheckedLock* predecessor_lock)
35     : WorkerThread(thread_type_hint,
36                    task_tracker,
37                    sequence_num,
38                    predecessor_lock),
39       delegate_(std::move(delegate)) {
40   DCHECK(delegate_);
41   delegate_->wake_up_event_.declare_only_used_while_idle();
42 }
43 
~WorkerThreadWaitableEvent()44 WorkerThreadWaitableEvent::~WorkerThreadWaitableEvent() {
45   Destroy();
46 }
47 
JoinForTesting()48 void WorkerThreadWaitableEvent::JoinForTesting() {
49   DCHECK(!join_called_for_testing_.IsSet());
50   join_called_for_testing_.Set();
51   delegate_->wake_up_event_.Signal();
52 
53   PlatformThreadHandle thread_handle;
54 
55   {
56     CheckedAutoLock auto_lock(thread_lock_);
57 
58     if (thread_handle_.is_null()) {
59       return;
60     }
61 
62     thread_handle = thread_handle_;
63     // Reset |thread_handle_| so it isn't joined by the destructor.
64     thread_handle_ = PlatformThreadHandle();
65   }
66 
67   PlatformThread::Join(thread_handle);
68 }
69 
Cleanup()70 void WorkerThreadWaitableEvent::Cleanup() {
71   DCHECK(!should_exit_.IsSet());
72   should_exit_.Set();
73   delegate_->wake_up_event_.Signal();
74 }
75 
join_called_for_testing() const76 bool WorkerThreadWaitableEvent::join_called_for_testing() const {
77   return join_called_for_testing_.IsSet();
78 }
79 
WakeUp()80 void WorkerThreadWaitableEvent::WakeUp() {
81   // Signalling an event can deschedule the current thread. Since being
82   // descheduled while holding a lock is undesirable (https://crbug.com/890978),
83   // assert that no lock is held by the current thread.
84   CheckedLock::AssertNoLockHeldOnCurrentThread();
85   // Calling WakeUp() after Cleanup() or Join() is wrong because the
86   // WorkerThread cannot run more tasks.
87   DCHECK(!join_called_for_testing_.IsSet());
88   DCHECK(!should_exit_.IsSet());
89   TRACE_EVENT_INSTANT("wakeup.flow", "WorkerThreadWaitableEvent::WakeUp",
90                       perfetto::Flow::FromPointer(this));
91 
92   delegate_->wake_up_event_.Signal();
93 }
94 
delegate()95 WorkerThreadWaitableEvent::Delegate* WorkerThreadWaitableEvent::delegate() {
96   return delegate_.get();
97 }
98 
99 }  // namespace base::internal
100