summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/pool/test/TestPoolWork.c
blob: ec50a229ee90e19648b85a52d8be419304a7d7bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include <winpr/wtypes.h>
#include <winpr/crt.h>
#include <winpr/pool.h>
#include <winpr/interlocked.h>

static LONG count = 0;

static void CALLBACK test_WorkCallback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work)
{
	printf("Hello %s: %03" PRId32 " (thread: 0x%08" PRIX32 ")\n", (char*)context,
	       InterlockedIncrement(&count), GetCurrentThreadId());

	for (int index = 0; index < 100; index++)
	{
		BYTE a[1024];
		BYTE b[1024];
		BYTE c[1024] = { 0 };

		FillMemory(a, ARRAYSIZE(a), 0xAA);
		FillMemory(b, ARRAYSIZE(b), 0xBB);

		CopyMemory(c, a, ARRAYSIZE(a));
		CopyMemory(c, b, ARRAYSIZE(b));
	}
}

static BOOL test1(void)
{
	PTP_WORK work = NULL;
	printf("Global Thread Pool\n");
	work = CreateThreadpoolWork(test_WorkCallback, "world", NULL);

	if (!work)
	{
		printf("CreateThreadpoolWork failure\n");
		return FALSE;
	}

	/**
	 * You can post a work object one or more times (up to MAXULONG) without waiting for prior
	 * callbacks to complete. The callbacks will execute in parallel. To improve efficiency, the
	 * thread pool may throttle the threads.
	 */

	for (int index = 0; index < 10; index++)
		SubmitThreadpoolWork(work);

	WaitForThreadpoolWorkCallbacks(work, FALSE);
	CloseThreadpoolWork(work);
	return TRUE;
}

static BOOL test2(void)
{
	BOOL rc = FALSE;
	PTP_POOL pool = NULL;
	PTP_WORK work = NULL;
	PTP_CLEANUP_GROUP cleanupGroup = NULL;
	TP_CALLBACK_ENVIRON environment;
	printf("Private Thread Pool\n");

	if (!(pool = CreateThreadpool(NULL)))
	{
		printf("CreateThreadpool failure\n");
		return FALSE;
	}

	if (!SetThreadpoolThreadMinimum(pool, 4))
	{
		printf("SetThreadpoolThreadMinimum failure\n");
		goto fail;
	}

	SetThreadpoolThreadMaximum(pool, 8);
	InitializeThreadpoolEnvironment(&environment);
	SetThreadpoolCallbackPool(&environment, pool);
	cleanupGroup = CreateThreadpoolCleanupGroup();

	if (!cleanupGroup)
	{
		printf("CreateThreadpoolCleanupGroup failure\n");
		goto fail;
	}

	SetThreadpoolCallbackCleanupGroup(&environment, cleanupGroup, NULL);
	work = CreateThreadpoolWork(test_WorkCallback, "world", &environment);

	if (!work)
	{
		printf("CreateThreadpoolWork failure\n");
		goto fail;
	}

	for (int index = 0; index < 10; index++)
		SubmitThreadpoolWork(work);

	WaitForThreadpoolWorkCallbacks(work, FALSE);
	rc = TRUE;
fail:

	if (cleanupGroup)
	{
		CloseThreadpoolCleanupGroupMembers(cleanupGroup, TRUE, NULL);
		CloseThreadpoolCleanupGroup(cleanupGroup);
		DestroyThreadpoolEnvironment(&environment);
		/**
		 * See Remarks at
		 * https://msdn.microsoft.com/en-us/library/windows/desktop/ms682043(v=vs.85).aspx If there
		 * is a cleanup group associated with the work object, it is not necessary to call
		 * CloseThreadpoolWork ! calling the CloseThreadpoolCleanupGroupMembers function releases
		 * the work, wait, and timer objects associated with the cleanup group.
		 */
#if 0
		CloseThreadpoolWork(work); // this would segfault, see comment above. */
#endif
	}

	CloseThreadpool(pool);
	return rc;
}

int TestPoolWork(int argc, char* argv[])
{

	WINPR_UNUSED(argc);
	WINPR_UNUSED(argv);

	if (!test1())
		return -1;

	if (!test2())
		return -1;

	return 0;
}