summaryrefslogtreecommitdiff
path: root/usr/src/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r--usr/src/lib/libc/inc/libc.h4
-rw-r--r--usr/src/lib/libc/inc/thr_uberdata.h7
-rw-r--r--usr/src/lib/libc/port/gen/getnetgrent.c14
-rw-r--r--usr/src/lib/libc/port/gen/ttyname.c6
-rw-r--r--usr/src/lib/libc/port/i18n/gettext.c40
-rw-r--r--usr/src/lib/libc/port/i18n/wdresolve.c32
-rw-r--r--usr/src/lib/libc/port/threads/scalls.c41
-rw-r--r--usr/src/lib/libc/port/threads/thr.c8
8 files changed, 83 insertions, 69 deletions
diff --git a/usr/src/lib/libc/inc/libc.h b/usr/src/lib/libc/inc/libc.h
index c77033490f..e3570f7d7d 100644
--- a/usr/src/lib/libc/inc/libc.h
+++ b/usr/src/lib/libc/inc/libc.h
@@ -68,8 +68,8 @@ extern int thr_kill(thread_t tid, int sig);
extern thread_t thr_self(void);
extern int mutex_lock(mutex_t *mp);
extern int mutex_unlock(mutex_t *mp);
-extern void atfork_lock_enter(void);
-extern void atfork_lock_exit(void);
+extern void callout_lock_enter(void);
+extern void callout_lock_exit(void);
extern void *lmalloc(size_t);
extern void lfree(void *, size_t);
extern void *libc_malloc(size_t);
diff --git a/usr/src/lib/libc/inc/thr_uberdata.h b/usr/src/lib/libc/inc/thr_uberdata.h
index b8dd212875..509149d62a 100644
--- a/usr/src/lib/libc/inc/thr_uberdata.h
+++ b/usr/src/lib/libc/inc/thr_uberdata.h
@@ -776,7 +776,8 @@ typedef struct uberdata {
pad_lock_t _link_lock;
pad32_lock_t _fork_lock;
pad32_lock_t _atfork_lock;
- pad_lock_t _tdb_hash_lock;
+ pad32_lock_t _callout_lock;
+ pad32_lock_t _tdb_hash_lock;
tdb_sync_stats_t tdb_hash_lock_stats;
siguaction_t siguaction[NSIG];
bucket_t bucket[NBUCKETS];
@@ -820,6 +821,7 @@ typedef struct uberdata {
#define link_lock _link_lock.pad_lock
#define fork_lock _fork_lock.pad_lock
#define atfork_lock _atfork_lock.pad_lock
+#define callout_lock _callout_lock.pad_lock
#define tdb_hash_lock _tdb_hash_lock.pad_lock
#pragma align 64(__uberdata)
@@ -980,7 +982,8 @@ typedef struct uberdata32 {
pad_lock_t _link_lock;
pad32_lock_t _fork_lock;
pad32_lock_t _atfork_lock;
- pad_lock_t _tdb_hash_lock;
+ pad32_lock_t _callout_lock;
+ pad32_lock_t _tdb_hash_lock;
tdb_sync_stats_t tdb_hash_lock_stats;
siguaction32_t siguaction[NSIG];
bucket32_t bucket[NBUCKETS];
diff --git a/usr/src/lib/libc/port/gen/getnetgrent.c b/usr/src/lib/libc/port/gen/getnetgrent.c
index 3de09819f0..8a8e7373c2 100644
--- a/usr/src/lib/libc/port/gen/getnetgrent.c
+++ b/usr/src/lib/libc/port/gen/getnetgrent.c
@@ -137,7 +137,7 @@ innetgr(group, host, user, domain)
* serialize them ourselves (anything to prevent a coredump)...
* We can't use lmutex_lock() here because we don't know what the backends
* that we call may call in turn. They might call malloc()/free().
- * So we use the brute-force atfork_lock_enter() instead.
+ * So we use the brute-force callout_lock_enter() instead.
*/
static nss_backend_t *getnetgrent_backend;
@@ -151,7 +151,7 @@ setnetgrent(const char *netgroup)
netgroup = "";
}
- atfork_lock_enter();
+ callout_lock_enter();
be = getnetgrent_backend;
if (be != NULL && NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT,
(void *)netgroup) != NSS_SUCCESS) {
@@ -168,7 +168,7 @@ setnetgrent(const char *netgroup)
be = args.iterator;
}
getnetgrent_backend = be;
- atfork_lock_exit();
+ callout_lock_exit();
return (0);
}
@@ -186,12 +186,12 @@ getnetgrent_r(machinep, namep, domainp, buffer, buflen)
args.buflen = buflen;
args.status = NSS_NETGR_NO;
- atfork_lock_enter();
+ callout_lock_enter();
if (getnetgrent_backend != 0) {
(void) NSS_INVOKE_DBOP(getnetgrent_backend,
NSS_DBOP_GETENT, &args);
}
- atfork_lock_exit();
+ callout_lock_exit();
if (args.status == NSS_NETGR_FOUND) {
*machinep = args.retp[NSS_NETGR_MACHINE];
@@ -219,13 +219,13 @@ getnetgrent(machinep, namep, domainp)
int
endnetgrent()
{
- atfork_lock_enter();
+ callout_lock_enter();
if (getnetgrent_backend != 0) {
(void) NSS_INVOKE_DBOP(getnetgrent_backend,
NSS_DBOP_DESTRUCTOR, 0);
getnetgrent_backend = 0;
}
- atfork_lock_exit();
+ callout_lock_exit();
nss_delete(&db_root); /* === ? */
NSS_XbyY_FREE(&buf);
return (0);
diff --git a/usr/src/lib/libc/port/gen/ttyname.c b/usr/src/lib/libc/port/gen/ttyname.c
index 7853b79e59..7de2085691 100644
--- a/usr/src/lib/libc/port/gen/ttyname.c
+++ b/usr/src/lib/libc/port/gen/ttyname.c
@@ -213,9 +213,9 @@ _ttyname_common(struct stat64 *fsp, char *buffer, uint_t match_mask)
/*
* We can't use lmutex_lock() here because we call malloc()/free()
- * and _libc_gettext(). Use the brute-force atfork_lock_enter().
+ * and _libc_gettext(). Use the brute-force callout_lock_enter().
*/
- atfork_lock_enter();
+ callout_lock_enter();
/*
* match special cases
@@ -320,7 +320,7 @@ _ttyname_common(struct stat64 *fsp, char *buffer, uint_t match_mask)
else
retval = NULL;
out: retval = (retval ? strcpy(buffer, retval) : NULL);
- atfork_lock_exit();
+ callout_lock_exit();
return (retval);
}
diff --git a/usr/src/lib/libc/port/i18n/gettext.c b/usr/src/lib/libc/port/i18n/gettext.c
index d44fc1a107..8d05103cbd 100644
--- a/usr/src/lib/libc/port/i18n/gettext.c
+++ b/usr/src/lib/libc/port/i18n/gettext.c
@@ -59,7 +59,7 @@
if (global_gt) \
global_gt->cur_domain = (char *)default_domain; \
else { \
- atfork_lock_exit(); \
+ callout_lock_exit(); \
return ((def)); \
} \
}
@@ -73,10 +73,10 @@ _bindtextdomain(const char *domain, const char *binding)
{
char *res;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT(NULL);
res = _real_bindtextdomain_u(domain, binding, TP_BINDING);
- atfork_lock_exit();
+ callout_lock_exit();
return (res);
}
@@ -85,10 +85,10 @@ _bind_textdomain_codeset(const char *domain, const char *codeset)
{
char *res;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT(NULL);
res = _real_bindtextdomain_u(domain, codeset, TP_CODESET);
- atfork_lock_exit();
+ callout_lock_exit();
return (res);
}
@@ -102,14 +102,14 @@ _textdomain(const char *domain)
char *res;
char tmp_domain[TEXTDOMAINMAX + 1];
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT(NULL);
res = _textdomain_u(domain, tmp_domain);
if (res == NULL) {
- atfork_lock_exit();
+ callout_lock_exit();
return (NULL);
}
- atfork_lock_exit();
+ callout_lock_exit();
return (CURRENT_DOMAIN(global_gt));
}
@@ -123,10 +123,10 @@ _gettext(const char *msg_id)
char *res;
int errno_save = errno;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT((char *)msg_id);
res = _real_gettext_u(NULL, msg_id, NULL, 0, LC_MESSAGES, 0);
- atfork_lock_exit();
+ callout_lock_exit();
errno = errno_save;
return (res);
}
@@ -141,10 +141,10 @@ _dgettext(const char *domain, const char *msg_id)
char *res;
int errno_save = errno;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT((char *)msg_id);
res = _real_gettext_u(domain, msg_id, NULL, 0, LC_MESSAGES, 0);
- atfork_lock_exit();
+ callout_lock_exit();
errno = errno_save;
return (res);
}
@@ -155,10 +155,10 @@ _dcgettext(const char *domain, const char *msg_id, const int category)
char *res;
int errno_save = errno;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT((char *)msg_id);
res = _real_gettext_u(domain, msg_id, NULL, 0, category, 0);
- atfork_lock_exit();
+ callout_lock_exit();
errno = errno_save;
return (res);
}
@@ -169,10 +169,10 @@ _ngettext(const char *msgid1, const char *msgid2, unsigned long int n)
char *res;
int errno_save = errno;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT((char *)msgid1);
res = _real_gettext_u(NULL, msgid1, msgid2, n, LC_MESSAGES, 1);
- atfork_lock_exit();
+ callout_lock_exit();
errno = errno_save;
return (res);
}
@@ -184,10 +184,10 @@ _dngettext(const char *domain, const char *msgid1, const char *msgid2,
char *res;
int errno_save = errno;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT((char *)msgid1);
res = _real_gettext_u(domain, msgid1, msgid2, n, LC_MESSAGES, 1);
- atfork_lock_exit();
+ callout_lock_exit();
errno = errno_save;
return (res);
}
@@ -199,10 +199,10 @@ _dcngettext(const char *domain, const char *msgid1, const char *msgid2,
char *res;
int errno_save = errno;
- atfork_lock_enter();
+ callout_lock_enter();
INIT_GT((char *)msgid1);
res = _real_gettext_u(domain, msgid1, msgid2, n, category, 1);
- atfork_lock_exit();
+ callout_lock_exit();
errno = errno_save;
return (res);
}
diff --git a/usr/src/lib/libc/port/i18n/wdresolve.c b/usr/src/lib/libc/port/i18n/wdresolve.c
index 66bea2e4ac..bb8d61c6c5 100644
--- a/usr/src/lib/libc/port/i18n/wdresolve.c
+++ b/usr/src/lib/libc/port/i18n/wdresolve.c
@@ -120,9 +120,9 @@ wdinit()
{
int res;
- atfork_lock_enter();
+ callout_lock_enter();
res = _wdinitialize();
- atfork_lock_exit();
+ callout_lock_exit();
return (res);
}
@@ -135,11 +135,11 @@ wdchkind(wchar_t wc)
{
int i;
- atfork_lock_enter();
+ callout_lock_enter();
if (!initialized)
(void) _wdinitialize();
i = (*wdchknd)(wc);
- atfork_lock_exit();
+ callout_lock_exit();
return (i);
}
static int
@@ -170,15 +170,15 @@ wdbindf(wchar_t wc1, wchar_t wc2, int type)
{
int i;
- atfork_lock_enter();
+ callout_lock_enter();
if (!initialized)
(void) _wdinitialize();
if (!iswprint(wc1) || !iswprint(wc2)) {
- atfork_lock_exit();
+ callout_lock_exit();
return (-1);
}
i = (*wdbdg)(wc1, wc2, type);
- atfork_lock_exit();
+ callout_lock_exit();
return (i);
}
/*ARGSUSED*/
@@ -203,15 +203,15 @@ wddelim(wchar_t wc1, wchar_t wc2, int type)
{
wchar_t *i;
- atfork_lock_enter();
+ callout_lock_enter();
if (!initialized)
(void) _wdinitialize();
if (!iswprint(wc1) || !iswprint(wc2)) {
- atfork_lock_exit();
+ callout_lock_exit();
return ((wchar_t *)L"");
}
i = (*wddlm)(wc1, wc2, type);
- atfork_lock_exit();
+ callout_lock_exit();
return (i);
}
/*ARGSUSED*/
@@ -230,7 +230,7 @@ mcfiller(void)
{
wchar_t fillerchar;
- atfork_lock_enter();
+ callout_lock_enter();
if (!initialized)
(void) _wdinitialize();
if (mcfllr) {
@@ -238,11 +238,11 @@ mcfiller(void)
if (!fillerchar)
fillerchar = (wchar_t)'~';
if (iswprint(fillerchar)) {
- atfork_lock_exit();
+ callout_lock_exit();
return (fillerchar);
}
}
- atfork_lock_exit();
+ callout_lock_exit();
return ((wchar_t)'~');
}
@@ -254,14 +254,14 @@ mcfiller(void)
int
mcwrap(void)
{
- atfork_lock_enter();
+ callout_lock_enter();
if (!initialized)
(void) _wdinitialize();
if (mcwrp)
if ((*mcwrp)() == 0) {
- atfork_lock_exit();
+ callout_lock_exit();
return (0);
}
- atfork_lock_exit();
+ callout_lock_exit();
return (1);
}
diff --git a/usr/src/lib/libc/port/threads/scalls.c b/usr/src/lib/libc/port/threads/scalls.c
index 2cbe81bec9..b2bc017ae9 100644
--- a/usr/src/lib/libc/port/threads/scalls.c
+++ b/usr/src/lib/libc/port/threads/scalls.c
@@ -35,28 +35,31 @@
#include <sys/uio.h>
/*
+ * atfork_lock protects the pthread_atfork() data structures.
+ *
* fork_lock does double-duty. Not only does it (and atfork_lock)
* serialize calls to fork() and forkall(), but it also serializes calls
* to thr_suspend() and thr_continue() (because fork() and forkall() also
* suspend and continue other threads and they want no competition).
*
- * atfork_lock also does double-duty. Not only does it protect the
- * pthread_atfork() data structures, but it also serializes I18N calls
- * to functions in dlopen()ed L10N objects. These functions can do
- * anything, including call malloc() and free(). Such calls are not
- * fork-safe when protected by an ordinary mutex because, with an
- * interposed malloc library present, there would be a lock ordering
- * violation due to the pthread_atfork() prefork function in the
- * interposition library acquiring its malloc lock(s) before the
+ * Functions called in dlopen()ed L10N objects can do anything, including
+ * call malloc() and free(). Such calls are not fork-safe when protected
+ * by an ordinary mutex that is acquired in libc's prefork processing
+ * because, with an interposed malloc library present, there would be a
+ * lock ordering violation due to the pthread_atfork() prefork function
+ * in the interposition library acquiring its malloc lock(s) before the
* ordinary mutex in libc being acquired by libc's prefork functions.
*
- * Within libc, calls to malloc() and free() are fork-safe only if the
- * calls are made while holding no other libc locks. This covers almost
- * all of libc's malloc() and free() calls. For those libc code paths,
- * such as the above-mentioned I18N calls, that require serialization and
- * that may call malloc() or free(), libc uses atfork_lock_enter() to perform
- * the serialization. This works because atfork_lock is acquired by fork()
- * before any of the pthread_atfork() prefork functions are called.
+ * Within libc, calls to malloc() and free() are fork-safe if the calls
+ * are made while holding no other libc locks. This covers almost all
+ * of libc's malloc() and free() calls. For those libc code paths, such
+ * as the above-mentioned L10N calls, that require serialization and that
+ * may call malloc() or free(), libc uses callout_lock_enter() to perform
+ * the serialization. This works because callout_lock is not acquired as
+ * part of running the pthread_atfork() prefork handlers (to avoid the
+ * lock ordering violation described above). Rather, it is simply
+ * reinitialized in postfork1_child() to cover the case that some
+ * now-defunct thread might have been suspended while holding it.
*/
void
@@ -74,17 +77,17 @@ fork_lock_exit(void)
}
void
-atfork_lock_enter(void)
+callout_lock_enter(void)
{
ASSERT(curthread->ul_critical == 0);
- (void) _private_mutex_lock(&curthread->ul_uberdata->atfork_lock);
+ (void) _private_mutex_lock(&curthread->ul_uberdata->callout_lock);
}
void
-atfork_lock_exit(void)
+callout_lock_exit(void)
{
ASSERT(curthread->ul_critical == 0);
- (void) _private_mutex_unlock(&curthread->ul_uberdata->atfork_lock);
+ (void) _private_mutex_unlock(&curthread->ul_uberdata->callout_lock);
}
#pragma weak forkx = _private_forkx
diff --git a/usr/src/lib/libc/port/threads/thr.c b/usr/src/lib/libc/port/threads/thr.c
index ad6ba56227..8d105fac08 100644
--- a/usr/src/lib/libc/port/threads/thr.c
+++ b/usr/src/lib/libc/port/threads/thr.c
@@ -76,6 +76,7 @@ uberdata_t __uberdata = {
{ DEFAULTMUTEX, NULL, 0 }, /* link_lock */
{ RECURSIVEMUTEX, NULL, 0 }, /* fork_lock */
{ RECURSIVEMUTEX, NULL, 0 }, /* atfork_lock */
+ { RECURSIVEMUTEX, NULL, 0 }, /* callout_lock */
{ DEFAULTMUTEX, NULL, 0 }, /* tdb_hash_lock */
{ 0, }, /* tdb_hash_lock_stats */
{ { 0 }, }, /* siguaction[NSIG] */
@@ -1630,6 +1631,13 @@ postfork1_child()
self->ul_lwpid = __lwp_self();
hash_in_unlocked(self, TIDHASH(self->ul_lwpid, udp), udp);
+ /*
+ * Some thread in the parent might have been suspended while
+ * holding udp->callout_lock. Reinitialize the child's copy.
+ */
+ _private_mutex_init(&udp->callout_lock,
+ USYNC_THREAD | LOCK_RECURSIVE, NULL);
+
/* no one in the child is on a sleep queue; reinitialize */
if (udp->queue_head) {
(void) _private_memset(udp->queue_head, 0,