xref: /aosp_15_r20/external/cronet/third_party/apache-portable-runtime/src/threadproc/win32/thread.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "apr_private.h"
18 #include "apr_arch_threadproc.h"
19 #include "apr_thread_proc.h"
20 #include "apr_general.h"
21 #include "apr_lib.h"
22 #include "apr_portable.h"
23 #if APR_HAVE_PROCESS_H
24 #include <process.h>
25 #endif
26 #include "apr_arch_misc.h"
27 
28 /* Chosen for us by apr_initialize */
29 DWORD tls_apr_thread = 0;
30 
apr_threadattr_create(apr_threadattr_t ** new,apr_pool_t * pool)31 APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new,
32                                                 apr_pool_t *pool)
33 {
34     (*new) = (apr_threadattr_t *)apr_palloc(pool,
35               sizeof(apr_threadattr_t));
36 
37     if ((*new) == NULL) {
38         return APR_ENOMEM;
39     }
40 
41     (*new)->pool = pool;
42     (*new)->detach = 0;
43     (*new)->stacksize = 0;
44 
45     return APR_SUCCESS;
46 }
47 
apr_threadattr_detach_set(apr_threadattr_t * attr,apr_int32_t on)48 APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr,
49                                                    apr_int32_t on)
50 {
51     attr->detach = on;
52     return APR_SUCCESS;
53 }
54 
apr_threadattr_detach_get(apr_threadattr_t * attr)55 APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr)
56 {
57     if (attr->detach == 1)
58         return APR_DETACH;
59     return APR_NOTDETACH;
60 }
61 
apr_threadattr_stacksize_set(apr_threadattr_t * attr,apr_size_t stacksize)62 APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr,
63                                                        apr_size_t stacksize)
64 {
65     attr->stacksize = stacksize;
66     return APR_SUCCESS;
67 }
68 
apr_threadattr_guardsize_set(apr_threadattr_t * attr,apr_size_t size)69 APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr,
70                                                        apr_size_t size)
71 {
72     return APR_ENOTIMPL;
73 }
74 
dummy_worker(void * opaque)75 static void *dummy_worker(void *opaque)
76 {
77     apr_thread_t *thd = (apr_thread_t *)opaque;
78     TlsSetValue(tls_apr_thread, thd->td);
79     return thd->func(thd, thd->data);
80 }
81 
apr_thread_create(apr_thread_t ** new,apr_threadattr_t * attr,apr_thread_start_t func,void * data,apr_pool_t * pool)82 APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new,
83                                             apr_threadattr_t *attr,
84                                             apr_thread_start_t func,
85                                             void *data, apr_pool_t *pool)
86 {
87     apr_status_t stat;
88 	unsigned temp;
89     HANDLE handle;
90 
91     (*new) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t));
92 
93     if ((*new) == NULL) {
94         return APR_ENOMEM;
95     }
96 
97     (*new)->data = data;
98     (*new)->func = func;
99     (*new)->td   = NULL;
100     stat = apr_pool_create(&(*new)->pool, pool);
101     if (stat != APR_SUCCESS) {
102         return stat;
103     }
104 
105     /* Use 0 for default Thread Stack Size, because that will
106      * default the stack to the same size as the calling thread.
107      */
108 #ifndef _WIN32_WCE
109     if ((handle = (HANDLE)_beginthreadex(NULL,
110                         (DWORD) (attr ? attr->stacksize : 0),
111                         (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker,
112                         (*new), 0, &temp)) == 0) {
113         return APR_FROM_OS_ERROR(_doserrno);
114     }
115 #else
116    if ((handle = CreateThread(NULL,
117                         attr && attr->stacksize > 0 ? attr->stacksize : 0,
118                         (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker,
119                         (*new), 0, &temp)) == 0) {
120         return apr_get_os_error();
121     }
122 #endif
123     if (attr && attr->detach) {
124         CloseHandle(handle);
125     }
126     else
127         (*new)->td = handle;
128 
129     return APR_SUCCESS;
130 }
131 
apr_thread_exit(apr_thread_t * thd,apr_status_t retval)132 APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd,
133                                           apr_status_t retval)
134 {
135     thd->exitval = retval;
136     apr_pool_destroy(thd->pool);
137     thd->pool = NULL;
138 #ifndef _WIN32_WCE
139     _endthreadex(0);
140 #else
141     ExitThread(0);
142 #endif
143     return APR_SUCCESS;
144 }
145 
apr_thread_join(apr_status_t * retval,apr_thread_t * thd)146 APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval,
147                                           apr_thread_t *thd)
148 {
149     apr_status_t rv = APR_SUCCESS;
150 
151     if (!thd->td) {
152         /* Can not join on detached threads */
153         return APR_DETACH;
154     }
155     rv = WaitForSingleObject(thd->td, INFINITE);
156     if ( rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) {
157         /* If the thread_exit has been called */
158         if (!thd->pool)
159             *retval = thd->exitval;
160         else
161             rv = APR_INCOMPLETE;
162     }
163     else
164         rv = apr_get_os_error();
165     CloseHandle(thd->td);
166     thd->td = NULL;
167 
168     return rv;
169 }
170 
apr_thread_detach(apr_thread_t * thd)171 APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd)
172 {
173     if (thd->td && CloseHandle(thd->td)) {
174         thd->td = NULL;
175         return APR_SUCCESS;
176     }
177     else {
178         return apr_get_os_error();
179     }
180 }
181 
apr_thread_yield()182 APR_DECLARE(void) apr_thread_yield()
183 {
184     /* SwitchToThread is not supported on Win9x, but since it's
185      * primarily a noop (entering time consuming code, therefore
186      * providing more critical threads a bit larger timeslice)
187      * we won't worry too much if it's not available.
188      */
189 #ifndef _WIN32_WCE
190     if (apr_os_level >= APR_WIN_NT) {
191         SwitchToThread();
192     }
193 #endif
194 }
195 
apr_thread_data_get(void ** data,const char * key,apr_thread_t * thread)196 APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key,
197                                              apr_thread_t *thread)
198 {
199     return apr_pool_userdata_get(data, key, thread->pool);
200 }
201 
apr_thread_data_set(void * data,const char * key,apr_status_t (* cleanup)(void *),apr_thread_t * thread)202 APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key,
203                                              apr_status_t (*cleanup) (void *),
204                                              apr_thread_t *thread)
205 {
206     return apr_pool_userdata_set(data, key, cleanup, thread->pool);
207 }
208 
209 
apr_os_thread_current(void)210 APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void)
211 {
212     HANDLE hthread = (HANDLE)TlsGetValue(tls_apr_thread);
213     HANDLE hproc;
214 
215     if (hthread) {
216         return hthread;
217     }
218 
219     hproc = GetCurrentProcess();
220     hthread = GetCurrentThread();
221     if (!DuplicateHandle(hproc, hthread,
222                          hproc, &hthread, 0, FALSE,
223                          DUPLICATE_SAME_ACCESS)) {
224         return NULL;
225     }
226     TlsSetValue(tls_apr_thread, hthread);
227     return hthread;
228 }
229 
apr_os_thread_get(apr_os_thread_t ** thethd,apr_thread_t * thd)230 APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd,
231                                             apr_thread_t *thd)
232 {
233     if (thd == NULL) {
234         return APR_ENOTHREAD;
235     }
236     *thethd = thd->td;
237     return APR_SUCCESS;
238 }
239 
apr_os_thread_put(apr_thread_t ** thd,apr_os_thread_t * thethd,apr_pool_t * pool)240 APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd,
241                                             apr_os_thread_t *thethd,
242                                             apr_pool_t *pool)
243 {
244     if (pool == NULL) {
245         return APR_ENOPOOL;
246     }
247     if ((*thd) == NULL) {
248         (*thd) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t));
249         (*thd)->pool = pool;
250     }
251     (*thd)->td = thethd;
252     return APR_SUCCESS;
253 }
254 
apr_thread_once_init(apr_thread_once_t ** control,apr_pool_t * p)255 APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control,
256                                                apr_pool_t *p)
257 {
258     (*control) = apr_pcalloc(p, sizeof(**control));
259     return APR_SUCCESS;
260 }
261 
apr_thread_once(apr_thread_once_t * control,void (* func)(void))262 APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control,
263                                           void (*func)(void))
264 {
265     if (!InterlockedExchange(&control->value, 1)) {
266         func();
267     }
268     return APR_SUCCESS;
269 }
270 
apr_os_thread_equal(apr_os_thread_t tid1,apr_os_thread_t tid2)271 APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1,
272                                      apr_os_thread_t tid2)
273 {
274     /* Since the only tid's we support our are own, and
275      * apr_os_thread_current returns the identical handle
276      * to the one we created initially, the test is simple.
277      */
278     return (tid1 == tid2);
279 }
280 
281 APR_POOL_IMPLEMENT_ACCESSOR(thread)
282