Loading...
--- Libc/Libc-583/stdtime/FreeBSD/localtime.c
+++ Libc/Libc-763.13/stdtime/FreeBSD/localtime.c
@@ -9,7 +9,7 @@
static char elsieid[] __unused = "@(#)localtime.c 7.78";
#endif /* !defined NOID */
#endif /* !defined lint */
-__FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.40 2004/08/24 00:15:37 peter Exp $");
+__FBSDID("$FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.43 2008/04/01 06:56:11 davidxu Exp $");
/*
** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
@@ -33,6 +33,21 @@
#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 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 @@
}
static void
-tzsetwall_basic(void)
-{
- if (lcl_is_set < 0)
+tzsetwall_basic(int rdlocked)
+{
+ 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 @@
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 @@
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 @@
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 @@
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);
}
/*
@@ -1093,14 +1134,16 @@
struct tm *p_tm;
if (__isthreaded != 0) {
- _pthread_mutex_lock(&localtime_mutex);
if (localtime_key < 0) {
- if (_pthread_key_create(&localtime_key, free) < 0) {
- _pthread_mutex_unlock(&localtime_mutex);
- return(NULL);
+ _pthread_mutex_lock(&localtime_mutex);
+ if (localtime_key < 0) {
+ if (_pthread_key_create(&localtime_key, free) < 0) {
+ _pthread_mutex_unlock(&localtime_mutex);
+ return(NULL);
+ }
}
- }
- _pthread_mutex_unlock(&localtime_mutex);
+ _pthread_mutex_unlock(&localtime_mutex);
+ }
p_tm = _pthread_getspecific(localtime_key);
if (p_tm == NULL) {
if ((p_tm = (struct tm *)malloc(sizeof(struct tm)))
@@ -1108,13 +1151,13 @@
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);
}
@@ -1129,10 +1172,10 @@
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;
}
@@ -1146,16 +1189,18 @@
const long offset;
struct tm * const tmp;
{
- _MUTEX_LOCK(&gmt_mutex);
if (!gmt_is_set) {
- gmt_is_set = TRUE;
+ _MUTEX_LOCK(&gmt_mutex);
+ if (!gmt_is_set) {
#ifdef ALL_STATE
- gmtptr = (struct state *) malloc(sizeof *gmtptr);
- if (gmtptr != NULL)
+ gmtptr = (struct state *) malloc(sizeof *gmtptr);
+ if (gmtptr != NULL)
#endif /* defined ALL_STATE */
- gmtload(gmtptr);
- }
- _MUTEX_UNLOCK(&gmt_mutex);
+ gmtload(gmtptr);
+ gmt_is_set = TRUE;
+ }
+ _MUTEX_UNLOCK(&gmt_mutex);
+ }
timesub(timep, offset, gmtptr, tmp);
#ifdef TM_ZONE
/*
@@ -1187,14 +1232,16 @@
struct tm *p_tm;
if (__isthreaded != 0) {
- _pthread_mutex_lock(&gmtime_mutex);
if (gmtime_key < 0) {
- if (_pthread_key_create(&gmtime_key, free) < 0) {
- _pthread_mutex_unlock(&gmtime_mutex);
- return(NULL);
+ _pthread_mutex_lock(&gmtime_mutex);
+ if (gmtime_key < 0) {
+ if (_pthread_key_create(&gmtime_key, free) < 0) {
+ _pthread_mutex_unlock(&gmtime_mutex);
+ return(NULL);
+ }
}
- }
- _pthread_mutex_unlock(&gmtime_mutex);
+ _pthread_mutex_unlock(&gmtime_mutex);
+ }
/*
* Changed to follow POSIX.1 threads standard, which
* is what BSD currently has.
@@ -1518,8 +1565,8 @@
** If we have more than this, we will overflow tm_year for tmcomp().
** We should really return an error if we cannot represent it.
*/
- if (bits > 56)
- bits = 56;
+ if (bits > 48)
+ bits = 48;
/*
** If time_t is signed, then 0 is just above the median,
** assuming two's complement arithmetic.
@@ -1680,10 +1727,10 @@
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);
}