diff options
Diffstat (limited to 'libc/misc/time/time.c')
| -rw-r--r-- | libc/misc/time/time.c | 47 | 
1 files changed, 42 insertions, 5 deletions
| diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c index 4371a9cfd..409be3247 100644 --- a/libc/misc/time/time.c +++ b/libc/misc/time/time.c @@ -69,8 +69,6 @@   * TODO - Implement getdate? tzfile? struct tm extensions?   *   * TODO - Rework _time_mktime to remove the dependency on long long. - * - * TODO - Make tzset and _time_tzinfo refs threadsafe.   */  #define _GNU_SOURCE @@ -120,6 +118,22 @@ typedef struct {  	char tzname[TZNAME_MAX+1];  } rule_struct; +#ifdef __UCLIBC_HAS_THREADS__ + +#include <pthread.h> + +extern pthread_mutex_t _time_tzlock; + +#define TZLOCK		pthread_mutex_lock(&_time_tzlock) +#define TZUNLOCK	pthread_mutex_unlock(&_time_tzlock) + +#else + +#define TZLOCK		((void) 0) +#define TZUNLOCK	((void) 0) + +#endif +  extern rule_struct _time_tzinfo[2];  extern struct tm *_time_t2tm(const time_t *__restrict timer, @@ -409,7 +423,7 @@ struct tm *localtime(const time_t *timer)  {  	register struct tm *ptm = &__time_tm; -	tzset(); +	/* In this implementation, tzset() is called by localtime_r().  */  	localtime_r(timer, ptm);	/* Can return NULL... */ @@ -426,6 +440,8 @@ static const unsigned char day_cor[] = { /* non-leap */  /*	    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 */  }; +/* Note: timezone locking is done by localtime_r. */ +  static int tm_isdst(register const struct tm *__restrict ptm)  {  	register rule_struct *r = _time_tzinfo; @@ -494,6 +510,7 @@ static int tm_isdst(register const struct tm *__restrict ptm)  			++r;  		} while (++i < 2);  	} +  	return (isdst & 1);  } @@ -504,6 +521,10 @@ struct tm *localtime_r(register const time_t *__restrict timer,  	long offset;  	int days, dst; +	TZLOCK; + +	tzset(); +  	dst = 0;  	do {  		days = -7; @@ -523,6 +544,8 @@ struct tm *localtime_r(register const time_t *__restrict timer,  		++dst;  	} while ((result->tm_isdst = tm_isdst(result)) != 0); +	TZUNLOCK; +  	return result;  } @@ -849,6 +872,8 @@ size_t strftime(char *__restrict s, size_t maxsize,  					goto OUTPUT;  				} +				TZLOCK; +  				rsp = _time_tzinfo;  				if (timeptr->tm_isdst > 0) {  					++rsp; @@ -863,6 +888,7 @@ size_t strftime(char *__restrict s, size_t maxsize,  					}  #endif  					o_count = SIZE_MAX; +					TZUNLOCK;  					goto OUTPUT;  				} else {		/* z */  					*s = '+'; @@ -870,6 +896,7 @@ size_t strftime(char *__restrict s, size_t maxsize,  						tzo = -tzo;  						*s = '-';  					} +					TZUNLOCK;  					++s;  					--count; @@ -1378,6 +1405,10 @@ int daylight = 0;  long timezone = 0;  char *tzname[2] = { (char *) UTC, (char *) (UTC-1) }; +#ifdef __UCLIBC_HAS_THREADS__ +pthread_mutex_t _time_tzlock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#endif +  rule_struct _time_tzinfo[2];  static const char *getoffset(register const char *e, long *pn) @@ -1451,6 +1482,8 @@ void tzset(void)  	int n, count, f;  	char c; +	TZLOCK; +  	if (!(e = getenv(TZ)) || !*e) { /* Not set or set to empty string. */  	ILLEGAL:					/* TODO: Clean up the following... */  		s = _time_tzinfo[0].tzname; @@ -1583,6 +1616,8 @@ void tzset(void)  	tzname[1] = _time_tzinfo[1].tzname;  	daylight = !!new_rules[1].tzname[0];  	timezone = new_rules[0].gmt_offset; + +	TZUNLOCK;  }  #endif @@ -1823,8 +1858,8 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	/* TODO - check */  	d = p[5] - 1;  	days = -719163L + d*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]); -	secs = p[0] + 60*( p[1] + 60*((long)(p[2])) ); - +	secs = p[0] + 60*( p[1] + 60*((long)(p[2])) ) +		+ _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset;  	if (secs < 0) {  		secs += 120009600L;  		days -= 1389; @@ -1834,6 +1869,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  	}  	secs += (days * 86400L);  #else +	TZLOCK;  	d = p[5] - 1;  	d = -719163L + d*365 + (d/4) - (d/100) + (d/400);  	secs = p[0] @@ -1842,6 +1878,7 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)  			   + 60*(p[2]  					 + 24*(((146073L * ((long long)(p[6])) + d)  							+ p[3]) + p[7]))); +	TZUNLOCK;  	if (((unsigned long long)(secs - LONG_MIN))  		> (((unsigned long long)LONG_MAX) - LONG_MIN)  		) { | 
