Coverage Report

Created: 2026-09-01 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/curl_threads.c
Line
Count
Source
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
#include "curl_setup.h"
25
#include "curl_threads.h"
26
#include "curlx/timeval.h"
27
28
#ifdef USE_THREADS
29
30
#ifdef _WIN32
31
32
curl_thread_t Curl_thread_create(
33
  CURL_THREAD_RETURN_T(CURL_STDCALL *func)(void *), void *arg)
34
{
35
  curl_thread_t t = CreateThread(NULL, 0, func, arg, 0, NULL);
36
  if(!t) {
37
    DWORD gle = GetLastError();
38
    /* !checksrc! disable ERRNOVAR 1 */
39
    errno = (gle == ERROR_ACCESS_DENIED ||
40
             gle == ERROR_NOT_ENOUGH_MEMORY) ?
41
             EACCES : EINVAL;
42
    return curl_thread_t_null;
43
  }
44
  return t;
45
}
46
47
void Curl_thread_destroy(curl_thread_t *hnd)
48
{
49
  if(*hnd != curl_thread_t_null) {
50
    CloseHandle(*hnd);
51
    *hnd = curl_thread_t_null;
52
  }
53
}
54
55
int Curl_thread_join(curl_thread_t *hnd)
56
{
57
  int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
58
59
  Curl_thread_destroy(hnd);
60
61
  return ret;
62
}
63
64
#elif defined(HAVE_THREADS_POSIX)
65
66
struct Curl_actual_call {
67
  unsigned int (*func)(void *);
68
  void *arg;
69
};
70
71
static void *curl_thread_create_thunk(void *arg)
72
0
{
73
0
  struct Curl_actual_call *ac = arg;
74
0
  unsigned int (*func)(void *) = ac->func;
75
0
  void *real_arg = ac->arg;
76
77
0
  curlx_free(ac);
78
79
0
  (*func)(real_arg);
80
81
0
  return 0;
82
0
}
83
84
curl_thread_t Curl_thread_create(
85
  CURL_THREAD_RETURN_T(CURL_STDCALL *func)(void *), void *arg)
86
0
{
87
0
  curl_thread_t t = curlx_malloc(sizeof(pthread_t));
88
0
  struct Curl_actual_call *ac = NULL;
89
0
  int rc;
90
91
0
  if(t)
92
0
    ac = curlx_malloc(sizeof(struct Curl_actual_call));
93
0
  if(!(ac && t))
94
0
    goto err;
95
96
0
  ac->func = func;
97
0
  ac->arg = arg;
98
99
0
  rc = pthread_create(t, NULL, curl_thread_create_thunk, ac);
100
0
  if(rc) {
101
0
    errno = rc;
102
0
    goto err;
103
0
  }
104
105
0
  return t;
106
107
0
err:
108
0
  curlx_free(t);
109
0
  curlx_free(ac);
110
0
  return curl_thread_t_null;
111
0
}
112
113
void Curl_thread_destroy(curl_thread_t *hnd)
114
0
{
115
0
  if(*hnd != curl_thread_t_null) {
116
0
    pthread_detach(**hnd);
117
0
    curlx_free(*hnd);
118
0
    *hnd = curl_thread_t_null;
119
0
  }
120
0
}
121
122
int Curl_thread_join(curl_thread_t *hnd)
123
0
{
124
0
  int ret = (pthread_join(**hnd, NULL) == 0);
125
126
0
  curlx_free(*hnd);
127
0
  *hnd = curl_thread_t_null;
128
129
0
  return ret;
130
0
}
131
132
#else
133
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
134
#endif
135
#endif /* USE_THREADS */
136
137
#ifdef USE_MUTEX
138
139
#ifdef _WIN32
140
141
void Curl_cond_signal(CONDITION_VARIABLE *c)
142
{
143
  WakeConditionVariable(c);
144
}
145
146
void Curl_cond_wait(CONDITION_VARIABLE *c, CRITICAL_SECTION *m)
147
{
148
  SleepConditionVariableCS(c, m, INFINITE);
149
}
150
151
CURLcode Curl_cond_timedwait(CONDITION_VARIABLE *c, CRITICAL_SECTION *m,
152
                             uint32_t timeout_ms)
153
{
154
  if(!SleepConditionVariableCS(c, m, (DWORD)timeout_ms)) {
155
    DWORD err = GetLastError();
156
    return (err == ERROR_TIMEOUT) ?
157
           CURLE_OPERATION_TIMEDOUT : CURLE_UNRECOVERABLE_POLL;
158
  }
159
  return CURLE_OK;
160
}
161
162
curl_thread_id_t Curl_thread_get_current_id(void)
163
{
164
  return GetCurrentThreadId();
165
}
166
167
bool Curl_thread_is_current(curl_thread_id_t tid)
168
{
169
  return tid == GetCurrentThreadId();
170
}
171
172
#elif defined(HAVE_THREADS_POSIX)
173
174
void Curl_cond_signal(pthread_cond_t *c)
175
0
{
176
  /* return code defined as always 0 */
177
0
  (void)pthread_cond_signal(c);
178
0
}
179
180
void Curl_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
181
0
{
182
  /* return code defined as always 0 */
183
0
  (void)pthread_cond_wait(c, m);
184
0
}
185
186
CURLcode Curl_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m,
187
                             uint32_t timeout_ms)
188
0
{
189
0
  struct curltime now;
190
0
  struct timespec ts;
191
0
  timediff_t usec;
192
0
  int rc;
193
194
  /* POSIX expects an "absolute" time until the condition wait ends.
195
   * We cannot use `curlx_now()` here that may run on some monotonic clock
196
   * that will be most likely in the past, as far as POSIX abstime is
197
   * concerned. */
198
0
#ifdef HAVE_GETTIMEOFDAY
199
0
  struct timeval tv;
200
0
  (void)gettimeofday(&tv, NULL);
201
0
  now.tv_sec = tv.tv_sec;
202
0
  now.tv_usec = (int)tv.tv_usec;
203
#else
204
  now.tv_sec = time(NULL);
205
  now.tv_usec = 0;
206
#endif
207
208
0
  ts.tv_sec = now.tv_sec + (timeout_ms / 1000);
209
0
  usec = now.tv_usec + ((timeout_ms % 1000) * 1000);
210
0
  if(usec >= 1000000) {
211
0
    ++ts.tv_sec;
212
0
    usec %= 1000000;
213
0
  }
214
0
  ts.tv_nsec = (long)usec * 1000;
215
216
0
  rc = pthread_cond_timedwait(c, m, &ts);
217
0
  if(rc == SOCKETIMEDOUT)
218
0
    return CURLE_OPERATION_TIMEDOUT;
219
0
  return rc ? CURLE_UNRECOVERABLE_POLL : CURLE_OK;
220
0
}
221
222
curl_thread_id_t Curl_thread_get_current_id(void)
223
1.29k
{
224
1.29k
  return pthread_self();
225
1.29k
}
226
227
bool Curl_thread_is_current(curl_thread_id_t tid)
228
0
{
229
0
  return !!pthread_equal(tid, pthread_self());
230
0
}
231
232
#else
233
#error neither HAVE_THREADS_POSIX nor _WIN32 defined
234
#endif
235
#endif /* USE_MUTEX */