| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2012 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 /* | 7 /* |
| 8 * Native Client threads library | 8 * Native Client threads library |
| 9 */ | 9 */ |
| 10 | 10 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 #endif | 56 #endif |
| 57 | 57 |
| 58 typedef struct nc_thread_cleanup_handler { | 58 typedef struct nc_thread_cleanup_handler { |
| 59 struct nc_thread_cleanup_handler *previous; | 59 struct nc_thread_cleanup_handler *previous; |
| 60 void (*handler_function)(void *arg); | 60 void (*handler_function)(void *arg); |
| 61 void *handler_arg; | 61 void *handler_arg; |
| 62 } nc_thread_cleanup_handler; | 62 } nc_thread_cleanup_handler; |
| 63 | 63 |
| 64 static __thread nc_thread_cleanup_handler *__nc_cleanup_handlers = NULL; | 64 static __thread nc_thread_cleanup_handler *__nc_cleanup_handlers = NULL; |
| 65 | 65 |
| 66 #define TDB_SIZE (sizeof(struct nc_combined_tdb)) |
| 67 |
| 66 static inline char *align(uint32_t offset, uint32_t alignment) { | 68 static inline char *align(uint32_t offset, uint32_t alignment) { |
| 67 return (char *) ((offset + alignment - 1) & ~(alignment - 1)); | 69 return (char *) ((offset + alignment - 1) & ~(alignment - 1)); |
| 68 } | 70 } |
| 69 | 71 |
| 70 /* Thread management global variables. */ | 72 /* Thread management global variables. */ |
| 71 const int __nc_kMaxCachedMemoryBlocks = 50; | 73 const int __nc_kMaxCachedMemoryBlocks = 50; |
| 72 | 74 |
| 73 int __nc_thread_initialized; | 75 int __nc_thread_initialized; |
| 74 | 76 |
| 75 /* Mutex used to synchronize thread management code. */ | 77 /* Mutex used to synchronize thread management code. */ |
| 76 pthread_mutex_t __nc_thread_management_lock; | 78 pthread_mutex_t __nc_thread_management_lock; |
| 77 | 79 |
| 78 /* | 80 /* |
| 79 * Condition variable that gets signaled when all the threads | 81 * Condition variable that gets signaled when all the threads |
| 80 * except the main thread have terminated. | 82 * except the main thread have terminated. |
| 81 */ | 83 */ |
| 82 static pthread_cond_t __nc_last_thread_cond; | 84 static pthread_cond_t __nc_last_thread_cond; |
| 83 pthread_t __nc_initial_thread_id; | 85 pthread_t __nc_initial_thread_id; |
| 84 | 86 |
| 85 /* Number of threads currently running in this NaCl module. */ | 87 /* Number of threads currently running in this NaCl module. */ |
| 86 int __nc_running_threads_counter = 1; | 88 int __nc_running_threads_counter = 1; |
| 87 | 89 |
| 88 /* We have two queues of memory blocks - one for each type. */ | 90 /* We have two queues of memory blocks - one for each type. */ |
| 89 STAILQ_HEAD(tailhead, entry) __nc_thread_memory_blocks[2]; | 91 STAILQ_HEAD(tailhead, entry) __nc_thread_memory_blocks[2]; |
| 90 /* We need a counter for each queue to keep track of number of blocks. */ | 92 /* We need a counter for each queue to keep track of number of blocks. */ |
| 91 int __nc_memory_block_counter[2]; | 93 int __nc_memory_block_counter[2]; |
| 92 | 94 |
| 93 /* Internal functions */ | 95 /* Internal functions */ |
| 94 | 96 |
| 97 static inline nc_thread_descriptor_t *nc_get_tdb(void) { |
| 98 /* |
| 99 * Fetch the thread-specific data pointer. This is usually just |
| 100 * a wrapper around __libnacl_irt_tls.tls_get() but we don't use |
| 101 * that here so that the IRT build can override the definition. |
| 102 */ |
| 103 return (void *) ((char *) __nacl_read_tp_inline() |
| 104 + __nacl_tp_tdb_offset(TDB_SIZE)); |
| 105 } |
| 106 |
| 95 static void nc_thread_starter(void) { | 107 static void nc_thread_starter(void) { |
| 96 nc_thread_descriptor_t *tdb = __nc_get_tdb(); | 108 nc_thread_descriptor_t *tdb = nc_get_tdb(); |
| 97 __newlib_thread_init(); | 109 __newlib_thread_init(); |
| 98 #if defined(NACL_IN_IRT) | 110 #if defined(NACL_IN_IRT) |
| 99 g_is_irt_internal_thread = 1; | 111 g_is_irt_internal_thread = 1; |
| 100 #endif | 112 #endif |
| 101 void *retval = tdb->start_func(tdb->state); | 113 void *retval = tdb->start_func(tdb->state); |
| 102 | 114 |
| 103 /* | 115 /* |
| 104 * Free handler list to prevent memory leak in case function returns | 116 * Free handler list to prevent memory leak in case function returns |
| 105 * without calling pthread_cleanup_pop(), although doing that is unspecified | 117 * without calling pthread_cleanup_pop(), although doing that is unspecified |
| 106 * behaviour. | 118 * behaviour. |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 224 nc_free_memory_block_mu(TLS_AND_TDB_MEMORY, block); | 236 nc_free_memory_block_mu(TLS_AND_TDB_MEMORY, block); |
| 225 } | 237 } |
| 226 } | 238 } |
| 227 | 239 |
| 228 /* Initialize a newly allocated TDB to some default values. */ | 240 /* Initialize a newly allocated TDB to some default values. */ |
| 229 static void nc_tdb_init(nc_thread_descriptor_t *tdb, | 241 static void nc_tdb_init(nc_thread_descriptor_t *tdb, |
| 230 nc_basic_thread_data_t *basic_data) { | 242 nc_basic_thread_data_t *basic_data) { |
| 231 tdb->tls_base = tdb; | 243 tdb->tls_base = tdb; |
| 232 tdb->joinable = PTHREAD_CREATE_JOINABLE; | 244 tdb->joinable = PTHREAD_CREATE_JOINABLE; |
| 233 tdb->join_waiting = 0; | 245 tdb->join_waiting = 0; |
| 234 tdb->rdlock_count = 0; | |
| 235 tdb->stack_node = NULL; | 246 tdb->stack_node = NULL; |
| 236 tdb->tls_node = NULL; | 247 tdb->tls_node = NULL; |
| 237 tdb->start_func = NULL; | 248 tdb->start_func = NULL; |
| 238 tdb->state = NULL; | 249 tdb->state = NULL; |
| 239 tdb->irt_thread_data = NULL; | 250 tdb->irt_thread_data = NULL; |
| 240 tdb->basic_data = basic_data; | 251 tdb->basic_data = basic_data; |
| 241 | 252 |
| 242 basic_data->retval = NULL; | 253 basic_data->retval = NULL; |
| 243 basic_data->status = THREAD_RUNNING; | 254 basic_data->status = THREAD_RUNNING; |
| 244 if (pthread_cond_init(&basic_data->join_condvar, NULL) != 0) | 255 if (pthread_cond_init(&basic_data->join_condvar, NULL) != 0) |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 | 297 |
| 287 #else | 298 #else |
| 288 | 299 |
| 289 /* | 300 /* |
| 290 * Will be called from the library startup code, | 301 * Will be called from the library startup code, |
| 291 * which always happens on the application's main thread. | 302 * which always happens on the application's main thread. |
| 292 */ | 303 */ |
| 293 void __pthread_initialize(void) { | 304 void __pthread_initialize(void) { |
| 294 __pthread_initialize_minimal(TDB_SIZE); | 305 __pthread_initialize_minimal(TDB_SIZE); |
| 295 | 306 |
| 296 struct nc_combined_tdb *tdb = (struct nc_combined_tdb *) __nc_get_tdb(); | 307 struct nc_combined_tdb *tdb = (struct nc_combined_tdb *) nc_get_tdb(); |
| 297 nc_tdb_init(&tdb->tdb, &tdb->basic_data); | 308 nc_tdb_init(&tdb->tdb, &tdb->basic_data); |
| 298 __nc_initial_thread_id = &tdb->basic_data; | 309 __nc_initial_thread_id = &tdb->basic_data; |
| 299 | 310 |
| 300 __nc_initialize_globals(); | 311 __nc_initialize_globals(); |
| 301 } | 312 } |
| 302 | 313 |
| 303 #endif | 314 #endif |
| 304 | 315 |
| 305 | 316 |
| 306 /* pthread functions */ | 317 /* pthread functions */ |
| (...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 474 nc_thread_cleanup_handler *handler = __nc_cleanup_handlers; | 485 nc_thread_cleanup_handler *handler = __nc_cleanup_handlers; |
| 475 __nc_cleanup_handlers = handler->previous; | 486 __nc_cleanup_handlers = handler->previous; |
| 476 if (execute) | 487 if (execute) |
| 477 handler->handler_function(handler->handler_arg); | 488 handler->handler_function(handler->handler_arg); |
| 478 free(handler); | 489 free(handler); |
| 479 } | 490 } |
| 480 } | 491 } |
| 481 | 492 |
| 482 void pthread_exit(void *retval) { | 493 void pthread_exit(void *retval) { |
| 483 /* Get all we need from the tdb before releasing it. */ | 494 /* Get all we need from the tdb before releasing it. */ |
| 484 nc_thread_descriptor_t *tdb = __nc_get_tdb(); | 495 nc_thread_descriptor_t *tdb = nc_get_tdb(); |
| 485 nc_thread_memory_block_t *stack_node = tdb->stack_node; | 496 nc_thread_memory_block_t *stack_node = tdb->stack_node; |
| 486 int32_t *is_used = &stack_node->is_used; | 497 int32_t *is_used = &stack_node->is_used; |
| 487 nc_basic_thread_data_t *basic_data = tdb->basic_data; | 498 nc_basic_thread_data_t *basic_data = tdb->basic_data; |
| 488 int joinable = tdb->joinable; | 499 int joinable = tdb->joinable; |
| 489 | 500 |
| 490 /* Call cleanup handlers. */ | 501 /* Call cleanup handlers. */ |
| 491 while (NULL != __nc_cleanup_handlers) { | 502 while (NULL != __nc_cleanup_handlers) { |
| 492 pthread_cleanup_pop(1); | 503 pthread_cleanup_pop(1); |
| 493 } | 504 } |
| 494 | 505 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 } | 623 } |
| 613 | 624 |
| 614 int pthread_kill(pthread_t thread_id, | 625 int pthread_kill(pthread_t thread_id, |
| 615 int sig) { | 626 int sig) { |
| 616 /* This function is currently unimplemented. */ | 627 /* This function is currently unimplemented. */ |
| 617 return ENOSYS; | 628 return ENOSYS; |
| 618 } | 629 } |
| 619 | 630 |
| 620 pthread_t pthread_self(void) { | 631 pthread_t pthread_self(void) { |
| 621 /* Get the tdb pointer from gs and use it to return the thread handle. */ | 632 /* Get the tdb pointer from gs and use it to return the thread handle. */ |
| 622 nc_thread_descriptor_t *tdb = __nc_get_tdb(); | 633 nc_thread_descriptor_t *tdb = nc_get_tdb(); |
| 623 return tdb->basic_data; | 634 return tdb->basic_data; |
| 624 } | 635 } |
| 625 | 636 |
| 626 int pthread_equal(pthread_t thread1, pthread_t thread2) { | 637 int pthread_equal(pthread_t thread1, pthread_t thread2) { |
| 627 return (thread1 == thread2); | 638 return (thread1 == thread2); |
| 628 } | 639 } |
| 629 | 640 |
| 630 int pthread_setschedprio(pthread_t thread_id, int prio) { | 641 int pthread_setschedprio(pthread_t thread_id, int prio) { |
| 631 if (thread_id != pthread_self()) { | 642 if (thread_id != pthread_self()) { |
| 632 /* | 643 /* |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 810 | 821 |
| 811 /* | 822 /* |
| 812 * We include this directly in this file rather than compiling it | 823 * We include this directly in this file rather than compiling it |
| 813 * separately because there is some code (e.g. libstdc++) that uses weak | 824 * separately because there is some code (e.g. libstdc++) that uses weak |
| 814 * references to all pthread functions, but conditionalizes its calls only | 825 * references to all pthread functions, but conditionalizes its calls only |
| 815 * on one symbol. So if these functions are in another file in a library | 826 * on one symbol. So if these functions are in another file in a library |
| 816 * archive, they might not be linked in by static linking. | 827 * archive, they might not be linked in by static linking. |
| 817 */ | 828 */ |
| 818 /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ | 829 /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ |
| 819 #include "native_client/src/untrusted/pthread/nc_tsd.c" | 830 #include "native_client/src/untrusted/pthread/nc_tsd.c" |
| OLD | NEW |