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_strings.h" 20#include "apr_arch_threadproc.h" 21 22static int thread_count = 0; 23 24apr_status_t apr_threadattr_create(apr_threadattr_t **new, 25 apr_pool_t *pool) 26{ 27 (*new) = (apr_threadattr_t *)apr_palloc(pool, 28 sizeof(apr_threadattr_t)); 29 30 if ((*new) == NULL) { 31 return APR_ENOMEM; 32 } 33 34 (*new)->pool = pool; 35 (*new)->stack_size = APR_DEFAULT_STACK_SIZE; 36 (*new)->detach = 0; 37 (*new)->thread_name = NULL; 38 return APR_SUCCESS; 39} 40 41apr_status_t apr_threadattr_detach_set(apr_threadattr_t *attr,apr_int32_t on) 42{ 43 attr->detach = on; 44 return APR_SUCCESS; 45} 46 47apr_status_t apr_threadattr_detach_get(apr_threadattr_t *attr) 48{ 49 if (attr->detach == 1) 50 return APR_DETACH; 51 return APR_NOTDETACH; 52} 53 54APR_DECLARE(apr_status_t) apr_threadattr_stacksize_set(apr_threadattr_t *attr, 55 apr_size_t stacksize) 56{ 57 attr->stack_size = stacksize; 58 return APR_SUCCESS; 59} 60 61APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, 62 apr_size_t size) 63{ 64 return APR_ENOTIMPL; 65} 66 67static void *dummy_worker(void *opaque) 68{ 69 apr_thread_t *thd = (apr_thread_t *)opaque; 70 return thd->func(thd, thd->data); 71} 72 73apr_status_t apr_thread_create(apr_thread_t **new, 74 apr_threadattr_t *attr, 75 apr_thread_start_t func, 76 void *data, 77 apr_pool_t *pool) 78{ 79 apr_status_t stat; 80 long flags = NX_THR_BIND_CONTEXT; 81 char threadName[NX_MAX_OBJECT_NAME_LEN+1]; 82 size_t stack_size = APR_DEFAULT_STACK_SIZE; 83 84 if (attr && attr->thread_name) { 85 strncpy (threadName, attr->thread_name, NX_MAX_OBJECT_NAME_LEN); 86 } 87 else { 88 sprintf(threadName, "APR_thread %04ld", ++thread_count); 89 } 90 91 /* An original stack size of 0 will allow NXCreateThread() to 92 * assign a default system stack size. An original stack 93 * size of less than 0 will assign the APR default stack size. 94 * anything else will be taken as is. 95 */ 96 if (attr && (attr->stack_size >= 0)) { 97 stack_size = attr->stack_size; 98 } 99 100 (*new) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); 101 102 if ((*new) == NULL) { 103 return APR_ENOMEM; 104 } 105 106 (*new)->data = data; 107 (*new)->func = func; 108 (*new)->thread_name = (char*)apr_pstrdup(pool, threadName); 109 110 stat = apr_pool_create(&(*new)->pool, pool); 111 if (stat != APR_SUCCESS) { 112 return stat; 113 } 114 115 if (attr && attr->detach) { 116 flags |= NX_THR_DETACHED; 117 } 118 119 (*new)->ctx = NXContextAlloc( 120 /* void(*start_routine)(void *arg) */ (void (*)(void *)) dummy_worker, 121 /* void *arg */ (*new), 122 /* int priority */ NX_PRIO_MED, 123 /* NXSize_t stackSize */ stack_size, 124 /* long flags */ NX_CTX_NORMAL, 125 /* int *error */ &stat); 126 127 stat = NXContextSetName( 128 /* NXContext_t ctx */ (*new)->ctx, 129 /* const char *name */ threadName); 130 131 stat = NXThreadCreate( 132 /* NXContext_t context */ (*new)->ctx, 133 /* long flags */ flags, 134 /* NXThreadId_t *thread_id */ &(*new)->td); 135 136 if (stat == 0) 137 return APR_SUCCESS; 138 139 return(stat); /* if error */ 140} 141 142apr_os_thread_t apr_os_thread_current() 143{ 144 return NXThreadGetId(); 145} 146 147int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2) 148{ 149 return (tid1 == tid2); 150} 151 152void apr_thread_yield() 153{ 154 NXThreadYield(); 155} 156 157apr_status_t apr_thread_exit(apr_thread_t *thd, 158 apr_status_t retval) 159{ 160 thd->exitval = retval; 161 apr_pool_destroy(thd->pool); 162 NXThreadExit(NULL); 163 return APR_SUCCESS; 164} 165 166apr_status_t apr_thread_join(apr_status_t *retval, 167 apr_thread_t *thd) 168{ 169 apr_status_t stat; 170 NXThreadId_t dthr; 171 172 if ((stat = NXThreadJoin(thd->td, &dthr, NULL)) == 0) { 173 *retval = thd->exitval; 174 return APR_SUCCESS; 175 } 176 else { 177 return stat; 178 } 179} 180 181apr_status_t apr_thread_detach(apr_thread_t *thd) 182{ 183 return APR_SUCCESS; 184} 185 186apr_status_t apr_thread_data_get(void **data, const char *key, 187 apr_thread_t *thread) 188{ 189 if (thread != NULL) { 190 return apr_pool_userdata_get(data, key, thread->pool); 191 } 192 else { 193 data = NULL; 194 return APR_ENOTHREAD; 195 } 196} 197 198apr_status_t apr_thread_data_set(void *data, const char *key, 199 apr_status_t (*cleanup) (void *), 200 apr_thread_t *thread) 201{ 202 if (thread != NULL) { 203 return apr_pool_userdata_set(data, key, cleanup, thread->pool); 204 } 205 else { 206 data = NULL; 207 return APR_ENOTHREAD; 208 } 209} 210 211APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, 212 apr_thread_t *thd) 213{ 214 if (thd == NULL) { 215 return APR_ENOTHREAD; 216 } 217 *thethd = &(thd->td); 218 return APR_SUCCESS; 219} 220 221APR_DECLARE(apr_status_t) apr_os_thread_put(apr_thread_t **thd, 222 apr_os_thread_t *thethd, 223 apr_pool_t *pool) 224{ 225 if (pool == NULL) { 226 return APR_ENOPOOL; 227 } 228 if ((*thd) == NULL) { 229 (*thd) = (apr_thread_t *)apr_palloc(pool, sizeof(apr_thread_t)); 230 (*thd)->pool = pool; 231 } 232 (*thd)->td = *thethd; 233 return APR_SUCCESS; 234} 235 236APR_DECLARE(apr_status_t) apr_thread_once_init(apr_thread_once_t **control, 237 apr_pool_t *p) 238{ 239 (*control) = apr_pcalloc(p, sizeof(**control)); 240 return APR_SUCCESS; 241} 242 243APR_DECLARE(apr_status_t) apr_thread_once(apr_thread_once_t *control, 244 void (*func)(void)) 245{ 246 if (!atomic_xchg(&control->value, 1)) { 247 func(); 248 } 249 return APR_SUCCESS; 250} 251 252APR_POOL_IMPLEMENT_ACCESSOR(thread) 253 254 255