blob: 67af332e3d7071fc2bbb03f28ea62845cde5cd19 [file] [log] [blame]
/*
* 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 <axutil_utils.h>
#include <platforms/windows/axutil_thread_windows.h>
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;
}