OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #include "vm/os_thread.h" | |
6 | |
7 #include "vm/atomic.h" | |
8 #include "vm/lockers.h" | |
9 #include "vm/log.h" | |
10 #include "vm/thread_interrupter.h" | |
11 | |
12 namespace dart { | |
13 | |
14 // The single thread local key which stores all the thread local data | |
15 // for a thread. | |
16 ThreadLocalKey OSThread::thread_key_ = OSThread::kUnsetThreadLocalKey; | |
17 OSThread* OSThread::thread_list_head_ = NULL; | |
18 Mutex* OSThread::thread_list_lock_ = NULL; | |
19 | |
20 | |
21 OSThread::OSThread() : | |
22 BaseThread(true), | |
23 id_(OSThread::GetCurrentThreadId()), | |
24 join_id_(OSThread::GetCurrentThreadJoinId()), | |
25 trace_id_(OSThread::GetCurrentThreadTraceId()), | |
26 name_(NULL), | |
27 timeline_block_lock_(new Mutex()), | |
28 timeline_block_(NULL), | |
29 thread_list_next_(NULL), | |
30 thread_interrupt_disabled_(1), // Thread interrupts disabled by default. | |
31 log_(new class Log()), | |
32 stack_base_(0), | |
33 thread_(NULL) { | |
34 AddThreadToList(this); | |
35 } | |
36 | |
37 | |
38 OSThread::~OSThread() { | |
39 RemoveThreadFromList(this); | |
40 delete log_; | |
41 log_ = NULL; | |
42 if (Timeline::recorder() != NULL) { | |
43 Timeline::recorder()->FinishBlock(timeline_block_); | |
44 } | |
45 timeline_block_ = NULL; | |
46 delete timeline_block_lock_; | |
Ivan Posva
2015/11/19 06:23:23
Who deletes name_? This also means that we have to
Cutch
2015/11/19 15:12:21
name_ must always be a statically allocated const
| |
47 } | |
48 | |
49 | |
50 void OSThread::DisableThreadInterrupts() { | |
51 ASSERT(OSThread::Current() == this); | |
52 AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_); | |
53 } | |
54 | |
55 | |
56 void OSThread::EnableThreadInterrupts() { | |
57 ASSERT(OSThread::Current() == this); | |
58 uintptr_t old = | |
59 AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_); | |
60 if (old == 1) { | |
61 // We just decremented from 1 to 0. | |
62 // Make sure the thread interrupter is awake. | |
63 ThreadInterrupter::WakeUp(); | |
64 } | |
Ivan Posva
2015/11/19 06:23:23
} else if (old == 0) {
Should we FATAL out in all
Cutch
2015/11/19 15:12:21
I wrote this code so that it would FATAL in all co
siva
2015/11/19 20:54:05
I am going to leave it the way it is now, we can a
| |
65 if (old == 0) { | |
66 // We just decremented from 0, this means we've got a mismatched pair | |
67 // of calls to EnableThreadInterrupts and DisableThreadInterrupts. | |
68 FATAL("Invalid call to OSThread::EnableThreadInterrupts()"); | |
69 } | |
70 } | |
71 | |
72 | |
73 bool OSThread::ThreadInterruptsEnabled() { | |
74 return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0; | |
75 } | |
76 | |
77 | |
78 static void DeleteThread(void* thread) { | |
79 delete reinterpret_cast<OSThread*>(thread); | |
80 } | |
81 | |
82 | |
83 void OSThread::InitOnce() { | |
84 // Allocate the global OSThread lock. | |
85 ASSERT(thread_list_lock_ == NULL); | |
86 thread_list_lock_ = new Mutex(); | |
87 ASSERT(thread_list_lock_ != NULL); | |
88 | |
89 // Create the thread local key. | |
90 ASSERT(thread_key_ == kUnsetThreadLocalKey); | |
91 thread_key_ = CreateThreadLocal(DeleteThread); | |
92 ASSERT(thread_key_ != kUnsetThreadLocalKey); | |
93 | |
94 // Create a new OSThread strcture and set it as the TLS. | |
95 OSThread* os_thread = new OSThread(); | |
96 OSThread::SetCurrent(os_thread); | |
97 os_thread->set_name("Dart_Initialize"); | |
98 } | |
99 | |
100 | |
101 void OSThread::Cleanup() { | |
102 if (thread_list_lock_ != NULL) { | |
103 // Delete the thread local key. | |
104 ASSERT(thread_key_ != kUnsetThreadLocalKey); | |
105 DeleteThreadLocal(thread_key_); | |
106 thread_key_ = kUnsetThreadLocalKey; | |
107 | |
108 // Delete the global OSThread lock. | |
109 ASSERT(thread_list_lock_ != NULL); | |
110 delete thread_list_lock_; | |
111 thread_list_lock_ = NULL; | |
112 } | |
113 } | |
114 | |
115 | |
116 bool OSThread::IsThreadInList(ThreadId join_id) { | |
117 if (join_id == OSThread::kInvalidThreadJoinId) { | |
118 return false; | |
119 } | |
120 OSThreadIterator it; | |
121 while (it.HasNext()) { | |
122 ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); | |
123 OSThread* t = it.Next(); | |
124 // An address test is not sufficient because the allocator may recycle | |
125 // the address for another Thread. Test against the thread's join id. | |
126 if (t->join_id() == join_id) { | |
127 return true; | |
128 } | |
129 } | |
130 return false; | |
131 } | |
132 | |
133 | |
134 OSThread* OSThread::GetOSThreadFromThread(Thread* thread) { | |
135 ASSERT(thread->os_thread() != NULL); | |
136 return thread->os_thread(); | |
137 } | |
138 | |
139 | |
140 void OSThread::AddThreadToList(OSThread* thread) { | |
141 ASSERT(thread != NULL); | |
142 ASSERT(thread_list_lock_ != NULL); | |
143 MutexLocker ml(thread_list_lock_); | |
144 | |
145 ASSERT(thread->thread_list_next_ == NULL); | |
146 | |
147 #if defined(DEBUG) | |
148 { | |
149 // Ensure that we aren't already in the list. | |
150 OSThread* current = thread_list_head_; | |
151 while (current != NULL) { | |
152 ASSERT(current != thread); | |
153 current = current->thread_list_next_; | |
154 } | |
155 } | |
156 #endif | |
157 | |
158 // Insert at head of list. | |
159 thread->thread_list_next_ = thread_list_head_; | |
160 thread_list_head_ = thread; | |
161 } | |
162 | |
163 | |
164 void OSThread::RemoveThreadFromList(OSThread* thread) { | |
165 { | |
166 ASSERT(thread != NULL); | |
167 ASSERT(thread_list_lock_ != NULL); | |
168 MutexLocker ml(thread_list_lock_); | |
169 OSThread* current = thread_list_head_; | |
170 OSThread* previous = NULL; | |
171 | |
172 // Scan across list and remove |thread|. | |
173 while (current != NULL) { | |
174 if (current == thread) { | |
175 // We found |thread|, remove from list. | |
176 if (previous == NULL) { | |
177 thread_list_head_ = thread->thread_list_next_; | |
178 } else { | |
179 previous->thread_list_next_ = current->thread_list_next_; | |
180 } | |
181 thread->thread_list_next_ = NULL; | |
182 break; | |
183 } | |
184 previous = current; | |
185 current = current->thread_list_next_; | |
186 } | |
187 } | |
188 // Check if this is the last thread. The last thread does a cleanup | |
189 // which removes the thread local key and the associated mutex. | |
190 if (thread_list_head_ == NULL) { | |
191 Cleanup(); | |
192 } | |
193 } | |
194 | |
195 | |
196 void OSThread::SetCurrent(OSThread* current) { | |
197 OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current)); | |
198 } | |
199 | |
200 | |
201 OSThreadIterator::OSThreadIterator() { | |
202 ASSERT(OSThread::thread_list_lock_ != NULL); | |
203 // Lock the thread list while iterating. | |
204 OSThread::thread_list_lock_->Lock(); | |
205 next_ = OSThread::thread_list_head_; | |
206 } | |
207 | |
208 | |
209 OSThreadIterator::~OSThreadIterator() { | |
210 ASSERT(OSThread::thread_list_lock_ != NULL); | |
211 // Unlock the thread list when done. | |
212 OSThread::thread_list_lock_->Unlock(); | |
213 } | |
214 | |
215 | |
216 bool OSThreadIterator::HasNext() const { | |
217 ASSERT(OSThread::thread_list_lock_ != NULL); | |
218 ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); | |
219 return next_ != NULL; | |
220 } | |
221 | |
222 | |
223 OSThread* OSThreadIterator::Next() { | |
224 ASSERT(OSThread::thread_list_lock_ != NULL); | |
225 ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread()); | |
226 OSThread* current = next_; | |
227 next_ = next_->thread_list_next_; | |
228 return current; | |
229 } | |
230 | |
231 } // namespace dart | |
OLD | NEW |