OLD | NEW |
1 // Copyright (c) 2008, Google Inc. | 1 // Copyright (c) 2008, Google Inc. |
2 // All rights reserved. | 2 // 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 13 matching lines...) Expand all Loading... |
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 // --- | 30 // --- |
31 // Author: Ken Ashcraft <opensource@google.com> | 31 // Author: Ken Ashcraft <opensource@google.com> |
32 | 32 |
33 #include <config.h> | 33 #include <config.h> |
34 #ifdef HAVE_INTTYPES_H | |
35 #include <inttypes.h> | |
36 #endif | |
37 #include <algorithm> // for min and max | |
38 #include "thread_cache.h" | 34 #include "thread_cache.h" |
| 35 #include <string.h> // for memcpy |
| 36 #include <algorithm> // for max, min |
| 37 #include "base/commandlineflags.h" // for SpinLockHolder |
| 38 #include "base/spinlock.h" // for SpinLockHolder |
| 39 #include "central_freelist.h" // for CentralFreeListPadded |
39 #include "maybe_threads.h" | 40 #include "maybe_threads.h" |
40 | 41 |
41 using std::min; | 42 using std::min; |
42 using std::max; | 43 using std::max; |
43 | 44 |
44 DEFINE_int64(tcmalloc_max_total_thread_cache_bytes, | 45 DEFINE_int64(tcmalloc_max_total_thread_cache_bytes, |
45 EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES", 16<<20), | 46 EnvToInt64("TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES", |
| 47 kDefaultOverallThreadCacheSize), |
46 "Bound on the total amount of bytes allocated to " | 48 "Bound on the total amount of bytes allocated to " |
47 "thread caches. This bound is not strict, so it is possible " | 49 "thread caches. This bound is not strict, so it is possible " |
48 "for the cache to go over this bound in certain circumstances. "); | 50 "for the cache to go over this bound in certain circumstances. "); |
49 | 51 |
50 namespace tcmalloc { | 52 namespace tcmalloc { |
51 | 53 |
52 static bool phinited = false; | 54 static bool phinited = false; |
53 | 55 |
54 volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize; | 56 volatile size_t ThreadCache::per_thread_cache_size_ = kMaxThreadCacheSize; |
55 size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize; | 57 size_t ThreadCache::overall_thread_cache_size_ = kDefaultOverallThreadCacheSize; |
(...skipping 248 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 Static::InitStaticVars(); | 306 Static::InitStaticVars(); |
305 threadcache_allocator.Init(); | 307 threadcache_allocator.Init(); |
306 phinited = 1; | 308 phinited = 1; |
307 } | 309 } |
308 } | 310 } |
309 | 311 |
310 void ThreadCache::InitTSD() { | 312 void ThreadCache::InitTSD() { |
311 ASSERT(!tsd_inited_); | 313 ASSERT(!tsd_inited_); |
312 perftools_pthread_key_create(&heap_key_, DestroyThreadCache); | 314 perftools_pthread_key_create(&heap_key_, DestroyThreadCache); |
313 tsd_inited_ = true; | 315 tsd_inited_ = true; |
314 | |
315 // We may have used a fake pthread_t for the main thread. Fix it. | |
316 pthread_t zero; | |
317 memset(&zero, 0, sizeof(zero)); | |
318 SpinLockHolder h(Static::pageheap_lock()); | |
319 for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { | |
320 if (h->tid_ == zero) { | |
321 h->tid_ = pthread_self(); | |
322 } | |
323 } | |
324 } | 316 } |
325 | 317 |
326 ThreadCache* ThreadCache::CreateCacheIfNecessary() { | 318 ThreadCache* ThreadCache::CreateCacheIfNecessary() { |
327 // Initialize per-thread data if necessary | 319 // Initialize per-thread data if necessary |
328 ThreadCache* heap = NULL; | 320 ThreadCache* heap = NULL; |
329 { | 321 { |
330 SpinLockHolder h(Static::pageheap_lock()); | 322 SpinLockHolder h(Static::pageheap_lock()); |
331 | 323 // On very old libc's, this call may crash if it happens too |
332 // Early on in glibc's life, we cannot even call pthread_self() | 324 // early. No libc using NPTL should be affected. If there |
333 pthread_t me; | 325 // is a crash here, we could use code (on linux, at least) |
334 if (!tsd_inited_) { | 326 // to detect NPTL vs LinuxThreads: |
335 memset(&me, 0, sizeof(me)); | 327 // http://www.redhat.com/archives/phil-list/2003-April/msg00038.html |
336 } else { | 328 // If we detect not-NPTL, we could execute the old code from |
337 me = pthread_self(); | 329 // http://google-perftools.googlecode.com/svn/tags/google-perftools-1.7/sr
c/thread_cache.cc |
338 } | 330 // that avoids calling pthread_self too early. The problem with |
| 331 // that code is it caused a race condition when tcmalloc is linked |
| 332 // in statically and other libraries spawn threads before main. |
| 333 const pthread_t me = pthread_self(); |
339 | 334 |
340 // This may be a recursive malloc call from pthread_setspecific() | 335 // This may be a recursive malloc call from pthread_setspecific() |
341 // In that case, the heap for this thread has already been created | 336 // In that case, the heap for this thread has already been created |
342 // and added to the linked list. So we search for that first. | 337 // and added to the linked list. So we search for that first. |
343 for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { | 338 for (ThreadCache* h = thread_heaps_; h != NULL; h = h->next_) { |
344 if (h->tid_ == me) { | 339 if (h->tid_ == me) { |
345 heap = h; | 340 heap = h; |
346 break; | 341 break; |
347 } | 342 } |
348 } | 343 } |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 void ThreadCache::set_overall_thread_cache_size(size_t new_size) { | 493 void ThreadCache::set_overall_thread_cache_size(size_t new_size) { |
499 // Clip the value to a reasonable range | 494 // Clip the value to a reasonable range |
500 if (new_size < kMinThreadCacheSize) new_size = kMinThreadCacheSize; | 495 if (new_size < kMinThreadCacheSize) new_size = kMinThreadCacheSize; |
501 if (new_size > (1<<30)) new_size = (1<<30); // Limit to 1GB | 496 if (new_size > (1<<30)) new_size = (1<<30); // Limit to 1GB |
502 overall_thread_cache_size_ = new_size; | 497 overall_thread_cache_size_ = new_size; |
503 | 498 |
504 RecomputePerThreadCacheSize(); | 499 RecomputePerThreadCacheSize(); |
505 } | 500 } |
506 | 501 |
507 } // namespace tcmalloc | 502 } // namespace tcmalloc |
OLD | NEW |