|
Message-ID: <87zgwo6ph2.fsf@oldenburg.str.redhat.com> Date: Fri, 21 May 2021 18:06:33 +0200 From: Florian Weimer <fweimer@...hat.com> To: libc-coord@...ts.openwall.com Cc: Kostya Serebryany <kcc@...gle.com> Subject: Thread properties API In glibc, we have a historic gap when it comes to access to per-thread data that may contain application data. Such functionality is required to support memory leak detectors and conservative garbage collectors that need to discover pointer values in TLS data. The sanitizers currently hard-code glibc implementation details (that are not really unchanging in practice), and we want to switch to a defined interface eventually. We provide some access to per-thread data using libthread_db, but that functionality is incomplete in several ways and not readily consumable inside a process. There is a completely different proposal here: <https://sourceware.org/glibc/wiki/ThreadPropertiesAPI> The interfaces that follow below avoid callback functions that must be invoked with internal locks held because that is prone to lead to deadlocks. They also avoid encoding a specific, unchanging layout for the static TLS area (which can be extended, but not moved) or internal pthread_setspecific tables, or whether any such per-thread data structures are allocated by malloc. I'd appreciate comments on this proposal. It's very early and I'm not entirely convinced yet that it is actually implementable. 8-) void pthread_retain_np (pthread_t thread); pthread_retain_np marks THREAD for retention. A retained thread identifier remains valid after the thread has exited and (if joinable) has been joined, but all subsequent operations on the thread ID, except for pthread_release_np, pthread_getattr_np and pthread_tls_areas_get_np, will fail. void pthread_release_np (pthread_t thread); pthread_release_np undoes the effect of a previous pthread_retain_np call (which can be implied by pthread_all_threads_np). Every pthread_retain_np call must eventually be paired with a pthread_release_np call, or otherwise there is a resource leak. Once the number of pthread_release_np calls is equal to the number of pthread_retain_np calls for a particular thread ID (including such calls implied by pthread_all_threads_np), the thread ID is again only valid while the thread is running or joinable. If the number of calls it is equal, it is undefined to call pthread_release_np. size_t pthread_all_threads_np (pthread_t *result, size_t length); pthread_all_threads_np returns the number of all currently running or joinable threads in the process. The identifiers of the first LENGTH such threads are written to the array starting at RESULT. For those thread identifiers, pthread_retrain_np is invoked; this happens in such a way that the thread is running or joinable at this point. Applications need to call pthread_release_np on all the thread identifiers that pthread_all_threads_np has written to RESULT. This also applies to the case where pthread_all_threads_np is called in a loop that grows the RESULT array to the size required to store all thread IDs in the current process. Due to the lack of synchronization, an unspecified time can pass between the termination of a detached thread and the time its thread ID no longer appears among the thread IDs provided by pthread_all_threads_np. It is unspecified whether threads that are neither running nor joinable, but have been retained, appear among those thread IDs. struct pthread_tls_area_np { const void *start; size_t length; }; size_t pthread_tls_areas_get_np (pthread_t thread, struct pthread_tls_area_np *areas, size_t length); size_t pthread_tls_areas_release_np (pthread_t thread, const struct pthread_tls_area_np *areas, size_t count); pthread_tls_area_get_np returns the number of TLS areas currently allocated for THREAD. This number may be zero if THREAD refers to a thread that is not running. The location and size of up to LENGTH of these areas are written to the array starting at AREAS, followed by zero elements until LENGTH array elements have been written. An application can detect that the provided array is too small by check the return value against LENGTH. The application may inspect the pointers and memory areas identified by the array elements (up to the return value of pthread_tls_area_np). At this point, it is guaranteed that the memory locations remain valid for access. After inspecting the TLS areas, the application must call pthread_tls_areas_release_np, passing the same THREAD, AREAS and LENGTH arguments that were used in the pthread_tls_areas_get_np. For example, if it has been previously determined that a __thread variable is at address P for a particular THREAD, and if the LENGTH argument to pthread_tls_area_np is sufficiently large to hold all TLS areas for THREAD, then P will be contain within one of the TLS areas. If the implementation supports access to __thread variables from other threads, it is safe to access *P, subject to the usual constraints regarding data races, until pthread_tls_areas_release_np is called. Similarly, pointer values stored by pthread_setspecific will appear in the TLS areas at unspecified locations, and the values will be current in the sense that if a pthread_setspecific call for a key happens-before the pthread_tls_areas_get_np call and the access to the TLS areas happens-before the next pthread_setspecific call for that key on the thread, then the pointer value stored by the first pthread_setspecific call will appear in one of the TLS areas listed by pthread_tls_areas_get_np. However, writes to that pointer value may not be reflected in future pthread_getspecific calls (even with synchronization). The distribution of various TLS data structures among the AREAS array is unspecified. Some of the areas may be allocated on the heap using malloc, or part of such heap allocations. It is unspecified whether previously allocated TLS areas are returned for a thread that is no longer running. If any per-thread data is allocated by the implementation in such a way that it will be deallocated using free, pointers to such allocations should appear among the areas returned by pthread_tls_areas_get_np, so that internal allocations made by the implementation are not falsely flagged as leaked. Thanks, Florian
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.