• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define INCL_DOSERRORS
18 #define INCL_DOS
19 #include "apr_arch_threadproc.h"
20 #include "apr_thread_proc.h"
21 #include "apr_general.h"
22 #include "apr_lib.h"
23 #include "apr_portable.h"
24 #include "apr_arch_file_io.h"
25 #include <stdlib.h>
26 
apr_threadattr_create(apr_threadattr_t ** new,apr_pool_t * pool)27 APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, apr_pool_t *pool)
28 {
29     (*new) = (apr_threadattr_t *)apr_palloc(pool, sizeof(apr_threadattr_t));
30 
31     if ((*new) == NULL) {
32         return APR_ENOMEM;
33     }
34 
35     (*new)->pool = pool;
36     (*new)->attr = 0;
37     (*new)->stacksize = 0;
38     return APR_SUCCESS;
39 }
40 
41 
42 
apr_threadattr_detach_set(apr_threadattr_t * attr,apr_int32_t on)43 APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, apr_int32_t on)
44 {
45     attr->attr |= APR_THREADATTR_DETACHED;
46     return APR_SUCCESS;
47 }
48 
49 
50 
apr_threadattr_detach_get(apr_threadattr_t * attr)51 APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr)
52 {
53     return (attr->attr & APR_THREADATTR_DETACHED) ? APR_DETACH : APR_NOTDETACH;
54 }
55 
apr_threadattr_stacksize_set(apr_threadattr_t * attr,apr_size_t stacksize)56 APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr,
57                                                        apr_size_t stacksize)
58 {
59     attr->stacksize = stacksize;
60     return APR_SUCCESS;
61 }
62 
apr_threadattr_guardsize_set(apr_threadattr_t * attr,apr_size_t size)63 APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr,
64                                                        apr_size_t size)
65 {
66     return APR_ENOTIMPL;
67 }
68 
apr_thread_begin(void * arg)69 static void apr_thread_begin(void *arg)
70 {
71   apr_thread_t *thread = (apr_thread_t *)arg;
72   thread->exitval = thread->func(thread, thread->data);
73 }
74 
75 
76 
apr_thread_create(apr_thread_t ** new,apr_threadattr_t * attr,apr_thread_start_t func,void * data,apr_pool_t * pool)77 APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t *attr,
78                                             apr_thread_start_t func, void *data,
79                                             apr_pool_t *pool)
80 {
81     apr_status_t stat;
82     apr_thread_t *thread;
83 
84     thread = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t));
85     *new = thread;
86 
87     if (thread == NULL) {
88         return APR_ENOMEM;
89     }
90 
91     thread->attr = attr;
92     thread->func = func;
93     thread->data = data;
94     stat = apr_pool_create(&thread->pool, pool);
95 
96     if (stat != APR_SUCCESS) {
97         return stat;
98     }
99 
100     if (attr == NULL) {
101         stat = apr_threadattr_create(&thread->attr, thread->pool);
102 
103         if (stat != APR_SUCCESS) {
104             return stat;
105         }
106     }
107 
108     thread->tid = _beginthread(apr_thread_begin, NULL,
109                                thread->attr->stacksize > 0 ?
110                                thread->attr->stacksize : APR_THREAD_STACKSIZE,
111                                thread);
112 
113     if (thread->tid < 0) {
114         return errno;
115     }
116 
117     return APR_SUCCESS;
118 }
119 
120 
121 
apr_os_thread_current()122 APR_DECLARE(apr_os_thread_t) apr_os_thread_current()
123 {
124     PIB *ppib;
125     TIB *ptib;
126     DosGetInfoBlocks(&ptib, &ppib);
127     return ptib->tib_ptib2->tib2_ultid;
128 }
129 
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, apr_status_t retval)
133 {
134     thd->exitval = retval;
135     _endthread();
136     return -1; /* If we get here something's wrong */
137 }
138 
139 
140 
apr_thread_join(apr_status_t * retval,apr_thread_t * thd)141 APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, apr_thread_t *thd)
142 {
143     ULONG rc;
144     TID waittid = thd->tid;
145 
146     if (thd->attr->attr & APR_THREADATTR_DETACHED)
147         return APR_EINVAL;
148 
149     rc = DosWaitThread(&waittid, DCWW_WAIT);
150 
151     if (rc == ERROR_INVALID_THREADID)
152         rc = 0; /* Thread had already terminated */
153 
154     *retval = thd->exitval;
155     return APR_OS2_STATUS(rc);
156 }
157 
158 
159 
apr_thread_detach(apr_thread_t * thd)160 APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd)
161 {
162     thd->attr->attr |= APR_THREADATTR_DETACHED;
163     return APR_SUCCESS;
164 }
165 
166 
167 
apr_thread_yield()168 void apr_thread_yield()
169 {
170     DosSleep(0);
171 }
172 
173 
174 
apr_os_thread_get(apr_os_thread_t ** thethd,apr_thread_t * thd)175 APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, apr_thread_t *thd)
176 {
177     *thethd = &thd->tid;
178     return APR_SUCCESS;
179 }
180 
181 
182 
apr_os_thread_put(apr_thread_t ** thd,apr_os_thread_t * thethd,apr_pool_t * pool)183 APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, apr_os_thread_t *thethd,
184                                             apr_pool_t *pool)
185 {
186     if ((*thd) == NULL) {
187         (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t));
188         (*thd)->pool = pool;
189     }
190     (*thd)->tid = *thethd;
191     return APR_SUCCESS;
192 }
193 
194 
195 
apr_os_thread_equal(apr_os_thread_t tid1,apr_os_thread_t tid2)196 int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2)
197 {
198     return tid1 == tid2;
199 }
200 
201 
202 
apr_thread_data_get(void ** data,const char * key,apr_thread_t * thread)203 APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread)
204 {
205     return apr_pool_userdata_get(data, key, thread->pool);
206 }
207 
208 
209 
apr_thread_data_set(void * data,const char * key,apr_status_t (* cleanup)(void *),apr_thread_t * thread)210 APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key,
211                                               apr_status_t (*cleanup) (void *),
212                                               apr_thread_t *thread)
213 {
214     return apr_pool_userdata_set(data, key, cleanup, thread->pool);
215 }
216 
APR_POOL_IMPLEMENT_ACCESSOR(thread)217 APR_POOL_IMPLEMENT_ACCESSOR(thread)
218 
219 
220 
221 static apr_status_t thread_once_cleanup(void *vcontrol)
222 {
223     apr_thread_once_t *control = (apr_thread_once_t *)vcontrol;
224 
225     if (control->sem) {
226         DosCloseEventSem(control->sem);
227     }
228 
229     return APR_SUCCESS;
230 }
231 
232 
233 
apr_thread_once_init(apr_thread_once_t ** control,apr_pool_t * p)234 APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control,
235                                                apr_pool_t *p)
236 {
237     ULONG rc;
238     *control = (apr_thread_once_t *)apr_pcalloc(p, sizeof(apr_thread_once_t));
239     rc = DosCreateEventSem(NULL, &(*control)->sem, 0, TRUE);
240     apr_pool_cleanup_register(p, control, thread_once_cleanup, apr_pool_cleanup_null);
241     return APR_FROM_OS_ERROR(rc);
242 }
243 
244 
245 
apr_thread_once(apr_thread_once_t * control,void (* func)(void))246 APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control,
247                                           void (*func)(void))
248 {
249     if (!control->hit) {
250         ULONG count, rc;
251         rc = DosResetEventSem(control->sem, &count);
252 
253         if (rc == 0 && count) {
254             control->hit = 1;
255             func();
256         }
257     }
258 
259     return APR_SUCCESS;
260 }
261