/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include DWORD tls_axutil_thread = 0; AXIS2_EXTERN axutil_threadattr_t *AXIS2_CALL axutil_threadattr_create( axutil_allocator_t * allocator) { axutil_threadattr_t *new = NULL; new = AXIS2_MALLOC(allocator, sizeof(axutil_threadattr_t)); if(!new) { /*AXIS2_ERROR_SET(env->error, AXIS2_ERROR_NO_MEMORY, AXIS2_FAILURE) */ return NULL; } new->detach = 0; new->stacksize = 0; return new; } /* Destroy the threadattr object */ AXIS2_EXTERN axis2_status_t AXIS2_CALL threadattr_cleanup( void *data) { /*axutil_threadattr_t *attr = data;*/ /*nothing to clean up */ return AXIS2_SUCCESS; } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_threadattr_detach_set( axutil_threadattr_t * attr, axis2_bool_t detached) { attr->detach = detached; return AXIS2_SUCCESS; } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_threadattr_detach_get( axutil_threadattr_t * attr, const axutil_env_t * env) { if(1 == attr->detach) { return AXIS2_TRUE; } return AXIS2_FALSE; } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_threadattr_stacksize_set( axutil_threadattr_t * attr, size_t stacksize) { attr->stacksize = stacksize; return AXIS2_SUCCESS; } static void * dummy_worker( void *opaque) { axutil_thread_t *thd = (axutil_thread_t *)opaque; TlsSetValue(tls_axutil_thread, thd->td); return thd->func(thd, thd->data); } AXIS2_EXTERN axutil_thread_t *AXIS2_CALL axutil_thread_create( axutil_allocator_t * allocator, axutil_threadattr_t * attr, axutil_thread_start_t func, void *data) { HANDLE handle; unsigned long temp; axutil_thread_t *new = NULL; new = (axutil_thread_t *)AXIS2_MALLOC(allocator, sizeof(axutil_thread_t)); if(!new) { return NULL; } new->data = data; new->func = func; new->td = NULL; new->try_exit = AXIS2_FALSE; /* Use 0 for Thread Stack Size, because that will default the stack to the * same size as the calling thread. */ if((handle = CreateThread(NULL, attr && attr->stacksize > 0 ? attr->stacksize : 0, (unsigned long (AXIS2_THREAD_FUNC *) (void *)) dummy_worker, new, 0, &temp)) == 0) { return NULL; } if(attr && attr->detach) { CloseHandle(handle); } else new->td = handle; return new; } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_thread_exit( axutil_thread_t * thd, axutil_allocator_t * allocator) { axis2_status_t status = AXIS2_SUCCESS; if(thd) { if(thd->td && (axis2_os_thread_current() != thd->td)) { TerminateThread(thd->td, 0); axutil_thread_join(thd); AXIS2_FREE(allocator, thd); return status; } AXIS2_FREE(allocator, thd); } if(status) { ExitThread(0); } return status; } AXIS2_EXTERN axis2_os_thread_t AXIS2_CALL axis2_os_thread_current( void) { HANDLE hthread = (HANDLE)TlsGetValue(tls_axutil_thread); HANDLE hproc; if(hthread) { return hthread; } hproc = GetCurrentProcess(); hthread = GetCurrentThread(); if(!DuplicateHandle(hproc, hthread, hproc, &hthread, 0, FALSE, DUPLICATE_SAME_ACCESS)) { return NULL; } TlsSetValue(tls_axutil_thread, hthread); return hthread; } AXIS2_EXTERN int AXIS2_CALL axis2_os_thread_equal( axis2_os_thread_t tid1, axis2_os_thread_t tid2) { return (tid1 == tid2); } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_thread_join( axutil_thread_t * thd) { axis2_status_t rv = AXIS2_SUCCESS, rv1; if(!thd->td) { /* Can not join on detached threads */ return AXIS2_FAILURE; } rv1 = WaitForSingleObject(thd->td, INFINITE); if(rv1 == WAIT_OBJECT_0 || rv1 == WAIT_ABANDONED) { /*rv = AXIS2_INCOMPLETE; */ } else rv = AXIS2_FAILURE; CloseHandle(thd->td); thd->td = NULL; return rv; } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_thread_detach( axutil_thread_t * thd) { if(thd->td && CloseHandle(thd->td)) { thd->td = NULL; return AXIS2_SUCCESS; } else { return AXIS2_FAILURE; } } AXIS2_EXTERN axis2_os_thread_t AXIS2_CALL axis2_os_thread_get( axutil_thread_t * thd, const axutil_env_t * env) { return thd->td; } /** * function is used to allocate a new key. This key now becomes valid for all threads in our process. * When a key is created, the value it points to defaults to NULL. Later on each thread may change * its copy of the value as it wishes. */ AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_thread_key_create( axutil_threadkey_t * axis2_key) { DWORD tls_key = axis2_key->key; if ((tls_key = TlsAlloc()) == TLS_OUT_OF_INDEXES) { return AXIS2_FAILURE; } else { return AXIS2_SUCCESS; } } /** * This function is used to get the value of a given key * @return void*. A key's value is simply a void pointer (void*) */ AXIS2_EXTERN void *AXIS2_CALL axutil_thread_getspecific( axutil_threadkey_t * axis2_key) { void *value = NULL; DWORD tls_key = axis2_key->key; value = TlsGetValue(tls_key); return value; } /** * This function is used to get the value of a given key * @param keys value. A key's value is simply a void pointer (void*), so we can * store in it anything that we want */ AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_thread_setspecific( axutil_threadkey_t * axis2_key, void *value) { DWORD tls_key = axis2_key->key; if(!TlsSetValue(tls_key, value)) { return AXIS2_FAILURE; } else { return AXIS2_SUCCESS; } } AXIS2_EXTERN void AXIS2_CALL axutil_thread_key_free( axutil_threadkey_t * axis2_key) { DWORD tls_key = axis2_key->key; TlsFree(tls_key); } AXIS2_EXTERN axutil_thread_once_t *AXIS2_CALL axutil_thread_once_init( axutil_allocator_t * allocator) { axutil_thread_once_t *control = NULL; control = AXIS2_MALLOC(allocator, sizeof(*control)); if(control) { control->value = 0; } return control; } AXIS2_EXTERN axis2_status_t AXIS2_CALL axutil_thread_once( axutil_thread_once_t * control, void (*func)( void)) { if(!InterlockedExchange(&control->value, 1)) { func(); } return AXIS2_SUCCESS; }