Run thread shutdown functions in an explicit order

This removes the __libc_thread_subfreeres hook in favor of explict
calls.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Florian Weimer 2018-06-26 15:13:54 +02:00
parent 935d920e76
commit 124e025864
14 changed files with 70 additions and 46 deletions

View File

@ -1,3 +1,33 @@
2018-06-26 Florian Weimer <fweimer@redhat.com>
Run thread shutdown functions in an explicit order.
* malloc/thread-freeres.c (__libc_thread_subfreeres): Remove hook
definition.
(__libc_thread_freeres): Call thread shutdown functions
explicitly.
* include/rpc/rpc.h (__rpc_thread_destroy): Add hidden attribute.
* include/string.h (__strerror_thread_freeres): Declare.
* malloc/arena.c (__malloc_arena_thread_freeres): Renamed from
arena_thread_freeres. No longer static. Remove thread shutdown
hook registration.
* malloc/malloc-internal.h (__malloc_arena_thread_freeres):
Declare.
* resolv/res-close.c (__res_thread_freeres): Renamed from
res_thread_freeres. No longer static. Remove thread shutdown
hook registration.
* resolv/resolv-internal.h (__res_thread_freeres): Declare.
* resolv/resolv_conf.c (freeres): Remove incorrect section
attribute and use libc_freeres_fn.
* string/strerror_l.c (__strerror_thread_freeres): Renamed from
strerror_thread_freeres. No longer static. Remove thread
shutdown hook registration.
* sysdeps/mach/strerror_l.c (__strerror_thread_freeres): Likewise.
* sunrpc/rpc_thread.c (__rpc_thread_destroy): Remove thread
shutdown hook registration.
* Makerules (shlib.lds): Do not provide section boundary symbols
for __libc_thread_subfreeres.
* manual/memory.texi (Basic Allocation): Update comment.
2018-06-26 Florian Weimer <fweimer@redhat.com> 2018-06-26 Florian Weimer <fweimer@redhat.com>
Remove always-defined _RPC_THREAD_SAFE_ macro. Remove always-defined _RPC_THREAD_SAFE_ macro.

View File

@ -648,9 +648,6 @@ $(common-objpfx)shlib.lds: $(common-objpfx)config.make $(..)Makerules
PROVIDE(__start___libc_atexit = .);\ PROVIDE(__start___libc_atexit = .);\
__libc_atexit : { *(__libc_atexit) }\ __libc_atexit : { *(__libc_atexit) }\
PROVIDE(__stop___libc_atexit = .);\ PROVIDE(__stop___libc_atexit = .);\
PROVIDE(__start___libc_thread_subfreeres = .);\
__libc_thread_subfreeres : { *(__libc_thread_subfreeres) }\
PROVIDE(__stop___libc_thread_subfreeres = .);\
PROVIDE(__start___libc_IO_vtables = .);\ PROVIDE(__start___libc_IO_vtables = .);\
__libc_IO_vtables : { *(__libc_IO_vtables) }\ __libc_IO_vtables : { *(__libc_IO_vtables) }\
PROVIDE(__stop___libc_IO_vtables = .);\ PROVIDE(__stop___libc_IO_vtables = .);\

View File

@ -45,7 +45,7 @@ extern void __rpc_thread_svc_cleanup (void) attribute_hidden;
extern void __rpc_thread_clnt_cleanup (void) attribute_hidden; extern void __rpc_thread_clnt_cleanup (void) attribute_hidden;
extern void __rpc_thread_key_cleanup (void) attribute_hidden; extern void __rpc_thread_key_cleanup (void) attribute_hidden;
extern void __rpc_thread_destroy (void); extern void __rpc_thread_destroy (void) attribute_hidden;
__libc_tsd_define (extern, struct rpc_thread_variables *, RPC_VARS) __libc_tsd_define (extern, struct rpc_thread_variables *, RPC_VARS)

View File

@ -50,6 +50,9 @@ extern int __ffs (int __i) __attribute__ ((const));
extern char *__strerror_r (int __errnum, char *__buf, size_t __buflen); extern char *__strerror_r (int __errnum, char *__buf, size_t __buflen);
/* Called as part of the thread shutdown sequence. */
void __strerror_thread_freeres (void) attribute_hidden;
/* Get _STRING_ARCH_unaligned. */ /* Get _STRING_ARCH_unaligned. */
#include <string_private.h> #include <string_private.h>
#endif #endif

