2019-04-23 21:49:28 -05:00
|
|
|
// 23 april 2019
|
|
|
|
#define UNICODE
|
|
|
|
#define _UNICODE
|
|
|
|
#define STRICT
|
|
|
|
#define STRICT_TYPED_ITEMIDS
|
|
|
|
#define WINVER 0x0600
|
|
|
|
#define _WIN32_WINNT 0x0600
|
|
|
|
#define _WIN32_WINDOWS 0x0600
|
|
|
|
#define _WIN32_IE 0x0700
|
|
|
|
#define NTDDI_VERSION 0x06000000
|
|
|
|
#include <windows.h>
|
2019-04-28 18:04:27 -05:00
|
|
|
#include <process.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <setjmp.h>
|
|
|
|
#include <stdio.h>
|
2019-04-23 21:49:28 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2019-05-02 21:03:57 -05:00
|
|
|
#include "timer.h"
|
2019-04-23 21:49:28 -05:00
|
|
|
#include "testing.h"
|
2019-04-29 22:46:08 -05:00
|
|
|
#include "testingpriv.h"
|
2019-04-23 21:49:28 -05:00
|
|
|
|
2019-04-30 00:18:48 -05:00
|
|
|
static HRESULT lastErrorCodeToHRESULT(DWORD lastError)
|
|
|
|
{
|
|
|
|
if (lastError == 0)
|
|
|
|
return E_FAIL;
|
|
|
|
return HRESULT_FROM_WIN32(lastError);
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT lastErrorToHRESULT(void)
|
|
|
|
{
|
|
|
|
return lastErrorCodeToHRESULT(GetLastError());
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT __cdecl hr_beginthreadex(void *security, unsigned stackSize, unsigned (__stdcall *threadProc)(void *arg), void *threadProcArg, unsigned flags, unsigned *thirdArg, uintptr_t *handle)
|
|
|
|
{
|
|
|
|
DWORD lastError;
|
|
|
|
|
|
|
|
// _doserrno is the equivalent of GetLastError(), or at least that's how _beginthreadex() uses it.
|
|
|
|
_doserrno = 0;
|
|
|
|
*handle = _beginthreadex(security, stackSize, threadProc, threadProcArg, flags, thirdArg);
|
|
|
|
if (*handle == 0) {
|
|
|
|
lastError = (DWORD) _doserrno;
|
|
|
|
return lastErrorCodeToHRESULT(lastError);
|
|
|
|
}
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT WINAPI hrWaitForSingleObject(HANDLE handle, DWORD timeout)
|
|
|
|
{
|
|
|
|
DWORD ret;
|
|
|
|
|
|
|
|
SetLastError(0);
|
|
|
|
ret = WaitForSingleObject(handle, timeout);
|
|
|
|
if (ret == WAIT_FAILED)
|
|
|
|
return lastErrorToHRESULT();
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2019-04-28 19:45:53 -05:00
|
|
|
struct testingThread {
|
|
|
|
uintptr_t handle;
|
|
|
|
void (*f)(void *data);
|
|
|
|
void *data;
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned __stdcall threadThreadProc(void *data)
|
|
|
|
{
|
|
|
|
testingThread *t = (testingThread *) data;
|
|
|
|
|
|
|
|
(*(t->f))(t->data);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
testingThread *testingNewThread(void (*f)(void *data), void *data)
|
|
|
|
{
|
|
|
|
testingThread *t;
|
2019-04-30 00:18:48 -05:00
|
|
|
HRESULT hr;
|
2019-04-28 19:45:53 -05:00
|
|
|
|
2019-04-29 22:46:08 -05:00
|
|
|
t = testingprivNew(testingThread);
|
2019-04-28 19:45:53 -05:00
|
|
|
t->f = f;
|
|
|
|
t->data = data;
|
|
|
|
|
2019-04-30 00:18:48 -05:00
|
|
|
hr = hr_beginthreadex(NULL, 0, threadThreadProc, t, 0, NULL, &(t->handle));
|
|
|
|
if (hr != S_OK)
|
|
|
|
testingprivInternalError("error creating thread: 0x%08I32X", hr);
|
2019-04-28 19:45:53 -05:00
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void testingThreadWaitAndFree(testingThread *t)
|
|
|
|
{
|
2019-04-30 00:18:48 -05:00
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
hr = hrWaitForSingleObject((HANDLE) (t->handle), INFINITE);
|
|
|
|
if (hr != S_OK)
|
|
|
|
testingprivInternalError("error waiting for thread to finish: 0x%08I32X", hr);
|
2019-04-28 19:45:53 -05:00
|
|
|
CloseHandle((HANDLE) (t->handle));
|
2019-04-29 22:46:08 -05:00
|
|
|
testingprivFree(t);
|
2019-04-28 19:45:53 -05:00
|
|
|
}
|