~ubuntu-branches/ubuntu/hardy/wget/hardy-security

« back to all changes in this revision

Viewing changes to src/ptimer.c

  • Committer: Bazaar Package Importer
  • Author(s): Noèl Köthe
  • Date: 2005-06-26 16:46:25 UTC
  • mfrom: (1.1.1 upstream) (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20050626164625-jjcde8hyztx7xq7o
Tags: 1.10-2
* wget-fix_error--save-headers patch from upstream
  (closes: Bug#314728)
* don't pattern-match server redirects patch from upstream
  (closes: Bug#163243)
* correct de.po typos
  (closes: Bug#313883)
* wget-E_html_behind_file_counting fix problem with adding the
  numbers after the html extension
* updated Standards-Version: to 3.6.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Portable timers.
 
2
   Copyright (C) 2005 Free Software Foundation, Inc.
 
3
 
 
4
This file is part of GNU Wget.
 
5
 
 
6
GNU Wget is free software; you can redistribute it and/or modify
 
7
it under the terms of the GNU General Public License as published by
 
8
the Free Software Foundation; either version 2 of the License, or
 
9
(at your option) any later version.
 
10
 
 
11
GNU Wget is distributed in the hope that it will be useful,
 
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with Wget; if not, write to the Free Software
 
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 
 
20
In addition, as a special exception, the Free Software Foundation
 
21
gives permission to link the code of its release of Wget with the
 
22
OpenSSL project's "OpenSSL" library (or with modified versions of it
 
23
that use the same license as the "OpenSSL" library), and distribute
 
24
the linked executables.  You must obey the GNU General Public License
 
25
in all respects for all of the code used other than "OpenSSL".  If you
 
26
modify this file, you may extend this exception to your version of the
 
27
file, but you are not obligated to do so.  If you do not wish to do
 
28
so, delete this exception statement from your version.  */
 
29
 
 
30
/* This file implements "portable timers" (ptimers), objects that
 
31
   measure elapsed time using the primitives most appropriate for the
 
32
   underlying operating system.  The entry points are:
 
33
 
 
34
     ptimer_new     -- creates a timer.
 
35
     ptimer_reset   -- resets the timer's elapsed time to zero.
 
36
     ptimer_measure -- measure and return the time elapsed since
 
37
                       creation or last reset.
 
38
     ptimer_read    -- reads the last measured elapsed value.
 
39
     ptimer_destroy -- destroy the timer.
 
40
     ptimer_granularity -- returns the approximate granularity of the timers.
 
41
 
 
42
   Timers measure time in milliseconds, but the timings they return
 
43
   are floating point numbers, so they can carry as much precision as
 
44
   the underlying system timer supports.  For example, to measure the
 
45
   time it takes to run a loop, you can use something like:
 
46
 
 
47
     ptimer *tmr = ptimer_new ();
 
48
     while (...)
 
49
       ... loop ...
 
50
     double msecs = ptimer_measure ();
 
51
     printf ("The loop took %.2f ms\n", msecs);  */
 
52
 
 
53
#include <config.h>
 
54
 
 
55
#include <stdio.h>
 
56
#include <stdlib.h>
 
57
#ifdef HAVE_STRING_H
 
58
# include <string.h>
 
59
#else  /* not HAVE_STRING_H */
 
60
# include <strings.h>
 
61
#endif /* not HAVE_STRING_H */
 
62
#include <sys/types.h>
 
63
#include <errno.h>
 
64
#ifdef HAVE_UNISTD_H
 
65
# include <unistd.h>
 
66
#endif
 
67
#include <assert.h>
 
68
 
 
69
/* Cygwin currently (as of 2005-04-08, Cygwin 1.5.14) lacks clock_getres,
 
70
   but still defines _POSIX_TIMERS!  Because of that we simply use the
 
71
   Windows timers under Cygwin.  */
 
72
#ifdef __CYGWIN__
 
73
# include <windows.h>
 
74
#endif
 
75
 
 
76
#include "wget.h"
 
77
#include "ptimer.h"
 
78
 
 
79
#ifndef errno
 
80
extern int errno;
 
81
#endif
 
82
 
 
83
/* Depending on the OS and availability of gettimeofday(), one and
 
84
   only one of PTIMER_POSIX, PTIMER_GETTIMEOFDAY, PTIMER_WINDOWS, or
 
85
   PTIMER_TIME will be defined.  */
 
86
 
 
87
#undef PTIMER_POSIX
 
88
#undef PTIMER_GETTIMEOFDAY
 
89
#undef PTIMER_TIME
 
90
#undef PTIMER_WINDOWS
 
91
 
 
92
#if defined(WINDOWS) || defined(__CYGWIN__)
 
93
# define PTIMER_WINDOWS         /* use Windows timers */
 
94
#else
 
95
# if _POSIX_TIMERS - 0 > 0
 
96
#  define PTIMER_POSIX          /* use POSIX timers (clock_gettime) */
 
97
# else
 
98
#  ifdef HAVE_GETTIMEOFDAY
 
99
#   define PTIMER_GETTIMEOFDAY  /* use gettimeofday */
 
100
#  else
 
101
#   define PTIMER_TIME
 
102
#  endif
 
103
# endif
 
104
#endif
 
105
 
 
106
#ifdef PTIMER_POSIX
 
107
/* Elapsed time measurement using POSIX timers: system time is held in
 
108
   struct timespec, time is retrieved using clock_gettime, and
 
109
   resolution using clock_getres.
 
110
 
 
111
   This method is used on Unix systems that implement POSIX
 
112
   timers.  */
 
113
 
 
114
typedef struct timespec ptimer_system_time;
 
115
 
 
116
#define IMPL_init posix_init
 
117
#define IMPL_measure posix_measure
 
118
#define IMPL_diff posix_diff
 
119
#define IMPL_resolution posix_resolution
 
120
 
 
121
/* clock_id to use for POSIX clocks.  This tries to use
 
122
   CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise.  */
 
123
static int posix_clock_id;
 
124
 
 
125
/* Resolution of the clock, in milliseconds. */
 
126
static double posix_millisec_resolution;
 
127
 
 
128
/* Decide which clock_id to use.  */
 
129
 
 
130
static void
 
131
posix_init (void)
 
132
{
 
133
  /* List of clocks we want to support: some systems support monotonic
 
134
     clocks, Solaris has "high resolution" clock (sometimes
 
135
     unavailable except to superuser), and all should support the
 
136
     real-time clock.  */
 
137
#define NO_SYSCONF_CHECK -1
 
138
  static const struct {
 
139
    int id;
 
140
    int sysconf_name;
 
141
  } clocks[] = {
 
142
#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK - 0 >= 0
 
143
    { CLOCK_MONOTONIC, _SC_MONOTONIC_CLOCK },
 
144
#endif
 
145
#ifdef CLOCK_HIGHRES
 
146
    { CLOCK_HIGHRES, NO_SYSCONF_CHECK },
 
147
#endif
 
148
    { CLOCK_REALTIME, NO_SYSCONF_CHECK },
 
149
  };
 
150
  int i;
 
151
 
 
152
  /* Determine the clock we can use.  For a clock to be usable, it
 
153
     must be confirmed with sysconf (where applicable) and with
 
154
     clock_getres.  If no clock is found, CLOCK_REALTIME is used.  */
 
155
 
 
156
  for (i = 0; i < countof (clocks); i++)
 
157
    {
 
158
      struct timespec r;
 
159
      if (clocks[i].sysconf_name != NO_SYSCONF_CHECK)
 
160
        if (sysconf (clocks[i].sysconf_name) < 0)
 
161
          continue;             /* sysconf claims this clock is unavailable */
 
162
      if (clock_getres (clocks[i].id, &r) < 0)
 
163
        continue;               /* clock_getres doesn't work for this clock */
 
164
      posix_clock_id = clocks[i].id;
 
165
      posix_millisec_resolution = r.tv_sec * 1000.0 + r.tv_nsec / 1000000.0;
 
166
      /* Guard against broken clock_getres returning nonsensical
 
167
         values.  */
 
168
      if (posix_millisec_resolution == 0)
 
169
        posix_millisec_resolution = 1;
 
170
      break;
 
171
    }
 
172
  if (i == countof (clocks))
 
173
    {
 
174
      /* If no clock was found, it means that clock_getres failed for
 
175
         the realtime clock.  */
 
176
      logprintf (LOG_NOTQUIET, _("Cannot get REALTIME clock frequency: %s\n"),
 
177
                 strerror (errno));
 
178
      /* Use CLOCK_REALTIME, but invent a plausible resolution. */
 
179
      posix_clock_id = CLOCK_REALTIME;
 
180
      posix_millisec_resolution = 1;
 
181
    }
 
182
}
 
183
 
 
184
static inline void
 
185
posix_measure (ptimer_system_time *pst)
 
186
{
 
187
  clock_gettime (posix_clock_id, pst);
 
188
}
 
189
 
 
190
static inline double
 
191
posix_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
 
192
{
 
193
  return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
 
194
          + (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0);
 
195
}
 
196
 
 
197
static inline double
 
198
posix_resolution (void)
 
199
{
 
200
  return posix_millisec_resolution;
 
201
}
 
202
#endif  /* PTIMER_POSIX */
 
203
 
 
204
#ifdef PTIMER_GETTIMEOFDAY
 
205
/* Elapsed time measurement using gettimeofday: system time is held in
 
206
   struct timeval, retrieved using gettimeofday, and resolution is
 
207
   unknown.
 
208
 
 
209
   This method is used Unix systems without POSIX timers.  */
 
210
 
 
211
typedef struct timeval ptimer_system_time;
 
212
 
 
213
#define IMPL_measure gettimeofday_measure
 
214
#define IMPL_diff gettimeofday_diff
 
215
#define IMPL_resolution gettimeofday_resolution
 
216
 
 
217
static inline void
 
218
gettimeofday_measure (ptimer_system_time *pst)
 
219
{
 
220
  gettimeofday (pst, NULL);
 
221
}
 
222
 
 
223
static inline double
 
224
gettimeofday_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
 
225
{
 
226
  return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
 
227
          + (pst1->tv_usec - pst2->tv_usec) / 1000.0);
 
228
}
 
229
 
 
230
static inline double
 
231
gettimeofday_resolution (void)
 
232
{
 
233
  /* Granularity of gettimeofday varies wildly between architectures.
 
234
     However, it appears that on modern machines it tends to be better
 
235
     than 1ms.  Assume 100 usecs.  */
 
236
  return 0.1;
 
237
}
 
238
#endif  /* PTIMER_GETTIMEOFDAY */
 
239
 
 
240
#ifdef PTIMER_TIME
 
241
/* Elapsed time measurement using the time(2) call: system time is
 
242
   held in time_t, retrieved using time, and resolution is 1 second.
 
243
 
 
244
   This method is a catch-all for non-Windows systems without
 
245
   gettimeofday -- e.g. DOS or really old or non-standard Unix
 
246
   systems.  */
 
247
 
 
248
typedef time_t ptimer_system_time;
 
249
 
 
250
#define IMPL_measure time_measure
 
251
#define IMPL_diff time_diff
 
252
#define IMPL_resolution time_resolution
 
253
 
 
254
static inline void
 
255
time_measure (ptimer_system_time *pst)
 
256
{
 
257
  time (pst);
 
258
}
 
259
 
 
260
static inline double
 
261
time_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
 
262
{
 
263
  return 1000.0 * (*pst1 - *pst2);
 
264
}
 
265
 
 
266
static inline double
 
267
time_resolution (void)
 
268
{
 
269
  return 1;
 
270
}
 
271
#endif  /* PTIMER_TIME */
 
272
 
 
273
#ifdef PTIMER_WINDOWS
 
274
/* Elapsed time measurement on Windows: where high-resolution timers
 
275
   are available, time is stored in a LARGE_INTEGER and retrieved
 
276
   using QueryPerformanceCounter.  Otherwise, it is stored in a DWORD
 
277
   and retrieved using GetTickCount.
 
278
 
 
279
   This method is used on Windows.  */
 
280
 
 
281
typedef union {
 
282
  DWORD lores;          /* In case GetTickCount is used */
 
283
  LARGE_INTEGER hires;  /* In case high-resolution timer is used */
 
284
} ptimer_system_time;
 
285
 
 
286
#define IMPL_init windows_init
 
287
#define IMPL_measure windows_measure
 
288
#define IMPL_diff windows_diff
 
289
#define IMPL_resolution windows_resolution
 
290
 
 
291
/* Whether high-resolution timers are used.  Set by ptimer_initialize_once
 
292
   the first time ptimer_new is called. */
 
293
static int windows_hires_timers;
 
294
 
 
295
/* Frequency of high-resolution timers -- number of updates per
 
296
   millisecond.  Calculated the first time ptimer_new is called
 
297
   provided that high-resolution timers are available. */
 
298
static double windows_hires_msfreq;
 
299
 
 
300
static void
 
301
windows_init (void)
 
302
{
 
303
  LARGE_INTEGER freq;
 
304
  freq.QuadPart = 0;
 
305
  QueryPerformanceFrequency (&freq);
 
306
  if (freq.QuadPart != 0)
 
307
    {
 
308
      windows_hires_timers = 1;
 
309
      windows_hires_msfreq = (double) freq.QuadPart / 1000.0;
 
310
    }
 
311
}
 
312
 
 
313
static inline void
 
314
windows_measure (ptimer_system_time *pst)
 
315
{
 
316
  if (windows_hires_timers)
 
317
    QueryPerformanceCounter (&pst->hires);
 
318
  else
 
319
    /* Where hires counters are not available, use GetTickCount rather
 
320
       GetSystemTime, because it is unaffected by clock skew and
 
321
       simpler to use.  Note that overflows don't affect us because we
 
322
       never use absolute values of the ticker, only the
 
323
       differences.  */
 
324
    pst->lores = GetTickCount ();
 
325
}
 
326
 
 
327
static inline double
 
328
windows_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
 
329
{
 
330
  if (windows_hires_timers)
 
331
    return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq;
 
332
  else
 
333
    return pst1->lores - pst2->lores;
 
334
}
 
335
 
 
336
static double
 
337
windows_resolution (void)
 
338
{
 
339
  if (windows_hires_timers)
 
340
    return 1.0 / windows_hires_msfreq;
 
341
  else
 
342
    return 10;                  /* according to MSDN */
 
343
}
 
344
#endif  /* PTIMER_WINDOWS */
 
345
 
 
346
/* The code below this point is independent of timer implementation. */
 
347
 
 
348
struct ptimer {
 
349
  /* The starting point in time which, subtracted from the current
 
350
     time, yields elapsed time. */
 
351
  ptimer_system_time start;
 
352
 
 
353
  /* The most recent elapsed time, calculated by ptimer_measure().
 
354
     Measured in milliseconds.  */
 
355
  double elapsed_last;
 
356
 
 
357
  /* Approximately, the time elapsed between the true start of the
 
358
     measurement and the time represented by START.  This is used for
 
359
     adjustment when clock skew is detected.  */
 
360
  double elapsed_pre_start;
 
361
};
 
362
 
 
363
/* Allocate a new timer and reset it.  Return the new timer. */
 
364
 
 
365
struct ptimer *
 
366
ptimer_new (void)
 
367
{
 
368
  struct ptimer *pt = xnew0 (struct ptimer);
 
369
#ifdef IMPL_init
 
370
  static int init_done;
 
371
  if (!init_done)
 
372
    {
 
373
      init_done = 1;
 
374
      IMPL_init ();
 
375
    }
 
376
#endif
 
377
  ptimer_reset (pt);
 
378
  return pt;
 
379
}
 
380
 
 
381
/* Free the resources associated with the timer.  Its further use is
 
382
   prohibited.  */
 
383
 
 
384
void
 
385
ptimer_destroy (struct ptimer *pt)
 
386
{
 
387
  xfree (pt);
 
388
}
 
389
 
 
390
/* Reset timer PT.  This establishes the starting point from which
 
391
   ptimer_read() will return the number of elapsed milliseconds.
 
392
   It is allowed to reset a previously used timer.  */
 
393
 
 
394
void
 
395
ptimer_reset (struct ptimer *pt)
 
396
{
 
397
  /* Set the start time to the current time. */
 
398
  IMPL_measure (&pt->start);
 
399
  pt->elapsed_last = 0;
 
400
  pt->elapsed_pre_start = 0;
 
401
}
 
402
 
 
403
/* Measure the elapsed time since timer creation/reset and return it
 
404
   to the caller.  The value remains stored for further reads by
 
405
   ptimer_read.
 
406
 
 
407
   This function causes the timer to call gettimeofday (or time(),
 
408
   etc.) to update its idea of current time.  To get the elapsed
 
409
   interval in milliseconds, use ptimer_read.
 
410
 
 
411
   This function handles clock skew, i.e. time that moves backwards is
 
412
   ignored.  */
 
413
 
 
414
double
 
415
ptimer_measure (struct ptimer *pt)
 
416
{
 
417
  ptimer_system_time now;
 
418
  double elapsed;
 
419
 
 
420
  IMPL_measure (&now);
 
421
  elapsed = pt->elapsed_pre_start + IMPL_diff (&now, &pt->start);
 
422
 
 
423
  /* Ideally we'd just return the difference between NOW and
 
424
     pt->start.  However, the system timer can be set back, and we
 
425
     could return a value smaller than when we were last called, even
 
426
     a negative value.  Both of these would confuse the callers, which
 
427
     expect us to return monotonically nondecreasing values.
 
428
 
 
429
     Therefore: if ELAPSED is smaller than its previous known value,
 
430
     we reset pt->start to the current time and effectively start
 
431
     measuring from this point.  But since we don't want the elapsed
 
432
     value to start from zero, we set elapsed_pre_start to the last
 
433
     elapsed time and increment all future calculations by that
 
434
     amount.
 
435
 
 
436
     This cannot happen with Windows and POSIX monotonic/highres
 
437
     timers, but the check is not expensive.  */
 
438
 
 
439
  if (elapsed < pt->elapsed_last)
 
440
    {
 
441
      pt->start = now;
 
442
      pt->elapsed_pre_start = pt->elapsed_last;
 
443
      elapsed = pt->elapsed_last;
 
444
    }
 
445
 
 
446
  pt->elapsed_last = elapsed;
 
447
  return elapsed;
 
448
}
 
449
 
 
450
/* Return the elapsed time in milliseconds between the last call to
 
451
   ptimer_reset and the last call to ptimer_update.  */
 
452
 
 
453
double
 
454
ptimer_read (const struct ptimer *pt)
 
455
{
 
456
  return pt->elapsed_last;
 
457
}
 
458
 
 
459
/* Return the assessed resolution of the timer implementation, in
 
460
   milliseconds.  This is used by code that tries to substitute a
 
461
   better value for timers that have returned zero.  */
 
462
 
 
463
double
 
464
ptimer_resolution (void)
 
465
{
 
466
  return IMPL_resolution ();
 
467
}