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 */ 26static 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 40APR_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 67APR_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 90APR_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 104APR_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 120APR_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 139static void *dummy_worker(void *opaque) 140{ 141 apr_thread_t *thread = (apr_thread_t*)opaque; 142 return thread->func(thread, thread->data); 143} 144 145APR_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 191APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) 192{ 193 return pthread_self(); 194} 195 196APR_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 202APR_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 211APR_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 230APR_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 251APR_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 266APR_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 272APR_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 279APR_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 286APR_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 303APR_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 313APR_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 319APR_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 */ 327APR_DECLARE(apr_status_t) apr_os_thread_get(void); 328 329APR_DECLARE(apr_status_t) apr_os_thread_get(void) 330{ 331 return APR_ENOTIMPL; 332} 333 334#endif 335