diff options
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r-- | usr/src/lib/libc/inc/libc.h | 4 | ||||
-rw-r--r-- | usr/src/lib/libc/inc/thr_uberdata.h | 7 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/getnetgrent.c | 14 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/ttyname.c | 6 | ||||
-rw-r--r-- | usr/src/lib/libc/port/i18n/gettext.c | 40 | ||||
-rw-r--r-- | usr/src/lib/libc/port/i18n/wdresolve.c | 32 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/scalls.c | 41 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/thr.c | 8 |
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, |