1 : // Copyright 2016 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/agent/asan/heap_managers/deferred_free_thread.h"
16 :
17 : namespace agent {
18 : namespace asan {
19 : namespace heap_managers {
20 :
21 : DeferredFreeThread::DeferredFreeThread(Callback deferred_free_callback)
22 E : : deferred_free_callback_(deferred_free_callback),
23 E : deferred_free_event_(false, false),
24 E : deferred_free_signaled_(0),
25 E : ready_event_(false, false),
26 E : enabled_(0) {
27 E : }
28 :
29 E : DeferredFreeThread::~DeferredFreeThread() {
30 E : DCHECK_EQ(0, base::subtle::NoBarrier_Load(&enabled_));
31 E : }
32 :
33 E : bool DeferredFreeThread::Start() {
34 E : auto old_enabled = base::subtle::NoBarrier_AtomicExchange(&enabled_, 1);
35 E : DCHECK_EQ(0, old_enabled);
36 : // Make sure the change to |enabled_| is not reordered.
37 E : base::subtle::MemoryBarrier();
38 E : if (!base::PlatformThread::CreateWithPriority(
39 : 0, this, &deferred_free_thread_handle_,
40 : base::ThreadPriority::BACKGROUND)) {
41 i : return false;
42 : }
43 E : ready_event_.Wait();
44 E : return true;
45 E : }
46 :
47 E : void DeferredFreeThread::Stop() {
48 E : auto old_enabled = base::subtle::NoBarrier_AtomicExchange(&enabled_, 0);
49 E : DCHECK_EQ(1, old_enabled);
50 : // Make sure the change to |enabled_| is not reordered.
51 E : base::subtle::MemoryBarrier();
52 : // Signal so that the thread can exit cleanly and then join it.
53 E : deferred_free_event_.Signal();
54 E : base::PlatformThread::Join(deferred_free_thread_handle_);
55 E : }
56 :
57 E : void DeferredFreeThread::SignalWork() {
58 : // Avoid over signaling by trying to raise the |deferred_free_signaled_| flag
59 : // and bailing if the flag was already raised.
60 : auto initial_deferred_free_signaled =
61 E : base::subtle::NoBarrier_CompareAndSwap(&deferred_free_signaled_, 0, 1);
62 E : if (initial_deferred_free_signaled)
63 i : return;
64 :
65 E : deferred_free_event_.Signal();
66 E : }
67 :
68 E : void DeferredFreeThread::ThreadMain() {
69 E : base::PlatformThread::SetName("SyzyASAN Deferred Free Thread");
70 E : deferred_free_thread_id_ = base::PlatformThread::CurrentId();
71 E : ready_event_.Signal();
72 E : while (true) {
73 E : deferred_free_event_.Wait();
74 E : if (!base::subtle::NoBarrier_Load(&enabled_))
75 E : break;
76 : // Clear the |deferred_free_signaled_| flag before executing the callback.
77 : auto initial_deferred_free_signaled =
78 E : base::subtle::NoBarrier_CompareAndSwap(&deferred_free_signaled_, 1, 0);
79 E : DCHECK(initial_deferred_free_signaled);
80 E : deferred_free_callback_.Run();
81 E : }
82 E : }
83 :
84 : } // namespace heap_managers
85 : } // namespace asan
86 : } // namespace agent
|