mutex.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Implementation of all threads interfaces between ld.so.1 and libthread.
*
* In a non-threaded environment all thread interfaces are vectored to noops.
* When called via _ld_concurrency() from libthread these vectors are reassigned
* to real threads interfaces. Two models are supported:
*
* TI_VERSION == 1
* we vector all rt_mutex_lock/rt_mutex_unlock calls.
* lwp/libthread that provided signal blocking via bind_guard/bind_clear.
*
* TI_VERSION == 2
* Under this model only libthreads bind_guard/bind_clear and thr_self
* interfaces are used. Both libthreads block signals under the
* bind_guard/bind_clear interfaces. Lower level locking is derived
* from internally bound _lwp_ interfaces. This removes recursive
* problems encountered when obtaining locking interfaces from libthread.
* condition variables for controlling thread concurrency (allows access to
* objects only after their .init has completed).
*
* CI_VERSION == 1
* introduced with CI_VERSION & CI_ATEXIT
*
* CI_VERSION == 2
* add support for CI_LCMESSAGES
*
* CI_VERSION == 3
* Add the following versions to the CI table:
*
* CI_BIND_GUARD, CI_BIND_CLEAR, CI_THR_SELF
* CI_TLS_MODADD, CI_TLS_MOD_REMOVE, CI_TLS_STATMOD
*
* It was also at this level that the DT_SUNW_RTLDINFO structure
* was introduced as a mechanism to handshake with ld.so.1
*
* CI_VERSION == 4
* merge project. libc now initializes the current thread pointer
* (%g7 for sparc) as part of this and no longer relies on the
* INITFIRST flag (which others have started to camp out on).
*/
#include "_synonyms.h"
#include <synch.h>
#include <signal.h>
#include <thread.h>
#include <synch.h>
#include <strings.h>
#include <stdio.h>
#include "thr_int.h"
#include "_elf.h"
#include "_rtld.h"
/*
* Define our own local mutex functions.
*/
static int bindmask = THR_FLG_RTLD;
static int
_rt_bind_guard(int bit)
{
return (1);
}
return (0);
}
static int
_rt_bind_clear(int bit)
{
if (bit == 0)
return (bindmask);
else {
return (0);
}
}
static int
{
return (1);
}
static int
_rt_null()
{
return (0);
}
#if (defined(DEBUG) || defined(SGS_PRE_UNIFIED_PROCESS))
/*
* These three routines are used to protect the locks that ld.so.1 has.
* They are passed to pthread_atfork() and used during a fork1() to make
* sure we do not do a fork while a lock is being held.
*/
static void
prepare_atfork(void)
{
(void) rt_bind_guard(THR_FLG_MASK);
(void) rt_mutex_lock(&rtldlock);
}
static void
child_atfork(void)
{
(void) rt_mutex_unlock(&rtldlock);
(void) rt_bind_clear(THR_FLG_MASK);
}
static void
parent_atfork(void)
{
(void) rt_mutex_unlock(&rtldlock);
(void) rt_bind_clear(THR_FLG_MASK);
}
#endif
/*
* Define the maximum number of thread interfaces ld.so.1 is interested in,
* this is a subset of the total number of interfaces communicated between
* libthread and libc.
*/
#define STI_MAX 11
/*
* Define our own thread jump table.
*/
#define RT_BIND_GUARD 0
#define RT_BIND_CLEAR 1
#define RT_THR_SELF 2
#define RT_MUTEX_LOCK 3
#define RT_MUTEX_UNLOCK 4
#define RT_COND_WAIT 5
#define RT_COND_BROAD 6
#define SRT_MAX 7
static int (* thr_jmp_table[SRT_MAX])() = {
_rt_bind_guard, /* RT_BIND_GUARD */
_rt_bind_clear, /* RT_BIND_CLEAR */
_rt_thr_self, /* RT_THR_SELF */
_rt_null, /* RT_MUTEX_LOCK */
_rt_null, /* RT_MUTEX_UNLOCK */
_rt_null, /* RT_COND_WAIT */
_rt_null /* RT_COND_BROAD */
};
#if (defined(DEBUG) || defined(SGS_PRE_UNIFIED_PROCESS))
static int (* thr_def_table[SRT_MAX])() = {
_rt_bind_guard, /* RT_BIND_GUARD */
_rt_bind_clear, /* RT_BIND_CLEAR */
_rt_thr_self, /* RT_THR_SELF */
_rt_null, /* RT_MUTEX_LOCK */
_rt_null, /* RT_MUTEX_UNLOCK */
_rt_null, /* RT_COND_WAIT */
_rt_null /* RT_COND_BROAD */
};
#endif
/*
* The interface with the threads library which is supplied through libdl.so.1.
* A non-null argument allows a function pointer array to be passed to us which
* is used to re-initialize the linker concurrency table. A null argument
* causes the table to be reset to the defaults.
*/
void
/* ARGSUSED */
_ld_concurrency(void * ptr)
{
#if (defined(DEBUG) || defined(SGS_PRE_UNIFIED_PROCESS))
int tag;
if (funcs) {
/*
* Collect all the threads interfaces we're interested in.
*/
}
/*
* At this point we've re-entered ld.so.1 from libthreads .init.
* All locks are down. Exercise any common thread interfaces
* before we remap ld.so.1 to use them, this allows us to be
* re-entered to resolve .plt's without exercising locks.
*/
(void) (*table[TI_THRSELF])();
/*
* Prepare atfork, if necessary.
*/
if (table[TI_LATFORK])
/*
* Establish what interfaces are available for this version of
* libthread and make them live.
*/
/*
*/
} else {
/*
* Go directly to our internal interfaces.
*/
/*
* If concurrency is requested inable it now.
*/
if ((rtld_flags & RT_FL_NOCONCUR) == 0)
}
/*
* Make all common interfaces go live.
*/
} else {
/*
* If libthread were to be dlclosed() we'd get here to reset
* our interfaces back to the internal noops (as libthread
* typically can't be dlclosed() it's unlikely we'll ever
* exercise this. If a bindlock is currently in place clear it.
*/
(void) rt_mutex_unlock(&rtldlock);
(void) rt_bind_clear(THR_FLG_RTLD);
}
rtld_flags &= ~RT_FL_THREADS;
}
#endif
}
void
{
int tag;
char *nlocale;
void *tlsmodadd = 0;
void *tlsmodrem = 0;
void *tlsstatmod = 0;
return;
switch (tag) {
case CI_ATEXIT:
/*
* If we obtained a _preexec_exit_handlers()
* call back (typically supplied via libc's
* .init) then register it for use in dlclose().
*/
}
break;
case CI_LCMESSAGES:
/*
* If we've obtained a message locale (typically
* supplied via libc's setlocale()) then
* register it for use in dgettext() to
* reestablish a locale for ld.so.1's messages.
*/
if ((locale == 0) ||
if (locale) {
}
/*
* Clear any cached messages.
*/
err_strs[ERR_WARNING] = 0;
nosym_str = 0;
}
}
break;
case CI_BIND_GUARD:
/*
* Go directly to our internal interfaces.
*/
/*
* If concurrency is requested inable it now.
*/
if ((rtld_flags & RT_FL_NOCONCUR) == 0)
break;
case CI_BIND_CLEAR:
break;
case CI_THR_SELF:
break;
case CI_TLS_MODADD:
break;
case CI_TLS_MODREM:
break;
case CI_TLS_STATMOD:
break;
#ifdef CI_THRINIT
case CI_THRINIT:
break;
#endif
#ifdef CI_V_FOUR
case CI_VERSION:
if ((rtld_flags2 & RT_FL2_RTLDSEEN) == 0) {
/*
* We might have seen auditor which
* is not dependent on libc. Such auditor's
* link map list has LML_FLG_HOLDLOCK on.
* It needs to be dropped. Refer to:
* audit_setup() in audit.c.
*/
if ((rtld_flags2 & RT_FL2_HASAUDIT) == 0)
break;
/*
* Yes, we did. Take care of them.
*/
}
}
}
}
break;
#endif
default:
break;
}
}
}
/*
* Define the local interface for each of the threads interfaces.
*/
{
return ((* thr_jmp_table[RT_THR_SELF])());
}
int
{
}
int
{
}
int
rt_bind_guard(int bindflag)
{
}
int
rt_bind_clear(int bindflag)
{
}
Rt_cond *
{
}
int
{
}
int
{
}
#ifdef EXPAND_RELATIVE
/*
* Mutex interfaces to resolve references from any objects extracted from
* libc_pic.a. Note, as ld.so.1 is essentially single threaded these can be
* noops.
*/
/* ARGSUSED */
int
{
return (0);
}
/* ARGSUSED */
int
{
return (0);
}
/*
* This is needed to satisfy sysconf() (case _SC_THREAD_STACK_MIN)
*/
{
#ifdef _LP64
return (8 * 1024);
#else
return (4 * 1024);
#endif
}
#endif /* EXPAND_RELATIVE */