|
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 |
|