View File

@ -941,8 +941,8 @@ arena_get_retry (mstate ar_ptr, size_t bytes)
return ar_ptr; return ar_ptr;
} }
static void __attribute__ ((section ("__libc_thread_freeres_fn"))) void
arena_thread_freeres (void) __malloc_arena_thread_freeres (void)
{ {
/* Shut down the thread cache first. This could deallocate data for /* Shut down the thread cache first. This could deallocate data for
the thread arena, so do this before we put the arena on the free the thread arena, so do this before we put the arena on the free
@ -966,7 +966,6 @@ arena_thread_freeres (void)
__libc_lock_unlock (free_list_lock); __libc_lock_unlock (free_list_lock);
} }
} }
text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
/* /*
* Local variables: * Local variables:

View File

@ -71,6 +71,9 @@ void __malloc_fork_unlock_parent (void) attribute_hidden;
/* Called in the child process after a fork. */ /* Called in the child process after a fork. */
void __malloc_fork_unlock_child (void) attribute_hidden; void __malloc_fork_unlock_child (void) attribute_hidden;
/* Called as part of the thread shutdown sequence. */
void __malloc_arena_thread_freeres (void) attribute_hidden;
/* Set *RESULT to LEFT * RIGHT. Return true if the multiplication /* Set *RESULT to LEFT * RIGHT. Return true if the multiplication
overflowed. */ overflowed. */
static inline bool static inline bool

View File

@ -16,16 +16,24 @@
License along with the GNU C Library; if not, see License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */ <http://www.gnu.org/licenses/>. */
#include <stdlib.h>
#include <libc-internal.h> #include <libc-internal.h>
#include <set-hooks.h> #include <malloc-internal.h>
#include <resolv/resolv-internal.h>
#include <rpc/rpc.h>
#include <string.h>
#ifdef _LIBC_REENTRANT /* Thread shutdown function. Note that this function must be called
DEFINE_HOOK (__libc_thread_subfreeres, (void)); for threads during shutdown for correctness reasons. Unlike
__libc_subfreeres, skipping calls to it is not a valid
void __attribute__ ((section ("__libc_thread_freeres_fn"))) optimization. */
void
__libc_thread_freeres (void) __libc_thread_freeres (void)
{ {
RUN_HOOK (__libc_thread_subfreeres, ()); call_function_static_weak (__rpc_thread_destroy);
call_function_static_weak (__res_thread_freeres);
call_function_static_weak (__strerror_thread_freeres);
/* This should come last because it shuts down malloc for this
thread and the other shutdown functions might well call free. */
call_function_static_weak (__malloc_arena_thread_freeres);
} }
#endif

View File

@ -404,7 +404,7 @@ this function is in @file{stdlib.h}.
@c reads&writes next_to_use and iterates over arena next without guards @c reads&writes next_to_use and iterates over arena next without guards
@c those are harmless as long as we don't drop arenas from the @c those are harmless as long as we don't drop arenas from the
@c NEXT list, and we never do; when a thread terminates, @c NEXT list, and we never do; when a thread terminates,
@c arena_thread_freeres prepends the arena to the free_list @c __malloc_arena_thread_freeres prepends the arena to the free_list
@c NEXT_FREE list, but NEXT is never modified, so it's safe! @c NEXT_FREE list, but NEXT is never modified, so it's safe!
@c mutex_trylock (arena lock) @asulock @aculock @c mutex_trylock (arena lock) @asulock @aculock
@c mutex_lock (arena lock) dup @asulock @aculock @c mutex_lock (arena lock) dup @asulock @aculock

View File

@ -126,8 +126,8 @@ res_nclose (res_state statp)
libc_hidden_def (__res_nclose) libc_hidden_def (__res_nclose)
/* This is called when a thread is exiting to free resources held in _res. */ /* This is called when a thread is exiting to free resources held in _res. */
static void __attribute__ ((section ("__libc_thread_freeres_fn"))) void
res_thread_freeres (void) __res_thread_freeres (void)
{ {
__resolv_context_freeres (); __resolv_context_freeres ();
@ -140,5 +140,4 @@ res_thread_freeres (void)
/* Make sure we do a full re-initialization the next time. */ /* Make sure we do a full re-initialization the next time. */
_res.options = 0; _res.options = 0;
} }
text_set_element (__libc_thread_subfreeres, res_thread_freeres); text_set_element (__libc_subfreeres, __res_thread_freeres);
text_set_element (__libc_subfreeres, res_thread_freeres);

View File

@ -97,4 +97,7 @@ int __res_nopt (struct resolv_context *, int n0,
int __inet_pton_length (int af, const char *src, size_t srclen, void *); int __inet_pton_length (int af, const char *src, size_t srclen, void *);
libc_hidden_proto (__inet_pton_length) libc_hidden_proto (__inet_pton_length)
/* Called as part of the thread shutdown sequence. */
void __res_thread_freeres (void) attribute_hidden;
#endif /* _RESOLV_INTERNAL_H */ #endif /* _RESOLV_INTERNAL_H */

View File

@ -673,8 +673,7 @@ __resolv_conf_detach (struct __res_state *resp)
} }
/* Deallocate the global data. */ /* Deallocate the global data. */
static void __attribute__ ((section ("__libc_thread_freeres_fn"))) libc_freeres_fn (freeres)
freeres (void)
{ {
/* No locking because this function is supposed to be called when /* No locking because this function is supposed to be called when
the process has turned single-threaded. */ the process has turned single-threaded. */
@ -698,4 +697,3 @@ freeres (void)
deallocated memory. */ deallocated memory. */
global = NULL; global = NULL;
} }
text_set_element (__libc_subfreeres, freeres);

View File

@ -57,15 +57,9 @@ strerror_l (int errnum, locale_t loc)
} }
#ifdef _LIBC void
# ifdef _LIBC_REENTRANT __strerror_thread_freeres (void)
/* This is called when a thread is exiting to free the last_value string. */
static void __attribute__ ((section ("__libc_thread_freeres_fn")))
strerror_thread_freeres (void)
{ {
free (last_value); free (last_value);
} }
text_set_element (__libc_thread_subfreeres, strerror_thread_freeres); text_set_element (__libc_subfreeres, __strerror_thread_freeres);
text_set_element (__libc_subfreeres, strerror_thread_freeres);
# endif
#endif

