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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "apr_private.h"
18 #include "win32/apr_arch_threadproc.h"
19 #include "apr_thread_proc.h"
20 #include "apr_general.h"
22 #include "apr_portable.h"
23 #if APR_HAVE_PROCESS_H
26 #include "apr_arch_misc.h"
28 /* Chosen for us by apr_initialize */
29 DWORD tls_apr_thread = 0;
31 APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new,
34 (*new) = (apr_threadattr_t *)apr_palloc(pool,
35 sizeof(apr_threadattr_t));
43 (*new)->stacksize = 0;
48 APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr,
55 APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr)
57 if (attr->detach == 1)
62 APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr,
65 attr->stacksize = stacksize;
69 static void *dummy_worker(void *opaque)
71 apr_thread_t *thd = (apr_thread_t *)opaque;
72 TlsSetValue(tls_apr_thread, thd->td);
73 return thd->func(thd, thd->data);
76 APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new,
77 apr_threadattr_t *attr,
78 apr_thread_start_t func,
79 void *data, apr_pool_t *pool)
85 (*new) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t));
96 stat = apr_pool_create(&(*new)->pool, pool);
97 if (stat != APR_SUCCESS) {
101 /* Use 0 for Thread Stack Size, because that will default the stack to the
102 * same size as the calling thread.
105 if ((handle = (HANDLE)_beginthreadex(NULL,
106 attr && attr->stacksize > 0 ? attr->stacksize : 0,
107 (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker,
108 (*new), 0, &temp)) == 0) {
109 return APR_FROM_OS_ERROR(_doserrno);
112 if ((handle = CreateThread(NULL,
113 attr && attr->stacksize > 0 ? attr->stacksize : 0,
114 (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker,
115 (*new), 0, &temp)) == 0) {
116 return apr_get_os_error();
119 if (attr && attr->detach) {
128 APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd,
131 thd->exitval = retval;
132 apr_pool_destroy(thd->pool);
142 APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval,
145 apr_status_t rv = APR_SUCCESS;
148 /* Can not join on detached threads */
151 rv = WaitForSingleObject(thd->td, INFINITE);
152 if ( rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) {
153 /* If the thread_exit has been called */
155 *retval = thd->exitval;
160 rv = apr_get_os_error();
161 CloseHandle(thd->td);
167 APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd)
169 if (thd->td && CloseHandle(thd->td)) {
174 return apr_get_os_error();
178 APR_DECLARE(void) apr_thread_yield()
180 /* SwitchToThread is not supported on Win9x, but since it's
181 * primarily a noop (entering time consuming code, therefore
182 * providing more critical threads a bit larger timeslice)
183 * we won't worry too much if it's not available.
186 if (apr_os_level >= APR_WIN_NT) {
192 APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key,
193 apr_thread_t *thread)
195 return apr_pool_userdata_get(data, key, thread->pool);
198 APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key,
199 apr_status_t (*cleanup) (void *),
200 apr_thread_t *thread)
202 return apr_pool_userdata_set(data, key, cleanup, thread->pool);
206 APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void)
208 HANDLE hthread = (HANDLE)TlsGetValue(tls_apr_thread);
215 hproc = GetCurrentProcess();
216 hthread = GetCurrentThread();
217 if (!DuplicateHandle(hproc, hthread,
218 hproc, &hthread, 0, FALSE,
219 DUPLICATE_SAME_ACCESS)) {
222 TlsSetValue(tls_apr_thread, hthread);
226 APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd,
230 return APR_ENOTHREAD;
236 APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd,
237 apr_os_thread_t *thethd,
243 if ((*thd) == NULL) {
244 (*thd) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t));
251 APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control,
254 (*control) = apr_pcalloc(p, sizeof(**control));
258 APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control,
261 if (!InterlockedExchange(&control->value, 1)) {
267 APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1,
268 apr_os_thread_t tid2)
270 /* Since the only tid's we support our are own, and
271 * apr_os_thread_current returns the identical handle
272 * to the one we created initially, the test is simple.
274 return (tid1 == tid2);
277 APR_POOL_IMPLEMENT_ACCESSOR(thread)