GTimer: switch to monotonic time
[platform/upstream/glib.git] / glib / gtimer.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/.
25  */
26
27 /*
28  * MT safe
29  */
30
31 #include "config.h"
32 #include "glibconfig.h"
33
34 #include <stdlib.h>
35
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif /* HAVE_UNISTD_H */
39
40 #include <sys/time.h>
41 #include <time.h>
42 #ifndef G_OS_WIN32
43 #include <errno.h>
44 #endif /* G_OS_WIN32 */
45
46 #ifdef G_OS_WIN32
47 #include <windows.h>
48 #endif /* G_OS_WIN32 */
49
50 #include "gtimer.h"
51
52 #include "gmem.h"
53 #include "gstrfuncs.h"
54 #include "gtestutils.h"
55 #include "gmain.h"
56
57 /**
58  * SECTION: timers
59  * @title: Timers
60  * @short_description: keep track of elapsed time
61  *
62  * #GTimer records a start time, and counts microseconds elapsed since
63  * that time. This is done somewhat differently on different platforms,
64  * and can be tricky to get exactly right, so #GTimer provides a
65  * portable/convenient interface.
66  **/
67
68 /**
69  * GTimer:
70  *
71  * Opaque datatype that records a start time.
72  **/
73 struct _GTimer
74 {
75   guint64 start;
76   guint64 end;
77
78   guint active : 1;
79 };
80
81 /**
82  * g_timer_new:
83  * @Returns: a new #GTimer.
84  *
85  * Creates a new timer, and starts timing (i.e. g_timer_start() is
86  * implicitly called for you).
87  **/
88 GTimer*
89 g_timer_new (void)
90 {
91   GTimer *timer;
92
93   timer = g_new (GTimer, 1);
94   timer->active = TRUE;
95
96   timer->start = g_get_monotonic_time ();
97
98   return timer;
99 }
100
101 /**
102  * g_timer_destroy:
103  * @timer: a #GTimer to destroy.
104  *
105  * Destroys a timer, freeing associated resources.
106  **/
107 void
108 g_timer_destroy (GTimer *timer)
109 {
110   g_return_if_fail (timer != NULL);
111
112   g_free (timer);
113 }
114
115 /**
116  * g_timer_start:
117  * @timer: a #GTimer.
118  *
119  * Marks a start time, so that future calls to g_timer_elapsed() will
120  * report the time since g_timer_start() was called. g_timer_new()
121  * automatically marks the start time, so no need to call
122  * g_timer_start() immediately after creating the timer.
123  **/
124 void
125 g_timer_start (GTimer *timer)
126 {
127   g_return_if_fail (timer != NULL);
128
129   timer->active = TRUE;
130
131   timer->start = g_get_monotonic_time ();
132 }
133
134 /**
135  * g_timer_stop:
136  * @timer: a #GTimer.
137  *
138  * Marks an end time, so calls to g_timer_elapsed() will return the
139  * difference between this end time and the start time.
140  **/
141 void
142 g_timer_stop (GTimer *timer)
143 {
144   g_return_if_fail (timer != NULL);
145
146   timer->active = FALSE;
147
148   timer->end = g_get_monotonic_time ();
149 }
150
151 /**
152  * g_timer_reset:
153  * @timer: a #GTimer.
154  *
155  * This function is useless; it's fine to call g_timer_start() on an
156  * already-started timer to reset the start time, so g_timer_reset()
157  * serves no purpose.
158  **/
159 void
160 g_timer_reset (GTimer *timer)
161 {
162   g_return_if_fail (timer != NULL);
163
164   timer->start = g_get_monotonic_time ();
165 }
166
167 /**
168  * g_timer_continue:
169  * @timer: a #GTimer.
170  *
171  * Resumes a timer that has previously been stopped with
172  * g_timer_stop(). g_timer_stop() must be called before using this
173  * function.
174  *
175  * Since: 2.4
176  **/
177 void
178 g_timer_continue (GTimer *timer)
179 {
180   guint64 elapsed;
181
182   g_return_if_fail (timer != NULL);
183   g_return_if_fail (timer->active == FALSE);
184
185   /* Get elapsed time and reset timer start time
186    *  to the current time minus the previously
187    *  elapsed interval.
188    */
189
190   elapsed = timer->end - timer->start;
191
192   timer->start = g_get_monotonic_time ();
193
194   timer->start -= elapsed;
195
196   timer->active = TRUE;
197 }
198
199 /**
200  * g_timer_elapsed:
201  * @timer: a #GTimer.
202  * @microseconds: return location for the fractional part of seconds
203  *                elapsed, in microseconds (that is, the total number
204  *                of microseconds elapsed, modulo 1000000), or %NULL
205  * @Returns: seconds elapsed as a floating point value, including any
206  *           fractional part.
207  *
208  * If @timer has been started but not stopped, obtains the time since
209  * the timer was started. If @timer has been stopped, obtains the
210  * elapsed time between the time it was started and the time it was
211  * stopped. The return value is the number of seconds elapsed,
212  * including any fractional part. The @microseconds out parameter is
213  * essentially useless.
214  *
215  * <warning><para>
216  *  Calling initialization functions, in particular g_thread_init(), while a
217  *  timer is running will cause invalid return values from this function.
218  * </para></warning>
219  **/
220 gdouble
221 g_timer_elapsed (GTimer *timer,
222                  gulong *microseconds)
223 {
224   gdouble total;
225   gint64 elapsed;
226
227   g_return_val_if_fail (timer != NULL, 0);
228
229   if (timer->active)
230     timer->end = g_get_monotonic_time ();
231
232   elapsed = timer->end - timer->start;
233
234   total = elapsed / 1e9;
235
236   if (microseconds)
237     *microseconds = (elapsed / 1000) % 1000000;
238
239   return total;
240 }
241
242 void
243 g_usleep (gulong microseconds)
244 {
245 #ifdef G_OS_WIN32
246   Sleep (microseconds / 1000);
247 #else /* !G_OS_WIN32 */
248 # ifdef HAVE_NANOSLEEP
249   struct timespec request, remaining;
250   request.tv_sec = microseconds / G_USEC_PER_SEC;
251   request.tv_nsec = 1000 * (microseconds % G_USEC_PER_SEC);
252   while (nanosleep (&request, &remaining) == -1 && errno == EINTR)
253     request = remaining;
254 # else /* !HAVE_NANOSLEEP */
255 #  ifdef HAVE_NSLEEP
256   /* on AIX, nsleep is analogous to nanosleep */
257   struct timespec request, remaining;
258   request.tv_sec = microseconds / G_USEC_PER_SEC;
259   request.tv_nsec = 1000 * (microseconds % G_USEC_PER_SEC);
260   while (nsleep (&request, &remaining) == -1 && errno == EINTR)
261     request = remaining;
262 #  else /* !HAVE_NSLEEP */
263   if (g_thread_supported ())
264     {
265       static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
266       static GCond* cond = NULL;
267       GTimeVal end_time;
268       
269       g_get_current_time (&end_time);
270       if (microseconds > G_MAXLONG)
271         {
272           microseconds -= G_MAXLONG;
273           g_time_val_add (&end_time, G_MAXLONG);
274         }
275       g_time_val_add (&end_time, microseconds);
276
277       g_static_mutex_lock (&mutex);
278       
279       if (!cond)
280         cond = g_cond_new ();
281       
282       while (g_cond_timed_wait (cond, g_static_mutex_get_mutex (&mutex), 
283                                 &end_time))
284         /* do nothing */;
285       
286       g_static_mutex_unlock (&mutex);
287     }
288   else
289     {
290       struct timeval tv;
291       tv.tv_sec = microseconds / G_USEC_PER_SEC;
292       tv.tv_usec = microseconds % G_USEC_PER_SEC;
293       select(0, NULL, NULL, NULL, &tv);
294     }
295 #  endif /* !HAVE_NSLEEP */
296 # endif /* !HAVE_NANOSLEEP */
297 #endif /* !G_OS_WIN32 */
298 }
299
300 /**
301  * g_time_val_add:
302  * @time_: a #GTimeVal
303  * @microseconds: number of microseconds to add to @time
304  *
305  * Adds the given number of microseconds to @time_. @microseconds can
306  * also be negative to decrease the value of @time_.
307  **/
308 void 
309 g_time_val_add (GTimeVal *time_, glong microseconds)
310 {
311   g_return_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC);
312
313   if (microseconds >= 0)
314     {
315       time_->tv_usec += microseconds % G_USEC_PER_SEC;
316       time_->tv_sec += microseconds / G_USEC_PER_SEC;
317       if (time_->tv_usec >= G_USEC_PER_SEC)
318        {
319          time_->tv_usec -= G_USEC_PER_SEC;
320          time_->tv_sec++;
321        }
322     }
323   else
324     {
325       microseconds *= -1;
326       time_->tv_usec -= microseconds % G_USEC_PER_SEC;
327       time_->tv_sec -= microseconds / G_USEC_PER_SEC;
328       if (time_->tv_usec < 0)
329        {
330          time_->tv_usec += G_USEC_PER_SEC;
331          time_->tv_sec--;
332        }      
333     }
334 }
335
336 /* converts a broken down date representation, relative to UTC, to
337  * a timestamp; it uses timegm() if it's available.
338  */
339 static time_t
340 mktime_utc (struct tm *tm)
341 {
342   time_t retval;
343   
344 #ifndef HAVE_TIMEGM
345   static const gint days_before[] =
346   {
347     0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
348   };
349 #endif
350
351 #ifndef HAVE_TIMEGM
352   if (tm->tm_mon < 0 || tm->tm_mon > 11)
353     return (time_t) -1;
354
355   retval = (tm->tm_year - 70) * 365;
356   retval += (tm->tm_year - 68) / 4;
357   retval += days_before[tm->tm_mon] + tm->tm_mday - 1;
358   
359   if (tm->tm_year % 4 == 0 && tm->tm_mon < 2)
360     retval -= 1;
361   
362   retval = ((((retval * 24) + tm->tm_hour) * 60) + tm->tm_min) * 60 + tm->tm_sec;
363 #else
364   retval = timegm (tm);
365 #endif /* !HAVE_TIMEGM */
366   
367   return retval;
368 }
369
370 /**
371  * g_time_val_from_iso8601:
372  * @iso_date: an ISO 8601 encoded date string
373  * @time_: a #GTimeVal
374  *
375  * Converts a string containing an ISO 8601 encoded date and time
376  * to a #GTimeVal and puts it into @time_.
377  *
378  * Return value: %TRUE if the conversion was successful.
379  *
380  * Since: 2.12
381  */
382 gboolean
383 g_time_val_from_iso8601 (const gchar *iso_date,
384                          GTimeVal    *time_)
385 {
386   struct tm tm = {0};
387   long val;
388
389   g_return_val_if_fail (iso_date != NULL, FALSE);
390   g_return_val_if_fail (time_ != NULL, FALSE);
391
392   /* Ensure that the first character is a digit,
393    * the first digit of the date, otherwise we don't
394    * have an ISO 8601 date */
395   while (g_ascii_isspace (*iso_date))
396     iso_date++;
397
398   if (*iso_date == '\0')
399     return FALSE;
400
401   if (!g_ascii_isdigit (*iso_date) && *iso_date != '-' && *iso_date != '+')
402     return FALSE;
403
404   val = strtoul (iso_date, (char **)&iso_date, 10);
405   if (*iso_date == '-')
406     {
407       /* YYYY-MM-DD */
408       tm.tm_year = val - 1900;
409       iso_date++;
410       tm.tm_mon = strtoul (iso_date, (char **)&iso_date, 10) - 1;
411       
412       if (*iso_date++ != '-')
413         return FALSE;
414       
415       tm.tm_mday = strtoul (iso_date, (char **)&iso_date, 10);
416     }
417   else
418     {
419       /* YYYYMMDD */
420       tm.tm_mday = val % 100;
421       tm.tm_mon = (val % 10000) / 100 - 1;
422       tm.tm_year = val / 10000 - 1900;
423     }
424
425   if (*iso_date != 'T')
426     {
427       /* Date only */
428       if (*iso_date == '\0')
429         return TRUE;
430       return FALSE;
431     }
432
433   iso_date++;
434
435   /* If there is a 'T' then there has to be a time */
436   if (!g_ascii_isdigit (*iso_date))
437     return FALSE;
438
439   val = strtoul (iso_date, (char **)&iso_date, 10);
440   if (*iso_date == ':')
441     {
442       /* hh:mm:ss */
443       tm.tm_hour = val;
444       iso_date++;
445       tm.tm_min = strtoul (iso_date, (char **)&iso_date, 10);
446       
447       if (*iso_date++ != ':')
448         return FALSE;
449       
450       tm.tm_sec = strtoul (iso_date, (char **)&iso_date, 10);
451     }
452   else
453     {
454       /* hhmmss */
455       tm.tm_sec = val % 100;
456       tm.tm_min = (val % 10000) / 100;
457       tm.tm_hour = val / 10000;
458     }
459
460   time_->tv_usec = 0;
461   
462   if (*iso_date == ',' || *iso_date == '.')
463     {
464       glong mul = 100000;
465
466       while (g_ascii_isdigit (*++iso_date))
467         {
468           time_->tv_usec += (*iso_date - '0') * mul;
469           mul /= 10;
470         }
471     }
472     
473   /* Now parse the offset and convert tm to a time_t */
474   if (*iso_date == 'Z')
475     {
476       iso_date++;
477       time_->tv_sec = mktime_utc (&tm);
478     }
479   else if (*iso_date == '+' || *iso_date == '-')
480     {
481       gint sign = (*iso_date == '+') ? -1 : 1;
482       
483       val = strtoul (iso_date + 1, (char **)&iso_date, 10);
484       
485       if (*iso_date == ':')
486         val = 60 * val + strtoul (iso_date + 1, (char **)&iso_date, 10);
487       else
488         val = 60 * (val / 100) + (val % 100);
489
490       time_->tv_sec = mktime_utc (&tm) + (time_t) (60 * val * sign);
491     }
492   else
493     {
494       /* No "Z" or offset, so local time */
495       tm.tm_isdst = -1; /* locale selects DST */
496       time_->tv_sec = mktime (&tm);
497     }
498
499   while (g_ascii_isspace (*iso_date))
500     iso_date++;
501
502   return *iso_date == '\0';
503 }
504
505 /**
506  * g_time_val_to_iso8601:
507  * @time_: a #GTimeVal
508  * 
509  * Converts @time_ into an ISO 8601 encoded string, relative to the
510  * Coordinated Universal Time (UTC).
511  *
512  * Return value: a newly allocated string containing an ISO 8601 date
513  *
514  * Since: 2.12
515  */
516 gchar *
517 g_time_val_to_iso8601 (GTimeVal *time_)
518 {
519   gchar *retval;
520   struct tm *tm;
521 #ifdef HAVE_GMTIME_R
522   struct tm tm_;
523 #endif
524   time_t secs;
525   
526   g_return_val_if_fail (time_->tv_usec >= 0 && time_->tv_usec < G_USEC_PER_SEC, NULL);
527
528  secs = time_->tv_sec;
529 #ifdef _WIN32
530  tm = gmtime (&secs);
531 #else
532 #ifdef HAVE_GMTIME_R
533   tm = gmtime_r (&secs, &tm_);
534 #else
535   tm = gmtime (&secs);
536 #endif
537 #endif
538
539   if (time_->tv_usec != 0)
540     {
541       /* ISO 8601 date and time format, with fractionary seconds:
542        *   YYYY-MM-DDTHH:MM:SS.MMMMMMZ
543        */
544       retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02d.%06ldZ",
545                                 tm->tm_year + 1900,
546                                 tm->tm_mon + 1,
547                                 tm->tm_mday,
548                                 tm->tm_hour,
549                                 tm->tm_min,
550                                 tm->tm_sec,
551                                 time_->tv_usec);
552     }
553   else
554     {
555       /* ISO 8601 date and time format:
556        *   YYYY-MM-DDTHH:MM:SSZ
557        */
558       retval = g_strdup_printf ("%4d-%02d-%02dT%02d:%02d:%02dZ",
559                                 tm->tm_year + 1900,
560                                 tm->tm_mon + 1,
561                                 tm->tm_mday,
562                                 tm->tm_hour,
563                                 tm->tm_min,
564                                 tm->tm_sec);
565     }
566   
567   return retval;
568 }