mirror of
https://github.com/moparisthebest/wget
synced 2024-07-03 16:38:41 -04:00
[svn] Extract timers to a separate file.
This commit is contained in:
parent
42139ce9b1
commit
2219d47ba3
@ -1,3 +1,8 @@
|
||||
2005-04-07 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* ptimer.c: New file. Move the "wtimer" functions from utils.c to
|
||||
this file and rename them to ptimer_.
|
||||
|
||||
2005-04-07 Hrvoje Niksic <hniksic@xemacs.org>
|
||||
|
||||
* host.c (NO_ADDRESS): Define NO_ADDRESS only after the system
|
||||
|
@ -76,7 +76,7 @@ GETOPT_OBJ = @GETOPT_OBJ@
|
||||
OBJ = $(ALLOCA) cmpt$o connect$o convert$o cookies$o \
|
||||
ftp$o ftp-basic$o ftp-ls$o $(OPIE_OBJ) $(GETOPT_OBJ) hash$o \
|
||||
host$o html-parse$o html-url$o http$o $(NTLM_OBJ) init$o \
|
||||
log$o main$o $(MD5_OBJ) netrc$o progress$o recur$o \
|
||||
log$o main$o $(MD5_OBJ) netrc$o progress$o ptimer$o recur$o \
|
||||
res$o retr$o safe-ctype$o snprintf$o $(SSL_OBJ) url$o \
|
||||
utils$o version$o xmalloc$o
|
||||
|
||||
|
@ -49,6 +49,7 @@ so, delete this exception statement from your version. */
|
||||
#include "recur.h"
|
||||
#include "utils.h"
|
||||
#include "hash.h"
|
||||
#include "ptimer.h"
|
||||
|
||||
static struct hash_table *dl_file_url_map;
|
||||
struct hash_table *dl_url_file_map;
|
||||
@ -81,7 +82,7 @@ convert_all_links (void)
|
||||
double secs;
|
||||
int file_count = 0;
|
||||
|
||||
struct wget_timer *timer = wtimer_new ();
|
||||
struct ptimer *timer = ptimer_new ();
|
||||
|
||||
int cnt;
|
||||
char **file_array;
|
||||
@ -170,9 +171,8 @@ convert_all_links (void)
|
||||
free_urlpos (urls);
|
||||
}
|
||||
|
||||
wtimer_update (timer);
|
||||
secs = wtimer_read (timer) / 1000;
|
||||
wtimer_delete (timer);
|
||||
secs = ptimer_measure (timer) / 1000;
|
||||
ptimer_destroy (timer);
|
||||
logprintf (LOG_VERBOSE, _("Converted %d files in %.*f seconds.\n"),
|
||||
file_count, secs < 10 ? 3 : 1, secs);
|
||||
}
|
||||
@ -834,8 +834,10 @@ register_html (const char *url, const char *file)
|
||||
string_set_add (downloaded_html_set, file);
|
||||
}
|
||||
|
||||
/* Cleanup the data structures associated with recursive retrieving
|
||||
(the variables above). */
|
||||
static void downloaded_files_free PARAMS ((void));
|
||||
|
||||
/* Cleanup the data structures associated with this file. */
|
||||
|
||||
void
|
||||
convert_cleanup (void)
|
||||
{
|
||||
@ -853,6 +855,7 @@ convert_cleanup (void)
|
||||
}
|
||||
if (downloaded_html_set)
|
||||
string_set_free (downloaded_html_set);
|
||||
downloaded_files_free ();
|
||||
}
|
||||
|
||||
/* Book-keeping code for downloaded files that enables extension
|
||||
@ -943,7 +946,7 @@ df_free_mapper (void *key, void *value, void *ignored)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
downloaded_files_free (void)
|
||||
{
|
||||
if (downloaded_files_hash)
|
||||
@ -953,3 +956,75 @@ downloaded_files_free (void)
|
||||
downloaded_files_hash = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* The function returns the pointer to the malloc-ed quoted version of
|
||||
string s. It will recognize and quote numeric and special graphic
|
||||
entities, as per RFC1866:
|
||||
|
||||
`&' -> `&'
|
||||
`<' -> `<'
|
||||
`>' -> `>'
|
||||
`"' -> `"'
|
||||
SP -> ` '
|
||||
|
||||
No other entities are recognized or replaced. */
|
||||
char *
|
||||
html_quote_string (const char *s)
|
||||
{
|
||||
const char *b = s;
|
||||
char *p, *res;
|
||||
int i;
|
||||
|
||||
/* Pass through the string, and count the new size. */
|
||||
for (i = 0; *s; s++, i++)
|
||||
{
|
||||
if (*s == '&')
|
||||
i += 4; /* `amp;' */
|
||||
else if (*s == '<' || *s == '>')
|
||||
i += 3; /* `lt;' and `gt;' */
|
||||
else if (*s == '\"')
|
||||
i += 5; /* `quot;' */
|
||||
else if (*s == ' ')
|
||||
i += 4; /* #32; */
|
||||
}
|
||||
res = (char *)xmalloc (i + 1);
|
||||
s = b;
|
||||
for (p = res; *s; s++)
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case '&':
|
||||
*p++ = '&';
|
||||
*p++ = 'a';
|
||||
*p++ = 'm';
|
||||
*p++ = 'p';
|
||||
*p++ = ';';
|
||||
break;
|
||||
case '<': case '>':
|
||||
*p++ = '&';
|
||||
*p++ = (*s == '<' ? 'l' : 'g');
|
||||
*p++ = 't';
|
||||
*p++ = ';';
|
||||
break;
|
||||
case '\"':
|
||||
*p++ = '&';
|
||||
*p++ = 'q';
|
||||
*p++ = 'u';
|
||||
*p++ = 'o';
|
||||
*p++ = 't';
|
||||
*p++ = ';';
|
||||
break;
|
||||
case ' ':
|
||||
*p++ = '&';
|
||||
*p++ = '#';
|
||||
*p++ = '3';
|
||||
*p++ = '2';
|
||||
*p++ = ';';
|
||||
break;
|
||||
default:
|
||||
*p++ = *s;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return res;
|
||||
}
|
||||
|
@ -101,4 +101,6 @@ void register_delete_file PARAMS ((const char *));
|
||||
void convert_all_links PARAMS ((void));
|
||||
void convert_cleanup PARAMS ((void));
|
||||
|
||||
char *html_quote_string PARAMS ((const char *));
|
||||
|
||||
#endif /* CONVERT_H */
|
||||
|
@ -47,6 +47,7 @@ so, delete this exception statement from your version. */
|
||||
#include "utils.h"
|
||||
#include "ftp.h"
|
||||
#include "url.h"
|
||||
#include "convert.h" /* for html_quote_string prototype */
|
||||
|
||||
extern FILE *output_stream;
|
||||
|
||||
|
@ -55,6 +55,7 @@ so, delete this exception statement from your version. */
|
||||
#include "progress.h"
|
||||
#include "recur.h" /* for INFINITE_RECURSION */
|
||||
#include "convert.h" /* for convert_cleanup */
|
||||
#include "res.h" /* for res_cleanup */
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
@ -1300,8 +1301,6 @@ check_user_specified_header (const char *s)
|
||||
}
|
||||
|
||||
void cleanup_html_url PARAMS ((void));
|
||||
void res_cleanup PARAMS ((void));
|
||||
void downloaded_files_free PARAMS ((void));
|
||||
void http_cleanup PARAMS ((void));
|
||||
|
||||
|
||||
@ -1332,7 +1331,6 @@ cleanup (void)
|
||||
res_cleanup ();
|
||||
http_cleanup ();
|
||||
cleanup_html_url ();
|
||||
downloaded_files_free ();
|
||||
host_cleanup ();
|
||||
log_cleanup ();
|
||||
|
||||
|
412
src/ptimer.c
Normal file
412
src/ptimer.c
Normal file
@ -0,0 +1,412 @@
|
||||
/* Portable timers.
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In addition, as a special exception, the Free Software Foundation
|
||||
gives permission to link the code of its release of Wget with the
|
||||
OpenSSL project's "OpenSSL" library (or with modified versions of it
|
||||
that use the same license as the "OpenSSL" library), and distribute
|
||||
the linked executables. You must obey the GNU General Public License
|
||||
in all respects for all of the code used other than "OpenSSL". If you
|
||||
modify this file, you may extend this exception to your version of the
|
||||
file, but you are not obligated to do so. If you do not wish to do
|
||||
so, delete this exception statement from your version. */
|
||||
|
||||
/* This file implements "portable timers" (ptimers), objects that
|
||||
measure elapsed time using the primitives most appropriate for the
|
||||
underlying operating system. The entry points are:
|
||||
|
||||
ptimer_new -- creates a timer.
|
||||
ptimer_reset -- resets the timer's elapsed time to zero.
|
||||
ptimer_measure -- measure and return the time elapsed since
|
||||
creation or last reset.
|
||||
ptimer_read -- reads the last measured elapsed value.
|
||||
ptimer_destroy -- destroy the timer.
|
||||
ptimer_granularity -- returns the approximate granularity of the timers.
|
||||
|
||||
Timers operate in milliseconds, but return floating point values
|
||||
that can be more precise. For example, to measure the time it
|
||||
takes to run a loop, you can use something like:
|
||||
|
||||
ptimer *tmr = ptimer_new ();
|
||||
while (...)
|
||||
... loop ...
|
||||
double msecs = ptimer_measure ();
|
||||
printf ("The loop took %.2f ms\n", msecs); */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else /* not HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* not HAVE_STRING_H */
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <assert.h>
|
||||
|
||||
#include "wget.h"
|
||||
#include "ptimer.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* Depending on the OS and availability of gettimeofday(), one and
|
||||
only one of PTIMER_WINDOWS, PTIMER_GETTIMEOFDAY, or PTIMER_TIME will
|
||||
be defined.
|
||||
|
||||
Virtually all modern Unix systems will define PTIMER_GETTIMEOFDAY;
|
||||
Windows will use PTIMER_WINDOWS. PTIMER_TIME is a catch-all method
|
||||
for non-Windows systems without gettimeofday, such as DOS or really
|
||||
old Unix-like systems. */
|
||||
|
||||
#undef PTIMER_POSIX
|
||||
#undef PTIMER_GETTIMEOFDAY
|
||||
#undef PTIMER_TIME
|
||||
#undef PTIMER_WINDOWS
|
||||
|
||||
#ifdef WINDOWS
|
||||
# define PTIMER_WINDOWS /* use Windows timers */
|
||||
#else
|
||||
# if _POSIX_TIMERS > 0
|
||||
# define PTIMER_POSIX /* use POSIX timers (clock_gettime) */
|
||||
# else
|
||||
# ifdef HAVE_GETTIMEOFDAY
|
||||
# define PTIMER_GETTIMEOFDAY /* use gettimeofday */
|
||||
# else
|
||||
# define PTIMER_TIME
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The type ptimer_system_time holds system time. */
|
||||
|
||||
#ifdef PTIMER_POSIX
|
||||
typedef struct timespec ptimer_system_time;
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_GETTIMEOFDAY
|
||||
typedef struct timeval ptimer_system_time;
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_TIME
|
||||
typedef time_t ptimer_system_time;
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_WINDOWS
|
||||
typedef union {
|
||||
DWORD lores; /* In case GetTickCount is used */
|
||||
LARGE_INTEGER hires; /* In case high-resolution timer is used */
|
||||
} ptimer_system_time;
|
||||
#endif
|
||||
|
||||
struct ptimer {
|
||||
/* Whether the start time has been set. */
|
||||
int initialized;
|
||||
|
||||
/* The starting point in time which, subtracted from the current
|
||||
time, yields elapsed time. */
|
||||
ptimer_system_time start;
|
||||
|
||||
/* The most recent elapsed time, calculated by ptimer_measure().
|
||||
Measured in milliseconds. */
|
||||
double elapsed_last;
|
||||
|
||||
/* Approximately, the time elapsed between the true start of the
|
||||
measurement and the time represented by START. */
|
||||
double elapsed_pre_start;
|
||||
};
|
||||
|
||||
#ifdef PTIMER_WINDOWS
|
||||
/* Whether high-resolution timers are used. Set by ptimer_initialize_once
|
||||
the first time ptimer_allocate is called. */
|
||||
static int windows_hires_timers;
|
||||
|
||||
/* Frequency of high-resolution timers -- number of updates per
|
||||
millisecond. Calculated the first time ptimer_allocate is called
|
||||
provided that high-resolution timers are available. */
|
||||
static double windows_hires_msfreq;
|
||||
|
||||
/* The first time a timer is created, determine whether to use
|
||||
high-resolution timers. */
|
||||
|
||||
static void
|
||||
ptimer_init (void)
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
freq.QuadPart = 0;
|
||||
QueryPerformanceFrequency (&freq);
|
||||
if (freq.QuadPart != 0)
|
||||
{
|
||||
windows_hires_timers = 1;
|
||||
windows_hires_msfreq = (double) freq.QuadPart / 1000.0;
|
||||
}
|
||||
}
|
||||
#define PTIMER_INIT_DEFINED
|
||||
#endif /* PTIMER_WINDOWS */
|
||||
|
||||
#ifdef PTIMER_POSIX
|
||||
|
||||
/* clock_id to use for POSIX clocks. This tries to use
|
||||
CLOCK_MONOTONIC where available, CLOCK_REALTIME otherwise. */
|
||||
static int posix_clock_id;
|
||||
|
||||
/* Resolution of the clock, in milliseconds. */
|
||||
static double posix_resolution;
|
||||
|
||||
/* Check whether the monotonic clock is available, and retrieve POSIX
|
||||
timer resolution. */
|
||||
|
||||
static void
|
||||
ptimer_init (void)
|
||||
{
|
||||
struct timespec res;
|
||||
|
||||
#if _POSIX_MONOTONIC_CLOCK > 0
|
||||
if (sysconf (_SC_MONOTONIC_CLOCK) > 0)
|
||||
posix_clock_id = CLOCK_MONOTONIC;
|
||||
else
|
||||
#endif
|
||||
posix_clock_id = CLOCK_REALTIME;
|
||||
|
||||
if (clock_getres (posix_clock_id, &res) < 0)
|
||||
{
|
||||
logprintf (LOG_NOTQUIET, _("Cannot read clock resolution: %s\n"),
|
||||
strerror (errno));
|
||||
/* Assume 1 ms resolution */
|
||||
res.tv_sec = 0;
|
||||
res.tv_nsec = 1000000;
|
||||
}
|
||||
|
||||
posix_resolution = res.tv_sec * 1000.0 + res.tv_nsec / 1000000.0;
|
||||
/* Guard against clock_getres reporting 0 resolution; after all, it
|
||||
can be used for division. */
|
||||
if (posix_resolution == 0)
|
||||
posix_resolution = 1;
|
||||
}
|
||||
#define PTIMER_INIT_DEFINED
|
||||
#endif
|
||||
|
||||
/* Allocate a timer. Calling ptimer_read on the timer will return
|
||||
zero. It is not legal to call ptimer_measure with a freshly
|
||||
allocated timer -- use ptimer_reset first. */
|
||||
|
||||
struct ptimer *
|
||||
ptimer_allocate (void)
|
||||
{
|
||||
struct ptimer *wt;
|
||||
|
||||
#ifdef PTIMER_INIT_DEFINED
|
||||
static int init_done;
|
||||
if (!init_done)
|
||||
{
|
||||
init_done = 1;
|
||||
ptimer_init ();
|
||||
}
|
||||
#endif
|
||||
|
||||
wt = xnew0 (struct ptimer);
|
||||
return wt;
|
||||
}
|
||||
|
||||
/* Allocate a new timer and reset it. Return the new timer. */
|
||||
|
||||
struct ptimer *
|
||||
ptimer_new (void)
|
||||
{
|
||||
struct ptimer *wt = ptimer_allocate ();
|
||||
ptimer_reset (wt);
|
||||
return wt;
|
||||
}
|
||||
|
||||
/* Free the resources associated with the timer. Its further use is
|
||||
prohibited. */
|
||||
|
||||
void
|
||||
ptimer_destroy (struct ptimer *wt)
|
||||
{
|
||||
xfree (wt);
|
||||
}
|
||||
|
||||
/* Store system time to PST. */
|
||||
|
||||
static void
|
||||
ptimer_sys_set (ptimer_system_time *pst)
|
||||
{
|
||||
#ifdef PTIMER_POSIX
|
||||
clock_gettime (posix_clock_id, pst);
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_GETTIMEOFDAY
|
||||
gettimeofday (pst, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_TIME
|
||||
time (pst);
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_WINDOWS
|
||||
if (windows_hires_timers)
|
||||
{
|
||||
QueryPerformanceCounter (&pst->hires);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Where hires counters are not available, use GetTickCount rather
|
||||
GetSystemTime, because it is unaffected by clock skew and simpler
|
||||
to use. Note that overflows don't affect us because we never use
|
||||
absolute values of the ticker, only the differences. */
|
||||
pst->lores = GetTickCount ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Reset timer WT. This establishes the starting point from which
|
||||
ptimer_read() will return the number of elapsed milliseconds.
|
||||
It is allowed to reset a previously used timer. */
|
||||
|
||||
void
|
||||
ptimer_reset (struct ptimer *wt)
|
||||
{
|
||||
/* Set the start time to the current time. */
|
||||
ptimer_sys_set (&wt->start);
|
||||
wt->elapsed_last = 0;
|
||||
wt->elapsed_pre_start = 0;
|
||||
wt->initialized = 1;
|
||||
}
|
||||
|
||||
static double
|
||||
ptimer_diff (ptimer_system_time *pst1, ptimer_system_time *pst2)
|
||||
{
|
||||
#ifdef PTIMER_POSIX
|
||||
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
|
||||
+ (pst1->tv_nsec - pst2->tv_nsec) / 1000000.0);
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_GETTIMEOFDAY
|
||||
return ((pst1->tv_sec - pst2->tv_sec) * 1000.0
|
||||
+ (pst1->tv_usec - pst2->tv_usec) / 1000.0);
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_TIME
|
||||
return 1000 * (*pst1 - *pst2);
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
if (using_hires_timers)
|
||||
return (pst1->hires.QuadPart - pst2->hires.QuadPart) / windows_hires_msfreq;
|
||||
else
|
||||
return pst1->lores - pst2->lores;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Measure the elapsed time since timer creation/reset and return it
|
||||
to the caller. The value remains stored for further reads by
|
||||
ptimer_read.
|
||||
|
||||
This function causes the timer to call gettimeofday (or time(),
|
||||
etc.) to update its idea of current time. To get the elapsed
|
||||
interval in milliseconds, use ptimer_read.
|
||||
|
||||
This function handles clock skew, i.e. time that moves backwards is
|
||||
ignored. */
|
||||
|
||||
double
|
||||
ptimer_measure (struct ptimer *wt)
|
||||
{
|
||||
ptimer_system_time now;
|
||||
double elapsed;
|
||||
|
||||
assert (wt->initialized != 0);
|
||||
|
||||
ptimer_sys_set (&now);
|
||||
elapsed = wt->elapsed_pre_start + ptimer_diff (&now, &wt->start);
|
||||
|
||||
/* Ideally we'd just return the difference between NOW and
|
||||
wt->start. However, the system timer can be set back, and we
|
||||
could return a value smaller than when we were last called, even
|
||||
a negative value. Both of these would confuse the callers, which
|
||||
expect us to return monotonically nondecreasing values.
|
||||
|
||||
Therefore: if ELAPSED is smaller than its previous known value,
|
||||
we reset wt->start to the current time and effectively start
|
||||
measuring from this point. But since we don't want the elapsed
|
||||
value to start from zero, we set elapsed_pre_start to the last
|
||||
elapsed time and increment all future calculations by that
|
||||
amount.
|
||||
|
||||
This cannot happen with Windows and CLOCK_MONOTONIC timers, but
|
||||
the check is not expensive. */
|
||||
|
||||
if (elapsed < wt->elapsed_last)
|
||||
{
|
||||
wt->start = now;
|
||||
wt->elapsed_pre_start = wt->elapsed_last;
|
||||
elapsed = wt->elapsed_last;
|
||||
}
|
||||
|
||||
wt->elapsed_last = elapsed;
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
/* Return the elapsed time in milliseconds between the last call to
|
||||
ptimer_reset and the last call to ptimer_update. */
|
||||
|
||||
double
|
||||
ptimer_read (const struct ptimer *wt)
|
||||
{
|
||||
return wt->elapsed_last;
|
||||
}
|
||||
|
||||
/* Return the assessed granularity of the timer implementation, in
|
||||
milliseconds. This is used by code that tries to substitute a
|
||||
better value for timers that have returned zero. */
|
||||
|
||||
double
|
||||
ptimer_granularity (void)
|
||||
{
|
||||
#ifdef PTIMER_POSIX
|
||||
/* POSIX timers give us a way to measure granularity. */
|
||||
assert (posix_resolution != 0);
|
||||
return posix_resolution;
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_GETTIMEOFDAY
|
||||
/* Granularity of gettimeofday varies wildly between architectures.
|
||||
However, it appears that on modern machines it tends to be better
|
||||
than 1ms. Assume 100 usecs. */
|
||||
return 0.1;
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_TIME
|
||||
return 1000;
|
||||
#endif
|
||||
|
||||
#ifdef PTIMER_WINDOWS
|
||||
if (windows_hires_timers)
|
||||
return 1.0 / windows_hires_msfreq;
|
||||
else
|
||||
return 10; /* according to MSDN */
|
||||
#endif
|
||||
}
|
46
src/ptimer.h
Normal file
46
src/ptimer.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* Declarations for ptimer.c.
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Wget.
|
||||
|
||||
GNU Wget is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Wget is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Wget; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
In addition, as a special exception, the Free Software Foundation
|
||||
gives permission to link the code of its release of Wget with the
|
||||
OpenSSL project's "OpenSSL" library (or with modified versions of it
|
||||
that use the same license as the "OpenSSL" library), and distribute
|
||||
the linked executables. You must obey the GNU General Public License
|
||||
in all respects for all of the code used other than "OpenSSL". If you
|
||||
modify this file, you may extend this exception to your version of the
|
||||
file, but you are not obligated to do so. If you do not wish to do
|
||||
so, delete this exception statement from your version. */
|
||||
|
||||
#ifndef PTIMER_H
|
||||
#define PTIMER_H
|
||||
|
||||
struct ptimer; /* forward declaration; all struct
|
||||
members are private */
|
||||
|
||||
struct ptimer *ptimer_allocate PARAMS ((void));
|
||||
struct ptimer *ptimer_new PARAMS ((void));
|
||||
void ptimer_destroy PARAMS ((struct ptimer *));
|
||||
|
||||
void ptimer_reset PARAMS ((struct ptimer *));
|
||||
double ptimer_measure PARAMS ((struct ptimer *));
|
||||
double ptimer_read PARAMS ((const struct ptimer *));
|
||||
|
||||
double ptimer_granularity PARAMS ((void));
|
||||
|
||||
#endif /* PTIMER_H */
|
39
src/retr.c
39
src/retr.c
@ -54,6 +54,7 @@ so, delete this exception statement from your version. */
|
||||
#include "connect.h"
|
||||
#include "hash.h"
|
||||
#include "convert.h"
|
||||
#include "ptimer.h"
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
# include "gen_sslfunc.h" /* for ssl_iread */
|
||||
@ -92,9 +93,9 @@ limit_bandwidth_reset (void)
|
||||
is the timer that started at the beginning of download. */
|
||||
|
||||
static void
|
||||
limit_bandwidth (wgint bytes, struct wget_timer *timer)
|
||||
limit_bandwidth (wgint bytes, struct ptimer *timer)
|
||||
{
|
||||
double delta_t = wtimer_read (timer) - limit_data.chunk_start;
|
||||
double delta_t = ptimer_read (timer) - limit_data.chunk_start;
|
||||
double expected;
|
||||
|
||||
limit_data.chunk_bytes += bytes;
|
||||
@ -119,10 +120,9 @@ limit_bandwidth (wgint bytes, struct wget_timer *timer)
|
||||
slp, number_to_static_string (limit_data.chunk_bytes),
|
||||
limit_data.sleep_adjust));
|
||||
|
||||
t0 = wtimer_read (timer);
|
||||
t0 = ptimer_read (timer);
|
||||
xsleep (slp / 1000);
|
||||
wtimer_update (timer);
|
||||
t1 = wtimer_read (timer);
|
||||
t1 = ptimer_measure (timer);
|
||||
|
||||
/* Due to scheduling, we probably slept slightly longer (or
|
||||
shorter) than desired. Calculate the difference between the
|
||||
@ -132,7 +132,7 @@ limit_bandwidth (wgint bytes, struct wget_timer *timer)
|
||||
}
|
||||
|
||||
limit_data.chunk_bytes = 0;
|
||||
limit_data.chunk_start = wtimer_read (timer);
|
||||
limit_data.chunk_start = ptimer_read (timer);
|
||||
}
|
||||
|
||||
#ifndef MIN
|
||||
@ -202,7 +202,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
static char dlbuf[16384];
|
||||
int dlbufsize = sizeof (dlbuf);
|
||||
|
||||
struct wget_timer *timer = NULL;
|
||||
struct ptimer *timer = NULL;
|
||||
double last_successful_read_tm = 0;
|
||||
|
||||
/* The progress gauge, set according to the user preferences. */
|
||||
@ -241,7 +241,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
the timer. */
|
||||
if (progress || opt.limit_rate || elapsed)
|
||||
{
|
||||
timer = wtimer_new ();
|
||||
timer = ptimer_new ();
|
||||
last_successful_read_tm = 0;
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
if (opt.read_timeout)
|
||||
{
|
||||
double waittm;
|
||||
waittm = (wtimer_read (timer) - last_successful_read_tm) / 1000;
|
||||
waittm = (ptimer_read (timer) - last_successful_read_tm) / 1000;
|
||||
if (waittm + tmout > opt.read_timeout)
|
||||
{
|
||||
/* Don't let total idle time exceed read timeout. */
|
||||
@ -292,9 +292,9 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
|
||||
if (progress || opt.limit_rate)
|
||||
{
|
||||
wtimer_update (timer);
|
||||
ptimer_measure (timer);
|
||||
if (ret > 0)
|
||||
last_successful_read_tm = wtimer_read (timer);
|
||||
last_successful_read_tm = ptimer_read (timer);
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
@ -311,7 +311,7 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
limit_bandwidth (ret, timer);
|
||||
|
||||
if (progress)
|
||||
progress_update (progress, ret, wtimer_read (timer));
|
||||
progress_update (progress, ret, ptimer_read (timer));
|
||||
#ifdef WINDOWS
|
||||
if (toread > 0 && !opt.quiet)
|
||||
ws_percenttitle (100.0 *
|
||||
@ -323,12 +323,12 @@ fd_read_body (int fd, FILE *out, wgint toread, wgint startpos,
|
||||
|
||||
out:
|
||||
if (progress)
|
||||
progress_finish (progress, wtimer_read (timer));
|
||||
progress_finish (progress, ptimer_read (timer));
|
||||
|
||||
if (elapsed)
|
||||
*elapsed = wtimer_read (timer);
|
||||
*elapsed = ptimer_read (timer);
|
||||
if (timer)
|
||||
wtimer_delete (timer);
|
||||
ptimer_destroy (timer);
|
||||
|
||||
if (qtyread)
|
||||
*qtyread += sum_read;
|
||||
@ -534,11 +534,12 @@ calc_rate (wgint bytes, double msecs, int *units)
|
||||
|
||||
if (msecs == 0)
|
||||
/* If elapsed time is exactly zero, it means we're under the
|
||||
granularity of the timer. This often happens on systems that
|
||||
use time() for the timer. */
|
||||
msecs = wtimer_granularity ();
|
||||
granularity of the timer. This can easily happen on systems
|
||||
that use time() for the timer. Since the interval lies between
|
||||
0 and the timer's granularity, assume half the granularity. */
|
||||
msecs = ptimer_granularity () / 2.0;
|
||||
|
||||
dlrate = (double)1000 * bytes / msecs;
|
||||
dlrate = 1000.0 * bytes / msecs;
|
||||
if (dlrate < 1024.0)
|
||||
*units = 0;
|
||||
else if (dlrate < 1024.0 * 1024.0)
|
||||
|
350
src/utils.c
350
src/utils.c
@ -1515,352 +1515,6 @@ number_to_static_string (wgint number)
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Support for timers. */
|
||||
|
||||
#undef TIMER_WINDOWS
|
||||
#undef TIMER_GETTIMEOFDAY
|
||||
#undef TIMER_TIME
|
||||
|
||||
/* Depending on the OS and availability of gettimeofday(), one and
|
||||
only one of the above constants will be defined. Virtually all
|
||||
modern Unix systems will define TIMER_GETTIMEOFDAY; Windows will
|
||||
use TIMER_WINDOWS. TIMER_TIME is a catch-all method for
|
||||
non-Windows systems without gettimeofday. */
|
||||
|
||||
#ifdef WINDOWS
|
||||
# define TIMER_WINDOWS
|
||||
#else /* not WINDOWS */
|
||||
# ifdef HAVE_GETTIMEOFDAY
|
||||
# define TIMER_GETTIMEOFDAY
|
||||
# else
|
||||
# define TIMER_TIME
|
||||
# endif
|
||||
#endif /* not WINDOWS */
|
||||
|
||||
#ifdef TIMER_GETTIMEOFDAY
|
||||
typedef struct timeval wget_sys_time;
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_TIME
|
||||
typedef time_t wget_sys_time;
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_WINDOWS
|
||||
typedef union {
|
||||
DWORD lores; /* In case GetTickCount is used */
|
||||
LARGE_INTEGER hires; /* In case high-resolution timer is used */
|
||||
} wget_sys_time;
|
||||
#endif
|
||||
|
||||
struct wget_timer {
|
||||
/* Whether the start time has been initialized. */
|
||||
int initialized;
|
||||
|
||||
/* The starting point in time which, subtracted from the current
|
||||
time, yields elapsed time. */
|
||||
wget_sys_time start;
|
||||
|
||||
/* The most recent elapsed time, calculated by wtimer_update().
|
||||
Measured in milliseconds. */
|
||||
double elapsed_last;
|
||||
|
||||
/* Approximately, the time elapsed between the true start of the
|
||||
measurement and the time represented by START. */
|
||||
double elapsed_pre_start;
|
||||
};
|
||||
|
||||
#ifdef TIMER_WINDOWS
|
||||
|
||||
/* Whether high-resolution timers are used. Set by wtimer_initialize_once
|
||||
the first time wtimer_allocate is called. */
|
||||
static int using_hires_timers;
|
||||
|
||||
/* Frequency of high-resolution timers -- number of updates per
|
||||
millisecond. Calculated the first time wtimer_allocate is called
|
||||
provided that high-resolution timers are available. */
|
||||
static double hires_millisec_freq;
|
||||
|
||||
/* The first time a timer is created, determine whether to use
|
||||
high-resolution timers. */
|
||||
|
||||
static void
|
||||
wtimer_initialize_once (void)
|
||||
{
|
||||
static int init_done;
|
||||
if (!init_done)
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
init_done = 1;
|
||||
freq.QuadPart = 0;
|
||||
QueryPerformanceFrequency (&freq);
|
||||
if (freq.QuadPart != 0)
|
||||
{
|
||||
using_hires_timers = 1;
|
||||
hires_millisec_freq = (double) freq.QuadPart / 1000.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* TIMER_WINDOWS */
|
||||
|
||||
/* Allocate a timer. Calling wtimer_read on the timer will return
|
||||
zero. It is not legal to call wtimer_update with a freshly
|
||||
allocated timer -- use wtimer_reset first. */
|
||||
|
||||
struct wget_timer *
|
||||
wtimer_allocate (void)
|
||||
{
|
||||
struct wget_timer *wt = xnew (struct wget_timer);
|
||||
xzero (*wt);
|
||||
|
||||
#ifdef TIMER_WINDOWS
|
||||
wtimer_initialize_once ();
|
||||
#endif
|
||||
|
||||
return wt;
|
||||
}
|
||||
|
||||
/* Allocate a new timer and reset it. Return the new timer. */
|
||||
|
||||
struct wget_timer *
|
||||
wtimer_new (void)
|
||||
{
|
||||
struct wget_timer *wt = wtimer_allocate ();
|
||||
wtimer_reset (wt);
|
||||
return wt;
|
||||
}
|
||||
|
||||
/* Free the resources associated with the timer. Its further use is
|
||||
prohibited. */
|
||||
|
||||
void
|
||||
wtimer_delete (struct wget_timer *wt)
|
||||
{
|
||||
xfree (wt);
|
||||
}
|
||||
|
||||
/* Store system time to WST. */
|
||||
|
||||
static void
|
||||
wtimer_sys_set (wget_sys_time *wst)
|
||||
{
|
||||
#ifdef TIMER_GETTIMEOFDAY
|
||||
gettimeofday (wst, NULL);
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_TIME
|
||||
time (wst);
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_WINDOWS
|
||||
if (using_hires_timers)
|
||||
{
|
||||
QueryPerformanceCounter (&wst->hires);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Where hires counters are not available, use GetTickCount rather
|
||||
GetSystemTime, because it is unaffected by clock skew and simpler
|
||||
to use. Note that overflows don't affect us because we never use
|
||||
absolute values of the ticker, only the differences. */
|
||||
wst->lores = GetTickCount ();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Reset timer WT. This establishes the starting point from which
|
||||
wtimer_read() will return the number of elapsed milliseconds.
|
||||
It is allowed to reset a previously used timer. */
|
||||
|
||||
void
|
||||
wtimer_reset (struct wget_timer *wt)
|
||||
{
|
||||
/* Set the start time to the current time. */
|
||||
wtimer_sys_set (&wt->start);
|
||||
wt->elapsed_last = 0;
|
||||
wt->elapsed_pre_start = 0;
|
||||
wt->initialized = 1;
|
||||
}
|
||||
|
||||
static double
|
||||
wtimer_sys_diff (wget_sys_time *wst1, wget_sys_time *wst2)
|
||||
{
|
||||
#ifdef TIMER_GETTIMEOFDAY
|
||||
return ((double)(wst1->tv_sec - wst2->tv_sec) * 1000
|
||||
+ (double)(wst1->tv_usec - wst2->tv_usec) / 1000);
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_TIME
|
||||
return 1000 * (*wst1 - *wst2);
|
||||
#endif
|
||||
|
||||
#ifdef WINDOWS
|
||||
if (using_hires_timers)
|
||||
return (wst1->hires.QuadPart - wst2->hires.QuadPart) / hires_millisec_freq;
|
||||
else
|
||||
return wst1->lores - wst2->lores;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Update the timer's elapsed interval. This function causes the
|
||||
timer to call gettimeofday (or time(), etc.) to update its idea of
|
||||
current time. To get the elapsed interval in milliseconds, use
|
||||
wtimer_read.
|
||||
|
||||
This function handles clock skew, i.e. time that moves backwards is
|
||||
ignored. */
|
||||
|
||||
void
|
||||
wtimer_update (struct wget_timer *wt)
|
||||
{
|
||||
wget_sys_time now;
|
||||
double elapsed;
|
||||
|
||||
assert (wt->initialized != 0);
|
||||
|
||||
wtimer_sys_set (&now);
|
||||
elapsed = wt->elapsed_pre_start + wtimer_sys_diff (&now, &wt->start);
|
||||
|
||||
/* Ideally we'd just return the difference between NOW and
|
||||
wt->start. However, the system timer can be set back, and we
|
||||
could return a value smaller than when we were last called, even
|
||||
a negative value. Both of these would confuse the callers, which
|
||||
expect us to return monotonically nondecreasing values.
|
||||
|
||||
Therefore: if ELAPSED is smaller than its previous known value,
|
||||
we reset wt->start to the current time and effectively start
|
||||
measuring from this point. But since we don't want the elapsed
|
||||
value to start from zero, we set elapsed_pre_start to the last
|
||||
elapsed time and increment all future calculations by that
|
||||
amount. */
|
||||
|
||||
if (elapsed < wt->elapsed_last)
|
||||
{
|
||||
wt->start = now;
|
||||
wt->elapsed_pre_start = wt->elapsed_last;
|
||||
elapsed = wt->elapsed_last;
|
||||
}
|
||||
|
||||
wt->elapsed_last = elapsed;
|
||||
}
|
||||
|
||||
/* Return the elapsed time in milliseconds between the last call to
|
||||
wtimer_reset and the last call to wtimer_update.
|
||||
|
||||
A typical use of the timer interface would be:
|
||||
|
||||
struct wtimer *timer = wtimer_new ();
|
||||
... do something that takes a while ...
|
||||
wtimer_update ();
|
||||
double msecs = wtimer_read (); */
|
||||
|
||||
double
|
||||
wtimer_read (const struct wget_timer *wt)
|
||||
{
|
||||
return wt->elapsed_last;
|
||||
}
|
||||
|
||||
/* Return the assessed granularity of the timer implementation, in
|
||||
milliseconds. This is used by code that tries to substitute a
|
||||
better value for timers that have returned zero. */
|
||||
|
||||
double
|
||||
wtimer_granularity (void)
|
||||
{
|
||||
#ifdef TIMER_GETTIMEOFDAY
|
||||
/* Granularity of gettimeofday varies wildly between architectures.
|
||||
However, it appears that on modern machines it tends to be better
|
||||
than 1ms. Assume 100 usecs. (Perhaps the configure process
|
||||
could actually measure this?) */
|
||||
return 0.1;
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_TIME
|
||||
return 1000;
|
||||
#endif
|
||||
|
||||
#ifdef TIMER_WINDOWS
|
||||
if (using_hires_timers)
|
||||
return 1.0 / hires_millisec_freq;
|
||||
else
|
||||
return 10; /* according to MSDN */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* This should probably be at a better place, but it doesn't really
|
||||
fit into html-parse.c. */
|
||||
|
||||
/* The function returns the pointer to the malloc-ed quoted version of
|
||||
string s. It will recognize and quote numeric and special graphic
|
||||
entities, as per RFC1866:
|
||||
|
||||
`&' -> `&'
|
||||
`<' -> `<'
|
||||
`>' -> `>'
|
||||
`"' -> `"'
|
||||
SP -> ` '
|
||||
|
||||
No other entities are recognized or replaced. */
|
||||
char *
|
||||
html_quote_string (const char *s)
|
||||
{
|
||||
const char *b = s;
|
||||
char *p, *res;
|
||||
int i;
|
||||
|
||||
/* Pass through the string, and count the new size. */
|
||||
for (i = 0; *s; s++, i++)
|
||||
{
|
||||
if (*s == '&')
|
||||
i += 4; /* `amp;' */
|
||||
else if (*s == '<' || *s == '>')
|
||||
i += 3; /* `lt;' and `gt;' */
|
||||
else if (*s == '\"')
|
||||
i += 5; /* `quot;' */
|
||||
else if (*s == ' ')
|
||||
i += 4; /* #32; */
|
||||
}
|
||||
res = (char *)xmalloc (i + 1);
|
||||
s = b;
|
||||
for (p = res; *s; s++)
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case '&':
|
||||
*p++ = '&';
|
||||
*p++ = 'a';
|
||||
*p++ = 'm';
|
||||
*p++ = 'p';
|
||||
*p++ = ';';
|
||||
break;
|
||||
case '<': case '>':
|
||||
*p++ = '&';
|
||||
*p++ = (*s == '<' ? 'l' : 'g');
|
||||
*p++ = 't';
|
||||
*p++ = ';';
|
||||
break;
|
||||
case '\"':
|
||||
*p++ = '&';
|
||||
*p++ = 'q';
|
||||
*p++ = 'u';
|
||||
*p++ = 'o';
|
||||
*p++ = 't';
|
||||
*p++ = ';';
|
||||
break;
|
||||
case ' ':
|
||||
*p++ = '&';
|
||||
*p++ = '#';
|
||||
*p++ = '3';
|
||||
*p++ = '2';
|
||||
*p++ = ';';
|
||||
break;
|
||||
default:
|
||||
*p++ = *s;
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Determine the width of the terminal we're running on. If that's
|
||||
not possible, return 0. */
|
||||
|
||||
@ -2284,7 +1938,7 @@ base64_decode (const char *base64, char *to)
|
||||
{
|
||||
NEXT_BASE64_CHAR (c, p);
|
||||
if (!c)
|
||||
return -1; /* premature EOF while dcoding base64 */
|
||||
return -1; /* premature EOF while decoding base64 */
|
||||
if (c != '=')
|
||||
return -1; /* padding `=' expected but not found */
|
||||
continue;
|
||||
@ -2296,7 +1950,7 @@ base64_decode (const char *base64, char *to)
|
||||
/* Process fourth byte of a quadruplet. */
|
||||
NEXT_BASE64_CHAR (c, p);
|
||||
if (!c)
|
||||
return -1; /* premature EOF while dcoding base64 */
|
||||
return -1; /* premature EOF while decoding base64 */
|
||||
if (c == '=')
|
||||
continue;
|
||||
|
||||
|
12
src/utils.h
12
src/utils.h
@ -44,8 +44,6 @@ struct file_memory {
|
||||
|
||||
#define HYPHENP(x) (*(x) == '-' && !*((x) + 1))
|
||||
|
||||
struct wget_timer;
|
||||
|
||||
char *time_str PARAMS ((time_t *));
|
||||
char *datetime_str PARAMS ((time_t *));
|
||||
|
||||
@ -108,16 +106,6 @@ int numdigit PARAMS ((wgint));
|
||||
char *number_to_string PARAMS ((char *, wgint));
|
||||
char *number_to_static_string PARAMS ((wgint));
|
||||
|
||||
struct wget_timer *wtimer_allocate PARAMS ((void));
|
||||
struct wget_timer *wtimer_new PARAMS ((void));
|
||||
void wtimer_delete PARAMS ((struct wget_timer *));
|
||||
void wtimer_reset PARAMS ((struct wget_timer *));
|
||||
void wtimer_update PARAMS ((struct wget_timer *));
|
||||
double wtimer_read PARAMS ((const struct wget_timer *));
|
||||
double wtimer_granularity PARAMS ((void));
|
||||
|
||||
char *html_quote_string PARAMS ((const char *));
|
||||
|
||||
int determine_screen_width PARAMS ((void));
|
||||
int random_number PARAMS ((int));
|
||||
double random_float PARAMS ((void));
|
||||
|
Loading…
Reference in New Issue
Block a user