2 * Copyright 2022 Daniel Lehman
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/test.h"
26 static unsigned int (__stdcall
*p___std_parallel_algorithms_hw_threads
)(void);
28 static void (__stdcall
*p___std_bulk_submit_threadpool_work
)(PTP_WORK
, size_t);
29 static void (__stdcall
*p___std_close_threadpool_work
)(PTP_WORK
);
30 static PTP_WORK (__stdcall
*p___std_create_threadpool_work
)(PTP_WORK_CALLBACK
, void*, PTP_CALLBACK_ENVIRON
);
31 static void (__stdcall
*p___std_submit_threadpool_work
)(PTP_WORK
);
32 static void (__stdcall
*p___std_wait_for_threadpool_work_callbacks
)(PTP_WORK
, BOOL
);
33 static BOOL (__stdcall
*p___std_atomic_wait_direct
)(volatile void*, void*, size_t, DWORD
);
34 static void (__stdcall
*p___std_atomic_notify_one_direct
)(void*);
36 #define SETNOFAIL(x,y) x = (void*)GetProcAddress(msvcp,y)
37 #define SET(x,y) do { SETNOFAIL(x,y); ok(x != NULL, "Export '%s' not found\n", y); } while(0)
38 static HMODULE
init(void)
42 if (!(msvcp
= LoadLibraryA("msvcp140_atomic_wait.dll")))
45 SET(p___std_parallel_algorithms_hw_threads
, "__std_parallel_algorithms_hw_threads");
47 SET(p___std_bulk_submit_threadpool_work
, "__std_bulk_submit_threadpool_work");
48 SET(p___std_close_threadpool_work
, "__std_close_threadpool_work");
49 SET(p___std_create_threadpool_work
, "__std_create_threadpool_work");
50 SET(p___std_submit_threadpool_work
, "__std_submit_threadpool_work");
51 SET(p___std_wait_for_threadpool_work_callbacks
, "__std_wait_for_threadpool_work_callbacks");
52 SET(p___std_atomic_wait_direct
, "__std_atomic_wait_direct");
53 SET(p___std_atomic_notify_one_direct
, "__std_atomic_notify_one_direct");
57 static void test___std_parallel_algorithms_hw_threads(void)
63 nthr
= p___std_parallel_algorithms_hw_threads();
64 ok(nthr
== si
.dwNumberOfProcessors
, "expected %lu, got %u\n", si
.dwNumberOfProcessors
, nthr
);
67 static PTP_WORK cb_work
;
68 static void *cb_context
;
69 static void WINAPI
threadpool_workcallback(PTP_CALLBACK_INSTANCE instance
, void *context
, PTP_WORK work
) {
70 LONG
*workcalled
= context
;
74 InterlockedIncrement(workcalled
);
77 static HANDLE cb_event
;
78 static void CALLBACK
threadpool_workfinalization(TP_CALLBACK_INSTANCE
*instance
, void *context
)
80 LONG
*workcalled
= context
;
82 InterlockedIncrement(workcalled
);
86 static void test_threadpool_work(void)
91 TP_CALLBACK_ENVIRON environment
;
92 TP_CALLBACK_ENVIRON_V3 environment3
;
94 if (0) /* crash on windows */
96 p___std_bulk_submit_threadpool_work(NULL
, 5);
97 p___std_create_threadpool_work(NULL
, NULL
, NULL
);
98 p___std_submit_threadpool_work(NULL
);
99 p___std_wait_for_threadpool_work_callbacks(NULL
, FALSE
);
100 p___std_close_threadpool_work(NULL
);
105 work
= p___std_create_threadpool_work(threadpool_workcallback
, &workcalled
, NULL
);
106 ok(!!work
, "failed to create threadpool_work\n");
107 p___std_submit_threadpool_work(work
);
108 p___std_wait_for_threadpool_work_callbacks(work
, FALSE
);
109 p___std_close_threadpool_work(work
);
110 ok(workcalled
== 1, "expected work to be called once, got %ld\n", workcalled
);
111 ok(cb_work
== work
, "expected %p, got %p\n", work
, cb_work
);
112 ok(cb_context
== &workcalled
, "expected %p, got %p\n", &workcalled
, cb_context
);
116 work
= p___std_create_threadpool_work(threadpool_workcallback
, &workcalled
, NULL
);
117 ok(!!work
, "failed to create threadpool_work\n");
118 p___std_bulk_submit_threadpool_work(work
, 13);
119 p___std_wait_for_threadpool_work_callbacks(work
, FALSE
);
120 p___std_close_threadpool_work(work
);
121 ok(workcalled
== 13, "expected work to be called 13 times, got %ld\n", workcalled
);
124 work
= p___std_create_threadpool_work(threadpool_workcallback
, &workcalled
, NULL
);
125 ok(!!work
, "failed to create threadpool_work\n");
126 p___std_bulk_submit_threadpool_work(work
, 0);
127 p___std_wait_for_threadpool_work_callbacks(work
, FALSE
);
128 p___std_close_threadpool_work(work
);
129 ok(workcalled
== 0, "expected no work, got %ld\n", workcalled
);
131 /* test with environment */
132 cb_event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
133 memset(&environment
, 0, sizeof(environment
));
134 environment
.Version
= 1;
135 environment
.FinalizationCallback
= threadpool_workfinalization
;
137 work
= p___std_create_threadpool_work(threadpool_workcallback
, &workcalled
, &environment
);
138 ok(!!work
, "failed to create threadpool_work\n");
139 p___std_submit_threadpool_work(work
);
140 p___std_wait_for_threadpool_work_callbacks(work
, FALSE
);
141 p___std_close_threadpool_work(work
);
142 ret
= WaitForSingleObject(cb_event
, 1000);
143 ok(ret
== WAIT_OBJECT_0
, "expected finalization callback to be called\n");
144 ok(workcalled
== 2, "expected work to be called twice, got %ld\n", workcalled
);
145 CloseHandle(cb_event
);
147 /* test with environment version 3 */
148 memset(&environment3
, 0, sizeof(environment3
));
149 environment3
.Version
= 3;
150 environment3
.CallbackPriority
= TP_CALLBACK_PRIORITY_NORMAL
;
151 SetLastError(0xdeadbeef);
152 work
= p___std_create_threadpool_work(threadpool_workcallback
, &workcalled
,
153 (TP_CALLBACK_ENVIRON
*)&environment3
);
154 gle
= GetLastError();
155 ok(gle
== 0xdeadbeef, "expected 0xdeadbeef, got %lx\n", gle
);
156 ok(!!work
, "failed to create threadpool_work\n");
157 p___std_close_threadpool_work(work
);
159 memset(&environment3
, 0, sizeof(environment3
));
160 environment3
.Version
= 3;
161 environment3
.CallbackPriority
= TP_CALLBACK_PRIORITY_INVALID
;
162 SetLastError(0xdeadbeef);
163 work
= p___std_create_threadpool_work(threadpool_workcallback
, &workcalled
,
164 (TP_CALLBACK_ENVIRON
*)&environment3
);
165 gle
= GetLastError();
166 ok(gle
== ERROR_INVALID_PARAMETER
, "expected %d, got %ld\n", ERROR_INVALID_PARAMETER
, gle
);
167 ok(!work
, "expected failure\n");
171 static void __cdecl
atomic_wait_thread(void *arg
)
176 r
= p___std_atomic_wait_direct(&address
, &compare
, sizeof(address
), 2000);
177 ok(r
== 1, "r = %d\n", r
);
180 static void test___std_atomic_wait_direct(void)
187 if (!GetProcAddress(GetModuleHandleA("kernelbase"), "WaitOnAddress"))
189 win_skip("WaitOnAddress not available\n");
193 address
= compare
= 0;
195 r
= p___std_atomic_wait_direct(&address
, &compare
, 5, 0);
196 ok(!r
, "r = %d\n", r
);
197 gle
= GetLastError();
198 ok(gle
== ERROR_INVALID_PARAMETER
, "expected %d, got %ld\n", ERROR_INVALID_PARAMETER
, gle
);
201 r
= p___std_atomic_wait_direct(&address
, &compare
, 1, 0);
202 ok(!r
, "r = %d\n", r
);
203 gle
= GetLastError();
204 ok(gle
== ERROR_TIMEOUT
, "expected %d, got %ld\n", ERROR_TIMEOUT
, gle
);
205 r
= p___std_atomic_wait_direct(&address
, &compare
, 2, 0);
206 ok(!r
, "r = %d\n", r
);
207 gle
= GetLastError();
208 ok(gle
== ERROR_TIMEOUT
, "expected %d, got %ld\n", ERROR_TIMEOUT
, gle
);
209 r
= p___std_atomic_wait_direct(&address
, &compare
, 4, 0);
210 ok(!r
, "r = %d\n", r
);
211 gle
= GetLastError();
212 ok(gle
== ERROR_TIMEOUT
, "expected %d, got %ld\n", ERROR_TIMEOUT
, gle
);
213 r
= p___std_atomic_wait_direct(&address
, &compare
, 8, 0);
214 ok(!r
, "r = %d\n", r
);
215 gle
= GetLastError();
216 ok(gle
== ERROR_TIMEOUT
, "expected %d, got %ld\n", ERROR_TIMEOUT
, gle
);
219 r
= p___std_atomic_wait_direct(&address
, &compare
, 8, 1);
220 ok(!r
, "r = %d\n", r
);
221 gle
= GetLastError();
222 ok(gle
== ERROR_TIMEOUT
, "expected %d, got %ld\n", ERROR_TIMEOUT
, gle
);
226 r
= p___std_atomic_wait_direct(&address
, &compare
, 8, 0);
227 ok(r
== 1, "r = %d\n", r
);
228 gle
= GetLastError();
229 ok(!gle
, "expected 0, got %ld\n", gle
);
231 thread
= (HANDLE
)_beginthread(atomic_wait_thread
, 0, NULL
);
232 ok(thread
!= INVALID_HANDLE_VALUE
, "_beginthread failed\n");
235 p___std_atomic_notify_one_direct(&address
);
236 WaitForSingleObject(thread
, INFINITE
);
240 START_TEST(msvcp140_atomic_wait
)
243 if (!(msvcp
= init()))
245 win_skip("msvcp140_atomic_wait.dll not installed\n");
248 test___std_parallel_algorithms_hw_threads();
249 test_threadpool_work();
250 test___std_atomic_wait_direct();