View File

@ -15,7 +15,7 @@ static __thread struct rpc_thread_variables *thread_rpc_vars
/* /*
* Task-variable destructor * Task-variable destructor
*/ */
void __attribute__ ((section ("__libc_thread_freeres_fn"))) void
__rpc_thread_destroy (void) __rpc_thread_destroy (void)
{ {
struct rpc_thread_variables *tvp = thread_rpc_vars; struct rpc_thread_variables *tvp = thread_rpc_vars;
@ -36,12 +36,8 @@ __rpc_thread_destroy (void)
thread_rpc_vars = NULL; thread_rpc_vars = NULL;
} }
} }
#ifdef _LIBC_REENTRANT
text_set_element (__libc_thread_subfreeres, __rpc_thread_destroy);
#endif
text_set_element (__libc_subfreeres, __rpc_thread_destroy); text_set_element (__libc_subfreeres, __rpc_thread_destroy);
/* /*
* Initialize RPC multi-threaded operation * Initialize RPC multi-threaded operation
*/ */

View File

@ -87,15 +87,9 @@ strerror_l (int errnum, locale_t loc)
} }
#ifdef _LIBC void
# ifdef _LIBC_REENTRANT __strerror_thread_freeres (void)
/* This is called when a thread is exiting to free the last_value string. */
static void __attribute__ ((section ("__libc_thread_freeres_fn")))
strerror_thread_freeres (void)
{ {
free (last_value); free (last_value);
} }
text_set_element (__libc_thread_subfreeres, strerror_thread_freeres); text_set_element (__libc_subfreeres, __strerror_thread_freeres);
text_set_element (__libc_subfreeres, strerror_thread_freeres);
# endif
#endif