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 *));
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.