Blame winpr/libwinpr/thread/thread.c

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * Process Thread Functions
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2015 Hewlett-Packard Development Company, L.P.
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <assert.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/handle.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/thread.h>
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * api-ms-win-core-processthreads-l1-1-1.dll
Packit Service fa4841
 *
Packit Service fa4841
 * CreateRemoteThread
Packit Service fa4841
 * CreateRemoteThreadEx
Packit Service fa4841
 * CreateThread
Packit Service fa4841
 * DeleteProcThreadAttributeList
Packit Service fa4841
 * ExitThread
Packit Service fa4841
 * FlushInstructionCache
Packit Service fa4841
 * FlushProcessWriteBuffers
Packit Service fa4841
 * GetCurrentThread
Packit Service fa4841
 * GetCurrentThreadId
Packit Service fa4841
 * GetCurrentThreadStackLimits
Packit Service fa4841
 * GetExitCodeThread
Packit Service fa4841
 * GetPriorityClass
Packit Service fa4841
 * GetStartupInfoW
Packit Service fa4841
 * GetThreadContext
Packit Service fa4841
 * GetThreadId
Packit Service fa4841
 * GetThreadIdealProcessorEx
Packit Service fa4841
 * GetThreadPriority
Packit Service fa4841
 * GetThreadPriorityBoost
Packit Service fa4841
 * GetThreadTimes
Packit Service fa4841
 * InitializeProcThreadAttributeList
Packit Service fa4841
 * OpenThread
Packit Service fa4841
 * OpenThreadToken
Packit Service fa4841
 * QueryProcessAffinityUpdateMode
Packit Service fa4841
 * QueueUserAPC
Packit Service fa4841
 * ResumeThread
Packit Service fa4841
 * SetPriorityClass
Packit Service fa4841
 * SetThreadContext
Packit Service fa4841
 * SetThreadPriority
Packit Service fa4841
 * SetThreadPriorityBoost
Packit Service fa4841
 * SetThreadStackGuarantee
Packit Service fa4841
 * SetThreadToken
Packit Service fa4841
 * SuspendThread
Packit Service fa4841
 * SwitchToThread
Packit Service fa4841
 * TerminateThread
