1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Use high-resolution timers on Windows.

This commit is contained in:
hniksic 2005-03-20 02:41:46 -08:00
parent 828a50e4f3
commit 6da4142b3b
8 changed files with 182 additions and 136 deletions

View File

@ -1,3 +1,34 @@
2005-03-12 Hrvoje Niksic <hniksic@xemacs.org>
* utils.c (debug_test_md5): Moved to gen-md5.c.
* mswindows.h: Don't declare inet_ntop, since we don't use it.
* mswindows.h: For consistency, also wrap closesocket, it being
a Winsock call.
* mswindows.h: Don't declare sleep and usleep; we're defining
xsleep now.
* mswindows.h (mkdir): Don't special-case Borland C, _mkdir
works there as well.
* host.c: Don't include winsock header files; the correct ones
are already included by mswindows.h.
* mswindows.c (xsleep): Round toward the nearest millisecond
in an attempt to avoid average short sleeps.
* utils.c (wtimer_granularity): Report correct values for
Windows timers and for high-resolution timers.
* utils.c (wtimer_initialize_once): New function, called to
initialize the timer frequency.
* utils.c: Replace the use of GetSystemTime with high-resolution
counters under Windows. When high-resolution counters are
unavailable, use GetTickCount().
2005-03-15 Hrvoje Niksic <hniksic@xemacs.org>
* retr.c (fd_read_body): Undo the 2004-11-18 change. Instead,

View File

