Various Windows fixes
Hrvoje Niksic <[email protected]>
| Newsgroups | gmane.comp.web.wget.patches |
|---|---|
| Message-ID | <[email protected]> |
This patch introduces finer-grained timers under Windows (GetSystemTime is replaced with high-resolution timer or, if those aren't available, with GetTickCount), and includes minor cleanups of Windows-related files. It also removes two functions from utils.c, which has grown uncomfortably large. 2005-03-12 Hrvoje Niksic <[email protected]> * 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(). Index: src/cookies.c =================================================================== RCS file: /pack/anoncvs/wget/src/cookies.c,v retrieving revision 1.39 diff -u -r1.39 cookies.c --- src/cookies.c 2005/03/04 19:34:30 1.39 +++ src/cookies.c 2005/03/15 21:17:32 @@ -898,6 +898,19 @@ /* 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. Index: src/gen-md5.c =================================================================== RCS file: /pack/anoncvs/wget/src/gen-md5.c,v retrieving revision 1.3 diff -u -r1.3 gen-md5.c --- src/gen-md5.c 2002/05/18 02:16:21 1.3 +++ src/gen-md5.c 2005/03/15 21:17:32 @@ -116,3 +116,37 @@ 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 Index: src/host.c =================================================================== RCS file: /pack/anoncvs/wget/src/host.c,v retrieving revision 1.80 diff -u -r1.80 host.c --- src/host.c 2005/03/04 19:34:30 1.80 +++ src/host.c 2005/03/15 21:17:33 @@ -43,10 +43,7 @@ #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 @@ # 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 Index: src/mswindows.c =================================================================== RCS file: /pack/anoncvs/wget/src/mswindows.c,v retrieving revision 1.38 diff -u -r1.38 mswindows.c --- src/mswindows.c 2005/03/06 16:36:45 1.38 +++ src/mswindows.c 2005/03/15 21:17:34 @@ -84,7 +84,7 @@ } 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 @@ 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 @@ 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 (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. */ Index: src/mswindows.h =================================================================== RCS file: /pack/anoncvs/wget/src/mswindows.h,v retrieving revision 1.21 diff -u -r1.21 mswindows.h --- src/mswindows.h 2005/03/06 16:36:45 1.21 +++ src/mswindows.h 2005/03/15 21:17:35 @@ -124,38 +124,36 @@ #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 @@ /* 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 @@ /* 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 */ Index: src/utils.c =================================================================== RCS file: /pack/anoncvs/wget/src/utils.c,v retrieving revision 1.82 diff -u -r1.82 utils.c --- src/utils.c 2005/03/06 02:11:10 1.82 +++ src/utils.c 2005/03/15 21:17:38 @@ -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 @@ 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. */ @@ -1516,11 +1503,7 @@ 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 @@ -1541,7 +1524,10 @@ #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 { @@ -1561,6 +1547,39 @@ 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. */ @@ -1570,6 +1589,11 @@ { struct wget_timer *wt = xnew (struct wget_timer); xzero (*wt); + +#ifdef TIMER_WINDOWS + wtimer_initialize_once (); +#endif + return wt; } @@ -1606,33 +1630,25 @@ #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. + 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. */ - void wtimer_reset (struct wget_timer *wt) { @@ -1656,10 +1672,10 @@ #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 } @@ -1741,9 +1757,10 @@ #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 } @@ -1916,40 +1933,6 @@ 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. */ @@ -2120,8 +2103,9 @@ #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); Index: src/utils.h =================================================================== RCS file: /pack/anoncvs/wget/src/utils.h,v retrieving revision 1.35 diff -u -r1.35 utils.h --- src/utils.h 2005/03/06 02:11:10 1.35 +++ src/utils.h 2005/03/15 21:17:38 @@ -61,7 +61,6 @@ #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 *));