windows: replace _beginthreadex() with CreateThread()

Replace `_beginthreadex()` C runtime calls with native win32 API
`CreateThread()`. The latter was already used in `src/tool_doswin.c`
and in UWP and Windows CE builds before this patch. After this patch
all Windows flavors use it. To drop PP logic and simplify code.

While working on this it turned out that `src/tool_doswin.c` calls
`TerminateThread()`, which isn't recommended by the documentation,
except for "the most extreme cases". This patch makes no attempt
to change that code.
Ref: 9a2663322c #17572
Ref: https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminatethread

Also:
- use `WaitForSingleObjectEx()` on all desktop Windows.
  Ref: 4be80d5109
  Ref: https://sourceforge.net/p/curl/feature-requests/82/
  Ref: https://learn.microsoft.com/windows/win32/api/synchapi/nf-synchapi-waitforsingleobjectex
- tests: drop redundant casts.
- lib3207: fix to not rely on thread macros when building without thread
  support.

Assisted-by: Jay Satiro
Assisted-by: Marcel Raad
Assisted-by: Michał Petryka
Follow-up to 38029101e2 #11625

Closes #18451
This commit is contained in:
Viktor Szakats 2025-08-01 21:09:52 +02:00
parent 8d004781a5
commit 1c49f2f26d
No known key found for this signature in database
GPG Key ID: B5ABD165E2AEF201
6 changed files with 29 additions and 68 deletions

View File

