Mercurial > illumos > illumos-gate
changeset 4914:8e96a2e351b2
6593908 fixes for 6518780 cause more deadlocks
author | raf |
---|---|
date | Mon, 20 Aug 2007 17:36:02 -0700 |
parents | 8d95fa5f1def |
children | b6d0b03690de |
files | usr/src/lib/libc/inc/libc.h usr/src/lib/libc/port/gen/getnetgrent.c usr/src/lib/libc/port/gen/ttyname.c usr/src/lib/libc/port/i18n/gettext.c usr/src/lib/libc/port/i18n/wdresolve.c usr/src/lib/libc/port/threads/scalls.c |
diffstat | 6 files changed, 102 insertions(+), 76 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libc/inc/libc.h Mon Aug 20 17:13:57 2007 -0700 +++ b/usr/src/lib/libc/inc/libc.h Mon Aug 20 17:36:02 2007 -0700 @@ -68,8 +68,8 @@ extern thread_t thr_self(void); extern int mutex_lock(mutex_t *mp); extern int mutex_unlock(mutex_t *mp); -extern void fork_lock_enter(void); -extern void fork_lock_exit(void); +extern void atfork_lock_enter(void); +extern void atfork_lock_exit(void); extern void *lmalloc(size_t); extern void lfree(void *, size_t); extern void *libc_malloc(size_t);
--- a/usr/src/lib/libc/port/gen/getnetgrent.c Mon Aug 20 17:13:57 2007 -0700 +++ b/usr/src/lib/libc/port/gen/getnetgrent.c Mon Aug 20 17:36:02 2007 -0700 @@ -137,7 +137,7 @@ * 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 fork_lock_enter() instead. + * So we use the brute-force atfork_lock_enter() instead. */ static nss_backend_t *getnetgrent_backend; @@ -151,7 +151,7 @@ netgroup = ""; } - fork_lock_enter(); + atfork_lock_enter(); be = getnetgrent_backend; if (be != NULL && NSS_INVOKE_DBOP(be, NSS_DBOP_SETENT, (void *)netgroup) != NSS_SUCCESS) { @@ -168,7 +168,7 @@ be = args.iterator; } getnetgrent_backend = be; - fork_lock_exit(); + atfork_lock_exit(); return (0); } @@ -186,12 +186,12 @@ args.buflen = buflen; args.status = NSS_NETGR_NO; - fork_lock_enter(); + atfork_lock_enter(); if (getnetgrent_backend != 0) { (void) NSS_INVOKE_DBOP(getnetgrent_backend, NSS_DBOP_GETENT, &args); } - fork_lock_exit(); + atfork_lock_exit(); if (args.status == NSS_NETGR_FOUND) { *machinep = args.retp[NSS_NETGR_MACHINE]; @@ -219,13 +219,13 @@ int endnetgrent() { - fork_lock_enter(); + atfork_lock_enter(); if (getnetgrent_backend != 0) { (void) NSS_INVOKE_DBOP(getnetgrent_backend, NSS_DBOP_DESTRUCTOR, 0); getnetgrent_backend = 0; } - fork_lock_exit(); + atfork_lock_exit(); nss_delete(&db_root); /* === ? */ NSS_XbyY_FREE(&buf); return (0);
--- a/usr/src/lib/libc/port/gen/ttyname.c Mon Aug 20 17:13:57 2007 -0700 +++ b/usr/src/lib/libc/port/gen/ttyname.c Mon Aug 20 17:36:02 2007 -0700 @@ -213,9 +213,9 @@ /* * We can't use lmutex_lock() here because we call malloc()/free() - * and _libc_gettext(). Use the brute-force fork_lock_enter(). + * and _libc_gettext(). Use the brute-force atfork_lock_enter(). */ - fork_lock_enter(); + atfork_lock_enter(); /* * match special cases @@ -320,7 +320,7 @@ else retval = NULL; out: retval = (retval ? strcpy(buffer, retval) : NULL); - fork_lock_exit(); + atfork_lock_exit(); return (retval); }
--- a/usr/src/lib/libc/port/i18n/gettext.c Mon Aug 20 17:13:57 2007 -0700 +++ b/usr/src/lib/libc/port/i18n/gettext.c Mon Aug 20 17:36:02 2007 -0700 @@ -59,7 +59,7 @@ if (global_gt) \ global_gt->cur_domain = (char *)default_domain; \ else { \ - fork_lock_exit(); \ + atfork_lock_exit(); \ return ((def)); \ } \ } @@ -73,10 +73,10 @@ { char *res; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT(NULL); res = _real_bindtextdomain_u(domain, binding, TP_BINDING); - fork_lock_exit(); + atfork_lock_exit(); return (res); } @@ -85,10 +85,10 @@ { char *res; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT(NULL); res = _real_bindtextdomain_u(domain, codeset, TP_CODESET); - fork_lock_exit(); + atfork_lock_exit(); return (res); } @@ -102,14 +102,14 @@ char *res; char tmp_domain[TEXTDOMAINMAX + 1]; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT(NULL); res = _textdomain_u(domain, tmp_domain); if (res == NULL) { - fork_lock_exit(); + atfork_lock_exit(); return (NULL); } - fork_lock_exit(); + atfork_lock_exit(); return (CURRENT_DOMAIN(global_gt)); } @@ -123,10 +123,10 @@ char *res; int errno_save = errno; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT((char *)msg_id); res = _real_gettext_u(NULL, msg_id, NULL, 0, LC_MESSAGES, 0); - fork_lock_exit(); + atfork_lock_exit(); errno = errno_save; return (res); } @@ -141,10 +141,10 @@ char *res; int errno_save = errno; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT((char *)msg_id); res = _real_gettext_u(domain, msg_id, NULL, 0, LC_MESSAGES, 0); - fork_lock_exit(); + atfork_lock_exit(); errno = errno_save; return (res); } @@ -155,10 +155,10 @@ char *res; int errno_save = errno; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT((char *)msg_id); res = _real_gettext_u(domain, msg_id, NULL, 0, category, 0); - fork_lock_exit(); + atfork_lock_exit(); errno = errno_save; return (res); } @@ -169,10 +169,10 @@ char *res; int errno_save = errno; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT((char *)msgid1); res = _real_gettext_u(NULL, msgid1, msgid2, n, LC_MESSAGES, 1); - fork_lock_exit(); + atfork_lock_exit(); errno = errno_save; return (res); } @@ -184,10 +184,10 @@ char *res; int errno_save = errno; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT((char *)msgid1); res = _real_gettext_u(domain, msgid1, msgid2, n, LC_MESSAGES, 1); - fork_lock_exit(); + atfork_lock_exit(); errno = errno_save; return (res); } @@ -199,10 +199,10 @@ char *res; int errno_save = errno; - fork_lock_enter(); + atfork_lock_enter(); INIT_GT((char *)msgid1); res = _real_gettext_u(domain, msgid1, msgid2, n, category, 1); - fork_lock_exit(); + atfork_lock_exit(); errno = errno_save; return (res); }
--- a/usr/src/lib/libc/port/i18n/wdresolve.c Mon Aug 20 17:13:57 2007 -0700 +++ b/usr/src/lib/libc/port/i18n/wdresolve.c Mon Aug 20 17:36:02 2007 -0700 @@ -120,9 +120,9 @@ { int res; - fork_lock_enter(); + atfork_lock_enter(); res = _wdinitialize(); - fork_lock_exit(); + atfork_lock_exit(); return (res); } @@ -135,11 +135,11 @@ { int i; - fork_lock_enter(); + atfork_lock_enter(); if (!initialized) (void) _wdinitialize(); i = (*wdchknd)(wc); - fork_lock_exit(); + atfork_lock_exit(); return (i); } static int @@ -170,15 +170,15 @@ { int i; - fork_lock_enter(); + atfork_lock_enter(); if (!initialized) (void) _wdinitialize(); if (!iswprint(wc1) || !iswprint(wc2)) { - fork_lock_exit(); + atfork_lock_exit(); return (-1); } i = (*wdbdg)(wc1, wc2, type); - fork_lock_exit(); + atfork_lock_exit(); return (i); } /*ARGSUSED*/ @@ -203,15 +203,15 @@ { wchar_t *i; - fork_lock_enter(); + atfork_lock_enter(); if (!initialized) (void) _wdinitialize(); if (!iswprint(wc1) || !iswprint(wc2)) { - fork_lock_exit(); + atfork_lock_exit(); return ((wchar_t *)L""); } i = (*wddlm)(wc1, wc2, type); - fork_lock_exit(); + atfork_lock_exit(); return (i); } /*ARGSUSED*/ @@ -230,7 +230,7 @@ { wchar_t fillerchar; - fork_lock_enter(); + atfork_lock_enter(); if (!initialized) (void) _wdinitialize(); if (mcfllr) { @@ -238,11 +238,11 @@ if (!fillerchar) fillerchar = (wchar_t)'~'; if (iswprint(fillerchar)) { - fork_lock_exit(); + atfork_lock_exit(); return (fillerchar); } } - fork_lock_exit(); + atfork_lock_exit(); return ((wchar_t)'~'); } @@ -254,14 +254,14 @@ int mcwrap(void) { - fork_lock_enter(); + atfork_lock_enter(); if (!initialized) (void) _wdinitialize(); if (mcwrp) if ((*mcwrp)() == 0) { - fork_lock_exit(); + atfork_lock_exit(); return (0); } - fork_lock_exit(); + atfork_lock_exit(); return (1); }
--- a/usr/src/lib/libc/port/threads/scalls.c Mon Aug 20 17:13:57 2007 -0700 +++ b/usr/src/lib/libc/port/threads/scalls.c Mon Aug 20 17:36:02 2007 -0700 @@ -35,28 +35,56 @@ #include <sys/uio.h> /* - * fork_lock_enter() does triple-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() (fork() and forkall() also suspend other - * threads), and furthermore it serializes I18N calls to functions in other - * dlopen()ed L10N objects that might be calling malloc()/free(). + * 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 + * 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. */ + void fork_lock_enter(void) { - ulwp_t *self = curthread; - - ASSERT(self->ul_critical == 0); - (void) _private_mutex_lock(&self->ul_uberdata->fork_lock); + ASSERT(curthread->ul_critical == 0); + (void) _private_mutex_lock(&curthread->ul_uberdata->fork_lock); } void fork_lock_exit(void) { - ulwp_t *self = curthread; + ASSERT(curthread->ul_critical == 0); + (void) _private_mutex_unlock(&curthread->ul_uberdata->fork_lock); +} - ASSERT(self->ul_critical == 0); - (void) _private_mutex_unlock(&self->ul_uberdata->fork_lock); +void +atfork_lock_enter(void) +{ + ASSERT(curthread->ul_critical == 0); + (void) _private_mutex_lock(&curthread->ul_uberdata->atfork_lock); +} + +void +atfork_lock_exit(void) +{ + ASSERT(curthread->ul_critical == 0); + (void) _private_mutex_unlock(&curthread->ul_uberdata->atfork_lock); } #pragma weak forkx = _private_forkx @@ -97,7 +125,6 @@ return (-1); } self->ul_fork = 1; - (void) _private_mutex_lock(&udp->atfork_lock); /* * The functions registered by pthread_atfork() are defined by @@ -105,20 +132,18 @@ * internal lmutex_lock()-acquired locks while invoking them. * We hold only udp->atfork_lock to protect the atfork linkages. * If one of these pthread_atfork() functions attempts to fork - * or to call pthread_atfork(), it will detect the error and - * fail with EDEADLK. Otherwise, the pthread_atfork() functions - * are free to do anything they please (except they will not - * receive any signals). + * or to call pthread_atfork(), libc will detect the error and + * fail the call with EDEADLK. Otherwise, the pthread_atfork() + * functions are free to do anything they please (except they + * will not receive any signals). */ + (void) _private_mutex_lock(&udp->atfork_lock); _prefork_handler(); /* * Block every other thread attempting thr_suspend() or thr_continue(). - * This also blocks every other thread attempting calls to I18N - * functions in dlopen()ed L10N objects, but this is benign; - * the other threads will soon be suspended anyway. */ - fork_lock_enter(); + (void) _private_mutex_lock(&udp->fork_lock); /* * Block all signals. @@ -131,8 +156,8 @@ /* * This suspends all threads but this one, leaving them * suspended outside of any critical regions in the library. - * Thus, we are assured that no library locks are held - * while we invoke fork() from the current thread. + * Thus, we are assured that no lmutex_lock()-acquired library + * locks are held while we invoke fork() from the current thread. */ suspend_fork(); @@ -154,13 +179,13 @@ unregister_locks(); postfork1_child(); restore_signals(self); - fork_lock_exit(); + (void) _private_mutex_unlock(&udp->fork_lock); _postfork_child_handler(); } else { /* restart all threads that were suspended for fork() */ continue_fork(0); restore_signals(self); - fork_lock_exit(); + (void) _private_mutex_unlock(&udp->fork_lock); _postfork_parent_handler(); } @@ -218,8 +243,8 @@ return (-1); } self->ul_fork = 1; - - fork_lock_enter(); + (void) _private_mutex_lock(&udp->atfork_lock); + (void) _private_mutex_lock(&udp->fork_lock); block_all_signals(self); suspend_fork(); @@ -237,7 +262,8 @@ continue_fork(0); } restore_signals(self); - fork_lock_exit(); + (void) _private_mutex_unlock(&udp->fork_lock); + (void) _private_mutex_unlock(&udp->atfork_lock); self->ul_fork = 0; sigon(self);