OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2014 Google Inc. All rights reserved. | 2 * Copyright (C) 2014 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 return *this; | 175 return *this; |
176 } | 176 } |
177 | 177 |
178 template<typename U> | 178 template<typename U> |
179 PersistentBase& operator=(const Member<U>& other) | 179 PersistentBase& operator=(const Member<U>& other) |
180 { | 180 { |
181 assign(other); | 181 assign(other); |
182 return *this; | 182 return *this; |
183 } | 183 } |
184 | 184 |
185 #if defined(LEAK_SANITIZER) | 185 // Register the persistent node as a 'static reference', |
186 // belonging to the current thread and a persistent that must | |
187 // be cleared when the ThreadState itself is cleared out and | |
188 // destructed. | |
189 // | |
190 // Static singletons arrange for this to happen, either to ensure | |
191 // clean LSan leak reports or to register a thread-local persistent | |
192 // needing to be cleared out before the thread is terminated. | |
186 PersistentBase* registerAsStaticReference() | 193 PersistentBase* registerAsStaticReference() |
187 { | 194 { |
188 if (m_persistentNode) { | 195 if (m_persistentNode) { |
189 ASSERT(ThreadState::current()); | 196 ASSERT(ThreadState::current()); |
190 ThreadState::current()->registerStaticPersistentNode(m_persistentNod e); | 197 ThreadState::current()->registerStaticPersistentNode(m_persistentNod e, nullptr); |
191 LEAK_SANITIZER_IGNORE_OBJECT(this); | 198 LEAK_SANITIZER_IGNORE_OBJECT(this); |
192 } | 199 } |
193 return this; | 200 return this; |
194 } | 201 } |
195 #endif | |
196 | 202 |
197 protected: | 203 protected: |
198 T* atomicGet() { return reinterpret_cast<T*>(acquireLoad(reinterpret_cast<vo id* volatile*>(&m_raw))); } | 204 T* atomicGet() { return reinterpret_cast<T*>(acquireLoad(reinterpret_cast<vo id* volatile*>(&m_raw))); } |
199 | 205 |
200 private: | 206 private: |
201 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 207 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
202 void assign(T* ptr) | 208 void assign(T* ptr) |
203 { | 209 { |
204 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) | 210 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) |
205 releaseStore(reinterpret_cast<void* volatile*>(&m_raw), ptr); | 211 releaseStore(reinterpret_cast<void* volatile*>(&m_raw), ptr); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
240 if (!m_persistentNode) | 246 if (!m_persistentNode) |
241 return; | 247 return; |
242 | 248 |
243 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { | 249 if (crossThreadnessConfiguration == CrossThreadPersistentConfiguration) { |
244 ProcessHeap::crossThreadPersistentRegion().freePersistentNode(m_pers istentNode); | 250 ProcessHeap::crossThreadPersistentRegion().freePersistentNode(m_pers istentNode); |
245 } else { | 251 } else { |
246 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::st ate(); | 252 ThreadState* state = ThreadStateFor<ThreadingTrait<T>::Affinity>::st ate(); |
247 ASSERT(state->checkThread()); | 253 ASSERT(state->checkThread()); |
248 // Persistent handle must be created and destructed in the same thre ad. | 254 // Persistent handle must be created and destructed in the same thre ad. |
249 ASSERT(m_state == state); | 255 ASSERT(m_state == state); |
250 state->getPersistentRegion()->freePersistentNode(m_persistentNode); | 256 state->freePersistentNode(m_persistentNode); |
251 } | 257 } |
252 m_persistentNode = nullptr; | 258 m_persistentNode = nullptr; |
253 } | 259 } |
254 | 260 |
255 void checkPointer() | 261 void checkPointer() |
256 { | 262 { |
257 #if ENABLE(ASSERT) && defined(ADDRESS_SANITIZER) | 263 #if ENABLE(ASSERT) && defined(ADDRESS_SANITIZER) |
258 if (!m_raw) | 264 if (!m_raw) |
259 return; | 265 return; |
260 | 266 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
323 Parent::operator=(other); | 329 Parent::operator=(other); |
324 return *this; | 330 return *this; |
325 } | 331 } |
326 | 332 |
327 template<typename U> | 333 template<typename U> |
328 Persistent& operator=(const Member<U>& other) | 334 Persistent& operator=(const Member<U>& other) |
329 { | 335 { |
330 Parent::operator=(other); | 336 Parent::operator=(other); |
331 return *this; | 337 return *this; |
332 } | 338 } |
333 | |
334 // Requests that the thread state clear this handle when the thread shuts | |
335 // down. This is intended for use with ThreadSpecific<Persistent<T>>. | |
336 // It's important that the Persistent<T> exist until then, because this | |
337 // takes a raw pointer to that handle. | |
338 // | |
339 // Example: | |
340 // Foo& sharedFoo() | |
341 // { | |
342 // DEFINE_THREAD_SAFE_STATIC_LOCAL( | |
343 // ThreadSpecific<Persistent<Foo>>, threadSpecificFoo, | |
344 // new ThreadSpecific<Persistent<Foo>>); | |
345 // Persistent<Foo>& fooHandle = *threadSpecificFoo; | |
346 // if (!fooHandle) { | |
347 // fooHandle = new Foo; | |
348 // fooHandle.clearOnThreadShutdown(); | |
349 // } | |
350 // return *fooHandle; | |
351 // } | |
352 void clearOnThreadShutdown() | |
353 { | |
354 void (*closure)(Persistent<T>*) = [](Persistent<T>* handle) | |
355 { | |
356 *handle = nullptr; | |
357 }; | |
358 ThreadState::current()->registerThreadShutdownHook(WTF::bind(closure, th is)); | |
359 } | |
360 }; | 339 }; |
361 | 340 |
362 // WeakPersistent is a way to create a weak pointer from an off-heap object | 341 // WeakPersistent is a way to create a weak pointer from an off-heap object |
363 // to an on-heap object. The m_raw is automatically cleared when the pointee | 342 // to an on-heap object. The m_raw is automatically cleared when the pointee |
364 // gets collected. | 343 // gets collected. |
365 // | 344 // |
366 // We have to construct and destruct WeakPersistent in the same thread. | 345 // We have to construct and destruct WeakPersistent in the same thread. |
367 // | 346 // |
368 // Note that collections of WeakPersistents are not supported. Use a persistent | 347 // Note that collections of WeakPersistents are not supported. Use a persistent |
369 // collection of WeakMembers instead. | 348 // collection of WeakMembers instead. |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
548 uninitialize(); | 527 uninitialize(); |
549 } | 528 } |
550 | 529 |
551 template<typename VisitorDispatcher> | 530 template<typename VisitorDispatcher> |
552 void trace(VisitorDispatcher visitor) | 531 void trace(VisitorDispatcher visitor) |
553 { | 532 { |
554 static_assert(sizeof(Collection), "Collection must be fully defined"); | 533 static_assert(sizeof(Collection), "Collection must be fully defined"); |
555 visitor->trace(*static_cast<Collection*>(this)); | 534 visitor->trace(*static_cast<Collection*>(this)); |
556 } | 535 } |
557 | 536 |
558 #if defined(LEAK_SANITIZER) | 537 // See PersistentBase::registerAsStaticReference() comment. |
559 PersistentHeapCollectionBase* registerAsStaticReference() | 538 PersistentHeapCollectionBase* registerAsStaticReference() |
560 { | 539 { |
561 if (m_persistentNode) { | 540 if (m_persistentNode) { |
562 ASSERT(ThreadState::current()); | 541 ASSERT(ThreadState::current()); |
563 ThreadState::current()->registerStaticPersistentNode(m_persistentNod e); | 542 ThreadState::current()->registerStaticPersistentNode(m_persistentNod e, &PersistentHeapCollectionBase<Collection>::clearPersistentNode); |
564 LEAK_SANITIZER_IGNORE_OBJECT(this); | 543 LEAK_SANITIZER_IGNORE_OBJECT(this); |
565 } | 544 } |
566 return this; | 545 return this; |
567 } | 546 } |
568 #endif | |
569 | 547 |
570 private: | 548 private: |
571 | 549 |
550 // Used when the registered PersistentNode of this object is | |
551 // released during ThreadState shutdown, clearing the association. | |
552 static void clearPersistentNode(void *self) | |
553 { | |
554 (reinterpret_cast<PersistentHeapCollectionBase<Collection>*>(self))->uni nitialize(); | |
haraken
2016/04/25 08:39:23
Why does PersistentHeapCollectionBase need to call
sof
2016/04/25 08:53:04
It also needs to clear the connection; see Persist
| |
555 } | |
556 | |
572 NO_LAZY_SWEEP_SANITIZE_ADDRESS | 557 NO_LAZY_SWEEP_SANITIZE_ADDRESS |
573 void initialize() | 558 void initialize() |
574 { | 559 { |
575 // FIXME: Derive affinity based on the collection. | 560 // FIXME: Derive affinity based on the collection. |
576 ThreadState* state = ThreadState::current(); | 561 ThreadState* state = ThreadState::current(); |
577 ASSERT(state->checkThread()); | 562 ASSERT(state->checkThread()); |
578 m_persistentNode = state->getPersistentRegion()->allocatePersistentNode( this, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentH eapCollectionBase<Collection>::trace>::trampoline); | 563 m_persistentNode = state->getPersistentRegion()->allocatePersistentNode( this, TraceMethodDelegate<PersistentHeapCollectionBase<Collection>, &PersistentH eapCollectionBase<Collection>::trace>::trampoline); |
579 #if ENABLE(ASSERT) | 564 #if ENABLE(ASSERT) |
580 m_state = state; | 565 m_state = state; |
581 #endif | 566 #endif |
582 } | 567 } |
583 | 568 |
584 void uninitialize() | 569 void uninitialize() |
585 { | 570 { |
571 if (!m_persistentNode) | |
haraken
2016/04/25 08:39:23
Just curious, why do we need this check?
sof
2016/04/25 08:53:05
If you have a PersistentCollectionBase stuck in TL
| |
572 return; | |
586 ThreadState* state = ThreadState::current(); | 573 ThreadState* state = ThreadState::current(); |
587 ASSERT(state->checkThread()); | 574 ASSERT(state->checkThread()); |
588 // Persistent handle must be created and destructed in the same thread. | 575 // Persistent handle must be created and destructed in the same thread. |
589 ASSERT(m_state == state); | 576 ASSERT(m_state == state); |
590 state->getPersistentRegion()->freePersistentNode(m_persistentNode); | 577 state->freePersistentNode(m_persistentNode); |
578 m_persistentNode = nullptr; | |
591 } | 579 } |
592 | 580 |
593 PersistentNode* m_persistentNode; | 581 PersistentNode* m_persistentNode; |
594 #if ENABLE(ASSERT) | 582 #if ENABLE(ASSERT) |
595 ThreadState* m_state; | 583 ThreadState* m_state; |
596 #endif | 584 #endif |
597 }; | 585 }; |
598 | 586 |
599 template< | 587 template< |
600 typename KeyArg, | 588 typename KeyArg, |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1227 // into it. | 1215 // into it. |
1228 // | 1216 // |
1229 // TODO(sof): remove this hack once wtf/Functional.h can also work with a ty pe like | 1217 // TODO(sof): remove this hack once wtf/Functional.h can also work with a ty pe like |
1230 // CrossThreadWeakPersistent<>. | 1218 // CrossThreadWeakPersistent<>. |
1231 static WeakPtr<T> unwrap(const StorageType& value) { return WeakPtr<T>(WeakR eference<T>::create(value.get())); } | 1219 static WeakPtr<T> unwrap(const StorageType& value) { return WeakPtr<T>(WeakR eference<T>::create(value.get())); } |
1232 }; | 1220 }; |
1233 | 1221 |
1234 } // namespace WTF | 1222 } // namespace WTF |
1235 | 1223 |
1236 #endif | 1224 #endif |
OLD | NEW |