The Pedigree Project 0.1
time-syscall-regressions.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/errors.h"
11#include "pedigree/kernel/process/Process.h"
12#include "pedigree/kernel/process/Scheduler.h"
13#include "pedigree/kernel/process/Thread.h"
14#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
15#include "pedigree/kernel/processor/Processor.h"
16#include "pedigree/kernel/processor/VirtualAddressSpace.h"
17#include "pedigree/kernel/time/Time.h"
18
19#include <stddef.h>
20#include <stdint.h>
21
22#include "modules/subsys/posix/PosixProcess.h"
23#include "modules/subsys/posix/PosixSubsystem.h"
24#include "modules/subsys/posix/system-syscalls.h"
26#include <sys/time.h>
27
28static_assert(sizeof(time_t) == 8);
29static_assert(sizeof(suseconds_t) == 8);
30static_assert(static_cast<time_t>(-1) < 0);
31static_assert(static_cast<suseconds_t>(-1) < 0);
32static_assert(sizeof(struct timeval) == 16);
33static_assert(offsetof(struct timeval, tv_sec) == 0);
34static_assert(offsetof(struct timeval, tv_usec) == 8);
35static_assert(sizeof(struct timezone) == 8);
36static_assert(offsetof(struct timezone, tz_minuteswest) == 0);
37static_assert(offsetof(struct timezone, tz_dsttime) == 4);
38static_assert(sizeof(struct itimerval) == 32);
39static_assert(offsetof(struct itimerval, it_interval) == 0);
40static_assert(offsetof(struct itimerval, it_value) == 16);
41
42namespace {
43constexpr int PreservedErrno = 123;
44constexpr Time::Timestamp MaximumLinuxTimerNanoseconds = 0x7FFFFFFFFFFFFFFFULL;
45
46struct TimeSyscallContext {
47 TimeSyscallContext() : passed(false), returned(0) {}
48
49 bool passed;
50 Atomic<size_t> returned;
51};
52
53struct AlarmThreadContext {
54 explicit AlarmThreadContext(uint32_t seconds)
55 : seconds(seconds), result(~static_cast<size_t>(0)), returned(0) {}
56
57 uint32_t seconds;
58 Atomic<size_t> result;
59 Atomic<size_t> returned;
60};
61
62struct itimerval timerValue(time_t intervalSeconds, suseconds_t intervalMicroseconds,
63 time_t valueSeconds = 0, suseconds_t valueMicroseconds = 0) {
64 struct itimerval result = {};
65 result.it_interval.tv_sec = intervalSeconds;
66 result.it_interval.tv_usec = intervalMicroseconds;
67 result.it_value.tv_sec = valueSeconds;
68 result.it_value.tv_usec = valueMicroseconds;
69 return result;
70}
71
72bool sameTimer(const struct itimerval& left, const struct itimerval& right) {
73 return left.it_interval.tv_sec == right.it_interval.tv_sec &&
74 left.it_interval.tv_usec == right.it_interval.tv_usec &&
75 left.it_value.tv_sec == right.it_value.tv_sec &&
76 left.it_value.tv_usec == right.it_value.tv_usec;
77}
78
79bool timerIsDisarmed(const struct itimerval& value) {
80 const struct itimerval zero = {};
81 return sameTimer(value, zero);
82}
83
84bool timeNotGreater(const struct timeval& left, const struct timeval& right) {
85 return left.tv_sec < right.tv_sec ||
86 (left.tv_sec == right.tv_sec && left.tv_usec <= right.tv_usec);
87}
88
89bool runningTimerMatches(const struct itimerval& observed, const struct itimerval& requested) {
90 const bool positive = observed.it_value.tv_sec > 0 || observed.it_value.tv_usec > 0;
91 return observed.it_interval.tv_sec == requested.it_interval.tv_sec &&
92 observed.it_interval.tv_usec == requested.it_interval.tv_usec &&
93 observed.it_value.tv_sec >= 0 && observed.it_value.tv_usec >= 0 &&
94 observed.it_value.tv_usec < 1000000 && positive &&
95 timeNotGreater(observed.it_value, requested.it_value);
96}
97
98bool cpuTimerReportInterest(Process* kernelProcess) {
99 // No runnable thread belongs to this process, so only explicit publications
100 // change its totals and an expiry cannot deliver a signal to the driver.
101 auto* process = new PosixProcess(kernelProcess);
102 process->publish();
103 auto& virtualTimer = process->getVirtualIntervalTimer();
104 auto& profileTimer = process->getProfileIntervalTimer();
105 constexpr size_t VirtualInterest = size_t(1) << IntervalTimer::Virtual;
106 constexpr size_t ProfileInterest = size_t(1) << IntervalTimer::Profile;
107 process->publishTimeAccountingForHostedTest(100, 200);
108 bool passed = !process->timeAccountingInterestForHostedTest() &&
109 !process->timeAccountingPendingForHostedTest() && process->getUserTime() == 100 &&
110 process->getKernelTime() == 200;
111
112 virtualTimer.setIntervalAndValue(0, 30);
113 profileTimer.setIntervalAndValue(50, 80);
114 passed &= process->timeAccountingInterestForHostedTest() == (VirtualInterest | ProfileInterest);
115 process->publishTimeAccountingForHostedTest(11, 7);
116 virtualTimer.disarm();
117 passed &= process->timeAccountingInterestForHostedTest() == ProfileInterest;
118 virtualTimer.setTimerValue(30);
119 process->publishTimeAccountingForHostedTest(31, 0);
120 for (size_t attempt = 0;
121 (process->timeAccountingInterestForHostedTest() & VirtualInterest) && attempt < 10000;
122 ++attempt) {
124 }
125 // Only the worker can expire the one-shot here. The periodic timer must
126 // retain its independent interest and all CPU time across the other arm.
127 passed &= process->timeAccountingInterestForHostedTest() == ProfileInterest;
128 Time::Timestamp interval = 0, value = 0;
129 profileTimer.getIntervalAndValue(interval, value);
130 passed &= interval == 50 && value == 31;
131 process->publishTimeAccountingForHostedTest(0, 40);
132 profileTimer.getIntervalAndValue(interval, value);
133 passed &= interval == 50 && value == 41 &&
134 process->timeAccountingInterestForHostedTest() == ProfileInterest;
135 profileTimer.disarm();
136 for (size_t attempt = 0; process->timeAccountingPendingForHostedTest() && attempt < 10000;
137 ++attempt) {
139 }
140 process->publishTimeAccountingForHostedTest(500, 700);
141 passed &= !process->timeAccountingInterestForHostedTest() &&
142 !process->timeAccountingPendingForHostedTest() && process->getUserTime() == 642 &&
143 process->getKernelTime() == 947;
144
145 virtualTimer.setTimerValue(9);
146 virtualTimer.getIntervalAndValue(interval, value);
147 passed &= value == 9;
148 process->publishTimeAccountingForHostedTest(8, 0);
149 virtualTimer.getIntervalAndValue(interval, value);
150 passed &= value == 1;
151 process->publishTimeAccountingForHostedTest(1, 0);
152 for (size_t attempt = 0; process->timeAccountingInterestForHostedTest() && attempt < 10000;
153 ++attempt) {
155 }
156 passed &= !process->timeAccountingInterestForHostedTest();
157 delete process;
158 if (passed) {
159 NOTICE("HOSTED-WAIT-TEST: PASS cpu-timer-report-interest");
160 } else {
161 ERROR("HOSTED-WAIT-TEST: FAIL cpu-timer-report-interest");
162 }
163 return passed;
164}
165
166int armAlarmAndExit(void* parameter) {
167 AlarmThreadContext* context = reinterpret_cast<AlarmThreadContext*>(parameter);
168 context->result = posix_alarm(context->seconds);
169 context->returned += 1;
170 return 0;
171}
172
173int exerciseTimeSyscalls(void* parameter) {
174 TimeSyscallContext* context = reinterpret_cast<TimeSyscallContext*>(parameter);
175 Thread* thread = Processor::information().getCurrentThread();
176 PosixProcess* process = static_cast<PosixProcess*>(thread->getParent());
177 bool passed = process->getType() == Process::Posix;
178
179 const size_t pageSize = PhysicalMemoryManager::getPageSize();
180 const size_t mappingLength = pageSize * 3;
181 uintptr_t address = 0;
182 const bool allocated =
183 process->allocateUserRange(Process::UserRegion::Normal, mappingLength, address);
184 uintptr_t mappedAddress = address;
185 MemoryMappedObject* mapping =
186 allocated
188 mappedAddress, mappingLength, MemoryMappedObject::Read | MemoryMappedObject::Write)
189 : nullptr;
190 if (!mapping || mappedAddress != address) {
191 if (mapping) {
192 MemoryMapManager::instance().remove(mappedAddress, mappingLength);
193 }
194 if (allocated) {
195 process->freeUserRange(Process::UserRegion::Normal, address, mappingLength);
196 }
197 context->passed = false;
198 context->returned += 1;
199 return 1;
200 }
201
202 struct itimerval* input = reinterpret_cast<struct itimerval*>(address + 64);
203 struct itimerval* output = reinterpret_cast<struct itimerval*>(address + 256);
204 struct itimerval* alias = reinterpret_cast<struct itimerval*>(address + 512);
205 struct itimerval* pageEdge =
206 reinterpret_cast<struct itimerval*>(address + pageSize - (sizeof(struct itimerval) / 2));
207 struct itimerval* readOnly = reinterpret_cast<struct itimerval*>(address + (pageSize * 2) + 64);
208 struct timeval* wallClock = reinterpret_cast<struct timeval*>(address + 768);
209 struct timezone* timezoneOutput = reinterpret_cast<struct timezone*>(address + 832);
210 time_t* secondsOutput = reinterpret_cast<time_t*>(address + 896);
211 const uintptr_t kernelStart = Processor::information().getVirtualAddressSpace().getKernelStart();
212 struct itimerval* bad = reinterpret_cast<struct itimerval*>(kernelStart);
213
214 struct timeval observedWallClock = {};
215 struct timezone observedTimezone = {};
216 thread->setErrno(PreservedErrno);
217 passed &= posix_gettimeofday(nullptr, nullptr) == 0 && thread->getErrno() == PreservedErrno;
218 thread->setErrno(PreservedErrno);
219 passed &=
220 posix_gettimeofday(wallClock, timezoneOutput) == 0 && thread->getErrno() == PreservedErrno &&
221 PosixSubsystem::copyFromUser(&observedWallClock, wallClock, sizeof(observedWallClock)) &&
222 PosixSubsystem::copyFromUser(&observedTimezone, timezoneOutput, sizeof(observedTimezone)) &&
223 observedWallClock.tv_sec >= 0 && observedWallClock.tv_usec >= 0 &&
224 observedWallClock.tv_usec < 1000000 && observedTimezone.tz_minuteswest == 0 &&
225 observedTimezone.tz_dsttime == 0;
226
227 time_t observedSeconds = static_cast<time_t>(-1);
228 thread->setErrno(PreservedErrno);
229 const time_t returnedSeconds = posix_time(secondsOutput);
230 passed &=
231 returnedSeconds != static_cast<time_t>(-1) && thread->getErrno() == PreservedErrno &&
232 PosixSubsystem::copyFromUser(&observedSeconds, secondsOutput, sizeof(observedSeconds)) &&
233 observedSeconds == returnedSeconds;
234 thread->setErrno(PreservedErrno);
235 passed &= posix_time(nullptr) != static_cast<time_t>(-1) && thread->getErrno() == PreservedErrno;
236
237 const struct timezone timezoneSentinel = {37, 1};
238 passed &= PosixSubsystem::copyToUser(timezoneOutput, &timezoneSentinel, sizeof(timezoneSentinel));
239 thread->setErrno(0);
240 passed &=
241 posix_gettimeofday(reinterpret_cast<struct timeval*>(kernelStart), timezoneOutput) == -1 &&
242 thread->getErrno() == Error::BadAddress &&
243 PosixSubsystem::copyFromUser(&observedTimezone, timezoneOutput, sizeof(observedTimezone)) &&
244 observedTimezone.tz_minuteswest == timezoneSentinel.tz_minuteswest &&
245 observedTimezone.tz_dsttime == timezoneSentinel.tz_dsttime;
246 thread->setErrno(0);
247 passed &= posix_gettimeofday(nullptr, reinterpret_cast<struct timezone*>(kernelStart)) == -1 &&
248 thread->getErrno() == Error::BadAddress;
249 thread->setErrno(0);
250 passed &= posix_time(reinterpret_cast<time_t*>(kernelStart)) == static_cast<time_t>(-1) &&
251 thread->getErrno() == Error::BadAddress;
252 thread->setErrno(0);
253 passed &=
254 posix_settimeofday(nullptr, nullptr) == -1 && thread->getErrno() == Error::Unimplemented;
255 thread->setErrno(0);
256 passed &= posix_settimeofday(reinterpret_cast<struct timeval*>(kernelStart), nullptr) == -1 &&
257 thread->getErrno() == Error::Unimplemented;
258
259 const int selectors[] = {ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF};
260 for (size_t i = 0; passed && i < sizeof(selectors) / sizeof(selectors[0]); ++i) {
261 const struct itimerval disarmed = {};
262 const struct itimerval requested =
263 timerValue(static_cast<time_t>(i + 1), static_cast<suseconds_t>(123456 + i),
264 static_cast<time_t>(60 + i), static_cast<suseconds_t>(654321 + i));
265 struct itimerval observed = {};
266 passed &= PosixSubsystem::copyToUser(input, &disarmed, sizeof(disarmed)) &&
267 posix_setitimer(selectors[i], input, nullptr) == 0 &&
268 posix_getitimer(selectors[i], output) == 0 &&
269 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
270 timerIsDisarmed(observed) &&
271 PosixSubsystem::copyToUser(input, &requested, sizeof(requested));
272 thread->setErrno(PreservedErrno);
273 passed &=
274 posix_setitimer(selectors[i], input, nullptr) == 0 && thread->getErrno() == PreservedErrno;
275 thread->setErrno(PreservedErrno);
276 passed &= posix_getitimer(selectors[i], output) == 0 && thread->getErrno() == PreservedErrno &&
277 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
278 runningTimerMatches(observed, requested);
279 }
280
281 const struct itimerval spanning = timerValue(4, 654321, 64, 456789);
282 struct itimerval observed = {};
283 passed &= PosixSubsystem::copyToUser(pageEdge, &spanning, sizeof(spanning)) &&
284 posix_setitimer(ITIMER_REAL, pageEdge, nullptr) == 0 &&
285 posix_getitimer(ITIMER_REAL, pageEdge) == 0 &&
286 PosixSubsystem::copyFromUser(&observed, pageEdge, sizeof(observed)) &&
287 runningTimerMatches(observed, spanning);
288
289 const struct itimerval baseline = timerValue(7, 700007, 67, 700007);
290 const struct itimerval aliasedRequest = timerValue(9, 900009, 69, 900009);
291 struct itimerval aliasResult = {};
292 passed &= PosixSubsystem::copyToUser(input, &baseline, sizeof(baseline)) &&
293 posix_setitimer(ITIMER_REAL, input, nullptr) == 0 &&
294 PosixSubsystem::copyToUser(alias, &aliasedRequest, sizeof(aliasedRequest)) &&
295 posix_setitimer(ITIMER_REAL, alias, alias) == 0 &&
296 PosixSubsystem::copyFromUser(&aliasResult, alias, sizeof(aliasResult)) &&
297 runningTimerMatches(aliasResult, baseline) &&
298 posix_getitimer(ITIMER_REAL, output) == 0 &&
299 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
300 runningTimerMatches(observed, aliasedRequest);
301
302 struct itimerval invalidValues[] = {
303 timerValue(-1, 0), timerValue(0, -1), timerValue(0, 1000000),
304 timerValue(0, 0, -1, 0), timerValue(0, 0, 0, -1), timerValue(0, 0, 0, 1000000),
305 };
306 for (size_t i = 0; passed && i < sizeof(invalidValues) / sizeof(invalidValues[0]); ++i) {
307 passed &= PosixSubsystem::copyToUser(input, &invalidValues[i], sizeof(invalidValues[i]));
308 thread->setErrno(0);
309 passed &= posix_setitimer(ITIMER_REAL, input, nullptr) == -1 &&
310 thread->getErrno() == Error::InvalidArgument &&
311 posix_getitimer(ITIMER_REAL, output) == 0 &&
312 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
313 runningTimerMatches(observed, aliasedRequest);
314 }
315
316 const time_t saturationSeconds =
317 static_cast<time_t>(MaximumLinuxTimerNanoseconds / Time::Multiplier::Second);
318 const struct itimerval huge = timerValue(saturationSeconds, 0, saturationSeconds, 0);
319 passed &= PosixSubsystem::copyToUser(input, &huge, sizeof(huge)) &&
320 posix_setitimer(ITIMER_VIRTUAL, input, nullptr) == 0 &&
321 process->getVirtualIntervalTimer().getInterval() == MaximumLinuxTimerNanoseconds &&
322 process->getVirtualIntervalTimer().getValue() == MaximumLinuxTimerNanoseconds;
323 thread->setErrno(PreservedErrno);
324 passed &= posix_setitimer(ITIMER_VIRTUAL, nullptr, output) == 0 &&
325 thread->getErrno() == PreservedErrno &&
326 process->getVirtualIntervalTimer().getInterval() == 0 &&
327 process->getVirtualIntervalTimer().getValue() == 0 &&
328 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
329 observed.it_interval.tv_sec ==
330 static_cast<time_t>(MaximumLinuxTimerNanoseconds / Time::Multiplier::Second) &&
331 observed.it_interval.tv_usec ==
332 static_cast<suseconds_t>((MaximumLinuxTimerNanoseconds % Time::Multiplier::Second) /
333 Time::Multiplier::Microsecond) &&
334 posix_getitimer(ITIMER_VIRTUAL, output) == 0 &&
335 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
336 timerIsDisarmed(observed);
337
338 thread->setErrno(0);
339 passed &= posix_getitimer(-1, bad) == -1 && thread->getErrno() == Error::InvalidArgument;
340 thread->setErrno(0);
341 passed &= posix_setitimer(-1, bad, nullptr) == -1 && thread->getErrno() == Error::BadAddress;
342 const struct itimerval malformed = timerValue(0, 1000000);
343 passed &= PosixSubsystem::copyToUser(input, &malformed, sizeof(malformed));
344 thread->setErrno(0);
345 passed &=
346 posix_setitimer(-1, input, nullptr) == -1 && thread->getErrno() == Error::InvalidArgument;
347 passed &= PosixSubsystem::copyToUser(input, &baseline, sizeof(baseline));
348 thread->setErrno(0);
349 passed &= posix_setitimer(-1, input, bad) == -1 && thread->getErrno() == Error::InvalidArgument;
350 thread->setErrno(0);
351 passed &= posix_setitimer(-1, nullptr, bad) == -1 && thread->getErrno() == Error::InvalidArgument;
352
353 const struct itimerval beforeFault = timerValue(11, 111111, 71, 111111);
354 passed &= PosixSubsystem::copyToUser(input, &beforeFault, sizeof(beforeFault)) &&
355 posix_setitimer(ITIMER_REAL, input, nullptr) == 0;
356 thread->setErrno(0);
357 passed &= posix_getitimer(ITIMER_REAL, nullptr) == -1 && thread->getErrno() == Error::BadAddress;
358 thread->setErrno(0);
359 passed &= posix_getitimer(ITIMER_REAL, bad) == -1 && thread->getErrno() == Error::BadAddress;
360 thread->setErrno(0);
361 passed &= posix_setitimer(ITIMER_REAL, bad, nullptr) == -1 &&
362 thread->getErrno() == Error::BadAddress && posix_getitimer(ITIMER_REAL, output) == 0 &&
363 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
364 runningTimerMatches(observed, beforeFault);
365
366 const struct itimerval readOnlyRequest = timerValue(12, 121212, 72, 121212);
367 passed &= PosixSubsystem::copyToUser(readOnly, &readOnlyRequest, sizeof(readOnlyRequest)) &&
368 MemoryMapManager::instance().setPermissions(address + (pageSize * 2), pageSize,
369 MemoryMappedObject::Read) == 1 &&
370 posix_setitimer(ITIMER_REAL, readOnly, nullptr) == 0;
371 thread->setErrno(0);
372 passed &= posix_getitimer(ITIMER_REAL, readOnly) == -1 && thread->getErrno() == Error::BadAddress;
373
374 const struct itimerval lateFaultRequest = timerValue(13, 131313, 73, 131313);
375 passed &= PosixSubsystem::copyToUser(input, &lateFaultRequest, sizeof(lateFaultRequest));
376 thread->setErrno(0);
377 passed &= posix_setitimer(ITIMER_REAL, input, readOnly) == -1 &&
378 thread->getErrno() == Error::BadAddress && posix_getitimer(ITIMER_REAL, output) == 0 &&
379 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
380 runningTimerMatches(observed, lateFaultRequest);
381
382 const struct itimerval alarmReplacementBaseline = timerValue(23, 232323, 600, 999999);
383 const struct itimerval alarmRequest = timerValue(0, 0, 120, 0);
384 passed &= PosixSubsystem::copyToUser(input, &alarmReplacementBaseline,
385 sizeof(alarmReplacementBaseline)) &&
386 posix_setitimer(ITIMER_REAL, input, nullptr) == 0;
387 thread->setErrno(PreservedErrno);
388 passed &= posix_alarm(120) == 601 && thread->getErrno() == PreservedErrno &&
389 posix_getitimer(ITIMER_REAL, output) == 0 &&
390 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
391 runningTimerMatches(observed, alarmRequest);
392
393 const struct itimerval setitimerReplacement = timerValue(5, 555555, 500, 999999);
394 struct itimerval previousAlarm = {};
395 passed &=
396 PosixSubsystem::copyToUser(input, &setitimerReplacement, sizeof(setitimerReplacement)) &&
397 posix_setitimer(ITIMER_REAL, input, alias) == 0 &&
398 PosixSubsystem::copyFromUser(&previousAlarm, alias, sizeof(previousAlarm)) &&
399 runningTimerMatches(previousAlarm, alarmRequest) &&
400 posix_getitimer(ITIMER_REAL, output) == 0 &&
401 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
402 runningTimerMatches(observed, setitimerReplacement);
403
404 thread->setErrno(PreservedErrno);
405 passed &= posix_alarm(0) == 501 && thread->getErrno() == PreservedErrno &&
406 posix_getitimer(ITIMER_REAL, output) == 0 &&
407 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
408 timerIsDisarmed(observed);
409
410 const struct itimerval belowHalfSecond = timerValue(0, 0, 400, 250000);
411 passed &= PosixSubsystem::copyToUser(input, &belowHalfSecond, sizeof(belowHalfSecond)) &&
412 posix_setitimer(ITIMER_REAL, input, nullptr) == 0 && posix_alarm(0) == 400;
413
414 const struct itimerval subsecondAlarm = timerValue(0, 0, 0, 999999);
415 passed &= PosixSubsystem::copyToUser(input, &subsecondAlarm, sizeof(subsecondAlarm)) &&
416 posix_setitimer(ITIMER_REAL, input, nullptr) == 0 && posix_alarm(0) == 1 &&
417 posix_getitimer(ITIMER_REAL, output) == 0 &&
418 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
419 timerIsDisarmed(observed);
420
421 AlarmThreadContext alarmThreadContext(300);
422 Thread* alarmThread =
423 new Thread(process, armAlarmAndExit, &alarmThreadContext, nullptr, false, true, true);
424 alarmThread->setName("hosted transient alarm caller");
425 const bool alarmThreadStarted = alarmThread->start();
426 const bool alarmThreadJoined = alarmThreadStarted && alarmThread->joinForCompletion();
427 if (!alarmThreadStarted) {
428 delete alarmThread;
429 }
430 passed &= alarmThreadStarted && alarmThreadJoined && alarmThreadContext.returned == 1 &&
431 alarmThreadContext.result == 0 && posix_getitimer(ITIMER_REAL, output) == 0 &&
432 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
433 runningTimerMatches(observed, timerValue(0, 0, 300, 0)) && posix_alarm(0) > 0 &&
434 posix_getitimer(ITIMER_REAL, output) == 0 &&
435 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
436 timerIsDisarmed(observed);
437
438 passed &= PosixSubsystem::copyToUser(input, &lateFaultRequest, sizeof(lateFaultRequest)) &&
439 posix_setitimer(ITIMER_REAL, input, nullptr) == 0;
440
441 const bool middleRemoved =
442 mapping && MemoryMapManager::instance().remove(address + pageSize, pageSize) == 1;
443 passed &= middleRemoved;
444 thread->setErrno(0);
445 passed &= posix_setitimer(ITIMER_REAL, pageEdge, nullptr) == -1 &&
446 thread->getErrno() == Error::BadAddress;
447 thread->setErrno(0);
448 passed &= posix_getitimer(ITIMER_REAL, pageEdge) == -1 && thread->getErrno() == Error::BadAddress;
449 thread->setErrno(0);
450 passed &= posix_setitimer(ITIMER_REAL, reinterpret_cast<struct itimerval*>(address + pageSize),
451 nullptr) == -1 &&
452 thread->getErrno() == Error::BadAddress && posix_getitimer(ITIMER_REAL, output) == 0 &&
453 PosixSubsystem::copyFromUser(&observed, output, sizeof(observed)) &&
454 runningTimerMatches(observed, lateFaultRequest);
455
456 for (size_t i = 0; i < sizeof(selectors) / sizeof(selectors[0]); ++i) {
457 passed &= posix_setitimer(selectors[i], nullptr, nullptr) == 0;
458 }
459 Time::Timestamp finalInterval = 1;
460 Time::Timestamp finalValue = 1;
461 process->getRealIntervalTimer().getIntervalAndValue(finalInterval, finalValue);
462 passed &= !finalInterval && !finalValue;
463 process->getVirtualIntervalTimer().getIntervalAndValue(finalInterval, finalValue);
464 passed &= !finalInterval && !finalValue;
465 process->getProfileIntervalTimer().getIntervalAndValue(finalInterval, finalValue);
466 passed &= !finalInterval && !finalValue;
467
468 if (mapping) {
469 MemoryMapManager::instance().remove(address, pageSize);
470 MemoryMapManager::instance().remove(address + (pageSize * 2), pageSize);
471 }
472 if (allocated) {
473 process->freeUserRange(Process::UserRegion::Normal, address, mappingLength);
474 }
475
476 context->passed = passed;
477 context->returned += 1;
478 return passed ? 0 : 1;
479}
480} // namespace
481
482bool runHostedTimeSyscallRegressions(Process* kernelProcess) {
483 const bool interestPassed = cpuTimerReportInterest(kernelProcess);
484 PosixProcess* process = new PosixProcess(kernelProcess);
485 process->setSubsystem(new PosixSubsystem);
486 TimeSyscallContext context;
487 Thread* worker = new Thread(process, exerciseTimeSyscalls, &context, nullptr, false, true, true);
488 worker->setName("hosted interval timer syscall worker");
489 process->publish();
490
491 const bool started = worker->start();
492 const bool joined = started && worker->joinForCompletion();
493 if (!started) {
494 delete worker;
495 }
496 const bool passed =
497 interestPassed && started && joined && context.returned == 1 && context.passed;
498 delete process;
499
500 if (!passed) {
501 ERROR(
502 "HOSTED-SYSCALL-TEST: FAIL time-syscall-usercopy: "
503 "wall-clock, interval-timer, or alarm behavior regressed");
504 return false;
505 }
506 NOTICE("HOSTED-SYSCALL-TEST: PASS time-syscall-usercopy");
507 return true;
508}
Memory-mapped file interface.
@ Virtual
CPU time in user mode only.
@ Profile
CPU time in user and system.
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
size_t remove(uintptr_t base, size_t length)
static MemoryMapManager & instance()
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
void publish()
Definition Process.cc:832
Time::Timestamp getUserTime() const
Definition Process.h:775
static ProcessorInformation & information()
static Scheduler & instance()
Definition Scheduler.h:96
void yield()
Definition Scheduler.cc:226
void setErrno(size_t err)
Definition Thread.h:478
size_t getErrno()
Definition Thread.h:473
bool joinForCompletion()
Definition Thread.cc:2771
Process * getParent() const
Definition Thread.h:338
bool start()
Definition Thread.cc:794