VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTR0ThreadPreemptionDriver.cpp@ 102792

Last change on this file since 102792 was 98103, checked in by vboxsync, 20 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.7 KB
Line 
1/* $Id: tstRTR0ThreadPreemptionDriver.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT R0 Testcase - Thread Preemption, driver program.
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/initterm.h>
42
43#include <iprt/asm.h>
44#include <iprt/cpuset.h>
45#include <iprt/errcore.h>
46#include <iprt/path.h>
47#include <iprt/param.h>
48#include <iprt/stream.h>
49#include <iprt/string.h>
50#include <iprt/test.h>
51#include <iprt/time.h>
52#include <iprt/thread.h>
53#ifdef VBOX
54# include <VBox/sup.h>
55# include "tstRTR0ThreadPreemption.h"
56#endif
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62static bool volatile g_fTerminate = false;
63
64
65/**
66 * Try make sure all online CPUs will be engaged.
67 */
68static DECLCALLBACK(int) MyThreadProc(RTTHREAD hSelf, void *pvCpuIdx)
69{
70 RT_NOREF1(hSelf);
71 RTCPUSET Affinity;
72 RTCpuSetEmpty(&Affinity);
73 RTCpuSetAddByIndex(&Affinity, (intptr_t)pvCpuIdx);
74 RTThreadSetAffinity(&Affinity); /* ignore return code as it's not supported on all hosts. */
75
76 while (!g_fTerminate)
77 {
78 uint64_t tsStart = RTTimeMilliTS();
79 do
80 {
81 ASMNopPause();
82 } while (RTTimeMilliTS() - tsStart < 8);
83 RTThreadSleep(4);
84 }
85
86 return VINF_SUCCESS;
87}
88
89
90/**
91 * Entry point.
92 */
93extern "C" DECLEXPORT(int) TrustedMain(int argc, char **argv, char **envp)
94{
95 RT_NOREF3(argc, argv, envp);
96#ifndef VBOX
97 RTPrintf("tstSup: SKIPPED\n");
98 return 0;
99#else
100 /*
101 * Init.
102 */
103 RTTEST hTest;
104 int rc = RTTestInitAndCreate("tstRTR0ThreadPreemption", &hTest);
105 if (rc)
106 return rc;
107 RTTestBanner(hTest);
108
109 PSUPDRVSESSION pSession;
110 rc = SUPR3Init(&pSession);
111 if (RT_FAILURE(rc))
112 {
113 RTTestFailed(hTest, "SUPR3Init failed with rc=%Rrc\n", rc);
114 return RTTestSummaryAndDestroy(hTest);
115 }
116
117 char szPath[RTPATH_MAX];
118 rc = RTPathExecDir(szPath, sizeof(szPath));
119 if (RT_SUCCESS(rc))
120 rc = RTPathAppend(szPath, sizeof(szPath), "tstRTR0ThreadPreemption.r0");
121 if (RT_FAILURE(rc))
122 {
123 RTTestFailed(hTest, "Failed constructing .r0 filename (rc=%Rrc)", rc);
124 return RTTestSummaryAndDestroy(hTest);
125 }
126
127 void *pvImageBase;
128 rc = SUPR3LoadServiceModule(szPath, "tstRTR0ThreadPreemption",
129 "TSTRTR0ThreadPreemptionSrvReqHandler",
130 &pvImageBase);
131 if (RT_FAILURE(rc))
132 {
133 RTTestFailed(hTest, "SUPR3LoadServiceModule(%s,,,) failed with rc=%Rrc\n", szPath, rc);
134 return RTTestSummaryAndDestroy(hTest);
135 }
136
137 /* test request */
138 struct
139 {
140 SUPR0SERVICEREQHDR Hdr;
141 char szMsg[256];
142 } Req;
143
144 /*
145 * Sanity checks.
146 */
147 RTTestSub(hTest, "Sanity");
148 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
149 Req.Hdr.cbReq = sizeof(Req);
150 Req.szMsg[0] = '\0';
151 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
152 TSTRTR0THREADPREEMPTION_SANITY_OK, 0, &Req.Hdr), VINF_SUCCESS);
153 if (RT_FAILURE(rc))
154 return RTTestSummaryAndDestroy(hTest);
155 RTTESTI_CHECK_MSG(Req.szMsg[0] == '\0', ("%s", Req.szMsg));
156 if (Req.szMsg[0] != '\0')
157 return RTTestSummaryAndDestroy(hTest);
158
159 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
160 Req.Hdr.cbReq = sizeof(Req);
161 Req.szMsg[0] = '\0';
162 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
163 TSTRTR0THREADPREEMPTION_SANITY_FAILURE, 0, &Req.Hdr), VINF_SUCCESS);
164 if (RT_FAILURE(rc))
165 return RTTestSummaryAndDestroy(hTest);
166 RTTESTI_CHECK_MSG(!strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")), ("%s", Req.szMsg));
167 if (strncmp(Req.szMsg, RT_STR_TUPLE("!42failure42")))
168 return RTTestSummaryAndDestroy(hTest);
169
170 /*
171 * Basic tests, bail out on failure.
172 */
173 RTTestSub(hTest, "Basics");
174 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
175 Req.Hdr.cbReq = sizeof(Req);
176 Req.szMsg[0] = '\0';
177 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
178 TSTRTR0THREADPREEMPTION_BASIC, 0, &Req.Hdr), VINF_SUCCESS);
179 if (RT_FAILURE(rc))
180 return RTTestSummaryAndDestroy(hTest);
181 if (Req.szMsg[0] == '!')
182 {
183 RTTestIFailed("%s", &Req.szMsg[1]);
184 return RTTestSummaryAndDestroy(hTest);
185 }
186 if (Req.szMsg[0])
187 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
188
189 /*
190 * Is it trusty.
191 */
192 RTTestSub(hTest, "RTThreadPreemptIsPendingTrusty");
193 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
194 Req.Hdr.cbReq = sizeof(Req);
195 Req.szMsg[0] = '\0';
196 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
197 TSTRTR0THREADPREEMPTION_IS_TRUSTY, 0, &Req.Hdr), VINF_SUCCESS);
198 if (RT_FAILURE(rc))
199 return RTTestSummaryAndDestroy(hTest);
200 if (Req.szMsg[0] == '!')
201 RTTestIFailed("%s", &Req.szMsg[1]);
202 else if (Req.szMsg[0])
203 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
204
205 /*
206 * Stay in ring-0 until preemption is pending.
207 */
208 RTTHREAD ahThreads[RTCPUSET_MAX_CPUS];
209 RTCPUSET OnlineSet;
210 RTMpGetOnlineSet(&OnlineSet);
211 for (uint32_t i = 0; i < RT_ELEMENTS(ahThreads); i++)
212 {
213 ahThreads[i] = NIL_RTTHREAD;
214 if (RTCpuSetIsMemberByIndex(&OnlineSet, i))
215 RTThreadCreateF(&ahThreads[i], MyThreadProc, (void *)(uintptr_t)i, 0, RTTHREADTYPE_DEFAULT,
216 RTTHREADFLAGS_WAITABLE, "cpu=%u", i);
217 }
218
219
220 RTTestSub(hTest, "Pending Preemption");
221 RTThreadSleep(250); /** @todo fix GIP initialization? */
222 for (int i = 0; ; i++)
223 {
224 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
225 Req.Hdr.cbReq = sizeof(Req);
226 Req.szMsg[0] = '\0';
227 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
228 TSTRTR0THREADPREEMPTION_IS_PENDING, 0, &Req.Hdr), VINF_SUCCESS);
229 if ( strcmp(Req.szMsg, "!cLoops=1\n")
230 || i >= 64)
231 {
232 if (Req.szMsg[0] == '!')
233 RTTestIFailed("%s", &Req.szMsg[1]);
234 else if (Req.szMsg[0])
235 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
236 break;
237 }
238 if ((i % 3) == 0)
239 RTThreadYield();
240 else if ((i % 16) == 0)
241 RTThreadSleep(8);
242 }
243
244 ASMAtomicWriteBool(&g_fTerminate, true);
245 for (uint32_t i = 0; i < RT_ELEMENTS(ahThreads); i++)
246 if (ahThreads[i] != NIL_RTTHREAD)
247 RTThreadWait(ahThreads[i], 5000, NULL);
248
249 /*
250 * Test nested RTThreadPreemptDisable calls.
251 */
252 RTTestSub(hTest, "Nested");
253 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
254 Req.Hdr.cbReq = sizeof(Req);
255 Req.szMsg[0] = '\0';
256 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
257 TSTRTR0THREADPREEMPTION_NESTED, 0, &Req.Hdr), VINF_SUCCESS);
258 if (Req.szMsg[0] == '!')
259 RTTestIFailed("%s", &Req.szMsg[1]);
260 else if (Req.szMsg[0])
261 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
262
263
264 /*
265 * Test thread-context hooks.
266 */
267 RTTestSub(hTest, "RTThreadCtxHooks");
268 uint64_t u64StartTS = RTTimeMilliTS();
269 uint64_t cMsMax = 60000; /* ca. 1 minute timeout. */
270 uint64_t cMsElapsed;
271 for (unsigned i = 0; i < 50; i++)
272 {
273 Req.Hdr.u32Magic = SUPR0SERVICEREQHDR_MAGIC;
274 Req.Hdr.cbReq = sizeof(Req);
275 Req.szMsg[0] = '\0';
276 RTTESTI_CHECK_RC(rc = SUPR3CallR0Service("tstRTR0ThreadPreemption", sizeof("tstRTR0ThreadPreemption") - 1,
277 TSTRTR0THREADPREEMPTION_CTXHOOKS, 0, &Req.Hdr), VINF_SUCCESS);
278 if (RT_FAILURE(rc))
279 return RTTestSummaryAndDestroy(hTest);
280 if (Req.szMsg[0] == '!')
281 RTTestIFailed("%s", &Req.szMsg[1]);
282 else if (Req.szMsg[0])
283 RTTestIPrintf(RTTESTLVL_ALWAYS, "%s", Req.szMsg);
284 if (!(i % 10))
285 RTTestIPrintf(RTTESTLVL_ALWAYS, "RTThreadCtxHooks passed %u iteration(s)\n", i);
286
287 /* Check timeout and bail. */
288 cMsElapsed = RTTimeMilliTS() - u64StartTS;
289 if (cMsElapsed > cMsMax)
290 {
291 RTTestIPrintf(RTTESTLVL_INFO, "RTThreadCtxHooks Stopping iterations. %RU64 ms. for %u iterations.\n",
292 cMsElapsed, i);
293 break;
294 }
295 }
296
297 /*
298 * Done.
299 */
300 return RTTestSummaryAndDestroy(hTest);
301#endif
302}
303
304
305#if !defined(VBOX_WITH_HARDENING) || !defined(RT_OS_WINDOWS)
306/**
307 * Main entry point.
308 */
309int main(int argc, char **argv, char **envp)
310{
311 return TrustedMain(argc, argv, envp);
312}
313#endif
314
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette