diff options
author | davidxu <davidxu@FreeBSD.org> | 2008-03-20 09:35:44 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2008-03-20 09:35:44 +0000 |
commit | 8326c062223a38eeb1d4cfb0ddf32a8fee20b743 (patch) | |
tree | 92134ce2740d526d06bcd2e56d04c37d75de77d2 | |
parent | b24f39223eb2d3d27b88fce15ebb098c2082cff3 (diff) | |
download | FreeBSD-src-8326c062223a38eeb1d4cfb0ddf32a8fee20b743.zip FreeBSD-src-8326c062223a38eeb1d4cfb0ddf32a8fee20b743.tar.gz |
Preserve application code's errno in rtld locking code, it attemps to keep
any case safe.
-rw-r--r-- | lib/libthr/thread/thr_rtld.c | 33 |
1 files changed, 31 insertions, 2 deletions
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c index 14fb127..411e995 100644 --- a/lib/libthr/thread/thr_rtld.c +++ b/lib/libthr/thread/thr_rtld.c @@ -36,6 +36,9 @@ #include "rtld_lock.h" #include "thr_private.h" +#undef errno +extern int errno; + #define CACHE_LINE_SIZE 64 #define WAFLAG 0x1 #define RC_INCR 0x2 @@ -88,20 +91,38 @@ _thr_rtld_lock_destroy(void *lock) free(l->base); } +#define SAVE_ERRNO() { \ + if (curthread != _thr_initial) \ + errsave = curthread->error; \ + else \ + errsave = errno; \ +} + +#define RESTORE_ERRNO() { \ + if (curthread != _thr_initial) \ + curthread->error = errsave; \ + else \ + errno = errsave; \ +} + static void _thr_rtld_rlock_acquire(void *lock) { struct pthread *curthread; struct rtld_lock *l; long v; + int errsave; curthread = _get_curthread(); + SAVE_ERRNO(); l = (struct rtld_lock *)lock; THR_CRITICAL_ENTER(curthread); atomic_add_acq_int(&l->lock, RC_INCR); - if (!(l->lock & WAFLAG)) + if (!(l->lock & WAFLAG)) { + RESTORE_ERRNO(); return; + } v = l->rd_cv; atomic_add_int(&l->rd_waiters, 1); while (l->lock & WAFLAG) { @@ -109,6 +130,7 @@ _thr_rtld_rlock_acquire(void *lock) v = l->rd_cv; } atomic_add_int(&l->rd_waiters, -1); + RESTORE_ERRNO(); } static void @@ -117,14 +139,18 @@ _thr_rtld_wlock_acquire(void *lock) struct pthread *curthread; struct rtld_lock *l; long v; + int errsave; curthread = _get_curthread(); + SAVE_ERRNO(); l = (struct rtld_lock *)lock; _thr_signal_block(curthread); for (;;) { - if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG)) + if (atomic_cmpset_acq_int(&l->lock, 0, WAFLAG)) { + RESTORE_ERRNO(); return; + } v = l->wr_cv; atomic_add_int(&l->wr_waiters, 1); while (l->lock != 0) { @@ -140,8 +166,10 @@ _thr_rtld_lock_release(void *lock) { struct pthread *curthread; struct rtld_lock *l; + int errsave; curthread = _get_curthread(); + SAVE_ERRNO(); l = (struct rtld_lock *)lock; if ((l->lock & WAFLAG) == 0) { @@ -162,6 +190,7 @@ _thr_rtld_lock_release(void *lock) } _thr_signal_unblock(curthread); } + RESTORE_ERRNO(); } static int |