diff options
Diffstat (limited to '')
-rw-r--r-- | winpr/libwinpr/synch/test/TestSynchAPC.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/winpr/libwinpr/synch/test/TestSynchAPC.c b/winpr/libwinpr/synch/test/TestSynchAPC.c new file mode 100644 index 0000000..d6239d8 --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchAPC.c @@ -0,0 +1,173 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * TestSyncAPC + * + * Copyright 2021 David Fort <contact@hardening-consulting.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <winpr/wtypes.h> +#include <winpr/thread.h> +#include <winpr/synch.h> + +typedef struct +{ + BOOL error; + BOOL called; +} UserApcArg; + +static void CALLBACK userApc(ULONG_PTR arg) +{ + UserApcArg* userArg = (UserApcArg*)arg; + userArg->called = TRUE; +} + +static DWORD WINAPI uncleanThread(LPVOID lpThreadParameter) +{ + /* this thread post an APC that will never get executed */ + UserApcArg* userArg = (UserApcArg*)lpThreadParameter; + if (!QueueUserAPC((PAPCFUNC)userApc, _GetCurrentThread(), (ULONG_PTR)lpThreadParameter)) + { + userArg->error = TRUE; + return 1; + } + + return 0; +} + +static DWORD WINAPI cleanThread(LPVOID lpThreadParameter) +{ + Sleep(500); + + SleepEx(500, TRUE); + return 0; +} + +typedef struct +{ + HANDLE timer1; + DWORD timer1Calls; + HANDLE timer2; + DWORD timer2Calls; + BOOL endTest; +} UncleanCloseData; + +static VOID CALLBACK Timer1APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue) +{ + UncleanCloseData* data = (UncleanCloseData*)lpArg; + data->timer1Calls++; + CloseHandle(data->timer2); + data->endTest = TRUE; +} + +static VOID CALLBACK Timer2APCProc(LPVOID lpArg, DWORD dwTimerLowValue, DWORD dwTimerHighValue) +{ + UncleanCloseData* data = (UncleanCloseData*)lpArg; + data->timer2Calls++; +} + +static DWORD /*WINAPI*/ closeHandleTest(LPVOID lpThreadParameter) +{ + LARGE_INTEGER dueTime; + UncleanCloseData* data = (UncleanCloseData*)lpThreadParameter; + data->endTest = FALSE; + + dueTime.QuadPart = -500; + if (!SetWaitableTimer(data->timer1, &dueTime, 0, Timer1APCProc, lpThreadParameter, FALSE)) + return 1; + + dueTime.QuadPart = -900; + if (!SetWaitableTimer(data->timer2, &dueTime, 0, Timer2APCProc, lpThreadParameter, FALSE)) + return 1; + + while (!data->endTest) + { + SleepEx(100, TRUE); + } + return 0; +} + +int TestSynchAPC(int argc, char* argv[]) +{ + HANDLE thread = NULL; + UserApcArg userApcArg; + + userApcArg.error = FALSE; + userApcArg.called = FALSE; + + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + /* first post an APC and check it is executed during a SleepEx */ + if (!QueueUserAPC((PAPCFUNC)userApc, _GetCurrentThread(), (ULONG_PTR)&userApcArg)) + return 1; + + if (SleepEx(100, FALSE) != 0) + return 2; + + if (SleepEx(100, TRUE) != WAIT_IO_COMPLETION) + return 3; + + if (!userApcArg.called) + return 4; + + userApcArg.called = FALSE; + + /* test that the APC is cleaned up even when not called */ + thread = CreateThread(NULL, 0, uncleanThread, &userApcArg, 0, NULL); + if (!thread) + return 10; + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + if (userApcArg.called || userApcArg.error) + return 11; + + /* test a remote APC queuing */ + thread = CreateThread(NULL, 0, cleanThread, &userApcArg, 0, NULL); + if (!thread) + return 20; + + if (!QueueUserAPC((PAPCFUNC)userApc, thread, (ULONG_PTR)&userApcArg)) + return 21; + + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + if (!userApcArg.called) + return 22; + +#if 0 + /* test cleanup of timer completions */ + memset(&uncleanCloseData, 0, sizeof(uncleanCloseData)); + uncleanCloseData.timer1 = CreateWaitableTimerA(NULL, FALSE, NULL); + if (!uncleanCloseData.timer1) + return 31; + + uncleanCloseData.timer2 = CreateWaitableTimerA(NULL, FALSE, NULL); + if (!uncleanCloseData.timer2) + return 32; + + thread = CreateThread(NULL, 0, closeHandleTest, &uncleanCloseData, 0, NULL); + if (!thread) + return 33; + + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); + + if (uncleanCloseData.timer1Calls != 1 || uncleanCloseData.timer2Calls != 0) + return 34; + CloseHandle(uncleanCloseData.timer1); +#endif + return 0; +} |