Packit Service fa4841
 * UpdateProcThreadAttribute
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
Packit Service fa4841
#include <winpr/crt.h>
Packit Service fa4841
#include <winpr/platform.h>
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_UNISTD_H
Packit Service fa4841
#include <unistd.h>
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
#include <sys/eventfd.h>
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <winpr/debug.h>
Packit Service fa4841
Packit Service fa4841
#include <errno.h>
Packit Service fa4841
#include <fcntl.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/collections.h>
Packit Service fa4841
Packit Service fa4841
#include "thread.h"
Packit Service fa4841
Packit Service fa4841
#include "../handle/handle.h"
Packit Service fa4841
#include "../log.h"
Packit Service fa4841
#define TAG WINPR_TAG("thread")
Packit Service fa4841
Packit Service fa4841
static wListDictionary* thread_list = NULL;
Packit Service fa4841
Packit Service fa4841
static BOOL ThreadCloseHandle(HANDLE handle);
Packit Service fa4841
static void cleanup_handle(void* obj);
Packit Service fa4841
Packit Service fa4841
static BOOL ThreadIsHandled(HANDLE handle)
Packit Service fa4841
{
Packit Service bb5c11
	WINPR_THREAD* pThread = (WINPR_THREAD*) handle;
Packit Service fa4841
Packit Service fa4841
	if (!pThread || (pThread->Type != HANDLE_TYPE_THREAD))
Packit Service fa4841
	{
Packit Service fa4841
		SetLastError(ERROR_INVALID_HANDLE);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int ThreadGetFd(HANDLE handle)
Packit Service fa4841
{
Packit Service bb5c11
	WINPR_THREAD* pThread = (WINPR_THREAD*) handle;
Packit Service fa4841
Packit Service fa4841
	if (!ThreadIsHandled(handle))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	return pThread->pipe_fd[0];
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD ThreadCleanupHandle(HANDLE handle)
Packit Service fa4841
{
Packit Service bb5c11
	WINPR_THREAD* thread = (WINPR_THREAD*) handle;
Packit Service fa4841
Packit Service fa4841
	if (!ThreadIsHandled(handle))
Packit Service fa4841
		return WAIT_FAILED;
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_lock(&thread->mutex))
Packit Service fa4841
		return WAIT_FAILED;
Packit Service fa4841
Packit Service fa4841
	if (!thread->joined)
Packit Service fa4841
	{
Packit Service fa4841
		int status;
Packit Service fa4841
		status = pthread_join(thread->thread, NULL);
Packit Service fa4841
Packit Service fa4841
		if (status != 0)
Packit Service fa4841
		{
Packit Service bb5c11
			WLog_ERR(TAG, "pthread_join failure: [%d] %s",
Packit Service bb5c11
			         status, strerror(status));
Packit Service fa4841
			pthread_mutex_unlock(&thread->mutex);
Packit Service fa4841
			return WAIT_FAILED;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
			thread->joined = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_unlock(&thread->mutex))
Packit Service fa4841
		return WAIT_FAILED;
Packit Service fa4841
Packit Service fa4841
	return WAIT_OBJECT_0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
static HANDLE_OPS ops =
Packit Service bb5c11
{
Packit Service bb5c11
	ThreadIsHandled,
Packit Service bb5c11
	ThreadCloseHandle,
Packit Service bb5c11
	ThreadGetFd,
Packit Service bb5c11
	ThreadCleanupHandle,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL,
Packit Service bb5c11
	NULL
Packit Service bb5c11
};
Packit Service bb5c11
Packit Service fa4841
Packit Service fa4841
static void dump_thread(WINPR_THREAD* thread)
Packit Service fa4841
{
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
	void* stack = winpr_backtrace(20);
Packit Service fa4841
	char** msg;
Packit Service fa4841
	size_t used, i;
Packit Service fa4841
	WLog_DBG(TAG, "Called from:");
Packit Service fa4841
	msg = winpr_backtrace_symbols(stack, &used);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < used; i++)
Packit Service bb5c11
		WLog_DBG(TAG, "[%"PRIdz"]: %s", i, msg[i]);
Packit Service fa4841
Packit Service fa4841
	free(msg);
Packit Service fa4841
	winpr_backtrace_free(stack);
Packit Service fa4841
	WLog_DBG(TAG, "Thread handle created still not closed!");
Packit Service fa4841
	msg = winpr_backtrace_symbols(thread->create_stack, &used);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < used; i++)
Packit Service bb5c11
		WLog_DBG(TAG, "[%"PRIdz"]: %s", i, msg[i]);
Packit Service fa4841
Packit Service fa4841
	free(msg);
Packit Service fa4841
Packit Service fa4841
	if (thread->started)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Thread still running!");
Packit Service fa4841
	}
Packit Service fa4841
	else if (!thread->exit_stack)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Thread suspended.");
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "Thread exited at:");
Packit Service fa4841
		msg = winpr_backtrace_symbols(thread->exit_stack, &used);
Packit Service fa4841
Packit Service fa4841
		for (i = 0; i < used; i++)
Packit Service bb5c11
			WLog_DBG(TAG, "[%"PRIdz"]: %s", i, msg[i]);
Packit Service fa4841
Packit Service fa4841
		free(msg);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * TODO: implement thread suspend/resume using pthreads
Packit Service fa4841
 * http://stackoverflow.com/questions/3140867/suspend-pthreads-without-using-condition
Packit Service fa4841
 */
Packit Service fa4841
static BOOL set_event(WINPR_THREAD* thread)
Packit Service fa4841
{
Packit Service fa4841
	int length;
Packit Service fa4841
	BOOL status = FALSE;
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
	eventfd_t val = 1;
Packit Service fa4841
Packit Service fa4841
	do
Packit Service fa4841
	{
Packit Service fa4841
		length = eventfd_write(thread->pipe_fd[0], val);
Packit Service bb5c11
	}
Packit Service bb5c11
	while ((length < 0) && (errno == EINTR));
Packit Service fa4841
Packit Service fa4841
	status = (length == 0) ? TRUE : FALSE;
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
	if (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0)
Packit Service fa4841
	{
Packit Service fa4841
		length = write(thread->pipe_fd[1], "-", 1);
Packit Service fa4841
Packit Service fa4841
		if (length == 1)
Packit Service fa4841
			status = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		status = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL reset_event(WINPR_THREAD* thread)
Packit Service fa4841
{
Packit Service fa4841
	int length;
Packit Service fa4841
	BOOL status = FALSE;
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
	eventfd_t value;
Packit Service fa4841
Packit Service fa4841
	do
Packit Service fa4841
	{
Packit Service fa4841
		length = eventfd_read(thread->pipe_fd[0], &value);
Packit Service bb5c11
	}
Packit Service bb5c11
	while ((length < 0) && (errno == EINTR));
Packit Service fa4841
Packit Service fa4841
	if ((length > 0) && (!status))
Packit Service fa4841
		status = TRUE;
Packit Service fa4841
Packit Service fa4841
#else
Packit Service fa4841
	length = read(thread->pipe_fd[0], &length, 1);
Packit Service fa4841
Packit Service fa4841
	if ((length == 1) && (!status))
Packit Service fa4841
		status = TRUE;
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL thread_compare(const void* a, const void* b)
Packit Service fa4841
{
Packit Service fa4841
	const pthread_t* p1 = a;
Packit Service fa4841
	const pthread_t* p2 = b;
Packit Service fa4841
	BOOL rc = pthread_equal(*p1, *p2);
Packit Service fa4841
	return rc;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/* Thread launcher function responsible for registering
Packit Service fa4841
 * cleanup handlers and calling pthread_exit, if not done
Packit Service fa4841
 * in thread function. */
Packit Service fa4841
static void* thread_launcher(void* arg)
Packit Service fa4841
{
Packit Service fa4841
	DWORD rc = 0;
Packit Service bb5c11
	WINPR_THREAD* thread = (WINPR_THREAD*) arg;
Packit Service fa4841
	LPTHREAD_START_ROUTINE fkt;
Packit Service fa4841
Packit Service fa4841
	if (!thread)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Called with invalid argument %p", arg);
Packit Service fa4841
		goto exit;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!(fkt = thread->lpStartAddress))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Thread function argument is %p", (void*)fkt);
Packit Service fa4841
		goto exit;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_lock(&thread->threadIsReadyMutex))
Packit Service fa4841
		goto exit;
Packit Service fa4841
Packit Service fa4841
	if (!ListDictionary_Contains(thread_list, &thread->thread))
Packit Service fa4841
	{
Packit Service fa4841
		if (pthread_cond_wait(&thread->threadIsReady, &thread->threadIsReadyMutex) != 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "The thread could not be made ready");
Packit Service fa4841
			pthread_mutex_unlock(&thread->threadIsReadyMutex);
Packit Service fa4841
			goto exit;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
Packit Service fa4841
		goto exit;
Packit Service fa4841
Packit Service fa4841
	assert(ListDictionary_Contains(thread_list, &thread->thread));
Packit Service fa4841
	rc = fkt(thread->lpParameter);
Packit Service fa4841
exit:
Packit Service fa4841
Packit Service fa4841
	if (thread)
Packit Service fa4841
	{
Packit Service fa4841
		if (!thread->exited)
Packit Service fa4841
			thread->dwExitCode = rc;
Packit Service fa4841
Packit Service fa4841
		set_event(thread);
Packit Service fa4841
Packit Service fa4841
		if (thread->detached || !thread->started)
Packit Service fa4841
			cleanup_handle(thread);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL winpr_StartThread(WINPR_THREAD* thread)
Packit Service fa4841
{
Packit Service fa4841
	pthread_attr_t attr;
Packit Service fa4841
	pthread_attr_init(&attr);
Packit Service fa4841
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
Packit Service fa4841
Packit Service fa4841
	if (thread->dwStackSize > 0)
Packit Service bb5c11
		pthread_attr_setstacksize(&attr, (size_t) thread->dwStackSize);
Packit Service fa4841
Packit Service fa4841
	thread->started = TRUE;
Packit Service fa4841
	reset_event(thread);
Packit Service fa4841
Packit Service fa4841
	if (pthread_create(&thread->thread, &attr, thread_launcher, thread))
Packit Service fa4841
		goto error;
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_lock(&thread->threadIsReadyMutex))
Packit Service fa4841
		goto error;
Packit Service fa4841
Packit Service fa4841
	if (!ListDictionary_Add(thread_list, &thread->thread, thread))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to add the thread to the thread list");
Packit Service fa4841
		pthread_mutex_unlock(&thread->threadIsReadyMutex);
Packit Service fa4841
		goto error;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_cond_signal(&thread->threadIsReady) != 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to signal the thread was ready");
Packit Service fa4841
		pthread_mutex_unlock(&thread->threadIsReadyMutex);
Packit Service fa4841
		goto error;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_unlock(&thread->threadIsReadyMutex))
Packit Service fa4841
		goto error;
Packit Service fa4841
Packit Service fa4841
	pthread_attr_destroy(&attr);
Packit Service fa4841
	dump_thread(thread);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
error:
Packit Service fa4841
	pthread_attr_destroy(&attr);
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
Packit Service bb5c11
                    SIZE_T dwStackSize,
Packit Service fa4841
                    LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
Packit Service fa4841
                    DWORD dwCreationFlags, LPDWORD lpThreadId)
Packit Service fa4841
{
Packit Service fa4841
	HANDLE handle;
Packit Service fa4841
	WINPR_THREAD* thread;
Packit Service bb5c11
	thread = (WINPR_THREAD*) calloc(1, sizeof(WINPR_THREAD));
Packit Service fa4841
Packit Service fa4841
	if (!thread)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	thread->dwStackSize = dwStackSize;
Packit Service fa4841
	thread->lpParameter = lpParameter;
Packit Service fa4841
	thread->lpStartAddress = lpStartAddress;
Packit Service fa4841
	thread->lpThreadAttributes = lpThreadAttributes;
Packit Service fa4841
	thread->ops = &ops;
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
	thread->create_stack = winpr_backtrace(20);
Packit Service fa4841
	dump_thread(thread);
Packit Service fa4841
#endif
Packit Service fa4841
	thread->pipe_fd[0] = -1;
Packit Service fa4841
	thread->pipe_fd[1] = -1;
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
	thread->pipe_fd[0] = eventfd(0, EFD_NONBLOCK);
Packit Service fa4841
Packit Service fa4841
	if (thread->pipe_fd[0] < 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to create thread pipe fd 0");
Packit Service fa4841
		goto error_pipefd0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
	if (pipe(thread->pipe_fd) < 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to create thread pipe");
Packit Service fa4841
		goto error_pipefd0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	{
Packit Service fa4841
		int flags = fcntl(thread->pipe_fd[0], F_GETFL);
Packit Service fa4841
		fcntl(thread->pipe_fd[0], F_SETFL, flags | O_NONBLOCK);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_init(&thread->mutex, 0) != 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to initialize thread mutex");
Packit Service fa4841
		goto error_mutex;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_init(&thread->threadIsReadyMutex, NULL) != 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to initialize a mutex for a condition variable");
Packit Service fa4841
		goto error_thread_ready_mutex;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (pthread_cond_init(&thread->threadIsReady, NULL) != 0)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "failed to initialize a condition variable");
Packit Service fa4841
		goto error_thread_ready;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ);
Packit Service bb5c11
	handle = (HANDLE) thread;
Packit Service fa4841
Packit Service fa4841
	if (!thread_list)
Packit Service fa4841
	{
Packit Service fa4841
		thread_list = ListDictionary_New(TRUE);
Packit Service fa4841
Packit Service fa4841
		if (!thread_list)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "Couldn't create global thread list");
Packit Service fa4841
			goto error_thread_list;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		thread_list->objectKey.fnObjectEquals = thread_compare;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!(dwCreationFlags & CREATE_SUSPENDED))
Packit Service fa4841
	{
Packit Service fa4841
		if (!winpr_StartThread(thread))
Packit Service fa4841
			goto error_thread_list;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		if (!set_event(thread))
Packit Service fa4841
			goto error_thread_list;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return handle;
Packit Service fa4841
error_thread_list:
Packit Service fa4841
	pthread_cond_destroy(&thread->threadIsReady);
Packit Service fa4841
error_thread_ready:
Packit Service fa4841
	pthread_mutex_destroy(&thread->threadIsReadyMutex);
Packit Service fa4841
error_thread_ready_mutex:
Packit Service fa4841
	pthread_mutex_destroy(&thread->mutex);
Packit Service fa4841
error_mutex:
Packit Service fa4841
Packit Service fa4841
	if (thread->pipe_fd[1] >= 0)
Packit Service fa4841
		close(thread->pipe_fd[1]);
Packit Service fa4841
Packit Service fa4841
	if (thread->pipe_fd[0] >= 0)
Packit Service fa4841
		close(thread->pipe_fd[0]);
Packit Service fa4841
Packit Service fa4841
error_pipefd0:
Packit Service fa4841
	free(thread);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void cleanup_handle(void* obj)
Packit Service fa4841
{
Packit Service fa4841
	int rc;
Packit Service bb5c11
	WINPR_THREAD* thread = (WINPR_THREAD*) obj;
Packit Service fa4841
	rc = pthread_cond_destroy(&thread->threadIsReady);
Packit Service fa4841
Packit Service fa4841
	if (rc)
Packit Service bb5c11
		WLog_ERR(TAG, "failed to destroy a condition variable [%d] %s (%d)",
Packit Service bb5c11
		         rc, strerror(errno), errno);
Packit Service fa4841
Packit Service fa4841
	rc = pthread_mutex_destroy(&thread->threadIsReadyMutex);
Packit Service fa4841
Packit Service fa4841
	if (rc)
Packit Service bb5c11
		WLog_ERR(TAG, "failed to destroy a condition variable mutex [%d] %s (%d)",
Packit Service bb5c11
		         rc, strerror(errno), errno);
Packit Service fa4841
Packit Service fa4841
	rc = pthread_mutex_destroy(&thread->mutex);
Packit Service fa4841
Packit Service fa4841
	if (rc)
Packit Service bb5c11
		WLog_ERR(TAG, "failed to destroy mutex [%d] %s (%d)",
Packit Service bb5c11
		         rc, strerror(errno), errno);
Packit Service fa4841
Packit Service fa4841
	if (thread->pipe_fd[0] >= 0)
Packit Service fa4841
		close(thread->pipe_fd[0]);
Packit Service fa4841
Packit Service fa4841
	if (thread->pipe_fd[1] >= 0)
Packit Service fa4841
		close(thread->pipe_fd[1]);
Packit Service fa4841
Packit Service fa4841
	if (thread_list && ListDictionary_Contains(thread_list, &thread->thread))
Packit Service fa4841
		ListDictionary_Remove(thread_list, &thread->thread);
Packit Service fa4841
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
Packit Service fa4841
	if (thread->create_stack)
Packit Service fa4841
		winpr_backtrace_free(thread->create_stack);
Packit Service fa4841
Packit Service fa4841
	if (thread->exit_stack)
Packit Service fa4841
		winpr_backtrace_free(thread->exit_stack);
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	free(thread);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL ThreadCloseHandle(HANDLE handle)
Packit Service fa4841
{
Packit Service bb5c11
	WINPR_THREAD* thread = (WINPR_THREAD*) handle;
Packit Service fa4841
Packit Service fa4841
	if (!thread_list)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Thread list does not exist, check call!");
Packit Service fa4841
		dump_thread(thread);
Packit Service fa4841
	}
Packit Service fa4841
	else if (!ListDictionary_Contains(thread_list, &thread->thread))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "Thread list does not contain this thread! check call!");
Packit Service fa4841
		dump_thread(thread);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		ListDictionary_Lock(thread_list);
Packit Service fa4841
		dump_thread(thread);
Packit Service fa4841
Packit Service fa4841
		if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0))
Packit Service fa4841
		{
Packit Service bb5c11
			WLog_ERR(TAG, "Thread running, setting to detached state!");
Packit Service fa4841
			thread->detached = TRUE;
Packit Service fa4841
			pthread_detach(thread->thread);
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			cleanup_handle(thread);
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		ListDictionary_Unlock(thread_list);
Packit Service fa4841
Packit Service fa4841
		if (ListDictionary_Count(thread_list) < 1)
Packit Service fa4841
		{
Packit Service fa4841
			ListDictionary_Free(thread_list);
Packit Service fa4841
			thread_list = NULL;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service bb5c11
HANDLE CreateRemoteThread(HANDLE hProcess,
Packit Service bb5c11
                          LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
Packit Service bb5c11
                          LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter,
Packit Service bb5c11
                          DWORD dwCreationFlags, LPDWORD lpThreadId)
Packit Service fa4841
{
Packit Service fa4841
	WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
Packit Service fa4841
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
VOID ExitThread(DWORD dwExitCode)
Packit Service fa4841
{
Packit Service fa4841
	DWORD rc;
Packit Service fa4841
	pthread_t tid = pthread_self();
Packit Service fa4841
Packit Service fa4841
	if (!thread_list)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "function called without existing thread list!");
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
		DumpThreadHandles();
Packit Service fa4841
#endif
Packit Service fa4841
		pthread_exit(0);
Packit Service fa4841
	}
Packit Service fa4841
	else if (!ListDictionary_Contains(thread_list, &tid))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "function called, but no matching entry in thread list!");
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
		DumpThreadHandles();
Packit Service fa4841
#endif
Packit Service fa4841
		pthread_exit(0);
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		WINPR_THREAD* thread;
Packit Service fa4841
		ListDictionary_Lock(thread_list);
Packit Service fa4841
		thread = ListDictionary_GetItemValue(thread_list, &tid;;
Packit Service fa4841
		assert(thread);
Packit Service fa4841
		thread->exited = TRUE;
Packit Service fa4841
		thread->dwExitCode = dwExitCode;
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
		thread->exit_stack = winpr_backtrace(20);
Packit Service fa4841
#endif
Packit Service fa4841
		ListDictionary_Unlock(thread_list);
Packit Service fa4841
		set_event(thread);
Packit Service fa4841
		rc = thread->dwExitCode;
Packit Service fa4841
Packit Service fa4841
		if (thread->detached || !thread->started)
Packit Service fa4841
			cleanup_handle(thread);
Packit Service fa4841
Packit Service bb5c11
		pthread_exit((void*)(size_t) rc);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode)
Packit Service fa4841
{
Packit Service fa4841
	ULONG Type;
Packit Service fa4841
	WINPR_HANDLE* Object;
Packit Service fa4841
	WINPR_THREAD* thread;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service bb5c11
	thread = (WINPR_THREAD*) Object;
Packit Service fa4841
	*lpExitCode = thread->dwExitCode;
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE _GetCurrentThread(VOID)
Packit Service fa4841
{
Packit Service fa4841
	HANDLE hdl = NULL;
Packit Service fa4841
	pthread_t tid = pthread_self();
Packit Service fa4841
Packit Service fa4841
	if (!thread_list)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "function called without existing thread list!");
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
		DumpThreadHandles();
Packit Service fa4841
#endif
Packit Service fa4841
	}
Packit Service fa4841
	else if (!ListDictionary_Contains(thread_list, &tid))
Packit Service fa4841
	{
Packit Service fa4841
		WLog_ERR(TAG, "function called, but no matching entry in thread list!");
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
		DumpThreadHandles();
Packit Service fa4841
#endif
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		hdl = ListDictionary_GetItemValue(thread_list, &tid;;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return hdl;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
DWORD GetCurrentThreadId(VOID)
Packit Service fa4841
{
Packit Service fa4841
	pthread_t tid;
Packit Service fa4841
	tid = pthread_self();
Packit Service fa4841
	/* Since pthread_t can be 64-bits on some systems, take just the    */
Packit Service fa4841
	/* lower 32-bits of it for the thread ID returned by this function. */
Packit Service fa4841
	return (DWORD)tid & 0xffffffffUL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
DWORD ResumeThread(HANDLE hThread)
Packit Service fa4841
{
Packit Service fa4841
	ULONG Type;
Packit Service fa4841
	WINPR_HANDLE* Object;
Packit Service fa4841
	WINPR_THREAD* thread;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
Packit Service bb5c11
		return (DWORD) - 1;
Packit Service fa4841
Packit Service bb5c11
	thread = (WINPR_THREAD*) Object;
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_lock(&thread->mutex))
Packit Service bb5c11
		return (DWORD) - 1;
Packit Service fa4841
Packit Service fa4841
	if (!thread->started)
Packit Service fa4841
	{
Packit Service fa4841
		if (!winpr_StartThread(thread))
Packit Service fa4841
		{
Packit Service fa4841
			pthread_mutex_unlock(&thread->mutex);
Packit Service bb5c11
			return (DWORD) - 1;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
		WLog_WARN(TAG, "Thread already started!");
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_unlock(&thread->mutex))
Packit Service bb5c11
		return (DWORD) - 1;
Packit Service fa4841
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
DWORD SuspendThread(HANDLE hThread)
Packit Service fa4841
{
Packit Service fa4841
	WLog_ERR(TAG, "%s: not implemented", __FUNCTION__);
Packit Service fa4841
	SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
Packit Service bb5c11
	return (DWORD) - 1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL SwitchToThread(VOID)
Packit Service fa4841
{
Packit Service fa4841
	/**
Packit Service fa4841
	 * Note: on some operating systems sched_yield is a stub returning -1.
Packit Service fa4841
	 * usleep should at least trigger a context switch if any thread is waiting.
Packit Service fa4841
	 */
Packit Service bb5c11
	if (!sched_yield())
Packit Service fa4841
		usleep(1);
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode)
Packit Service fa4841
{
Packit Service fa4841
	ULONG Type;
Packit Service fa4841
	WINPR_HANDLE* Object;
Packit Service fa4841
	WINPR_THREAD* thread;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Handle_GetInfo(hThread, &Type, &Object))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service bb5c11
	thread = (WINPR_THREAD*) Object;
Packit Service fa4841
	thread->exited = TRUE;
Packit Service fa4841
	thread->dwExitCode = dwExitCode;
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_lock(&thread->mutex))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
#ifndef ANDROID
Packit Service fa4841
	pthread_cancel(thread->thread);
Packit Service fa4841
#else
Packit Service fa4841
	WLog_ERR(TAG, "Function not supported on this platform!");
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	if (pthread_mutex_unlock(&thread->mutex))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	set_event(thread);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#if defined(WITH_DEBUG_THREADS)
Packit Service fa4841
VOID DumpThreadHandles(void)
Packit Service fa4841
{
Packit Service fa4841
	char** msg;
Packit Service fa4841
	size_t used, i;
Packit Service fa4841
	void* stack = winpr_backtrace(20);
Packit Service fa4841
	WLog_DBG(TAG, "---------------- Called from ----------------------------");
Packit Service fa4841
	msg = winpr_backtrace_symbols(stack, &used);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < used; i++)
Packit Service fa4841
	{
Packit Service bb5c11
		WLog_DBG(TAG, "[%"PRIdz"]: %s", i, msg[i]);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(msg);
Packit Service fa4841
	winpr_backtrace_free(stack);
Packit Service fa4841
	WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------");
Packit Service fa4841
Packit Service fa4841
	if (!thread_list)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_DBG(TAG, "All threads properly shut down and disposed of.");
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		ULONG_PTR* keys = NULL;
Packit Service fa4841
		ListDictionary_Lock(thread_list);
Packit Service fa4841
		int x, count = ListDictionary_GetKeys(thread_list, &keys);
Packit Service fa4841
		WLog_DBG(TAG, "Dumping %d elements", count);
Packit Service fa4841
Packit Service fa4841
		for (x = 0; x < count; x++)
Packit Service fa4841
		{
Packit Service bb5c11
			WINPR_THREAD* thread = ListDictionary_GetItemValue(thread_list,
Packit Service bb5c11
			                       (void*) keys[x]);
Packit Service fa4841
			WLog_DBG(TAG, "Thread [%d] handle created still not closed!", x);
Packit Service fa4841
			msg = winpr_backtrace_symbols(thread->create_stack, &used);
Packit Service fa4841
Packit Service fa4841
			for (i = 0; i < used; i++)
Packit Service fa4841
			{
Packit Service bb5c11
				WLog_DBG(TAG, "[%"PRIdz"]: %s", i, msg[i]);
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			free(msg);
Packit Service fa4841
Packit Service fa4841
			if (thread->started)
Packit Service fa4841
			{
Packit Service bb5c11
				WLog_DBG(TAG, "Thread [%d] still running!",	x);
Packit Service fa4841
			}
Packit Service fa4841
			else
Packit Service fa4841
			{
Packit Service fa4841
				WLog_DBG(TAG, "Thread [%d] exited at:", x);
Packit Service fa4841
				msg = winpr_backtrace_symbols(thread->exit_stack, &used);
Packit Service fa4841
Packit Service fa4841
				for (i = 0; i < used; i++)
Packit Service bb5c11
					WLog_DBG(TAG, "[%"PRIdz"]: %s", i, msg[i]);
Packit Service fa4841
Packit Service fa4841
				free(msg);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		free(keys);
Packit Service fa4841
		ListDictionary_Unlock(thread_list);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	WLog_DBG(TAG, "---------------- End Dumping thread handles -------------");
Packit Service fa4841
}
Packit Service fa4841
#endif
Packit Service fa4841
#endif
Packit Service bb5c11