1*fcf53d9bSJohn Marino /*- 2*fcf53d9bSJohn Marino * Copyright 1999, 2000 John D. Polstra. 3*fcf53d9bSJohn Marino * All rights reserved. 4*fcf53d9bSJohn Marino * 5*fcf53d9bSJohn Marino * Redistribution and use in source and binary forms, with or without 6*fcf53d9bSJohn Marino * modification, are permitted provided that the following conditions 7*fcf53d9bSJohn Marino * are met: 8*fcf53d9bSJohn Marino * 1. Redistributions of source code must retain the above copyright 9*fcf53d9bSJohn Marino * notice, this list of conditions and the following disclaimer. 10*fcf53d9bSJohn Marino * 2. Redistributions in binary form must reproduce the above copyright 11*fcf53d9bSJohn Marino * notice, this list of conditions and the following disclaimer in the 12*fcf53d9bSJohn Marino * documentation and/or other materials provided with the distribution. 13*fcf53d9bSJohn Marino * 14*fcf53d9bSJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*fcf53d9bSJohn Marino * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16*fcf53d9bSJohn Marino * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17*fcf53d9bSJohn Marino * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18*fcf53d9bSJohn Marino * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19*fcf53d9bSJohn Marino * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20*fcf53d9bSJohn Marino * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21*fcf53d9bSJohn Marino * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22*fcf53d9bSJohn Marino * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23*fcf53d9bSJohn Marino * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24*fcf53d9bSJohn Marino * 25*fcf53d9bSJohn Marino * from: FreeBSD: src/libexec/rtld-elf/sparc64/lockdflt.c,v 1.3 2002/10/09 26*fcf53d9bSJohn Marino * $FreeBSD: src/libexec/rtld-elf/rtld_lock.c,v 1.11 2011/02/09 09:20:27 kib Exp $ 27*fcf53d9bSJohn Marino */ 28*fcf53d9bSJohn Marino 29*fcf53d9bSJohn Marino /* 30*fcf53d9bSJohn Marino * Thread locking implementation for the dynamic linker. 31*fcf53d9bSJohn Marino * 32*fcf53d9bSJohn Marino * We use the "simple, non-scalable reader-preference lock" from: 33*fcf53d9bSJohn Marino * 34*fcf53d9bSJohn Marino * J. M. Mellor-Crummey and M. L. Scott. "Scalable Reader-Writer 35*fcf53d9bSJohn Marino * Synchronization for Shared-Memory Multiprocessors." 3rd ACM Symp. on 36*fcf53d9bSJohn Marino * Principles and Practice of Parallel Programming, April 1991. 37*fcf53d9bSJohn Marino * 38*fcf53d9bSJohn Marino * In this algorithm the lock is a single word. Its low-order bit is 39*fcf53d9bSJohn Marino * set when a writer holds the lock. The remaining high-order bits 40*fcf53d9bSJohn Marino * contain a count of readers desiring the lock. The algorithm requires 41*fcf53d9bSJohn Marino * atomic "compare_and_store" and "add" operations, which we implement 42*fcf53d9bSJohn Marino * using assembly language sequences in "rtld_start.S". 43*fcf53d9bSJohn Marino */ 44*fcf53d9bSJohn Marino 45*fcf53d9bSJohn Marino #include <sys/param.h> 46*fcf53d9bSJohn Marino #include <signal.h> 47*fcf53d9bSJohn Marino #include <stdlib.h> 48*fcf53d9bSJohn Marino #include <time.h> 49*fcf53d9bSJohn Marino 50*fcf53d9bSJohn Marino #include "debug.h" 51*fcf53d9bSJohn Marino #include "rtld.h" 52*fcf53d9bSJohn Marino #include "rtld_machdep.h" 53*fcf53d9bSJohn Marino 54*fcf53d9bSJohn Marino #define WAFLAG 0x1 /* A writer holds the lock */ 55*fcf53d9bSJohn Marino #define RC_INCR 0x2 /* Adjusts count of readers desiring lock */ 56*fcf53d9bSJohn Marino 57*fcf53d9bSJohn Marino typedef struct Struct_Lock { 58*fcf53d9bSJohn Marino volatile u_int lock; 59*fcf53d9bSJohn Marino void *base; 60*fcf53d9bSJohn Marino } Lock; 61*fcf53d9bSJohn Marino 62*fcf53d9bSJohn Marino static sigset_t fullsigmask, oldsigmask; 63*fcf53d9bSJohn Marino static int thread_flag; 64*fcf53d9bSJohn Marino 65*fcf53d9bSJohn Marino static void * 66*fcf53d9bSJohn Marino def_lock_create() 67*fcf53d9bSJohn Marino { 68*fcf53d9bSJohn Marino void *base; 69*fcf53d9bSJohn Marino char *p; 70*fcf53d9bSJohn Marino uintptr_t r; 71*fcf53d9bSJohn Marino Lock *l; 72*fcf53d9bSJohn Marino 73*fcf53d9bSJohn Marino /* 74*fcf53d9bSJohn Marino * Arrange for the lock to occupy its own cache line. First, we 75*fcf53d9bSJohn Marino * optimistically allocate just a cache line, hoping that malloc 76*fcf53d9bSJohn Marino * will give us a well-aligned block of memory. If that doesn't 77*fcf53d9bSJohn Marino * work, we allocate a larger block and take a well-aligned cache 78*fcf53d9bSJohn Marino * line from it. 79*fcf53d9bSJohn Marino */ 80*fcf53d9bSJohn Marino base = xmalloc(CACHE_LINE_SIZE); 81*fcf53d9bSJohn Marino p = (char *)base; 82*fcf53d9bSJohn Marino if ((uintptr_t)p % CACHE_LINE_SIZE != 0) { 83*fcf53d9bSJohn Marino free(base); 84*fcf53d9bSJohn Marino base = xmalloc(2 * CACHE_LINE_SIZE); 85*fcf53d9bSJohn Marino p = (char *)base; 86*fcf53d9bSJohn Marino if ((r = (uintptr_t)p % CACHE_LINE_SIZE) != 0) 87*fcf53d9bSJohn Marino p += CACHE_LINE_SIZE - r; 88*fcf53d9bSJohn Marino } 89*fcf53d9bSJohn Marino l = (Lock *)p; 90*fcf53d9bSJohn Marino l->base = base; 91*fcf53d9bSJohn Marino l->lock = 0; 92*fcf53d9bSJohn Marino return l; 93*fcf53d9bSJohn Marino } 94*fcf53d9bSJohn Marino 95*fcf53d9bSJohn Marino static void 96*fcf53d9bSJohn Marino def_lock_destroy(void *lock) 97*fcf53d9bSJohn Marino { 98*fcf53d9bSJohn Marino Lock *l = (Lock *)lock; 99*fcf53d9bSJohn Marino 100*fcf53d9bSJohn Marino free(l->base); 101*fcf53d9bSJohn Marino } 102*fcf53d9bSJohn Marino 103*fcf53d9bSJohn Marino static void 104*fcf53d9bSJohn Marino def_rlock_acquire(void *lock) 105*fcf53d9bSJohn Marino { 106*fcf53d9bSJohn Marino Lock *l = (Lock *)lock; 107*fcf53d9bSJohn Marino 108*fcf53d9bSJohn Marino atomic_add_acq_int(&l->lock, RC_INCR); 109*fcf53d9bSJohn Marino while (l->lock & WAFLAG) 110*fcf53d9bSJohn Marino ; /* Spin */ 111*fcf53d9bSJohn Marino } 112*fcf53d9bSJohn Marino 113*fcf53d9bSJohn Marino static void 114*fcf53d9bSJohn Marino def_wlock_acquire(void *lock) 115*fcf53d9bSJohn Marino { 116*fcf53d9bSJohn Marino Lock *l = (Lock *)lock; 117*fcf53d9bSJohn Marino sigset_t tmp_oldsigmask; 118*fcf53d9bSJohn Marino 119*fcf53d9bSJohn Marino for ( ; ; ) { 120*fcf53d9bSJohn Marino sigprocmask(SIG_BLOCK, &fullsigmask, &tmp_oldsigmask); 121*fcf53d9bSJohn Marino if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG)) 122*fcf53d9bSJohn Marino break; 123*fcf53d9bSJohn Marino sigprocmask(SIG_SETMASK, &tmp_oldsigmask, NULL); 124*fcf53d9bSJohn Marino } 125*fcf53d9bSJohn Marino oldsigmask = tmp_oldsigmask; 126*fcf53d9bSJohn Marino } 127*fcf53d9bSJohn Marino 128*fcf53d9bSJohn Marino static void 129*fcf53d9bSJohn Marino def_lock_release(void *lock) 130*fcf53d9bSJohn Marino { 131*fcf53d9bSJohn Marino Lock *l = (Lock *)lock; 132*fcf53d9bSJohn Marino 133*fcf53d9bSJohn Marino if ((l->lock & WAFLAG) == 0) 134*fcf53d9bSJohn Marino atomic_add_rel_int(&l->lock, -RC_INCR); 135*fcf53d9bSJohn Marino else { 136*fcf53d9bSJohn Marino atomic_add_rel_int(&l->lock, -WAFLAG); 137*fcf53d9bSJohn Marino sigprocmask(SIG_SETMASK, &oldsigmask, NULL); 138*fcf53d9bSJohn Marino } 139*fcf53d9bSJohn Marino } 140*fcf53d9bSJohn Marino 141*fcf53d9bSJohn Marino static int 142*fcf53d9bSJohn Marino def_thread_set_flag(int mask) 143*fcf53d9bSJohn Marino { 144*fcf53d9bSJohn Marino int old_val = thread_flag; 145*fcf53d9bSJohn Marino thread_flag |= mask; 146*fcf53d9bSJohn Marino return (old_val); 147*fcf53d9bSJohn Marino } 148*fcf53d9bSJohn Marino 149*fcf53d9bSJohn Marino static int 150*fcf53d9bSJohn Marino def_thread_clr_flag(int mask) 151*fcf53d9bSJohn Marino { 152*fcf53d9bSJohn Marino int old_val = thread_flag; 153*fcf53d9bSJohn Marino thread_flag &= ~mask; 154*fcf53d9bSJohn Marino return (old_val); 155*fcf53d9bSJohn Marino } 156*fcf53d9bSJohn Marino 157*fcf53d9bSJohn Marino /* 158*fcf53d9bSJohn Marino * Public interface exposed to the rest of the dynamic linker. 159*fcf53d9bSJohn Marino */ 160*fcf53d9bSJohn Marino static struct RtldLockInfo lockinfo; 161*fcf53d9bSJohn Marino static struct RtldLockInfo deflockinfo; 162*fcf53d9bSJohn Marino 163*fcf53d9bSJohn Marino static __inline int 164*fcf53d9bSJohn Marino thread_mask_set(int mask) 165*fcf53d9bSJohn Marino { 166*fcf53d9bSJohn Marino return lockinfo.thread_set_flag(mask); 167*fcf53d9bSJohn Marino } 168*fcf53d9bSJohn Marino 169*fcf53d9bSJohn Marino static __inline void 170*fcf53d9bSJohn Marino thread_mask_clear(int mask) 171*fcf53d9bSJohn Marino { 172*fcf53d9bSJohn Marino lockinfo.thread_clr_flag(mask); 173*fcf53d9bSJohn Marino } 174*fcf53d9bSJohn Marino 175*fcf53d9bSJohn Marino #define RTLD_LOCK_CNT 3 176*fcf53d9bSJohn Marino struct rtld_lock { 177*fcf53d9bSJohn Marino void *handle; 178*fcf53d9bSJohn Marino int mask; 179*fcf53d9bSJohn Marino } rtld_locks[RTLD_LOCK_CNT]; 180*fcf53d9bSJohn Marino 181*fcf53d9bSJohn Marino rtld_lock_t rtld_bind_lock = &rtld_locks[0]; 182*fcf53d9bSJohn Marino rtld_lock_t rtld_libc_lock = &rtld_locks[1]; 183*fcf53d9bSJohn Marino rtld_lock_t rtld_phdr_lock = &rtld_locks[2]; 184*fcf53d9bSJohn Marino 185*fcf53d9bSJohn Marino #define print_ebp(str) do {register long ebp asm("ebp"); printf("%s 0x%0lx\n", str, ebp);} while (0) 186*fcf53d9bSJohn Marino 187*fcf53d9bSJohn Marino void 188*fcf53d9bSJohn Marino rlock_acquire(rtld_lock_t lock, RtldLockState *lockstate) 189*fcf53d9bSJohn Marino { 190*fcf53d9bSJohn Marino 191*fcf53d9bSJohn Marino if (lockstate == NULL) 192*fcf53d9bSJohn Marino return; 193*fcf53d9bSJohn Marino 194*fcf53d9bSJohn Marino if (thread_mask_set(lock->mask) & lock->mask) { 195*fcf53d9bSJohn Marino dbg("rlock_acquire: recursed"); 196*fcf53d9bSJohn Marino lockstate->lockstate = RTLD_LOCK_UNLOCKED; 197*fcf53d9bSJohn Marino return; 198*fcf53d9bSJohn Marino } 199*fcf53d9bSJohn Marino lockinfo.rlock_acquire(lock->handle); 200*fcf53d9bSJohn Marino lockstate->lockstate = RTLD_LOCK_RLOCKED; 201*fcf53d9bSJohn Marino } 202*fcf53d9bSJohn Marino 203*fcf53d9bSJohn Marino void 204*fcf53d9bSJohn Marino wlock_acquire(rtld_lock_t lock, RtldLockState *lockstate) 205*fcf53d9bSJohn Marino { 206*fcf53d9bSJohn Marino 207*fcf53d9bSJohn Marino if (lockstate == NULL) 208*fcf53d9bSJohn Marino return; 209*fcf53d9bSJohn Marino 210*fcf53d9bSJohn Marino if (thread_mask_set(lock->mask) & lock->mask) { 211*fcf53d9bSJohn Marino dbg("wlock_acquire: recursed"); 212*fcf53d9bSJohn Marino lockstate->lockstate = RTLD_LOCK_UNLOCKED; 213*fcf53d9bSJohn Marino return; 214*fcf53d9bSJohn Marino } 215*fcf53d9bSJohn Marino lockinfo.wlock_acquire(lock->handle); 216*fcf53d9bSJohn Marino lockstate->lockstate = RTLD_LOCK_WLOCKED; 217*fcf53d9bSJohn Marino } 218*fcf53d9bSJohn Marino 219*fcf53d9bSJohn Marino void 220*fcf53d9bSJohn Marino lock_release(rtld_lock_t lock, RtldLockState *lockstate) 221*fcf53d9bSJohn Marino { 222*fcf53d9bSJohn Marino 223*fcf53d9bSJohn Marino if (lockstate == NULL) 224*fcf53d9bSJohn Marino return; 225*fcf53d9bSJohn Marino 226*fcf53d9bSJohn Marino switch (lockstate->lockstate) { 227*fcf53d9bSJohn Marino case RTLD_LOCK_UNLOCKED: 228*fcf53d9bSJohn Marino break; 229*fcf53d9bSJohn Marino case RTLD_LOCK_RLOCKED: 230*fcf53d9bSJohn Marino case RTLD_LOCK_WLOCKED: 231*fcf53d9bSJohn Marino thread_mask_clear(lock->mask); 232*fcf53d9bSJohn Marino lockinfo.lock_release(lock->handle); 233*fcf53d9bSJohn Marino break; 234*fcf53d9bSJohn Marino default: 235*fcf53d9bSJohn Marino assert(0); 236*fcf53d9bSJohn Marino } 237*fcf53d9bSJohn Marino } 238*fcf53d9bSJohn Marino 239*fcf53d9bSJohn Marino void 240*fcf53d9bSJohn Marino lock_upgrade(rtld_lock_t lock, RtldLockState *lockstate) 241*fcf53d9bSJohn Marino { 242*fcf53d9bSJohn Marino 243*fcf53d9bSJohn Marino if (lockstate == NULL) 244*fcf53d9bSJohn Marino return; 245*fcf53d9bSJohn Marino 246*fcf53d9bSJohn Marino lock_release(lock, lockstate); 247*fcf53d9bSJohn Marino wlock_acquire(lock, lockstate); 248*fcf53d9bSJohn Marino } 249*fcf53d9bSJohn Marino 250*fcf53d9bSJohn Marino void 251*fcf53d9bSJohn Marino lock_restart_for_upgrade(RtldLockState *lockstate) 252*fcf53d9bSJohn Marino { 253*fcf53d9bSJohn Marino 254*fcf53d9bSJohn Marino if (lockstate == NULL) 255*fcf53d9bSJohn Marino return; 256*fcf53d9bSJohn Marino 257*fcf53d9bSJohn Marino switch (lockstate->lockstate) { 258*fcf53d9bSJohn Marino case RTLD_LOCK_UNLOCKED: 259*fcf53d9bSJohn Marino case RTLD_LOCK_WLOCKED: 260*fcf53d9bSJohn Marino break; 261*fcf53d9bSJohn Marino case RTLD_LOCK_RLOCKED: 262*fcf53d9bSJohn Marino siglongjmp(lockstate->env, 1); 263*fcf53d9bSJohn Marino break; 264*fcf53d9bSJohn Marino default: 265*fcf53d9bSJohn Marino assert(0); 266*fcf53d9bSJohn Marino } 267*fcf53d9bSJohn Marino } 268*fcf53d9bSJohn Marino 269*fcf53d9bSJohn Marino void 270*fcf53d9bSJohn Marino lockdflt_init() 271*fcf53d9bSJohn Marino { 272*fcf53d9bSJohn Marino int i; 273*fcf53d9bSJohn Marino 274*fcf53d9bSJohn Marino deflockinfo.rtli_version = RTLI_VERSION; 275*fcf53d9bSJohn Marino deflockinfo.lock_create = def_lock_create; 276*fcf53d9bSJohn Marino deflockinfo.lock_destroy = def_lock_destroy; 277*fcf53d9bSJohn Marino deflockinfo.rlock_acquire = def_rlock_acquire; 278*fcf53d9bSJohn Marino deflockinfo.wlock_acquire = def_wlock_acquire; 279*fcf53d9bSJohn Marino deflockinfo.lock_release = def_lock_release; 280*fcf53d9bSJohn Marino deflockinfo.thread_set_flag = def_thread_set_flag; 281*fcf53d9bSJohn Marino deflockinfo.thread_clr_flag = def_thread_clr_flag; 282*fcf53d9bSJohn Marino deflockinfo.at_fork = NULL; 283*fcf53d9bSJohn Marino 284*fcf53d9bSJohn Marino for (i = 0; i < RTLD_LOCK_CNT; i++) { 285*fcf53d9bSJohn Marino rtld_locks[i].mask = (1 << i); 286*fcf53d9bSJohn Marino rtld_locks[i].handle = NULL; 287*fcf53d9bSJohn Marino } 288*fcf53d9bSJohn Marino 289*fcf53d9bSJohn Marino memcpy(&lockinfo, &deflockinfo, sizeof(lockinfo)); 290*fcf53d9bSJohn Marino _rtld_thread_init(NULL); 291*fcf53d9bSJohn Marino /* 292*fcf53d9bSJohn Marino * Construct a mask to block all signals except traps which might 293*fcf53d9bSJohn Marino * conceivably be generated within the dynamic linker itself. 294*fcf53d9bSJohn Marino */ 295*fcf53d9bSJohn Marino sigfillset(&fullsigmask); 296*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGILL); 297*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGTRAP); 298*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGABRT); 299*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGEMT); 300*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGFPE); 301*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGBUS); 302*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGSEGV); 303*fcf53d9bSJohn Marino sigdelset(&fullsigmask, SIGSYS); 304*fcf53d9bSJohn Marino } 305*fcf53d9bSJohn Marino 306*fcf53d9bSJohn Marino /* 307*fcf53d9bSJohn Marino * Callback function to allow threads implementation to 308*fcf53d9bSJohn Marino * register their own locking primitives if the default 309*fcf53d9bSJohn Marino * one is not suitable. 310*fcf53d9bSJohn Marino * The current context should be the only context 311*fcf53d9bSJohn Marino * executing at the invocation time. 312*fcf53d9bSJohn Marino */ 313*fcf53d9bSJohn Marino void 314*fcf53d9bSJohn Marino _rtld_thread_init(struct RtldLockInfo *pli) 315*fcf53d9bSJohn Marino { 316*fcf53d9bSJohn Marino int flags, i; 317*fcf53d9bSJohn Marino void *locks[RTLD_LOCK_CNT]; 318*fcf53d9bSJohn Marino 319*fcf53d9bSJohn Marino /* disable all locking while this function is running */ 320*fcf53d9bSJohn Marino flags = thread_mask_set(~0); 321*fcf53d9bSJohn Marino 322*fcf53d9bSJohn Marino if (pli == NULL) 323*fcf53d9bSJohn Marino pli = &deflockinfo; 324*fcf53d9bSJohn Marino 325*fcf53d9bSJohn Marino 326*fcf53d9bSJohn Marino for (i = 0; i < RTLD_LOCK_CNT; i++) 327*fcf53d9bSJohn Marino if ((locks[i] = pli->lock_create()) == NULL) 328*fcf53d9bSJohn Marino break; 329*fcf53d9bSJohn Marino 330*fcf53d9bSJohn Marino if (i < RTLD_LOCK_CNT) { 331*fcf53d9bSJohn Marino while (--i >= 0) 332*fcf53d9bSJohn Marino pli->lock_destroy(locks[i]); 333*fcf53d9bSJohn Marino abort(); 334*fcf53d9bSJohn Marino } 335*fcf53d9bSJohn Marino 336*fcf53d9bSJohn Marino for (i = 0; i < RTLD_LOCK_CNT; i++) { 337*fcf53d9bSJohn Marino if (rtld_locks[i].handle == NULL) 338*fcf53d9bSJohn Marino continue; 339*fcf53d9bSJohn Marino if (flags & rtld_locks[i].mask) 340*fcf53d9bSJohn Marino lockinfo.lock_release(rtld_locks[i].handle); 341*fcf53d9bSJohn Marino lockinfo.lock_destroy(rtld_locks[i].handle); 342*fcf53d9bSJohn Marino } 343*fcf53d9bSJohn Marino 344*fcf53d9bSJohn Marino for (i = 0; i < RTLD_LOCK_CNT; i++) { 345*fcf53d9bSJohn Marino rtld_locks[i].handle = locks[i]; 346*fcf53d9bSJohn Marino if (flags & rtld_locks[i].mask) 347*fcf53d9bSJohn Marino pli->wlock_acquire(rtld_locks[i].handle); 348*fcf53d9bSJohn Marino } 349*fcf53d9bSJohn Marino 350*fcf53d9bSJohn Marino lockinfo.lock_create = pli->lock_create; 351*fcf53d9bSJohn Marino lockinfo.lock_destroy = pli->lock_destroy; 352*fcf53d9bSJohn Marino lockinfo.rlock_acquire = pli->rlock_acquire; 353*fcf53d9bSJohn Marino lockinfo.wlock_acquire = pli->wlock_acquire; 354*fcf53d9bSJohn Marino lockinfo.lock_release = pli->lock_release; 355*fcf53d9bSJohn Marino lockinfo.thread_set_flag = pli->thread_set_flag; 356*fcf53d9bSJohn Marino lockinfo.thread_clr_flag = pli->thread_clr_flag; 357*fcf53d9bSJohn Marino lockinfo.at_fork = pli->at_fork; 358*fcf53d9bSJohn Marino 359*fcf53d9bSJohn Marino /* restore thread locking state, this time with new locks */ 360*fcf53d9bSJohn Marino thread_mask_clear(~0); 361*fcf53d9bSJohn Marino thread_mask_set(flags); 362*fcf53d9bSJohn Marino dbg("_rtld_thread_init: done"); 363*fcf53d9bSJohn Marino } 364