@ -898,6 +898,19 @@ cookie_handle_set_cookie (struct cookie_jar *jar,
/* Support for sending out cookies in HTTP requests, based on
previously stored cookies. Entry point is
`build_cookies_request'. */
/* Return a count of how many times CHR occurs in STRING. */
static int
count_char (const char *string, char chr)
{
const char *p;
int count = 0;
for (p = string; *p; p++)
if (*p == chr)
++count;
return count;
}
/* Find the cookie chains whose domains match HOST and store them to
DEST.

View File

@ -116,3 +116,37 @@ gen_md5_finish (gen_md5_context *ctx, unsigned char *result)
MD5_Final (result, ctx_imp);
#endif
}
#if 0
/* A debugging function for checking whether an MD5 library works. */
#include "gen-md5.h"
char *
debug_test_md5 (char *buf)
{
unsigned char raw[16];
static char res[33];
unsigned char *p1;
char *p2;
int cnt;
ALLOCA_MD5_CONTEXT (ctx);
gen_md5_init (ctx);
gen_md5_update ((unsigned char *)buf, strlen (buf), ctx);
gen_md5_finish (ctx, raw);
p1 = raw;
p2 = res;
cnt = 16;
while (cnt--)
{
*p2++ = XNUM_TO_digit (*p1 >> 4);
*p2++ = XNUM_TO_digit (*p1 & 0xf);
++p1;
}
*p2 = '\0';
return res;
}
#endif

View File

@ -43,10 +43,7 @@ so, delete this exception statement from your version. */
#include <assert.h>
#include <sys/types.h>
#ifdef WINDOWS
# include <winsock.h>
# define SET_H_ERRNO(err) WSASetLastError (err)
#else
#ifndef WINDOWS
# include <sys/socket.h>
# include <netinet/in.h>
# ifndef __BEOS__
@ -54,6 +51,8 @@ so, delete this exception statement from your version. */
# endif
# include <netdb.h>
# define SET_H_ERRNO(err) ((void)(h_errno = (err)))
#else /* WINDOWS */
# define SET_H_ERRNO(err) WSASetLastError (err)
#endif /* WINDOWS */
#ifndef NO_ADDRESS

View File

@ -84,7 +84,7 @@ xsleep (double seconds)
}
usleep (seconds * 1000000L);
#else /* not HAVE_USLEEP */
SleepEx (seconds * 1000, FALSE);
SleepEx ((DWORD) (seconds * 1000 + .5), FALSE);
#endif /* not HAVE_USLEEP */
}
@ -589,12 +589,9 @@ set_sleep_mode (void)
void
ws_startup (void)
{
WORD requested;
WSADATA data;
int err;
requested = MAKEWORD (1, 1);
err = WSAStartup (requested, &data);
WORD requested = MAKEWORD (1, 1);
int err = WSAStartup (requested, &data);
if (err != 0)
{
fprintf (stderr, _("%s: Couldn't find usable socket driver.\n"),
@ -741,16 +738,16 @@ run_with_timeout (double seconds, void (*fun) (void *), void *arg)
return rc;
}
/* Wget expects network calls such as bind, connect, etc., to set errno.
To achieve that, we place Winsock calls in wrapper functions that, in
case of error, sets errno to the value of GetLastError(). In addition,
we provide a wrapper around strerror, which recognizes Winsock errors
and prints the appropriate error message. */
/* Wget expects network calls such as connect, recv, send, etc., to set
errno on failure. To achieve that, Winsock calls are wrapped with code
that, in case of error, sets errno to the value of WSAGetLastError().
In addition, we provide a wrapper around strerror, which recognizes
Winsock errors and prints the appropriate error message. */
/* Define a macro that creates a function definition that wraps FUN into
a function that sets errno the way the rest of the code expects. */
#define WRAP(fun, decl, call) int wrap_##fun decl { \
#define WRAP(fun, decl, call) int wrapped_##fun decl { \
int retval = fun call; \
if (retval < 0) \
errno = WSAGetLastError (); \
@ -768,6 +765,7 @@ WRAP (getsockname, (int s, struct sockaddr *n, int *nlen), (s, n, nlen))
WRAP (getpeername, (int s, struct sockaddr *n, int *nlen), (s, n, nlen))
WRAP (setsockopt, (int s, int level, int opt, const void *val, int len),
(s, level, opt, val, len))
WRAP (closesocket, (int s), (s))
/* Return the text of the error message for Winsock error WSERR. */

View File

@ -124,38 +124,36 @@ __int64 str_to_int64 (const char *, char **, int);
#include <direct.h>
/* Windows compilers accept only one arg to mkdir. */
#ifndef __BORLANDC__
# define mkdir(a, b) _mkdir(a)
#else /* __BORLANDC__ */
# define mkdir(a, b) mkdir(a)
#endif /* __BORLANDC__ */
#define mkdir(a, b) _mkdir(a)
#ifndef INHIBIT_WRAP
/* Winsock functions don't set errno, so we provide wrappers
that do. */
#define socket wrap_socket
#define bind wrap_bind
#define connect wrap_connect
#define recv wrap_recv
#define send wrap_send
#define select wrap_select
#define getsockname wrap_getsockname
#define getpeername wrap_getpeername
#define setsockopt wrap_setsockopt
#define socket wrapped_socket
#define bind wrapped_bind
#define connect wrapped_connect
#define recv wrapped_recv
#define send wrapped_send
#define select wrapped_select
#define getsockname wrapped_getsockname
#define getpeername wrapped_getpeername
#define setsockopt wrapped_setsockopt
#define closesocket wrapped_closesocket
#endif /* not INHIBIT_WRAP */
int wrap_socket (int, int, int);
int wrap_bind (int, struct sockaddr *, int);
int wrap_connect (int, const struct sockaddr *, int);
int wrap_recv (int, void *, int, int);
int wrap_send (int, const void *, int, int);
int wrap_select (int, fd_set *, fd_set *, fd_set *, const struct timeval *);
int wrap_getsockname (int, struct sockaddr *, int *);
int wrap_getpeername (int, struct sockaddr *, int *);
int wrap_setsockopt (int, int, int, const void *, int);
int wrapped_socket (int, int, int);
int wrapped_bind (int, struct sockaddr *, int);
int wrapped_connect (int, const struct sockaddr *, int);
int wrapped_recv (int, void *, int, int);
int wrapped_send (int, const void *, int, int);
int wrapped_select (int, fd_set *, fd_set *, fd_set *, const struct timeval *);
int wrapped_getsockname (int, struct sockaddr *, int *);
int wrapped_getpeername (int, struct sockaddr *, int *);
int wrapped_setsockopt (int, int, int, const void *, int);
int wrapped_closesocket (int);
/* Finally, provide a private version of strerror that does the
right thing with Winsock errors. */
@ -204,13 +202,6 @@ const char *windows_strerror (int);
/* Public functions. */
#ifndef HAVE_SLEEP
unsigned int sleep (unsigned);
#endif
#ifndef HAVE_USLEEP
int usleep (unsigned long);
#endif
void ws_startup (void);
void ws_changetitle (const char *);
void ws_percenttitle (double);
@ -219,11 +210,8 @@ void windows_main (int *, char **, char **);
/* Things needed for IPv6; missing in <ws2tcpip.h>. */
#ifdef ENABLE_IPV6
# ifndef HAVE_NTOP
extern const char *inet_ntop (int af, const void *src, char *dst, size_t size);
# endif
# ifndef HAVE_PTON
extern int inet_pton (int af, const char *src, void *dst);
# ifndef HAVE_INET_NTOP
extern const char *inet_ntop (int af, const void *src, char *dst, size_t size);
# endif
#endif /* ENABLE_IPV6 */

View File

@ -1,5 +1,5 @@
/* Various utility functions.
Copyright (C) 2003 Free Software Foundation, Inc.
Copyright (C) 2005 Free Software Foundation, Inc.
This file is part of GNU Wget.
@ -120,19 +120,6 @@ xstrdup_lower (const char *s)
return copy;
}
/* Return a count of how many times CHR occurs in STRING. */
int
count_char (const char *string, char chr)
{
const char *p;
int count = 0;
for (p = string; *p; p++)
if (*p == chr)
++count;
return count;
}
/* Copy the string formed by two pointers (one on the beginning, other
on the char after the last char) to a new, malloc-ed location.
0-terminate it. */
@ -1564,11 +1551,7 @@ number_to_static_string (wgint number)
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.
#### Perhaps we should also support ftime(), which exists on old
BSD 4.2-influenced systems? (It also existed under MS DOS Borland
C, if memory serves me.) */
non-Windows systems without gettimeofday. */
#ifdef WINDOWS
# define TIMER_WINDOWS
@ -1589,7 +1572,10 @@ typedef time_t wget_sys_time;
#endif
#ifdef TIMER_WINDOWS
typedef ULARGE_INTEGER wget_sys_time;
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 {
@ -1609,6 +1595,39 @@ struct wget_timer {
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. */
@ -1618,6 +1637,11 @@ wtimer_allocate (void)
{
struct wget_timer *wt = xnew (struct wget_timer);
xzero (*wt);
#ifdef TIMER_WINDOWS
wtimer_initialize_once ();
#endif
return wt;
}
@ -1654,32 +1678,24 @@ wtimer_sys_set (wget_sys_time *wst)
#endif
#ifdef TIMER_WINDOWS
/* We use GetSystemTime to get the elapsed time. MSDN warns that
system clock adjustments can skew the output of GetSystemTime
when used as a timer and gives preference to GetTickCount and
high-resolution timers. But GetTickCount can overflow, and hires
timers are typically used for profiling, not for regular time
measurement. Since we handle clock skew anyway, we just use
GetSystemTime. */
FILETIME ft;
SYSTEMTIME st;
GetSystemTime (&st);
/* As recommended by MSDN, we convert SYSTEMTIME to FILETIME, copy
FILETIME to ULARGE_INTEGER, and use regular 64-bit integer
arithmetic on that. */
SystemTimeToFileTime (&st, &ft);
wst->HighPart = ft.dwHighDateTime;
wst->LowPart = ft.dwLowDateTime;
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_elapsed() will return the number of elapsed milliseconds.
It is allowed to reset a previously used timer.
If a non-zero value is used as START, the timer's values will be
offset by START. */
It is allowed to reset a previously used timer. */
void
wtimer_reset (struct wget_timer *wt)
@ -1704,10 +1720,10 @@ wtimer_sys_diff (wget_sys_time *wst1, wget_sys_time *wst2)
#endif
#ifdef WINDOWS
/* VC++ 6 doesn't support direct cast of uint64 to double. To work
around this, we subtract, then convert to signed, then finally to
double. */
return (double)(signed __int64)(wst1->QuadPart - wst2->QuadPart) / 10000;
if (using_hires_timers)
return (wst1->hires.QuadPart - wst2->hires.QuadPart) / hires_millisec_freq;
else
return wst1->lores - wst2->lores;
#endif
}
@ -1789,9 +1805,10 @@ wtimer_granularity (void)
#endif
#ifdef TIMER_WINDOWS
/* According to MSDN, GetSystemTime returns a broken-down time
structure the smallest member of which are milliseconds. */
return 1;
if (using_hires_timers)
return 1.0 / hires_millisec_freq;
else
return 10; /* according to MSDN */
#endif
}
@ -1964,40 +1981,6 @@ random_float (void)
int rnd3 = random_number (1000);
return rnd1 / 1000.0 + rnd2 / 1000000.0 + rnd3 / 1000000000.0;
}
#if 0
/* A debugging function for checking whether an MD5 library works. */
#include "gen-md5.h"
char *
debug_test_md5 (char *buf)
{
unsigned char raw[16];
static char res[33];
unsigned char *p1;
char *p2;
int cnt;
ALLOCA_MD5_CONTEXT (ctx);
gen_md5_init (ctx);
gen_md5_update ((unsigned char *)buf, strlen (buf), ctx);
gen_md5_finish (ctx, raw);
p1 = raw;
p2 = res;
cnt = 16;
while (cnt--)
{
*p2++ = XNUM_TO_digit (*p1 >> 4);
*p2++ = XNUM_TO_digit (*p1 & 0xf);
++p1;
}
*p2 = '\0';
return res;
}
#endif
/* Implementation of run_with_timeout, a generic timeout-forcing
routine for systems with Unix-like signal handling. */
@ -2168,8 +2151,9 @@ xsleep (double seconds)
#ifdef HAVE_NANOSLEEP
/* nanosleep is the preferred interface because it offers high
accuracy and, more importantly, because it allows us to reliably
restart after having been interrupted by a signal such as
SIGWINCH. */
restart receiving a signal such as SIGWINCH. (There was an
actual Debian bug report about --limit-rate malfunctioning while
the terminal was being resized.) */
struct timespec sleep, remaining;
sleep.tv_sec = (long) seconds;
sleep.tv_nsec = 1000000000L * (seconds - (long) seconds);

View File

@ -61,7 +61,6 @@ void print_malloc_debug_stats ();
#endif
char *xstrdup_lower PARAMS ((const char *));
int count_char PARAMS ((const char *, char));
char *strdupdelim PARAMS ((const char *, const char *));
char **sepstring PARAMS ((const char *));