• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/allocator/partition_allocator/src/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 
44 WorkerThreadWaitableEvent::~WorkerThreadWaitableEvent() = default;
45 
JoinForTesting()46 void WorkerThreadWaitableEvent::JoinForTesting() {
47   DCHECK(!join_called_for_testing_.IsSet());
48   join_called_for_testing_.Set();
49   delegate_->wake_up_event_.Signal();
50 
51   PlatformThreadHandle thread_handle;
52 
53   {
54     CheckedAutoLock auto_lock(thread_lock_);
55 
56     if (thread_handle_.is_null()) {
57       return;
58     }
59 
60     thread_handle = thread_handle_;
61     // Reset |thread_handle_| so it isn't joined by the destructor.
62     thread_handle_ = PlatformThreadHandle();
63   }
64 
65   PlatformThread::Join(thread_handle);
66 }
67 
Cleanup()68 void WorkerThreadWaitableEvent::Cleanup() {
69   DCHECK(!should_exit_.IsSet());
70   should_exit_.Set();
71   delegate_->wake_up_event_.Signal();
72 }
73 
WakeUp()74 void WorkerThreadWaitableEvent::WakeUp() {
75   // Signalling an event can deschedule the current thread. Since being
76   // descheduled while holding a lock is undesirable (https://crbug.com/890978),
77   // assert that no lock is held by the current thread.
78   CheckedLock::AssertNoLockHeldOnCurrentThread();
79   // Calling WakeUp() after Cleanup() or Join() is wrong because the
80   // WorkerThread cannot run more tasks.
81   DCHECK(!join_called_for_testing_.IsSet());
82   DCHECK(!should_exit_.IsSet());
83   TRACE_EVENT_INSTANT("wakeup.flow", "WorkerThreadWaitableEvent::WakeUp",
84                       perfetto::Flow::FromPointer(this));
85 
86   delegate_->wake_up_event_.Signal();
87 }
88 
delegate()89 WorkerThreadWaitableEvent::Delegate* WorkerThreadWaitableEvent::delegate() {
90   return delegate_.get();
91 }
92 
93 }  // namespace base::internal
94