I've patched util.c to make run_with_timeout() work on Windows (better than it does with alarm()!).
In short it creates and starts a thread, then loops querying the thread exit-code. breaks if != STLL_ACTIVE, else sleep for 0.1 sec. Uses a wget_timer too for added accuracy. Tested with --dns-timeout, --connect-timeout, gethostbyname() and getaddrinfo(). Built and tested wih MingW/gcc 3,3,1, OpenWatcom 1.1 and DMC 8.36, but not MSVC 6. All seems okay. I have a problem with run_with_timeout() returning 1 and hence lookup_host() reporting ETIMEDOUT. Isn't TRY_AGAIN more suited indicating the caller should try a longer timeout? Patch against beta-2 (I think): --- src/utils.c.orig Sun Sep 21 01:12:18 2003 +++ src/utils.c Thu Oct 02 22:04:01 2003 @@ -1965,12 +1965,141 @@ # endif /* not HAVE_SIGSETJMP */ #endif /* USE_SIGNAL_TIMEOUT */ + +#if defined(WINDOWS) + +/* Wait for thread completion in 0.1s intervals (a tradeoff between + * CPU loading and resolution). + */ +#define THREAD_WAIT_INTV 100 +#define THREAD_STACK_SIZE 4096 + +struct thread_data { + void (*fun) (void *); + void *arg; + DWORD ws_error; +}; + +static DWORD WINAPI +thread_helper (void *arg) +{ + struct thread_data *td = (struct thread_data *) arg; + + WSASetLastError (0); + td->ws_error = 0; + (*td->fun) (td->arg); + + /* Since run_with_timeout() is only used for Winsock functions and + * Winsock errors are per-thread, we must return this to caller. + */ + td->ws_error = WSAGetLastError(); + return (0); +} + +#ifdef GV_DEBUG /* I'll remove this eventually */ +#define DEBUGN(lvl,x) do { if (opt.verbose >= (lvl)) DEBUGP (x); } while (0) +#else +#define DEBUGN(lvl,x) ((void)0) +#endif + +/* + * Create a thread for 'fun' to run in. Since call-convention of 'fun' is + * undefined [1], we must call it via thread_helper() which must be __stdcall/WINAPI. + * + * Return -1 if illegal timeout or failed to create thread. + * Return +1 on thread timeout, + * else 0 (okay) + * + * [1] MSVC can use __fastcall globally (cl /Gr) and on Watcom this is the + * default (wcc386 -3r). + */ +static BOOL +spawn_thread (double seconds, void (*fun) (void *), void *arg) +{ + static HANDLE thread_hnd = NULL; + struct thread_data thread_arg; + struct wget_timer *timer; + DWORD thread_id, exitCode; + double elapsed, max_msec; + + DEBUGN (2, ("seconds %.2f, ", seconds)); + + if (seconds == 0.0) + return (-1); /* run blocking 'fun' */ + + if (seconds < 1.0) + seconds = 1.0; + + /* Should never happen, but test for recursivety anyway */ + assert (thread_hnd == NULL); + thread_arg.arg = arg; + thread_arg.fun = fun; + thread_hnd = CreateThread (NULL, THREAD_STACK_SIZE, + thread_helper, (void*)&thread_arg, + 0, &thread_id); + if (!thread_hnd) + { + DEBUGP (("CreateThread() failed; %s\n", strerror(GetLastError()))); + return (-1); + } + + exitCode = STILL_ACTIVE; + max_msec = 1000.0 * seconds; + timer = wtimer_new(); + + /* Sleep() isn't very accurate, so do a double check in the for-loop */ + for (elapsed = 0.0; + elapsed < max_msec && wtimer_elapsed(timer) < max_msec; + elapsed += (double)THREAD_WAIT_INTV) + { + GetExitCodeThread (thread_hnd, &exitCode); + DEBUGN (2, ("thread exit-code %lu\n", exitCode)); + if (exitCode != STILL_ACTIVE) + break; + Sleep (THREAD_WAIT_INTV); + } + + DEBUGN (2, ("elapsed %.2f, wtimer_elapsed %.2f, ", elapsed, wtimer_elapsed(timer))); + + wtimer_delete (timer); + + /* If we timed out kill the thread. Normal thread exitCode would be 0. + */ + if (exitCode == STILL_ACTIVE) + { + DEBUGN (2, ("thread timed out\n")); + exitCode = 1; + TerminateThread (thread_hnd, exitCode); + WSASetLastError (ETIMEDOUT); /* overridden by caller */ + } + else + { + DEBUGN (2, ("thread exit-code %lu, WS error %lu\n", exitCode, thread_arg.ws_error)); + exitCode = 0; + WSASetLastError (thread_arg.ws_error); + } + thread_hnd = NULL; + return (exitCode); +} +#endif /* WINDOWS */ + int run_with_timeout (double timeout, void (*fun) (void *), void *arg) { -#ifndef USE_SIGNAL_TIMEOUT +#if defined(WINDOWS) + int rc = spawn_thread (timeout, fun, arg); + + if (rc < 0) + { + fun (arg); + rc = 0; + } + return rc; + +#elif !defined(USE_SIGNAL_TIMEOUT) fun (arg); return 0; + #else int saved_errno; ---------------------------------------------------------------- Gisle V. # rm /bin/laden /bin/laden: Not found