Module Name: src Committed By: martin Date: Tue Nov 24 17:37:16 UTC 2015
Modified Files: src/include [netbsd-7]: limits.h src/lib/libc/stdlib [netbsd-7]: jemalloc.c src/lib/libpthread [netbsd-7]: pthread.c pthread_int.h pthread_key_create.3 pthread_tsd.c src/lib/libpthread_dbg [netbsd-7]: pthread_dbg.c Log Message: Pull up following revision(s) (requested by manu in ticket #829): lib/libpthread_dbg/pthread_dbg.c: revision 1.43 (via patch) lib/libpthread/pthread_int.h: revision 1.91-1.92 (via patch) lib/libc/stdlib/jemalloc.c: revision 1.37-1.38 lib/libpthread/pthread_tsd.c: revision 1.12-1.14 (via patch) include/limits.h: revision 1.34 (via patch) lib/libpthread/pthread.c: revision 1.146-1.147 (via patch) lib/libpthread/pthread_key_create.3: revision 1.7 (via patch) libpthread: Make PTHREAD_KEYS_MAX dynamically adjustable NetBSD's PTHREAD_KEYS_MAX is set to 256, which is low compared to other systems like Linux (1024) or MacOS X (512). As a result some setups tested on Linux will exhibit problems on NetBSD because of pthread_keys usage beyond the limit. This happens for instance on Apache with various module loaded, and in this case no particular developper can be blamed for going beyond the limit, since several modules from different sources contribute to the problem. This patch makes the limit conigurable through the PTHREAD_KEYS_MAX environement variable. If undefined, the default remains unchanged (256). In any case, the value cannot be lowered below POSIX-mandated _POSIX_THREAD_KEYS_MAX (128). While there: - use EXIT_FAILURE instead of 1 when calling err(3) in libpthread. - Reset _POSIX_THREAD_KEYS_MAX to POSIX mandated 128, instead of 256. Fix previous: Can't use calloc/malloc before we complete initialization of the thread library, because malloc uses pthread_foo_specific, and it will end up initializing itself incorrectly. Thanks rump for not letting us use even mmap during initialization. libc/jemalloc: Fix non _REENTRANT build. Defer using pthread keys until we are threaded. >From Christos, fixes PR port-arm/50087 by allowing malloc calls prior to libpthread initialization. To generate a diff of this commit: cvs rdiff -u -r1.33 -r1.33.8.1 src/include/limits.h cvs rdiff -u -r1.34 -r1.34.2.1 src/lib/libc/stdlib/jemalloc.c cvs rdiff -u -r1.144 -r1.144.4.1 src/lib/libpthread/pthread.c cvs rdiff -u -r1.89 -r1.89.8.1 src/lib/libpthread/pthread_int.h cvs rdiff -u -r1.6 -r1.6.24.1 src/lib/libpthread/pthread_key_create.3 cvs rdiff -u -r1.11 -r1.11.8.1 src/lib/libpthread/pthread_tsd.c cvs rdiff -u -r1.42 -r1.42.8.1 src/lib/libpthread_dbg/pthread_dbg.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/include/limits.h diff -u src/include/limits.h:1.33 src/include/limits.h:1.33.8.1 --- src/include/limits.h:1.33 Sun Nov 18 17:41:53 2012 +++ src/include/limits.h Tue Nov 24 17:37:16 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: limits.h,v 1.33 2012/11/18 17:41:53 manu Exp $ */ +/* $NetBSD: limits.h,v 1.33.8.1 2015/11/24 17:37:16 martin Exp $ */ /* * Copyright (c) 1988, 1993 @@ -75,18 +75,20 @@ */ /* - * The following 3 are not part of the standard - * but left here for compatibility + * The following 3 are defined in + * Open Group Base Specifications Issue 7 */ #define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 -#define _POSIX_THREAD_KEYS_MAX 256 +#define _POSIX_THREAD_KEYS_MAX 128 #define _POSIX_THREAD_THREADS_MAX 64 /* * These are the correct names, defined in terms of the above + * except for PTHREAD_KEYS_MAX which is bigger than standard + * mandated minimum value _POSIX_THREAD_KEYS_MAX. */ #define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS -#define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX +#define PTHREAD_KEYS_MAX 256 /* Not yet: PTHREAD_STACK_MIN */ #define PTHREAD_THREADS_MAX _POSIX_THREAD_THREADS_MAX Index: src/lib/libc/stdlib/jemalloc.c diff -u src/lib/libc/stdlib/jemalloc.c:1.34 src/lib/libc/stdlib/jemalloc.c:1.34.2.1 --- src/lib/libc/stdlib/jemalloc.c:1.34 Sun Aug 10 05:57:31 2014 +++ src/lib/libc/stdlib/jemalloc.c Tue Nov 24 17:37:16 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: jemalloc.c,v 1.34 2014/08/10 05:57:31 matt Exp $ */ +/* $NetBSD: jemalloc.c,v 1.34.2.1 2015/11/24 17:37:16 martin Exp $ */ /*- * Copyright (C) 2006,2007 Jason Evans <jas...@freebsd.org>. @@ -118,7 +118,7 @@ #include <sys/cdefs.h> /* __FBSDID("$FreeBSD: src/lib/libc/stdlib/malloc.c,v 1.147 2007/06/15 22:00:16 jasone Exp $"); */ -__RCSID("$NetBSD: jemalloc.c,v 1.34 2014/08/10 05:57:31 matt Exp $"); +__RCSID("$NetBSD: jemalloc.c,v 1.34.2.1 2015/11/24 17:37:16 martin Exp $"); #ifdef __FreeBSD__ #include "libc_private.h" @@ -382,9 +382,11 @@ static malloc_mutex_t init_lock = {_SPIN /* Set to true once the allocator has been initialized. */ static bool malloc_initialized = false; +#ifdef _REENTRANT /* Used to avoid initialization races. */ static mutex_t init_lock = MUTEX_INITIALIZER; #endif +#endif /******************************************************************************/ /* @@ -694,8 +696,10 @@ static size_t arena_maxclass; /* Max si * Chunks. */ +#ifdef _REENTRANT /* Protects chunk-related data structures. */ static malloc_mutex_t chunks_mtx; +#endif /* Tree of chunks that are stand-alone huge allocations. */ static chunk_tree_t huge; @@ -746,7 +750,9 @@ static void *base_pages; static void *base_next_addr; static void *base_past_addr; /* Addr immediately past base_pages. */ static chunk_node_t *base_chunk_nodes; /* LIFO cache of chunk nodes. */ +#ifdef _REENTRANT static malloc_mutex_t base_mtx; +#endif #ifdef MALLOC_STATS static size_t base_mapped; #endif @@ -763,20 +769,62 @@ static size_t base_mapped; static arena_t **arenas; static unsigned narenas; static unsigned next_arena; +#ifdef _REENTRANT static malloc_mutex_t arenas_mtx; /* Protects arenas initialization. */ +#endif -#ifndef NO_TLS /* * Map of pthread_self() --> arenas[???], used for selecting an arena to use * for allocations. */ -static __thread arena_t *arenas_map; -#define get_arenas_map() (arenas_map) -#define set_arenas_map(x) (arenas_map = x) +#ifndef NO_TLS +static __thread arena_t **arenas_map; #else -static thread_key_t arenas_map_key; -#define get_arenas_map() thr_getspecific(arenas_map_key) -#define set_arenas_map(x) thr_setspecific(arenas_map_key, x) +static arena_t **arenas_map; +#endif + +#if !defined(NO_TLS) || !defined(_REENTRANT) +# define get_arenas_map() (arenas_map) +# define set_arenas_map(x) (arenas_map = x) +#else + +static thread_key_t arenas_map_key = -1; + +static inline arena_t ** +get_arenas_map(void) +{ + if (!__isthreaded) + return arenas_map; + + if (arenas_map_key == -1) { + (void)thr_keycreate(&arenas_map_key, NULL); + if (arenas_map != NULL) { + thr_setspecific(arenas_map_key, arenas_map); + arenas_map = NULL; + } + } + + return thr_getspecific(arenas_map_key); +} + +static __inline void +set_arenas_map(arena_t **a) +{ + if (!__isthreaded) { + arenas_map = a; + return; + } + + if (arenas_map_key == -1) { + (void)thr_keycreate(&arenas_map_key, NULL); + if (arenas_map != NULL) { + _DIAGASSERT(arenas_map == a); + arenas_map = NULL; + } + } + + thr_setspecific(arenas_map_key, a); +} #endif #ifdef MALLOC_STATS @@ -3634,11 +3682,6 @@ malloc_init_hard(void) opt_narenas_lshift += 2; } -#ifdef NO_TLS - /* Initialize arena key. */ - (void)thr_keycreate(&arenas_map_key, NULL); -#endif - /* Determine how many arenas to use. */ narenas = ncpus; if (opt_narenas_lshift > 0) { Index: src/lib/libpthread/pthread.c diff -u src/lib/libpthread/pthread.c:1.144 src/lib/libpthread/pthread.c:1.144.4.1 --- src/lib/libpthread/pthread.c:1.144 Fri Jan 31 20:44:01 2014 +++ src/lib/libpthread/pthread.c Tue Nov 24 17:37:16 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pthread.c,v 1.144 2014/01/31 20:44:01 christos Exp $ */ +/* $NetBSD: pthread.c,v 1.144.4.1 2015/11/24 17:37:16 martin Exp $ */ /*- * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread.c,v 1.144 2014/01/31 20:44:01 christos Exp $"); +__RCSID("$NetBSD: pthread.c,v 1.144.4.1 2015/11/24 17:37:16 martin Exp $"); #define __EXPOSE_STACK 1 @@ -115,7 +115,8 @@ int pthread__dbg; /* set by libpthread_d */ size_t pthread__stacksize; size_t pthread__pagesize; -static struct __pthread_st pthread__main; +static struct __pthread_st *pthread__main; +static size_t __pthread_st_size; int _sys___sigprocmask14(int, const sigset_t *, sigset_t *); @@ -164,6 +165,17 @@ pthread__init(void) int i; extern int __isthreaded; + /* + * Allocate pthread_keys descriptors before + * reseting __uselibcstub because otherwise + * malloc() will call pthread_keys_create() + * while pthread_keys descriptors are not + * yet allocated. + */ + pthread__main = pthread_tsd_init(&__pthread_st_size); + if (pthread__main == NULL) + err(EXIT_FAILURE, "Cannot allocate pthread storage"); + __uselibcstub = 0; pthread__pagesize = (size_t)sysconf(_SC_PAGESIZE); @@ -178,7 +190,7 @@ pthread__init(void) /* Fetch parameters. */ i = (int)_lwp_unpark_all(NULL, 0, NULL); if (i == -1) - err(1, "_lwp_unpark_all"); + err(EXIT_FAILURE, "_lwp_unpark_all"); if (i < pthread__unpark_max) pthread__unpark_max = i; @@ -199,7 +211,7 @@ pthread__init(void) (void)rb_tree_insert_node(&pthread__alltree, first); if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &first->pt_lwpctl) != 0) { - err(1, "_lwp_ctl"); + err(EXIT_FAILURE, "_lwp_ctl"); } /* Start subsystems */ @@ -240,7 +252,7 @@ pthread__fork_callback(void) /* lwpctl state is not copied across fork. */ if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { - err(1, "_lwp_ctl"); + err(EXIT_FAILURE, "_lwp_ctl"); } self->pt_lid = _lwp_self(); } @@ -298,7 +310,6 @@ pthread__initthread(pthread_t t) pthread_mutex_init(&t->pt_lock, NULL); PTQ_INIT(&t->pt_cleanup_stack); pthread_cond_init(&t->pt_joiners, NULL); - memset(&t->pt_specific, 0, sizeof(t->pt_specific)); } static void @@ -451,7 +462,7 @@ pthread_create(pthread_t *thread, const * and initialize it. */ if (newthread == NULL) { - newthread = malloc(sizeof(*newthread)); + newthread = calloc(1, __pthread_st_size); if (newthread == NULL) { free(name); return ENOMEM; @@ -566,7 +577,7 @@ pthread__create_tramp(void *cookie) } if (_lwp_ctl(LWPCTL_FEATURE_CURCPU, &self->pt_lwpctl)) { - err(1, "_lwp_ctl"); + err(EXIT_FAILURE, "_lwp_ctl"); } retval = (*self->pt_func)(self->pt_arg); @@ -1281,17 +1292,18 @@ pthread__initmainstack(void) _DIAGASSERT(_dlauxinfo() != NULL); if (getrlimit(RLIMIT_STACK, &slimit) == -1) - err(1, "Couldn't get stack resource consumption limits"); + err(EXIT_FAILURE, + "Couldn't get stack resource consumption limits"); size = slimit.rlim_cur; - pthread__main.pt_stack.ss_size = size; + pthread__main->pt_stack.ss_size = size; for (aux = _dlauxinfo(); aux->a_type != AT_NULL; ++aux) { if (aux->a_type == AT_STACKBASE) { - pthread__main.pt_stack.ss_sp = (void *)aux->a_v; + pthread__main->pt_stack.ss_sp = (void *)aux->a_v; #ifdef __MACHINE_STACK_GROWS_UP - pthread__main.pt_stack.ss_sp = (void *)aux->a_v; + pthread__main->pt_stack.ss_sp = (void *)aux->a_v; #else - pthread__main.pt_stack.ss_sp = (char *)aux->a_v - size; + pthread__main->pt_stack.ss_sp = (char *)aux->a_v - size; #endif break; } @@ -1313,24 +1325,24 @@ pthread__initmain(pthread_t *newt) value = pthread__getenv("PTHREAD_STACKSIZE"); if (value != NULL) { pthread__stacksize = atoi(value) * 1024; - if (pthread__stacksize > pthread__main.pt_stack.ss_size) - pthread__stacksize = pthread__main.pt_stack.ss_size; + if (pthread__stacksize > pthread__main->pt_stack.ss_size) + pthread__stacksize = pthread__main->pt_stack.ss_size; } if (pthread__stacksize == 0) - pthread__stacksize = pthread__main.pt_stack.ss_size; + pthread__stacksize = pthread__main->pt_stack.ss_size; pthread__stacksize += pthread__pagesize - 1; pthread__stacksize &= ~(pthread__pagesize - 1); if (pthread__stacksize < 4 * pthread__pagesize) errx(1, "Stacksize limit is too low, minimum %zd kbyte.", 4 * pthread__pagesize / 1024); - *newt = &pthread__main; + *newt = pthread__main; #ifdef __HAVE___LWP_GETTCB_FAST - pthread__main.pt_tls = __lwp_gettcb_fast(); + pthread__main->pt_tls = __lwp_gettcb_fast(); #else - pthread__main.pt_tls = _lwp_getprivate(); + pthread__main->pt_tls = _lwp_getprivate(); #endif - pthread__main.pt_tls->tcb_pthread = &pthread__main; + pthread__main->pt_tls->tcb_pthread = pthread__main; } static signed int Index: src/lib/libpthread/pthread_int.h diff -u src/lib/libpthread/pthread_int.h:1.89 src/lib/libpthread/pthread_int.h:1.89.8.1 --- src/lib/libpthread/pthread_int.h:1.89 Thu Mar 21 16:49:12 2013 +++ src/lib/libpthread/pthread_int.h Tue Nov 24 17:37:16 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_int.h,v 1.89 2013/03/21 16:49:12 christos Exp $ */ +/* $NetBSD: pthread_int.h,v 1.89.8.1 2015/11/24 17:37:16 martin Exp $ */ /*- * Copyright (c) 2001, 2002, 2003, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -148,16 +148,18 @@ struct __pthread_st { /* Thread-specific data. Large so it sits close to the end. */ int pt_havespecific; - struct pt_specific { - void *pts_value; - PTQ_ENTRY(pt_specific) pts_next; - } pt_specific[PTHREAD_KEYS_MAX]; /* * Context for thread creation. At the end as it's cached * and then only ever passed to _lwp_create(). */ ucontext_t pt_uc; + + struct pt_specific { + void *pts_value; + PTQ_ENTRY(pt_specific) pts_next; + } pt_specific[]; + }; /* Thread states */ @@ -187,6 +189,7 @@ extern int pthread__nspins; extern int pthread__concurrency; extern int pthread__osrev; extern int pthread__unpark_max; +extern int pthread_keys_max; extern int __uselibcstub; @@ -291,6 +294,7 @@ pthread__self(void) } \ } while (/*CONSTCOND*/0) +void *pthread_tsd_init(size_t *) PTHREAD_HIDE; void pthread__destroy_tsd(pthread_t) PTHREAD_HIDE; __dead void pthread__assertfunc(const char *, int, const char *, const char *) PTHREAD_HIDE; Index: src/lib/libpthread/pthread_key_create.3 diff -u src/lib/libpthread/pthread_key_create.3:1.6 src/lib/libpthread/pthread_key_create.3:1.6.24.1 --- src/lib/libpthread/pthread_key_create.3:1.6 Fri Jul 9 10:55:11 2010 +++ src/lib/libpthread/pthread_key_create.3 Tue Nov 24 17:37:16 2015 @@ -1,4 +1,4 @@ -.\" $NetBSD: pthread_key_create.3,v 1.6 2010/07/09 10:55:11 wiz Exp $ +.\" $NetBSD: pthread_key_create.3,v 1.6.24.1 2015/11/24 17:37:16 martin Exp $ .\" .\" Copyright (c) 2002, 2010 The NetBSD Foundation, Inc. .\" All rights reserved. @@ -151,6 +151,13 @@ Also .Fn pthread_key_delete will return zero upon success. Upon failure both functions return an error number to indicate the cause. +.Sh ENVIRONMENT +.Bl -tag -width PTHREAD_KEYS_MAX +.It Ev PTHREAD_KEYS_MAX +Maximum per process thread-specific data keys. This cannot be set +below +.Dv _POSIX_THREAD_KEYS_MAX . +.El .Sh ERRORS The .Fn pthread_key_create Index: src/lib/libpthread/pthread_tsd.c diff -u src/lib/libpthread/pthread_tsd.c:1.11 src/lib/libpthread/pthread_tsd.c:1.11.8.1 --- src/lib/libpthread/pthread_tsd.c:1.11 Thu Mar 21 16:49:12 2013 +++ src/lib/libpthread/pthread_tsd.c Tue Nov 24 17:37:16 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_tsd.c,v 1.11 2013/03/21 16:49:12 christos Exp $ */ +/* $NetBSD: pthread_tsd.c,v 1.11.8.1 2015/11/24 17:37:16 martin Exp $ */ /*- * Copyright (c) 2001, 2007 The NetBSD Foundation, Inc. @@ -30,22 +30,22 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_tsd.c,v 1.11 2013/03/21 16:49:12 christos Exp $"); +__RCSID("$NetBSD: pthread_tsd.c,v 1.11.8.1 2015/11/24 17:37:16 martin Exp $"); /* Functions and structures dealing with thread-specific data */ #include <errno.h> +#include <sys/mman.h> #include "pthread.h" #include "pthread_int.h" #include "reentrant.h" - +int pthread_keys_max; static pthread_mutex_t tsd_mutex = PTHREAD_MUTEX_INITIALIZER; static int nextkey; -PTQ_HEAD(pthread__tsd_list, pt_specific) - pthread__tsd_list[PTHREAD_KEYS_MAX]; -void (*pthread__tsd_destructors[PTHREAD_KEYS_MAX])(void *); +PTQ_HEAD(pthread__tsd_list, pt_specific) *pthread__tsd_list = NULL; +void (**pthread__tsd_destructors)(void *) = NULL; __strong_alias(__libc_thr_keycreate,pthread_key_create) __strong_alias(__libc_thr_keydelete,pthread_key_delete) @@ -58,6 +58,49 @@ null_destructor(void *p) #include <err.h> #include <stdlib.h> +#include <stdio.h> + +/* Can't use mmap directly so early in the process because rump hijacks it */ +void *_mmap(void *, size_t, int, int, int, off_t); + +void * +pthread_tsd_init(size_t *tlen) +{ + char *pkm; + size_t alen; + char *arena; + + if ((pkm = pthread__getenv("PTHREAD_KEYS_MAX")) != NULL) { + pthread_keys_max = (int)strtol(pkm, NULL, 0); + if (pthread_keys_max < _POSIX_THREAD_KEYS_MAX) + pthread_keys_max = _POSIX_THREAD_KEYS_MAX; + } else { + pthread_keys_max = PTHREAD_KEYS_MAX; + } + + /* + * Can't use malloc here yet, because malloc will use the fake + * libc thread functions to initialize itself, so mmap the space. + */ + *tlen = sizeof(struct __pthread_st) + + pthread_keys_max * sizeof(struct pt_specific); + alen = *tlen + + sizeof(*pthread__tsd_list) * pthread_keys_max + + sizeof(*pthread__tsd_destructors) * pthread_keys_max; + + arena = _mmap(NULL, alen, PROT_READ|PROT_WRITE, MAP_ANON, -1, 0); + if (arena == MAP_FAILED) { + pthread_keys_max = 0; + return NULL; + } + + pthread__tsd_list = (void *)arena; + arena += sizeof(*pthread__tsd_list) * pthread_keys_max; + pthread__tsd_destructors = (void *)arena; + arena += sizeof(*pthread__tsd_destructors) * pthread_keys_max; + return arena; +} + int pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) { @@ -75,11 +118,11 @@ pthread_key_create(pthread_key_t *key, v * our own internal destructor to satisfy the non NULL condition. */ /* 1. Search from "nextkey" to the end of the list. */ - for (i = nextkey; i < PTHREAD_KEYS_MAX; i++) + for (i = nextkey; i < pthread_keys_max; i++) if (pthread__tsd_destructors[i] == NULL) break; - if (i == PTHREAD_KEYS_MAX) { + if (i == pthread_keys_max) { /* 2. If that didn't work, search from the start * of the list back to "nextkey". */ @@ -100,7 +143,7 @@ pthread_key_create(pthread_key_t *key, v pthread__assert(PTQ_EMPTY(&pthread__tsd_list[i])); pthread__tsd_destructors[i] = destructor ? destructor : null_destructor; - nextkey = (i + 1) % PTHREAD_KEYS_MAX; + nextkey = (i + 1) % pthread_keys_max; pthread_mutex_unlock(&tsd_mutex); *key = i; @@ -108,7 +151,7 @@ pthread_key_create(pthread_key_t *key, v } /* - * Each thread holds an array of PTHREAD_KEYS_MAX pt_specific list + * Each thread holds an array of pthread_keys_max pt_specific list * elements. When an element is used it is inserted into the appropriate * key bucket of pthread__tsd_list. This means that ptqe_prev == NULL, * means that the element is not threaded, ptqe_prev != NULL it is @@ -130,7 +173,7 @@ pthread__add_specific(pthread_t self, pt { struct pt_specific *pt; - pthread__assert(key >= 0 && key < PTHREAD_KEYS_MAX); + pthread__assert(key >= 0 && key < pthread_keys_max); pthread_mutex_lock(&tsd_mutex); pthread__assert(pthread__tsd_destructors[key] != NULL); @@ -237,7 +280,7 @@ pthread_key_delete(pthread_key_t key) if (__predict_false(__uselibcstub)) return __libc_thr_keydelete_stub(key); - pthread__assert(key >= 0 && key < PTHREAD_KEYS_MAX); + pthread__assert(key >= 0 && key < pthread_keys_max); pthread_mutex_lock(&tsd_mutex); @@ -295,7 +338,7 @@ pthread__destroy_tsd(pthread_t self) iterations = 4; /* We're not required to try very hard */ do { done = 1; - for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + for (i = 0; i < pthread_keys_max; i++) { struct pt_specific *pt = &self->pt_specific[i]; if (pt->pts_next.ptqe_prev == NULL) continue; Index: src/lib/libpthread_dbg/pthread_dbg.c diff -u src/lib/libpthread_dbg/pthread_dbg.c:1.42 src/lib/libpthread_dbg/pthread_dbg.c:1.42.8.1 --- src/lib/libpthread_dbg/pthread_dbg.c:1.42 Sun Jan 20 18:45:19 2013 +++ src/lib/libpthread_dbg/pthread_dbg.c Tue Nov 24 17:37:15 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_dbg.c,v 1.42 2013/01/20 18:45:19 christos Exp $ */ +/* $NetBSD: pthread_dbg.c,v 1.42.8.1 2015/11/24 17:37:15 martin Exp $ */ /*- * Copyright (c) 2002 Wasabi Systems, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: pthread_dbg.c,v 1.42 2013/01/20 18:45:19 christos Exp $"); +__RCSID("$NetBSD: pthread_dbg.c,v 1.42.8.1 2015/11/24 17:37:15 martin Exp $"); #define __EXPOSE_STACK 1 @@ -415,7 +415,7 @@ td_tsd_iter(td_proc_t *proc, void *allocated; void (*destructor)(void *); - for (i = 0; i < PTHREAD_KEYS_MAX; i++) { + for (i = 0; i < pthread_keys_max; i++) { val = READ(proc, proc->tsdlistaddr + i * sizeof(allocated), &allocated, sizeof(allocated)); if (val != 0)