1 // Copyright 2024 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_semaphore.h"
6
7 #include "base/check_op.h"
8 #include "base/debug/alias.h"
9 #include "base/task/thread_pool/semaphore.h"
10 #include "base/task/thread_pool/task_tracker.h"
11 #include "base/task/thread_pool/worker_thread_observer.h"
12 #include "base/threading/hang_watcher.h"
13 #include "base/time/time.h"
14 #include "base/trace_event/base_tracing.h"
15
16 namespace base::internal {
17
TimedWait(TimeDelta timeout)18 bool WorkerThreadSemaphore::Delegate::TimedWait(TimeDelta timeout) {
19 const bool signaled = semaphore_->TimedWait(timeout);
20 timed_out_ = !signaled;
21 return signaled;
22 }
23
Delegate(Semaphore * semaphore,AtomicFlag * join_called_for_testing)24 WorkerThreadSemaphore::Delegate::Delegate(Semaphore* semaphore,
25 AtomicFlag* join_called_for_testing)
26 : semaphore_(semaphore),
27 join_called_for_testing_(join_called_for_testing) {}
28
WorkerThreadSemaphore(ThreadType thread_type_hint,std::unique_ptr<Delegate> delegate,TrackedRef<TaskTracker> task_tracker,size_t sequence_num,const CheckedLock * predecessor_lock,void * flow_terminator)29 WorkerThreadSemaphore::WorkerThreadSemaphore(
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 void* flow_terminator)
36 : WorkerThread(thread_type_hint,
37 task_tracker,
38 sequence_num,
39 predecessor_lock,
40 flow_terminator),
41 delegate_(std::move(delegate)) {
42 DCHECK(delegate_);
43 }
44
~WorkerThreadSemaphore()45 WorkerThreadSemaphore::~WorkerThreadSemaphore() {
46 Destroy();
47 }
48
delegate()49 WorkerThreadSemaphore::Delegate* WorkerThreadSemaphore::delegate() {
50 return delegate_.get();
51 }
52
join_called_for_testing() const53 bool WorkerThreadSemaphore::join_called_for_testing() const {
54 return delegate_->join_called_for_testing_->IsSet();
55 }
56
JoinForTesting()57 void WorkerThreadSemaphore::JoinForTesting() {
58 // join_called_for_testing_ is shared between semaphore workers and must be
59 // set before entering this function.
60 CHECK(delegate_->join_called_for_testing_->IsSet());
61
62 PlatformThreadHandle thread_handle;
63 {
64 CheckedAutoLock auto_lock(thread_lock_);
65
66 if (thread_handle_.is_null()) {
67 return;
68 }
69
70 thread_handle = thread_handle_;
71 // Reset |thread_handle_| so it isn't joined by the destructor.
72 thread_handle_ = PlatformThreadHandle();
73 }
74
75 PlatformThread::Join(thread_handle);
76 }
77
Cleanup()78 void WorkerThreadSemaphore::Cleanup() {
79 DCHECK(!should_exit_.IsSet());
80 should_exit_.Set();
81 // The semaphore is not signaled here (contrasted with
82 // WorkerThreadWaitableEvent), because when this is called (in
83 // GetWork/SwapProcessedTask) the worker is awake and won't sleep without
84 // checking ShouldExit().
85 }
86
87 } // namespace base::internal
88