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