Blame winpr/libwinpr/thread/thread.c

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