diff options
author | davidxu <davidxu@FreeBSD.org> | 2008-04-01 06:56:11 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2008-04-01 06:56:11 +0000 |
commit | 09e95ab21c092ac94a8bffaf2c60bcdf14566c26 (patch) | |
tree | d737ce96ac79dbb43961af2617bc7b745801d30f /lib | |
parent | 111802a962883418b89f19ea37fb8d91d91909a1 (diff) | |
download | FreeBSD-src-09e95ab21c092ac94a8bffaf2c60bcdf14566c26.zip FreeBSD-src-09e95ab21c092ac94a8bffaf2c60bcdf14566c26.tar.gz |
Normally, we are often reading local time rather than setting time zone,
replace mutex with rwlock, this should eliminate lock contention in
most cases.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/stdtime/localtime.c | 85 |
1 files changed, 63 insertions, 22 deletions
diff --git a/lib/libc/stdtime/localtime.c b/lib/libc/stdtime/localtime.c index bbffea5..5928943 100644 --- a/lib/libc/stdtime/localtime.c +++ b/lib/libc/stdtime/localtime.c @@ -34,6 +34,21 @@ __FBSDID("$FreeBSD$"); #define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) #define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) +#define _RWLOCK_RDLOCK(x) \ + do { \ + if (__isthreaded) _pthread_rwlock_rdlock(x); \ + } while (0) + +#define _RWLOCK_WRLOCK(x) \ + do { \ + if (__isthreaded) _pthread_rwlock_wrlock(x); \ + } while (0) + +#define _RWLOCK_UNLOCK(x) \ + do { \ + if (__isthreaded) _pthread_rwlock_unlock(x); \ + } while (0) + /* ** SunOS 4.1.1 headers lack O_BINARY. */ @@ -196,7 +211,7 @@ static struct state gmtmem; static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; static int gmt_is_set; -static pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t lcl_rwlock = PTHREAD_RWLOCK_INITIALIZER; static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER; char * tzname[2] = { @@ -949,10 +964,18 @@ struct state * const sp; } static void -tzsetwall_basic(void) +tzsetwall_basic(int rdlocked) { - if (lcl_is_set < 0) + if (!rdlocked) + _RWLOCK_RDLOCK(&lcl_rwlock); + if (lcl_is_set < 0) { + if (!rdlocked) + _RWLOCK_UNLOCK(&lcl_rwlock); return; + } + _RWLOCK_UNLOCK(&lcl_rwlock); + + _RWLOCK_WRLOCK(&lcl_rwlock); lcl_is_set = -1; #ifdef ALL_STATE @@ -960,6 +983,9 @@ tzsetwall_basic(void) lclptr = (struct state *) malloc(sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ + _RWLOCK_UNLOCK(&lcl_rwlock); + if (rdlocked) + _RWLOCK_RDLOCK(&lcl_rwlock); return; } } @@ -967,29 +993,39 @@ tzsetwall_basic(void) if (tzload((char *) NULL, lclptr) != 0) gmtload(lclptr); settzname(); + _RWLOCK_UNLOCK(&lcl_rwlock); + + if (rdlocked) + _RWLOCK_RDLOCK(&lcl_rwlock); } void tzsetwall(void) { - _MUTEX_LOCK(&lcl_mutex); - tzsetwall_basic(); - _MUTEX_UNLOCK(&lcl_mutex); + tzsetwall_basic(0); } static void -tzset_basic(void) +tzset_basic(int rdlocked) { const char * name; name = getenv("TZ"); if (name == NULL) { - tzsetwall_basic(); + tzsetwall_basic(rdlocked); return; } - if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) + if (!rdlocked) + _RWLOCK_RDLOCK(&lcl_rwlock); + if (lcl_is_set > 0 && strcmp(lcl_TZname, name) == 0) { + if (!rdlocked) + _RWLOCK_UNLOCK(&lcl_rwlock); return; + } + _RWLOCK_UNLOCK(&lcl_rwlock); + + _RWLOCK_WRLOCK(&lcl_rwlock); lcl_is_set = strlen(name) < sizeof lcl_TZname; if (lcl_is_set) (void) strcpy(lcl_TZname, name); @@ -999,6 +1035,9 @@ tzset_basic(void) lclptr = (struct state *) malloc(sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ + _RWLOCK_UNLOCK(&lcl_rwlock); + if (rdlocked) + _RWLOCK_RDLOCK(&lcl_rwlock); return; } } @@ -1018,14 +1057,16 @@ tzset_basic(void) if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0) (void) gmtload(lclptr); settzname(); + _RWLOCK_UNLOCK(&lcl_rwlock); + + if (rdlocked) + _RWLOCK_RDLOCK(&lcl_rwlock); } void tzset(void) { - _MUTEX_LOCK(&lcl_mutex); - tzset_basic(); - _MUTEX_UNLOCK(&lcl_mutex); + tzset_basic(0); } /* @@ -1110,13 +1151,13 @@ const time_t * const timep; return(NULL); _pthread_setspecific(localtime_key, p_tm); } - _pthread_mutex_lock(&lcl_mutex); - tzset_basic(); + _RWLOCK_RDLOCK(&lcl_rwlock); + tzset_basic(1); localsub(timep, 0L, p_tm); - _pthread_mutex_unlock(&lcl_mutex); + _RWLOCK_UNLOCK(&lcl_rwlock); return(p_tm); } else { - tzset_basic(); + tzset_basic(0); localsub(timep, 0L, &tm); return(&tm); } @@ -1131,10 +1172,10 @@ localtime_r(timep, tm) const time_t * const timep; struct tm * tm; { - _MUTEX_LOCK(&lcl_mutex); - tzset_basic(); + _RWLOCK_RDLOCK(&lcl_rwlock); + tzset_basic(1); localsub(timep, 0L, tm); - _MUTEX_UNLOCK(&lcl_mutex); + _RWLOCK_UNLOCK(&lcl_rwlock); return tm; } @@ -1686,10 +1727,10 @@ mktime(tmp) struct tm * const tmp; { time_t mktime_return_value; - _MUTEX_LOCK(&lcl_mutex); - tzset_basic(); + _RWLOCK_RDLOCK(&lcl_rwlock); + tzset_basic(1); mktime_return_value = time1(tmp, localsub, 0L); - _MUTEX_UNLOCK(&lcl_mutex); + _RWLOCK_UNLOCK(&lcl_rwlock); return(mktime_return_value); } |