Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/unix/tclUnixTime.c @ 25

Last change on this file since 25 was 25, checked in by landauf, 16 years ago

added tcl to libs

File size: 15.2 KB
Line 
1/*
2 * tclUnixTime.c --
3 *
4 *      Contains Unix specific versions of Tcl functions that obtain time
5 *      values from the operating system.
6 *
7 * Copyright (c) 1995 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution of
10 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 *
12 * RCS: @(#) $Id: tclUnixTime.c,v 1.33 2007/12/13 15:28:42 dgp Exp $
13 */
14
15#include "tclInt.h"
16#include <locale.h>
17#if defined(TCL_WIDE_CLICKS) && defined(MAC_OSX_TCL)
18#include <mach/mach_time.h>
19#endif
20
21#define TM_YEAR_BASE 1900
22#define IsLeapYear(x)   (((x)%4 == 0) && ((x)%100 != 0 || (x)%400 == 0))
23
24/*
25 * TclpGetDate is coded to return a pointer to a 'struct tm'. For thread
26 * safety, this structure must be in thread-specific data. The 'tmKey'
27 * variable is the key to this buffer.
28 */
29
30static Tcl_ThreadDataKey tmKey;
31typedef struct ThreadSpecificData {
32    struct tm gmtime_buf;
33    struct tm localtime_buf;
34} ThreadSpecificData;
35
36/*
37 * If we fall back on the thread-unsafe versions of gmtime and localtime, use
38 * this mutex to try to protect them.
39 */
40
41TCL_DECLARE_MUTEX(tmMutex)
42
43static char *lastTZ = NULL;     /* Holds the last setting of the TZ
44                                 * environment variable, or an empty string if
45                                 * the variable was not set. */
46
47/*
48 * Static functions declared in this file.
49 */
50
51static void             SetTZIfNecessary(void);
52static void             CleanupMemory(ClientData clientData);
53static void             NativeScaleTime(Tcl_Time *timebuf,
54                            ClientData clientData);
55static void             NativeGetTime(Tcl_Time *timebuf,
56                            ClientData clientData);
57
58/*
59 * TIP #233 (Virtualized Time): Data for the time hooks, if any.
60 */
61
62Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime;
63Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime;
64ClientData tclTimeClientData = NULL;
65
66/*
67 *-----------------------------------------------------------------------------
68 *
69 * TclpGetSeconds --
70 *
71 *      This procedure returns the number of seconds from the epoch. On most
72 *      Unix systems the epoch is Midnight Jan 1, 1970 GMT.
73 *
74 * Results:
75 *      Number of seconds from the epoch.
76 *
77 * Side effects:
78 *      None.
79 *
80 *-----------------------------------------------------------------------------
81 */
82
83unsigned long
84TclpGetSeconds(void)
85{
86    return time(NULL);
87}
88
89/*
90 *-----------------------------------------------------------------------------
91 *
92 * TclpGetClicks --
93 *
94 *      This procedure returns a value that represents the highest resolution
95 *      clock available on the system. There are no garantees on what the
96 *      resolution will be. In Tcl we will call this value a "click". The
97 *      start time is also system dependant.
98 *
99 * Results:
100 *      Number of clicks from some start time.
101 *
102 * Side effects:
103 *      None.
104 *
105 *-----------------------------------------------------------------------------
106 */
107
108unsigned long
109TclpGetClicks(void)
110{
111    unsigned long now;
112
113#ifdef NO_GETTOD
114    if (tclGetTimeProcPtr != NativeGetTime) {
115        Tcl_Time time;
116
117        (*tclGetTimeProcPtr) (&time, tclTimeClientData);
118        now = time.sec*1000000 + time.usec;
119    } else {
120        /*
121         * A semi-NativeGetTime, specialized to clicks.
122         */
123        struct tms dummy;
124
125        now = (unsigned long) times(&dummy);
126    }
127#else
128    Tcl_Time time;
129
130    (*tclGetTimeProcPtr) (&time, tclTimeClientData);
131    now = time.sec*1000000 + time.usec;
132#endif
133
134    return now;
135}
136#ifdef TCL_WIDE_CLICKS
137
138/*
139 *-----------------------------------------------------------------------------
140 *
141 * TclpGetWideClicks --
142 *
143 *      This procedure returns a WideInt value that represents the highest
144 *      resolution clock available on the system. There are no garantees on
145 *      what the resolution will be. In Tcl we will call this value a "click".
146 *      The start time is also system dependant.
147 *
148 * Results:
149 *      Number of WideInt clicks from some start time.
150 *
151 * Side effects:
152 *      None.
153 *
154 *-----------------------------------------------------------------------------
155 */
156
157Tcl_WideInt
158TclpGetWideClicks(void)
159{
160    Tcl_WideInt now;
161
162    if (tclGetTimeProcPtr != NativeGetTime) {
163        Tcl_Time time;
164
165        (*tclGetTimeProcPtr) (&time, tclTimeClientData);
166        now = (Tcl_WideInt) (time.sec*1000000 + time.usec);
167    } else {
168#ifdef MAC_OSX_TCL
169        now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX);
170#else
171#error Wide high-resolution clicks not implemented on this platform
172#endif
173    }
174
175    return now;
176}
177
178/*
179 *-----------------------------------------------------------------------------
180 *
181 * TclpWideClicksToNanoseconds --
182 *
183 *      This procedure converts click values from the TclpGetWideClicks native
184 *      resolution to nanosecond resolution.
185 *
186 * Results:
187 *      Number of nanoseconds from some start time.
188 *
189 * Side effects:
190 *      None.
191 *
192 *-----------------------------------------------------------------------------
193 */
194
195double
196TclpWideClicksToNanoseconds(
197    Tcl_WideInt clicks)
198{
199    double nsec;
200
201    if (tclGetTimeProcPtr != NativeGetTime) {
202        nsec = clicks * 1000;
203    } else {
204#ifdef MAC_OSX_TCL
205        static mach_timebase_info_data_t tb;
206        static uint64_t maxClicksForUInt64;
207       
208        if (!tb.denom) {
209            mach_timebase_info(&tb);
210            maxClicksForUInt64 = UINT64_MAX / tb.numer;
211        }
212        if ((uint64_t) clicks < maxClicksForUInt64) {
213            nsec = ((uint64_t) clicks) * tb.numer / tb.denom;
214        } else {
215            nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom;
216        }
217#else
218#error Wide high-resolution clicks not implemented on this platform
219#endif
220    }
221
222    return nsec;
223}
224#endif /* TCL_WIDE_CLICKS */
225
226/*
227 *----------------------------------------------------------------------
228 *
229 * TclpGetTimeZone --
230 *
231 *      Determines the current timezone. The method varies wildly between
232 *      different platform implementations, so its hidden in this function.
233 *
234 * Results:
235 *      The return value is the local time zone, measured in minutes away from
236 *      GMT (-ve for east, +ve for west).
237 *
238 * Side effects:
239 *      None.
240 *
241 *----------------------------------------------------------------------
242 */
243
244int
245TclpGetTimeZone(
246    unsigned long currentTime)
247{
248    int timeZone;
249
250    /*
251     * We prefer first to use the time zone in "struct tm" if the structure
252     * contains such a member. Following that, we try to locate the external
253     * 'timezone' variable and use its value. If both of those methods fail,
254     * we attempt to convert a known time to local time and use the difference
255     * from UTC as the local time zone. In all cases, we need to undo any
256     * Daylight Saving Time adjustment.
257     */
258
259#if defined(HAVE_TM_TZADJ)
260#define TCL_GOT_TIMEZONE
261    /*
262     * Struct tm contains tm_tzadj - that value may be used.
263     */
264
265    time_t curTime = (time_t) currentTime;
266    struct tm *timeDataPtr = TclpLocaltime(&curTime);
267
268    timeZone = timeDataPtr->tm_tzadj / 60;
269    if (timeDataPtr->tm_isdst) {
270        timeZone += 60;
271    }
272#endif
273
274#if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE)
275#define TCL_GOT_TIMEZONE
276    /*
277     * Struct tm contains tm_gmtoff - that value may be used.
278     */
279
280    time_t curTime = (time_t) currentTime;
281    struct tm *timeDataPtr = TclpLocaltime(&curTime);
282
283    timeZone = -(timeDataPtr->tm_gmtoff / 60);
284    if (timeDataPtr->tm_isdst) {
285        timeZone += 60;
286    }
287#endif
288
289#if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ)
290#define TCL_GOT_TIMEZONE
291    /*
292     * The 'timezone' external var is present and may be used.
293     */
294
295    SetTZIfNecessary();
296
297    /*
298     * Note: this is not a typo in "timezone" below! See tzset documentation
299     * for details.
300     */
301
302    timeZone = timezone / 60;
303#endif
304
305#if !defined(TCL_GOT_TIMEZONE)
306#define TCL_GOT_TIMEZONE
307    /*
308     * Fallback - determine time zone with a known reference time.
309     */
310
311    time_t tt;
312    struct tm *stm;
313
314    tt = 849268800L;            /* 1996-11-29 12:00:00  GMT */
315    stm = TclpLocaltime(&tt);   /* eg 1996-11-29  6:00:00  CST6CDT */
316
317    /*
318     * The calculation below assumes a max of +12 or -12 hours from GMT.
319     */
320
321    timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min);
322    if (stm->tm_isdst) {
323        timeZone += 60;
324    }
325
326    /*
327     * Now have offset for our known reference time, eg +360 for CST6CDT.
328     */
329#endif
330
331#ifndef TCL_GOT_TIMEZONE
332    /*
333     * Cause fatal compile error, we don't know how to get timezone.
334     */
335
336#error autoconf did not figure out how to determine the timezone.
337#endif
338
339    return timeZone;
340}
341
342/*
343 *----------------------------------------------------------------------
344 *
345 * Tcl_GetTime --
346 *
347 *      Gets the current system time in seconds and microseconds since the
348 *      beginning of the epoch: 00:00 UCT, January 1, 1970.
349 *
350 *      This function is hooked, allowing users to specify their own virtual
351 *      system time.
352 *
353 * Results:
354 *      Returns the current time in timePtr.
355 *
356 * Side effects:
357 *      None.
358 *
359 *----------------------------------------------------------------------
360 */
361
362void
363Tcl_GetTime(
364    Tcl_Time *timePtr)          /* Location to store time information. */
365{
366    (*tclGetTimeProcPtr) (timePtr, tclTimeClientData);
367}
368
369/*
370 *----------------------------------------------------------------------
371 *
372 * TclpGetDate --
373 *
374 *      This function converts between seconds and struct tm. If useGMT is
375 *      true, then the returned date will be in Greenwich Mean Time (GMT).
376 *      Otherwise, it will be in the local time zone.
377 *
378 * Results:
379 *      Returns a static tm structure.
380 *
381 * Side effects:
382 *      None.
383 *
384 *----------------------------------------------------------------------
385 */
386
387struct tm *
388TclpGetDate(
389    CONST time_t *time,
390    int useGMT)
391{
392    if (useGMT) {
393        return TclpGmtime(time);
394    } else {
395        return TclpLocaltime(time);
396    }
397}
398
399/*
400 *----------------------------------------------------------------------
401 *
402 * TclpGmtime --
403 *
404 *      Wrapper around the 'gmtime' library function to make it thread safe.
405 *
406 * Results:
407 *      Returns a pointer to a 'struct tm' in thread-specific data.
408 *
409 * Side effects:
410 *      Invokes gmtime or gmtime_r as appropriate.
411 *
412 *----------------------------------------------------------------------
413 */
414
415struct tm *
416TclpGmtime(
417    CONST time_t *timePtr)      /* Pointer to the number of seconds since the
418                                 * local system's epoch */
419{
420    /*
421     * Get a thread-local buffer to hold the returned time.
422     */
423
424    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey);
425
426#ifdef HAVE_GMTIME_R
427    gmtime_r(timePtr, &(tsdPtr->gmtime_buf));
428#else
429    Tcl_MutexLock(&tmMutex);
430    memcpy(&(tsdPtr->gmtime_buf), gmtime(timePtr), sizeof(struct tm));
431    Tcl_MutexUnlock(&tmMutex);
432#endif
433
434    return &(tsdPtr->gmtime_buf);
435}
436
437/*
438 * Forwarder for obsolete item in Stubs
439 */
440
441struct tm *
442TclpGmtime_unix(
443    CONST time_t *timePtr)
444{
445    return TclpGmtime(timePtr);
446}
447
448/*
449 *----------------------------------------------------------------------
450 *
451 * TclpLocaltime --
452 *
453 *      Wrapper around the 'localtime' library function to make it thread
454 *      safe.
455 *
456 * Results:
457 *      Returns a pointer to a 'struct tm' in thread-specific data.
458 *
459 * Side effects:
460 *      Invokes localtime or localtime_r as appropriate.
461 *
462 *----------------------------------------------------------------------
463 */
464
465struct tm *
466TclpLocaltime(
467    CONST time_t *timePtr)      /* Pointer to the number of seconds since the
468                                 * local system's epoch */
469{
470    /*
471     * Get a thread-local buffer to hold the returned time.
472     */
473
474    ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey);
475
476    SetTZIfNecessary();
477#ifdef HAVE_LOCALTIME_R
478    localtime_r(timePtr, &(tsdPtr->localtime_buf));
479#else
480    Tcl_MutexLock(&tmMutex);
481    memcpy(&(tsdPtr->localtime_buf), localtime(timePtr), sizeof(struct tm));
482    Tcl_MutexUnlock(&tmMutex);
483#endif
484
485    return &(tsdPtr->localtime_buf);
486}
487/*
488 * Forwarder for obsolete item in Stubs
489 */
490struct tm*
491TclpLocaltime_unix(
492    CONST time_t *timePtr)
493{
494    return TclpLocaltime(timePtr);
495}
496
497/*
498 *----------------------------------------------------------------------
499 *
500 * Tcl_SetTimeProc --
501 *
502 *      TIP #233 (Virtualized Time): Registers two handlers for the
503 *      virtualization of Tcl's access to time information.
504 *
505 * Results:
506 *      None.
507 *
508 * Side effects:
509 *      Remembers the handlers, alters core behaviour.
510 *
511 *----------------------------------------------------------------------
512 */
513
514void
515Tcl_SetTimeProc(
516    Tcl_GetTimeProc *getProc,
517    Tcl_ScaleTimeProc *scaleProc,
518    ClientData clientData)
519{
520    tclGetTimeProcPtr = getProc;
521    tclScaleTimeProcPtr = scaleProc;
522    tclTimeClientData = clientData;
523}
524
525/*
526 *----------------------------------------------------------------------
527 *
528 * Tcl_QueryTimeProc --
529 *
530 *      TIP #233 (Virtualized Time): Query which time handlers are registered.
531 *
532 * Results:
533 *      None.
534 *
535 * Side effects:
536 *      None.
537 *
538 *----------------------------------------------------------------------
539 */
540
541void
542Tcl_QueryTimeProc(
543    Tcl_GetTimeProc **getProc,
544    Tcl_ScaleTimeProc **scaleProc,
545    ClientData *clientData)
546{
547    if (getProc) {
548        *getProc = tclGetTimeProcPtr;
549    }
550    if (scaleProc) {
551        *scaleProc = tclScaleTimeProcPtr;
552    }
553    if (clientData) {
554        *clientData = tclTimeClientData;
555    }
556}
557
558/*
559 *----------------------------------------------------------------------
560 *
561 * NativeScaleTime --
562 *
563 *      TIP #233: Scale from virtual time to the real-time. For native scaling
564 *      the relationship is 1:1 and nothing has to be done.
565 *
566 * Results:
567 *      Scales the time in timePtr.
568 *
569 * Side effects:
570 *      See above.
571 *
572 *----------------------------------------------------------------------
573 */
574
575static void
576NativeScaleTime(
577    Tcl_Time *timePtr,
578    ClientData clientData)
579{
580    /* Native scale is 1:1. Nothing is done */
581}
582
583/*
584 *----------------------------------------------------------------------
585 *
586 * NativeGetTime --
587 *
588 *      TIP #233: Gets the current system time in seconds and microseconds
589 *      since the beginning of the epoch: 00:00 UCT, January 1, 1970.
590 *
591 * Results:
592 *      Returns the current time in timePtr.
593 *
594 * Side effects:
595 *      None.
596 *
597 *----------------------------------------------------------------------
598 */
599
600static void
601NativeGetTime(
602    Tcl_Time *timePtr,
603    ClientData clientData)
604{
605    struct timeval tv;
606    struct timezone tz;
607
608    (void) gettimeofday(&tv, &tz);
609    timePtr->sec = tv.tv_sec;
610    timePtr->usec = tv.tv_usec;
611}
612/*
613 *----------------------------------------------------------------------
614 *
615 * SetTZIfNecessary --
616 *
617 *      Determines whether a call to 'tzset' is needed prior to the next call
618 *      to 'localtime' or examination of the 'timezone' variable.
619 *
620 * Results:
621 *      None.
622 *
623 * Side effects:
624 *      If 'tzset' has never been called in the current process, or if the
625 *      value of the environment variable TZ has changed since the last call
626 *      to 'tzset', then 'tzset' is called again.
627 *
628 *----------------------------------------------------------------------
629 */
630
631static void
632SetTZIfNecessary(void)
633{
634    CONST char *newTZ = getenv("TZ");
635
636    Tcl_MutexLock(&tmMutex);
637    if (newTZ == NULL) {
638        newTZ = "";
639    }
640    if (lastTZ == NULL || strcmp(lastTZ, newTZ)) {
641        tzset();
642        if (lastTZ == NULL) {
643            Tcl_CreateExitHandler(CleanupMemory, (ClientData) NULL);
644        } else {
645            Tcl_Free(lastTZ);
646        }
647        lastTZ = ckalloc(strlen(newTZ) + 1);
648        strcpy(lastTZ, newTZ);
649    }
650    Tcl_MutexUnlock(&tmMutex);
651}
652
653/*
654 *----------------------------------------------------------------------
655 *
656 * CleanupMemory --
657 *
658 *      Releases the private copy of the TZ environment variable upon exit
659 *      from Tcl.
660 *
661 * Results:
662 *      None.
663 *
664 * Side effects:
665 *      Frees allocated memory.
666 *
667 *----------------------------------------------------------------------
668 */
669
670static void
671CleanupMemory(
672    ClientData ignored)
673{
674    ckfree(lastTZ);
675}
676
677/*
678 * Local Variables:
679 * mode: c
680 * c-basic-offset: 4
681 * fill-column: 78
682 * End:
683 */
Note: See TracBrowser for help on using the repository browser.