Loading...
stdtime/FreeBSD/localtime.c Libc-583 Libc-763.13
--- 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);
 }