mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-10-28 21:25:06 +00:00
Assisted-by: Claude Code:claude-opus-5-5 AI-Scope: Wrote timer queues, private pools and GetThreadIOPendingFlag with their tests.
94 lines
3.9 KiB
C
94 lines
3.9 KiB
C
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
|
|
static volatile LONG once_count, periodic_count, changed_count, fired_value = -1;
|
|
static HANDLE once_done, periodic_done, changed_done;
|
|
|
|
static void CALLBACK once(void *parameter, BOOLEAN fired)
|
|
{
|
|
fired_value = fired;
|
|
InterlockedIncrement(&once_count);
|
|
SetEvent(once_done);
|
|
}
|
|
|
|
static void CALLBACK periodic(void *parameter, BOOLEAN fired)
|
|
{
|
|
if (InterlockedIncrement(&periodic_count) == 3)
|
|
SetEvent(periodic_done);
|
|
}
|
|
|
|
static void CALLBACK changed(void *parameter, BOOLEAN fired)
|
|
{
|
|
InterlockedIncrement(&changed_count);
|
|
SetEvent(changed_done);
|
|
}
|
|
|
|
/* Timer queues as services schedule their work with them: a timer of its own queue runs once, a periodic timer of the default queue
|
|
* keeps running until it is deleted and not after, a far timer brought forward runs, a timer runs for a thread that only polls, and
|
|
* deleting a queue sets the event it names. */
|
|
static volatile LONG pool_runs;
|
|
|
|
static void CALLBACK pool_work(PTP_CALLBACK_INSTANCE instance, void *parameter, PTP_WORK work)
|
|
{
|
|
Sleep(20);
|
|
InterlockedIncrement(&pool_runs);
|
|
}
|
|
|
|
/* A private pool with a cleanup group: closing the group's members lets their submitted callbacks finish and frees the work items. */
|
|
static int private_pool(void)
|
|
{
|
|
PTP_POOL pool = CreateThreadpool(NULL);
|
|
if (!pool) return 20;
|
|
SetThreadpoolThreadMaximum(pool, 2);
|
|
if (!SetThreadpoolThreadMinimum(pool, 1)) return 21;
|
|
PTP_CLEANUP_GROUP group = CreateThreadpoolCleanupGroup();
|
|
if (!group) return 22;
|
|
TP_CALLBACK_ENVIRON environment;
|
|
InitializeThreadpoolEnvironment(&environment);
|
|
SetThreadpoolCallbackPool(&environment, pool);
|
|
SetThreadpoolCallbackCleanupGroup(&environment, group, NULL);
|
|
PTP_WORK first = CreateThreadpoolWork(pool_work, NULL, &environment), second = CreateThreadpoolWork(pool_work, NULL, &environment);
|
|
if (!first || !second) return 23;
|
|
SubmitThreadpoolWork(first);
|
|
SubmitThreadpoolWork(second);
|
|
SubmitThreadpoolWork(first);
|
|
CloseThreadpoolCleanupGroupMembers(group, FALSE, NULL);
|
|
if (pool_runs != 3) return 24;
|
|
CloseThreadpoolCleanupGroup(group);
|
|
CloseThreadpool(pool);
|
|
return 0;
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
HANDLE queue = CreateTimerQueue(), first = NULL, repeating = NULL, distant = NULL;
|
|
once_done = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
periodic_done = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
changed_done = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
if (!queue || !once_done || !periodic_done || !changed_done) return 1;
|
|
if (CreateTimerQueueTimer(&first, queue, NULL, NULL, 10, 0, 0) || GetLastError() != ERROR_INVALID_PARAMETER) return 2;
|
|
if (!CreateTimerQueueTimer(&first, queue, once, NULL, 20, 0, WT_EXECUTEDEFAULT) || !first) return 3;
|
|
if (WaitForSingleObject(once_done, 5000) != WAIT_OBJECT_0 || fired_value != TRUE) return 4;
|
|
if (!CreateTimerQueueTimer(&repeating, NULL, periodic, NULL, 10, 10, 0)) return 5;
|
|
if (WaitForSingleObject(periodic_done, 5000) != WAIT_OBJECT_0) return 6;
|
|
if (!DeleteTimerQueueTimer(NULL, repeating, INVALID_HANDLE_VALUE)) return 7;
|
|
const LONG stopped = periodic_count;
|
|
Sleep(80);
|
|
if (periodic_count != stopped) return 8;
|
|
if (!CreateTimerQueueTimer(&distant, queue, changed, NULL, 600000, 0, 0) || !ChangeTimerQueueTimer(queue, distant, 10, 0)) return 9;
|
|
if (WaitForSingleObject(changed_done, 5000) != WAIT_OBJECT_0 || changed_count != 1) return 10;
|
|
Sleep(40);
|
|
if (once_count != 1 || changed_count != 1) return 11;
|
|
/* A thread that only polls with a zero timeout still sees a due timer start its callback. */
|
|
HANDLE polled = NULL;
|
|
ResetEvent(changed_done);
|
|
if (!CreateTimerQueueTimer(&polled, queue, changed, NULL, 10, 0, 0)) return 13;
|
|
const ULONGLONG until = GetTickCount64() + 5000;
|
|
while (WaitForSingleObject(changed_done, 0) == WAIT_TIMEOUT)
|
|
if (GetTickCount64() > until) return 14;
|
|
if (changed_count != 2) return 15;
|
|
HANDLE deleted = CreateEventW(NULL, TRUE, FALSE, NULL);
|
|
if (!DeleteTimerQueueEx(queue, deleted) || WaitForSingleObject(deleted, 5000) != WAIT_OBJECT_0) return 12;
|
|
return private_pool();
|
|
}
|