@ -26,13 +26,9 @@
#include <curl/curl.h> #include <curl/curl.h>
#ifdef USE_THREADS_POSIX #if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
# ifdef HAVE_PTHREAD_H
#include <pthread.h> #include <pthread.h>
#endif #endif
#elif defined(USE_THREADS_WIN32)
# include <process.h>
#endif
#include "curl_threads.h" #include "curl_threads.h"
#include "curl_memory.h" #include "curl_memory.h"
@ -105,20 +101,8 @@ int Curl_thread_join(curl_thread_t *hnd)
curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T
(CURL_STDCALL *func) (void *), void *arg) (CURL_STDCALL *func) (void *), void *arg)
{ {
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL);
typedef HANDLE curl_win_thread_handle_t; if(!t) {
#else
typedef uintptr_t curl_win_thread_handle_t;
#endif
curl_thread_t t;
curl_win_thread_handle_t thread_handle;
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
#endif
t = (curl_thread_t)thread_handle;
if((t == 0) || (t == LongToHandle(-1L))) {
#ifdef UNDER_CE #ifdef UNDER_CE
DWORD gle = GetLastError(); DWORD gle = GetLastError();
/* !checksrc! disable ERRNOVAR 1 */ /* !checksrc! disable ERRNOVAR 1 */
@ -142,7 +126,7 @@ void Curl_thread_destroy(curl_thread_t *hnd)
int Curl_thread_join(curl_thread_t *hnd) int Curl_thread_join(curl_thread_t *hnd)
{ {
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < _WIN32_WINNT_VISTA) #ifdef UNDER_CE
int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
#else #else
int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);

View File

@ -26,6 +26,7 @@
#include "curl_setup.h" #include "curl_setup.h"
#ifdef USE_THREADS_POSIX #ifdef USE_THREADS_POSIX
# define CURL_THREAD_RETURN_T unsigned int
# define CURL_STDCALL # define CURL_STDCALL
# define curl_mutex_t pthread_mutex_t # define curl_mutex_t pthread_mutex_t
# define curl_thread_t pthread_t * # define curl_thread_t pthread_t *
@ -35,7 +36,8 @@
# define Curl_mutex_release(m) pthread_mutex_unlock(m) # define Curl_mutex_release(m) pthread_mutex_unlock(m)
# define Curl_mutex_destroy(m) pthread_mutex_destroy(m) # define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
#elif defined(USE_THREADS_WIN32) #elif defined(USE_THREADS_WIN32)
# define CURL_STDCALL __stdcall # define CURL_THREAD_RETURN_T DWORD
# define CURL_STDCALL WINAPI
# define curl_mutex_t CRITICAL_SECTION # define curl_mutex_t CRITICAL_SECTION
# define curl_thread_t HANDLE # define curl_thread_t HANDLE
# define curl_thread_t_null (HANDLE)0 # define curl_thread_t_null (HANDLE)0
@ -47,14 +49,6 @@
# define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_acquire(m) EnterCriticalSection(m)
# define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m)
# define Curl_mutex_destroy(m) DeleteCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m)
#else
# define CURL_STDCALL
#endif
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
#define CURL_THREAD_RETURN_T DWORD
#else
#define CURL_THREAD_RETURN_T unsigned int
#endif #endif
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)

View File

@ -26,12 +26,7 @@
#define NUM_THREADS 100 #define NUM_THREADS 100
#ifdef _WIN32 #ifdef _WIN32
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) static DWORD WINAPI t3026_run_thread(void *ptr)
static DWORD WINAPI t3026_run_thread(LPVOID ptr)
#else
#include <process.h>
static unsigned int WINAPI t3026_run_thread(void *ptr)
#endif
{ {
CURLcode *result = ptr; CURLcode *result = ptr;
@ -44,13 +39,8 @@ static unsigned int WINAPI t3026_run_thread(void *ptr)
static CURLcode test_lib3026(const char *URL) static CURLcode test_lib3026(const char *URL)
{ {
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
typedef HANDLE curl_win_thread_handle_t;
#else
typedef uintptr_t curl_win_thread_handle_t;
#endif
CURLcode results[NUM_THREADS]; CURLcode results[NUM_THREADS];
curl_win_thread_handle_t thread_handles[NUM_THREADS]; HANDLE thread_handles[NUM_THREADS];
unsigned tid_count = NUM_THREADS, i; unsigned tid_count = NUM_THREADS, i;
CURLcode test_failure = CURLE_OK; CURLcode test_failure = CURLE_OK;
curl_version_info_data *ver; curl_version_info_data *ver;
@ -65,13 +55,9 @@ static CURLcode test_lib3026(const char *URL)
} }
for(i = 0; i < tid_count; i++) { for(i = 0; i < tid_count; i++) {
curl_win_thread_handle_t th; HANDLE th;
results[i] = CURL_LAST; /* initialize with invalid value */ results[i] = CURL_LAST; /* initialize with invalid value */
#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE)
th = CreateThread(NULL, 0, t3026_run_thread, &results[i], 0, NULL); th = CreateThread(NULL, 0, t3026_run_thread, &results[i], 0, NULL);
#else
th = _beginthreadex(NULL, 0, t3026_run_thread, &results[i], 0, NULL);
#endif
if(!th) { if(!th) {
curl_mfprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n", curl_mfprintf(stderr, "%s:%d Couldn't create thread, errno %lu\n",
__FILE__, __LINE__, GetLastError()); __FILE__, __LINE__, GetLastError());
@ -84,8 +70,8 @@ static CURLcode test_lib3026(const char *URL)
cleanup: cleanup:
for(i = 0; i < tid_count; i++) { for(i = 0; i < tid_count; i++) {
WaitForSingleObject((HANDLE)thread_handles[i], INFINITE); WaitForSingleObject(thread_handles[i], INFINITE);
CloseHandle((HANDLE)thread_handles[i]); CloseHandle(thread_handles[i]);
if(results[i] != CURLE_OK) { if(results[i] != CURLE_OK) {
curl_mfprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed," curl_mfprintf(stderr, "%s:%d thread[%u]: curl_global_init() failed,"
"with code %d (%s)\n", __FILE__, __LINE__, "with code %d (%s)\n", __FILE__, __LINE__,

View File

@ -68,7 +68,11 @@ static size_t write_memory_callback(char *contents, size_t size,
return realsize; return realsize;
} }
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
static CURL_THREAD_RETURN_T CURL_STDCALL test_thread(void *ptr) static CURL_THREAD_RETURN_T CURL_STDCALL test_thread(void *ptr)
#else
static unsigned int test_thread(void *ptr)
#endif
{ {
struct Ctx *ctx = (struct Ctx *)ptr; struct Ctx *ctx = (struct Ctx *)ptr;
CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;

View File

@ -412,8 +412,7 @@ struct select_ws_wait_data {
HANDLE signal; /* internal event to signal handle trigger */ HANDLE signal; /* internal event to signal handle trigger */
HANDLE abort; /* internal event to abort waiting threads */ HANDLE abort; /* internal event to abort waiting threads */
}; };
#include <process.h> static DWORD WINAPI select_ws_wait_thread(void *lpParameter)
static unsigned int WINAPI select_ws_wait_thread(void *lpParameter)
{ {
struct select_ws_wait_data *data; struct select_ws_wait_data *data;
HANDLE signal, handle, handles[2]; HANDLE signal, handle, handles[2];
@ -557,25 +556,25 @@ static unsigned int WINAPI select_ws_wait_thread(void *lpParameter)
static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort) static HANDLE select_ws_wait(HANDLE handle, HANDLE signal, HANDLE abort)
{ {
typedef uintptr_t curl_win_thread_handle_t;
struct select_ws_wait_data *data; struct select_ws_wait_data *data;
curl_win_thread_handle_t thread;
/* allocate internal waiting data structure */ /* allocate internal waiting data structure */
data = malloc(sizeof(struct select_ws_wait_data)); data = malloc(sizeof(struct select_ws_wait_data));
if(data) { if(data) {
HANDLE thread;
data->handle = handle; data->handle = handle;
data->signal = signal; data->signal = signal;
data->abort = abort; data->abort = abort;
/* launch waiting thread */ /* launch waiting thread */
thread = _beginthreadex(NULL, 0, &select_ws_wait_thread, data, 0, NULL); thread = CreateThread(NULL, 0, &select_ws_wait_thread, data, 0, NULL);
/* free data if thread failed to launch */ /* free data if thread failed to launch */
if(!thread) { if(!thread) {
free(data); free(data);
} }
return (HANDLE)thread; return thread;
} }
return NULL; return NULL;
} }

View File

@ -350,7 +350,7 @@ static SIGHANDLER_T old_sigbreak_handler = SIG_ERR;
#endif #endif
#if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) #if defined(_WIN32) && !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
static unsigned int thread_main_id = 0; static DWORD thread_main_id = 0;
static HANDLE thread_main_window = NULL; static HANDLE thread_main_window = NULL;
static HWND hidden_main_window = NULL; static HWND hidden_main_window = NULL;
#endif #endif
@ -487,8 +487,7 @@ static LRESULT CALLBACK main_window_proc(HWND hwnd, UINT uMsg,
} }
/* Window message queue loop for hidden main window, details see above. /* Window message queue loop for hidden main window, details see above.
*/ */
#include <process.h> static DWORD WINAPI main_window_loop(void *lpParameter)
static unsigned int WINAPI main_window_loop(void *lpParameter)
{ {
WNDCLASS wc; WNDCLASS wc;
BOOL ret; BOOL ret;
@ -509,7 +508,7 @@ static unsigned int WINAPI main_window_loop(void *lpParameter)
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
(HWND)NULL, (HMENU)NULL, (HWND)NULL, (HMENU)NULL,
wc.hInstance, (LPVOID)NULL); wc.hInstance, NULL);
if(!hidden_main_window) { if(!hidden_main_window) {
win32_perror("CreateWindowEx failed"); win32_perror("CreateWindowEx failed");
return (DWORD)-1; return (DWORD)-1;
@ -623,15 +622,10 @@ void install_signal_handlers(bool keep_sigalrm)
#endif #endif
#if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE) #if !defined(CURL_WINDOWS_UWP) && !defined(UNDER_CE)
{ thread_main_window = CreateThread(NULL, 0, &main_window_loop,
typedef uintptr_t curl_win_thread_handle_t; GetModuleHandle(NULL), 0, &thread_main_id);
curl_win_thread_handle_t thread;
thread = _beginthreadex(NULL, 0, &main_window_loop,
(void *)GetModuleHandle(NULL), 0, &thread_main_id);
thread_main_window = (HANDLE)thread;
if(!thread_main_window || !thread_main_id) if(!thread_main_window || !thread_main_id)
logmsg("cannot start main window loop"); logmsg("cannot start main window loop");
}
#endif #endif
#endif #endif
} }