OSDN Git Service

Add in thread locking for tzset() and associated data. Also, fix a bug so
authorManuel Novoa III <mjn3@codepoet.org>
Tue, 18 Jun 2002 10:03:43 +0000 (10:03 -0000)
committerManuel Novoa III <mjn3@codepoet.org>
Tue, 18 Jun 2002 10:03:43 +0000 (10:03 -0000)
that localtime_r() calls tzset() to initialize/update timezone data.

libc/misc/time/time.c

index 4371a9c..409be32 100644 (file)
@@ -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)
                ) {