1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25 #include "curl_setup.h"
26
27 #include <curl/curl.h>
28
29 #if defined(USE_THREADS_POSIX)
30 # ifdef HAVE_PTHREAD_H
31 # include <pthread.h>
32 # endif
33 #elif defined(USE_THREADS_WIN32)
34 # include <process.h>
35 #endif
36
37 #include "curl_threads.h"
38 #ifdef BUILDING_LIBCURL
39 #include "curl_memory.h"
40 #endif
41 /* The last #include file should be: */
42 #include "memdebug.h"
43
44 #if defined(USE_THREADS_POSIX)
45
46 struct Curl_actual_call {
47 unsigned int (*func)(void *);
48 void *arg;
49 };
50
curl_thread_create_thunk(void * arg)51 static void *curl_thread_create_thunk(void *arg)
52 {
53 struct Curl_actual_call *ac = arg;
54 unsigned int (*func)(void *) = ac->func;
55 void *real_arg = ac->arg;
56
57 free(ac);
58
59 (*func)(real_arg);
60
61 return 0;
62 }
63
Curl_thread_create(unsigned int (* func)(void *),void * arg)64 curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg)
65 {
66 curl_thread_t t = malloc(sizeof(pthread_t));
67 struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call));
68 if(!(ac && t))
69 goto err;
70
71 ac->func = func;
72 ac->arg = arg;
73
74 if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0)
75 goto err;
76
77 return t;
78
79 err:
80 free(t);
81 free(ac);
82 return curl_thread_t_null;
83 }
84
Curl_thread_destroy(curl_thread_t hnd)85 void Curl_thread_destroy(curl_thread_t hnd)
86 {
87 if(hnd != curl_thread_t_null) {
88 pthread_detach(*hnd);
89 free(hnd);
90 }
91 }
92
Curl_thread_join(curl_thread_t * hnd)93 int Curl_thread_join(curl_thread_t *hnd)
94 {
95 int ret = (pthread_join(**hnd, NULL) == 0);
96
97 free(*hnd);
98 *hnd = curl_thread_t_null;
99
100 return ret;
101 }
102
103 #elif defined(USE_THREADS_WIN32)
104
Curl_thread_create(DWORD (CURL_STDCALL * func)(void *),void * arg)105 curl_thread_t Curl_thread_create(
106 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
107 DWORD
108 #else
109 unsigned int
110 #endif
111 (CURL_STDCALL *func) (void *),
112 void *arg)
113 {
114 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
115 typedef HANDLE curl_win_thread_handle_t;
116 #else
117 typedef uintptr_t curl_win_thread_handle_t;
118 #endif
119 curl_thread_t t;
120 curl_win_thread_handle_t thread_handle;
121 #if defined(_WIN32_WCE) || defined(CURL_WINDOWS_UWP)
122 thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
123 #else
124 thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
125 #endif
126 t = (curl_thread_t)thread_handle;
127 if((t == 0) || (t == LongToHandle(-1L))) {
128 #ifdef _WIN32_WCE
129 DWORD gle = GetLastError();
130 errno = ((gle == ERROR_ACCESS_DENIED ||
131 gle == ERROR_NOT_ENOUGH_MEMORY) ?
132 EACCES : EINVAL);
133 #endif
134 return curl_thread_t_null;
135 }
136 return t;
137 }
138
Curl_thread_destroy(curl_thread_t hnd)139 void Curl_thread_destroy(curl_thread_t hnd)
140 {
141 if(hnd != curl_thread_t_null)
142 CloseHandle(hnd);
143 }
144
Curl_thread_join(curl_thread_t * hnd)145 int Curl_thread_join(curl_thread_t *hnd)
146 {
147 #if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
148 (_WIN32_WINNT < _WIN32_WINNT_VISTA)
149 int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
150 #else
151 int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
152 #endif
153
154 Curl_thread_destroy(*hnd);
155
156 *hnd = curl_thread_t_null;
157
158 return ret;
159 }
160
161 #endif /* USE_THREADS_* */
162