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.h" 18 #include "apr_portable.h" 19 #include "apr_arch_threadproc.h" 20 21 #if APR_HAS_THREADS 22 23 #if APR_HAVE_PTHREAD_H 24 25 /* Destroy the threadattr object */ 26 static apr_status_t threadattr_cleanup(void *data) 27 { 28 apr_threadattr_t *attr = data; 29 apr_status_t rv; 30 31 rv = pthread_attr_destroy(&attr->attr); 32 #ifdef HAVE_ZOS_PTHREADS 33 if (rv) { 34 rv = errno; 35 } 36 #endif 37 return rv; 38 } 39 40 APR_DECLARE(apr_status_t) apr_threadattr_create(apr_threadattr_t **new, 41 apr_pool_t *pool) 42 { 43 apr_status_t stat; 44 45 (*new) = apr_palloc(pool, sizeof(apr_threadattr_t)); 46 (*new)->pool = pool; 47 stat = pthread_attr_init(&(*new)->attr); 48 49 if (stat == 0) { 50 apr_pool_cleanup_register(pool, *new, threadattr_cleanup, 51 apr_pool_cleanup_null); 52 return APR_SUCCESS; 53 } 54 #ifdef HAVE_ZOS_PTHREADS 55 stat = errno; 56 #endif 57 58 return stat; 59 } 60 61 #if defined(PTHREAD_CREATE_DETACHED) 62 #define DETACH_ARG(v) ((v) ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE) 63 #else 64 #define DETACH_ARG(v) ((v) ? 1 : 0) 65 #endif 66 67 APR_DECLARE(apr_status_t) apr_threadattr_detach_set(apr_threadattr_t *attr, 68 apr_int32_t on) 69 { 70 apr_status_t stat; 71 #ifdef HAVE_ZOS_PTHREADS 72 int arg = DETACH_ARG(on); 73 74 if ((stat = pthread_attr_setdetachstate(&attr->attr, &arg)) == 0) { 75 #else 76 if ((stat = pthread_attr_setdetachstate(&attr->attr, 77 DETACH_ARG(on))) == 0) { 78 #endif 79 return APR_SUCCESS; 80 } 81 else { 82 #ifdef HAVE_ZOS_PTHREADS 83 stat = errno; 84 #endif 85 86 return stat; 87 } 88 } 89 90 APR_DECLARE(apr_status_t) apr_threadattr_detach_get(apr_threadattr_t *attr) 91 { 92 int state; 93 94 #ifdef PTHREAD_ATTR_GETDETACHSTATE_TAKES_ONE_ARG 95 state = pthread_attr_getdetachstate(&attr->attr); 96 #else 97 pthread_attr_getdetachstate(&attr->attr, &state); 98 #endif 99 if (state == DETACH_ARG(1)) 100 return APR_DETACH; 101 return APR_NOTDETACH; 102 } 103 104 APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, 105 apr_size_t stacksize) 106 { 107 int stat; 108 109 stat = pthread_attr_setstacksize(&attr->attr, stacksize); 110 if (stat == 0) { 111 return APR_SUCCESS; 112 } 113 #ifdef HAVE_ZOS_PTHREADS 114 stat = errno; 115 #endif 116 117 return stat; 118 } 119 120 APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, 121 apr_size_t size) 122 { 123 #ifdef HAVE_PTHREAD_ATTR_SETGUARDSIZE 124 apr_status_t rv; 125 126 rv = pthread_attr_setguardsize(&attr->attr, size); 127 if (rv == 0) { 128 return APR_SUCCESS; 129 } 130 #ifdef HAVE_ZOS_PTHREADS 131 rv = errno; 132 #endif 133 return rv; 134 #else 135 return APR_ENOTIMPL; 136 #endif 137 } 138 139 static void *dummy_worker(void *opaque) 140 { 141 apr_thread_t *thread = (apr_thread_t*)opaque; 142 return thread->func(thread, thread->data); 143 } 144 145 APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, 146 apr_threadattr_t *attr, 147 apr_thread_start_t func, 148 void *data, 149 apr_pool_t *pool) 150 { 151 apr_status_t stat; 152 pthread_attr_t *temp; 153 154 (*new) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); 155 156 if ((*new) == NULL) { 157 return APR_ENOMEM; 158 } 159 160 (*new)->td = (pthread_t *)apr_pcalloc(pool, sizeof(pthread_t)); 161 162 if ((*new)->td == NULL) { 163 return APR_ENOMEM; 164 } 165 166 (*new)->data = data; 167 (*new)->func = func; 168 169 if (attr) 170 temp = &attr->attr; 171 else 172 temp = NULL; 173 174 stat = apr_pool_create(&(*new)->pool, pool); 175 if (stat != APR_SUCCESS) { 176 return stat; 177 } 178 179 if ((stat = pthread_create((*new)->td, temp, dummy_worker, (*new))) == 0) { 180 return APR_SUCCESS; 181 } 182 else { 183 #ifdef HAVE_ZOS_PTHREADS 184 stat = errno; 185 #endif 186 187 return stat; 188 } 189 } 190 191 APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) 192 { 193 return pthread_self(); 194 } 195 196 APR_DECLARE(int) apr_os_thread_equal(apr_os_thread_t tid1, 197 apr_os_thread_t tid2) 198 { 199 return pthread_equal(tid1, tid2); 200 } 201 202 APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, 203 apr_status_t retval) 204 { 205 thd->exitval = retval; 206 apr_pool_destroy(thd->pool); 207 pthread_exit(NULL); 208 return APR_SUCCESS; 209 } 210 211 APR_DECLARE(apr_status_t) apr_thread_join(apr_status_t *retval, 212 apr_thread_t *thd) 213 { 214 apr_status_t stat; 215 apr_status_t *thread_stat; 216 217 if ((stat = pthread_join(*thd->td,(void *)&thread_stat)) == 0) { 218 *retval = thd->exitval; 219 return APR_SUCCESS; 220 } 221 else { 222 #ifdef HAVE_ZOS_PTHREADS 223 stat = errno; 224 #endif 225 226 return stat; 227 } 228 } 229 230 APR_DECLARE(apr_status_t) apr_thread_detach(apr_thread_t *thd) 231 { 232 apr_status_t stat; 233 234 #ifdef HAVE_ZOS_PTHREADS 235 if ((stat = pthread_detach(thd->td)) == 0) { 236 #else 237 if ((stat = pthread_detach(*thd->td)) == 0) { 238 #endif 239 240 return APR_SUCCESS; 241 } 242 else { 243 #ifdef HAVE_ZOS_PTHREADS 244 stat = errno; 245 #endif 246 247 return stat; 248 } 249 } 250 251 APR_DECLARE(void) apr_thread_yield(void) 252 { 253 #ifdef HAVE_PTHREAD_YIELD 254 #ifdef HAVE_ZOS_PTHREADS 255 pthread_yield(NULL); 256 #else 257 pthread_yield(); 258 #endif /* HAVE_ZOS_PTHREADS */ 259 #else 260 #ifdef HAVE_SCHED_YIELD 261 sched_yield(); 262 #endif 263 #endif 264 } 265 266 APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, 267 apr_thread_t *thread) 268 { 269 return apr_pool_userdata_get(data, key, thread->pool); 270 } 271 272 APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, 273 apr_status_t (*cleanup)(void *), 274 apr_thread_t *thread) 275 { 276 return apr_pool_userdata_set(data, key, cleanup, thread->pool); 277 } 278 279 APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, 280 apr_thread_t *thd) 281 { 282 *thethd = thd->td; 283 return APR_SUCCESS; 284 } 285 286 APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, 287 apr_os_thread_t *thethd, 288 apr_pool_t *pool) 289 { 290 if (pool == NULL) { 291 return APR_ENOPOOL; 292 } 293 294 if ((*thd) == NULL) { 295 (*thd) = (apr_thread_t *)apr_pcalloc(pool, sizeof(apr_thread_t)); 296 (*thd)->pool = pool; 297 } 298 299 (*thd)->td = thethd; 300 return APR_SUCCESS; 301 } 302 303 APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, 304 apr_pool_t *p) 305 { 306 static const pthread_once_t once_init = PTHREAD_ONCE_INIT; 307 308 *control = apr_palloc(p, sizeof(**control)); 309 (*control)->once = once_init; 310 return APR_SUCCESS; 311 } 312 313 APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, 314 void (*func)(void)) 315 { 316 return pthread_once(&control->once, func); 317 } 318 319 APR_POOL_IMPLEMENT_ACCESSOR(thread) 320 321 #endif /* HAVE_PTHREAD_H */ 322 #endif /* APR_HAS_THREADS */ 323 324 #if !APR_HAS_THREADS 325 326 /* avoid warning for no prototype */ 327 APR_DECLARE(apr_status_t) apr_os_thread_get(void); 328 329 APR_DECLARE(apr_status_t) apr_os_thread_get(void) 330 { 331 return APR_ENOTIMPL; 332 } 333 334 #endif 335