1#include <stdlib.h> 2#include <dlfcn.h> 3#include <stdio.h> 4#include <string.h> 5#include <stdint.h> 6#include <pthread.h> 7#include "typeinfo.h" 8#include "dwarf_eh.h" 9#include "cxxabi.h" 10 |
11#pragma weak pthread_key_create 12#pragma weak pthread_setspecific 13#pragma weak pthread_getspecific 14#pragma weak pthread_once 15#pragma weak pthread_once 16#pragma weak pthread_cond_signal 17#pragma weak pthread_cond_wait 18#pragma weak pthread_mutex_lock 19#pragma weak pthread_mutex_unlock 20 21 |
22using namespace ABI_NAMESPACE; 23 24/** 25 * Saves the result of the landing pad that we have found. For ARM, this is 26 * stored in the generic unwind structure, while on other platforms it is 27 * stored in the C++ exception. 28 */ 29static void saveLandingPad(struct _Unwind_Context *context, --- 265 unchanged lines hidden (view full) --- 295 296 297/** 298 * Once control used to protect the key creation. 299 */ 300static pthread_once_t once_control = PTHREAD_ONCE_INIT; 301 302/** |
303 * We may not be linked against a full pthread implementation. If we're not, 304 * then we need to fake the thread-local storage by storing 'thread-local' 305 * things in a global. 306 */ 307static bool fakeTLS; 308/** 309 * Thread-local storage for a single-threaded program. 310 */ 311static __cxa_thread_info singleThreadInfo; 312/** |
313 * Initialise eh_key. 314 */ 315static void init_key(void) 316{ |
317 if ((0 == pthread_key_create) || 318 (0 == pthread_setspecific) || 319 (0 == pthread_getspecific)) 320 { 321 fakeTLS = true; 322 return; 323 } |
324 pthread_key_create(&eh_key, thread_cleanup); |
325 pthread_setspecific(eh_key, (void*)0x42); 326 fakeTLS = (pthread_getspecific(eh_key) != (void*)0x42); 327 pthread_setspecific(eh_key, 0); |
328} 329 330/** 331 * Returns the thread info structure, creating it if it is not already created. 332 */ 333static __cxa_thread_info *thread_info() 334{ |
335 if ((0 == pthread_once) || pthread_once(&once_control, init_key)) 336 { 337 fakeTLS = true; 338 } 339 if (fakeTLS) { return &singleThreadInfo; } |
340 __cxa_thread_info *info = (__cxa_thread_info*)pthread_getspecific(eh_key); 341 if (0 == info) 342 { 343 info = (__cxa_thread_info*)calloc(1, sizeof(__cxa_thread_info)); 344 pthread_setspecific(eh_key, info); 345 } 346 return info; 347} 348/** 349 * Fast version of thread_info(). May fail if thread_info() is not called on 350 * this thread at least once already. 351 */ 352static __cxa_thread_info *thread_info_fast() 353{ |
354 if (fakeTLS) { return &singleThreadInfo; } |
355 return (__cxa_thread_info*)pthread_getspecific(eh_key); 356} 357/** 358 * ABI function returning the __cxa_eh_globals structure. 359 */ 360extern "C" __cxa_eh_globals *ABI_NAMESPACE::__cxa_get_globals(void) 361{ 362 return &(thread_info()->globals); --- 35 unchanged lines hidden (view full) --- 398static char *emergency_malloc(size_t size) 399{ 400 if (size > 1024) { return 0; } 401 402 __cxa_thread_info *info = thread_info(); 403 // Only 4 emergency buffers allowed per thread! 404 if (info->emergencyBuffersHeld > 3) { return 0; } 405 |
406 if (pthread_mutex_lock) 407 { 408 pthread_mutex_lock(&emergency_malloc_lock); 409 } |
410 int buffer = -1; 411 while (buffer < 0) 412 { 413 // While we were sleeping on the lock, another thread might have free'd 414 // enough memory for us to use, so try the allocation again - no point 415 // using the emergency buffer if there is some real memory that we can 416 // use... 417 void *m = calloc(1, size); 418 if (0 != m) 419 { |
420 if (pthread_mutex_unlock) 421 { 422 pthread_mutex_unlock(&emergency_malloc_lock); 423 } |
424 return (char*)m; 425 } 426 for (int i=0 ; i<16 ; i++) 427 { 428 if (!buffer_allocated[i]) 429 { 430 buffer = i; 431 buffer_allocated[i] = true; 432 break; 433 } 434 } 435 // If there still isn't a buffer available, then sleep on the condition 436 // variable. This will be signalled when another thread releases one 437 // of the emergency buffers. 438 if (buffer < 0) 439 { |
440 // If we don't have pthread_cond_wait, then there is only one 441 // thread and it's already used all of the emergency buffers, so we 442 // have no alternative but to die. Calling abort() instead of 443 // terminate, because terminate can throw exceptions, which can 444 // bring us back here and infinite loop. 445 if (!pthread_cond_wait) 446 { 447 fputs("Terminating while out of memory trying to throw an exception", 448 stderr); 449 abort(); 450 } |
451 pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock); 452 } 453 } |
454 if (pthread_mutex_unlock) 455 { 456 pthread_mutex_unlock(&emergency_malloc_lock); 457 } |
458 info->emergencyBuffersHeld++; 459 return emergency_buffer + (1024 * buffer); 460} 461 462/** 463 * Frees a buffer returned by emergency_malloc(). 464 * 465 * Note: Neither this nor emergency_malloc() is particularly efficient. This --- 16 unchanged lines hidden (view full) --- 482 assert(buffer > 0 && 483 "Trying to free something that is not an emergency buffer!"); 484 // emergency_malloc() is expected to return 0-initialized data. We don't 485 // zero the buffer when allocating it, because the static buffers will 486 // begin life containing 0 values. 487 memset((void*)ptr, 0, 1024); 488 // Signal the condition variable to wake up any threads that are blocking 489 // waiting for some space in the emergency buffer |
490 if (pthread_mutex_lock) 491 { 492 pthread_mutex_lock(&emergency_malloc_lock); 493 } |
494 // In theory, we don't need to do this with the lock held. In practice, 495 // our array of bools will probably be updated using 32-bit or 64-bit 496 // memory operations, so this update may clobber adjacent values. 497 buffer_allocated[buffer] = false; |
498 if (pthread_cond_signal && pthread_mutex_unlock) 499 { 500 pthread_cond_signal(&emergency_malloc_wait); 501 pthread_mutex_unlock(&emergency_malloc_lock); 502 } |
503} 504 505static char *alloc_or_die(size_t size) 506{ 507 char *buffer = (char*)calloc(1, size); 508 509 // If calloc() doesn't want to give us any memory, try using an emergency 510 // buffer. --- 973 unchanged lines hidden --- |