The Pedigree Project 0.1
scm-stream-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/Log.h"
9#include "pedigree/kernel/process/Process.h"
10#include "pedigree/kernel/process/Thread.h"
11#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
12#include "pedigree/kernel/processor/Processor.h"
13#include "pedigree/kernel/utilities/lib.h"
14
15#include <fcntl.h>
16
17#include "modules/subsys/posix/FileDescriptor.h"
18#include "modules/subsys/posix/PosixProcess.h"
19#include "modules/subsys/posix/PosixSubsystem.h"
20#include "modules/subsys/posix/UnixFilesystem.h"
21#include "modules/subsys/posix/file-syscalls.h"
22#include "modules/subsys/posix/net-syscalls.h"
24#include "modules/system/vfs/VFS.h"
25#include <sys/socket.h>
26
27namespace {
28constexpr size_t SourceDescriptor = 90;
29constexpr size_t SecondSourceDescriptor = 91;
30
31union ControlBuffer {
32 struct cmsghdr alignment;
33 uint8_t bytes[CMSG_SPACE(2 * sizeof(int))];
34};
35
36struct StreamFixture {
37 int sockets[2];
38 uint8_t sendPayload[512];
39 uint8_t receivePayload[512];
40 struct iovec sendVector;
41 struct iovec receiveVector;
42 ControlBuffer sendControl;
43 ControlBuffer receiveControl;
44 struct msghdr sendMessage;
45 struct msghdr receiveMessage;
46};
47
48struct StreamContext {
49 explicit StreamContext(Process* process) : process(process), completed(false), result(false) {}
50
51 Process* process;
52 bool completed;
53 bool result;
54};
55
56void prepareSend(StreamFixture& fixture, const void* payload, size_t payloadLength,
57 const int* descriptors, size_t descriptorCount) {
58 ByteSet(&fixture.sendControl, 0, sizeof(fixture.sendControl));
59 fixture.sendVector = {const_cast<void*>(payload), payloadLength};
60 fixture.sendMessage = {};
61 fixture.sendMessage.msg_iov = &fixture.sendVector;
62 fixture.sendMessage.msg_iovlen = 1;
63 fixture.sendMessage.msg_control = fixture.sendControl.bytes;
64 fixture.sendMessage.msg_controllen = CMSG_SPACE(descriptorCount * sizeof(int));
65 struct cmsghdr* header = CMSG_FIRSTHDR(&fixture.sendMessage);
66 header->cmsg_len = CMSG_LEN(descriptorCount * sizeof(int));
67 header->cmsg_level = SOL_SOCKET;
68 header->cmsg_type = SCM_RIGHTS;
69 MemoryCopy(CMSG_DATA(header), descriptors, descriptorCount * sizeof(int));
70}
71
72void prepareReceive(StreamFixture& fixture, size_t payloadCapacity, size_t controlCapacity) {
73 ByteSet(fixture.receivePayload, 0, sizeof(fixture.receivePayload));
74 ByteSet(&fixture.receiveControl, 0, sizeof(fixture.receiveControl));
75 fixture.receiveVector = {fixture.receivePayload, payloadCapacity};
76 fixture.receiveMessage = {};
77 fixture.receiveMessage.msg_iov = &fixture.receiveVector;
78 fixture.receiveMessage.msg_iovlen = 1;
79 fixture.receiveMessage.msg_control = fixture.receiveControl.bytes;
80 fixture.receiveMessage.msg_controllen = controlCapacity;
81}
82
83int receivedDescriptor(const StreamFixture& fixture, size_t expectedCount) {
84 const struct cmsghdr* header = CMSG_FIRSTHDR(&fixture.receiveMessage);
85 if (!header || header->cmsg_level != SOL_SOCKET || header->cmsg_type != SCM_RIGHTS ||
86 header->cmsg_len != CMSG_LEN(expectedCount * sizeof(int))) {
87 return -1;
88 }
89
90 int descriptor = -1;
91 MemoryCopy(&descriptor, CMSG_DATA(header), sizeof(descriptor));
92 return descriptor;
93}
94
95FileDescriptor::OpenFileDescriptionLease addSource(PosixSubsystem* subsystem, size_t descriptor) {
96 FileDescriptor* source = new FileDescriptor;
97 source->fd = descriptor;
99 subsystem->addFileDescriptor(descriptor, source);
100 return description;
101}
102
103bool closePair(StreamFixture& fixture) {
104 bool passed = true;
105 for (size_t i = 0; i < 2; ++i) {
106 if (fixture.sockets[i] >= 0) {
107 passed = posix_close(fixture.sockets[i]) == 0 && passed;
108 fixture.sockets[i] = -1;
109 }
110 }
111 return passed;
112}
113
114bool orderingAndSenderClose(PosixSubsystem* subsystem, StreamFixture& fixture) {
115 fixture.sockets[0] = fixture.sockets[1] = -1;
116 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fixture.sockets)) {
117 return false;
118 }
119
120 prepareReceive(fixture, 1, sizeof(fixture.receiveControl));
121 bool passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == -1;
122
123 FileDescriptor::OpenFileDescriptionLease description = addSource(subsystem, SourceDescriptor);
124 MemoryCopy(fixture.sendPayload, "ab", 2);
125 passed = posix_send(fixture.sockets[0], fixture.sendPayload, 2, 0) == 2 && passed;
126 MemoryCopy(fixture.sendPayload, "cd", 2);
127 int source = SourceDescriptor;
128 prepareSend(fixture, fixture.sendPayload, 2, &source, 1);
129 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2 &&
130 SocketRights::inFlightForTest() == 1 && posix_close(SourceDescriptor) == 0 &&
131 description->descriptorOwnerCount() == 1 && passed;
132 MemoryCopy(fixture.sendPayload, "ef", 2);
133 passed = posix_send(fixture.sockets[0], fixture.sendPayload, 2, 0) == 2 &&
134 posix_close(fixture.sockets[0]) == 0 && passed;
135 fixture.sockets[0] = -1;
136
137 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
138 fixture.receivePayload[0] == 'a' && SocketRights::inFlightForTest() == 1 && passed;
139 prepareReceive(fixture, sizeof(fixture.receivePayload), CMSG_SPACE(sizeof(int)));
140 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, MSG_CMSG_CLOEXEC) == 2 &&
141 fixture.receivePayload[0] == 'b' && fixture.receivePayload[1] == 'c' &&
142 !fixture.receiveMessage.msg_flags && SocketRights::inFlightForTest() == 0 && passed;
143 const int received = receivedDescriptor(fixture, 1);
144 passed = received >= 0 &&
145 posix_fcntl(received, F_GETFD, reinterpret_cast<void*>(0)) == FD_CLOEXEC &&
146 description->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
147 description->descriptorOwnerCount() == 0 && passed;
148
149 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 4, 0) == 3 &&
150 fixture.receivePayload[0] == 'd' && fixture.receivePayload[1] == 'e' &&
151 fixture.receivePayload[2] == 'f' &&
152 posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 0 && passed;
153 return closePair(fixture) && passed;
154}
155
156bool splitIovecMarker(PosixSubsystem* subsystem, StreamFixture& fixture) {
157 fixture.sockets[0] = fixture.sockets[1] = -1;
158 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
159 return false;
160 }
161
162 FileDescriptor::OpenFileDescriptionLease description = addSource(subsystem, SourceDescriptor);
163 int source = SourceDescriptor;
164 fixture.sendPayload[0] = 'a';
165 MemoryCopy(fixture.sendPayload + 1, "bc", 2);
166 ByteSet(&fixture.sendControl, 0, sizeof(fixture.sendControl));
167 struct iovec sendVectors[2] = {
168 {fixture.sendPayload, 0},
169 {fixture.sendPayload + 1, 2},
170 };
171 fixture.sendMessage = {};
172 fixture.sendMessage.msg_iov = sendVectors;
173 fixture.sendMessage.msg_iovlen = 2;
174 fixture.sendMessage.msg_control = fixture.sendControl.bytes;
175 fixture.sendMessage.msg_controllen = CMSG_SPACE(sizeof(int));
176 struct cmsghdr* header = CMSG_FIRSTHDR(&fixture.sendMessage);
177 header->cmsg_len = CMSG_LEN(sizeof(int));
178 header->cmsg_level = SOL_SOCKET;
179 header->cmsg_type = SCM_RIGHTS;
180 MemoryCopy(CMSG_DATA(header), &source, sizeof(source));
181
182 bool passed = posix_send(fixture.sockets[0], fixture.sendPayload, 1, 0) == 1 &&
183 posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2 &&
184 posix_close(SourceDescriptor) == 0 && description->descriptorOwnerCount() == 1 &&
185 SocketRights::inFlightForTest() == 1;
186
187 ByteSet(fixture.receivePayload, 0, sizeof(fixture.receivePayload));
188 ByteSet(&fixture.receiveControl, 0, sizeof(fixture.receiveControl));
189 struct iovec receiveVectors[2] = {
190 {fixture.receivePayload, 1},
191 {fixture.receivePayload + 1, sizeof(fixture.receivePayload) - 1},
192 };
193 fixture.receiveMessage = {};
194 fixture.receiveMessage.msg_iov = receiveVectors;
195 fixture.receiveMessage.msg_iovlen = 2;
196 fixture.receiveMessage.msg_control = fixture.receiveControl.bytes;
197 fixture.receiveMessage.msg_controllen = CMSG_SPACE(sizeof(int));
198 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 2 &&
199 fixture.receivePayload[0] == 'a' && fixture.receivePayload[1] == 'b' &&
200 SocketRights::inFlightForTest() == 0 && passed;
201 const int received = receivedDescriptor(fixture, 1);
202 passed = received >= 0 && description->descriptorOwnerCount() == 1 &&
203 posix_close(received) == 0 && description->descriptorOwnerCount() == 0 && passed;
204 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
205 fixture.receivePayload[0] == 'c' && closePair(fixture) && passed;
206 return passed;
207}
208
209bool plainReadAndTruncation(PosixSubsystem* subsystem, StreamFixture& fixture) {
210 fixture.sockets[0] = fixture.sockets[1] = -1;
211 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
212 return false;
213 }
214
215 FileDescriptor::OpenFileDescriptionLease discarded = addSource(subsystem, SourceDescriptor);
216 int source = SourceDescriptor;
217 fixture.sendPayload[0] = 'p';
218 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
219 bool passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
220 posix_close(SourceDescriptor) == 0 && discarded->descriptorOwnerCount() == 1 &&
221 SocketRights::inFlightForTest() == 1;
222 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
223 fixture.receivePayload[0] == 'p' && discarded->descriptorOwnerCount() == 0 &&
224 SocketRights::inFlightForTest() == 0 && passed;
225
226 FileDescriptor::OpenFileDescriptionLease first = addSource(subsystem, SourceDescriptor);
227 FileDescriptor::OpenFileDescriptionLease second = addSource(subsystem, SecondSourceDescriptor);
228 int sources[2] = {static_cast<int>(SourceDescriptor), static_cast<int>(SecondSourceDescriptor)};
229 fixture.sendPayload[0] = 't';
230 prepareSend(fixture, fixture.sendPayload, 1, sources, 2);
231 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
232 posix_close(SourceDescriptor) == 0 && posix_close(SecondSourceDescriptor) == 0 &&
233 first->descriptorOwnerCount() == 1 && second->descriptorOwnerCount() == 1 && passed;
234
235 prepareReceive(fixture, 1, CMSG_LEN(sizeof(int)));
236 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
237 fixture.receivePayload[0] == 't' && (fixture.receiveMessage.msg_flags & MSG_CTRUNC) &&
238 SocketRights::inFlightForTest() == 0 && second->descriptorOwnerCount() == 0 && passed;
239 const int received = receivedDescriptor(fixture, 1);
240 passed = received >= 0 && first->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
241 first->descriptorOwnerCount() == 0 && passed;
242 return closePair(fixture) && passed;
243}
244
245bool multipleControlsAndFaultRetry(PosixSubsystem* subsystem, StreamFixture& fixture) {
246 fixture.sockets[0] = fixture.sockets[1] = -1;
247 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
248 return false;
249 }
250
251 FileDescriptor::OpenFileDescriptionLease first = addSource(subsystem, SourceDescriptor);
252 int source = SourceDescriptor;
253 MemoryCopy(fixture.sendPayload, "12", 2);
254 prepareSend(fixture, fixture.sendPayload, 2, &source, 1);
255 bool passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2;
256
257 FileDescriptor::OpenFileDescriptionLease second = addSource(subsystem, SecondSourceDescriptor);
258 source = SecondSourceDescriptor;
259 MemoryCopy(fixture.sendPayload, "34", 2);
260 prepareSend(fixture, fixture.sendPayload, 2, &source, 1);
261 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 2 &&
262 posix_close(SourceDescriptor) == 0 && posix_close(SecondSourceDescriptor) == 0 &&
263 SocketRights::inFlightForTest() == 2 && first->descriptorOwnerCount() == 1 &&
264 second->descriptorOwnerCount() == 1 && passed;
265
266 prepareReceive(fixture, sizeof(fixture.receivePayload), CMSG_SPACE(sizeof(int)));
267 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
268 fixture.receivePayload[0] == '1' && SocketRights::inFlightForTest() == 1 && passed;
269 int received = receivedDescriptor(fixture, 1);
270 passed = received >= 0 && first->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
271 first->descriptorOwnerCount() == 0 && passed;
272
273 prepareReceive(fixture, sizeof(fixture.receivePayload), CMSG_SPACE(sizeof(int)));
274 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 2 &&
275 fixture.receivePayload[0] == '2' && fixture.receivePayload[1] == '3' &&
276 SocketRights::inFlightForTest() == 0 && passed;
277 received = receivedDescriptor(fixture, 1);
278 passed = received >= 0 && second->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
279 second->descriptorOwnerCount() == 0 && passed;
280 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
281 fixture.receivePayload[0] == '4' && closePair(fixture) && passed;
282
283 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
284 return false;
285 }
286 FileDescriptor::OpenFileDescriptionLease faultOwner = addSource(subsystem, SourceDescriptor);
287 source = SourceDescriptor;
288 fixture.sendPayload[0] = 'f';
289 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
290 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
291 posix_close(SourceDescriptor) == 0 && faultOwner->descriptorOwnerCount() == 1 &&
292 SocketRights::inFlightForTest() == 1 && passed;
293
294 prepareReceive(fixture, 1, CMSG_SPACE(sizeof(int)));
295 fixture.receiveMessage.msg_control = reinterpret_cast<void*>(~static_cast<uintptr_t>(0));
296 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == -1 &&
297 faultOwner->descriptorOwnerCount() == 1 && SocketRights::inFlightForTest() == 1 &&
298 passed;
299 prepareReceive(fixture, 1, CMSG_SPACE(sizeof(int)));
300 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
301 fixture.receivePayload[0] == 'f' && SocketRights::inFlightForTest() == 0 && passed;
302 received = receivedDescriptor(fixture, 1);
303 passed = received >= 0 && faultOwner->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
304 faultOwner->descriptorOwnerCount() == 0 && closePair(fixture) && passed;
305 return passed;
306}
307
308bool sendRetryDoesNotDuplicate(PosixSubsystem* subsystem, StreamFixture& fixture) {
309 fixture.sockets[0] = fixture.sockets[1] = -1;
310 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fixture.sockets)) {
311 return false;
312 }
313
314 ByteSet(fixture.sendPayload, 'q', sizeof(fixture.sendPayload));
315 size_t queued = 0;
316 while (queued < MAX_UNIX_STREAM_QUEUE) {
317 const size_t remaining = MAX_UNIX_STREAM_QUEUE - queued;
318 const size_t amount =
319 remaining < sizeof(fixture.sendPayload) ? remaining : sizeof(fixture.sendPayload);
320 const ssize_t written = posix_send(fixture.sockets[0], fixture.sendPayload, amount, 0);
321 if (written <= 0) {
322 closePair(fixture);
323 return false;
324 }
325 queued += static_cast<size_t>(written);
326 }
327 bool passed = posix_send(fixture.sockets[0], fixture.sendPayload, 1, 0) == -1;
328
329 FileDescriptor::OpenFileDescriptionLease retryOwner = addSource(subsystem, SourceDescriptor);
330 int source = SourceDescriptor;
331 fixture.sendPayload[0] = 'r';
332 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
333 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == -1 &&
334 SocketRights::inFlightForTest() == 0 && retryOwner->descriptorOwnerCount() == 1 &&
335 passed;
336
337 passed = posix_recv(fixture.sockets[1], fixture.receivePayload, 1, 0) == 1 &&
338 posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
339 SocketRights::inFlightForTest() == 1 && posix_close(SourceDescriptor) == 0 &&
340 retryOwner->descriptorOwnerCount() == 1 && passed;
341
342 size_t toDrain = queued - 1;
343 while (toDrain) {
344 const size_t amount =
345 toDrain < sizeof(fixture.receivePayload) ? toDrain : sizeof(fixture.receivePayload);
346 const ssize_t received = posix_recv(fixture.sockets[1], fixture.receivePayload, amount, 0);
347 if (received <= 0) {
348 closePair(fixture);
349 return false;
350 }
351 toDrain -= static_cast<size_t>(received);
352 }
353 passed = SocketRights::inFlightForTest() == 1 && passed;
354
355 prepareReceive(fixture, 1, CMSG_SPACE(sizeof(int)));
356 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == 1 &&
357 fixture.receivePayload[0] == 'r' && SocketRights::inFlightForTest() == 0 && passed;
358 const int received = receivedDescriptor(fixture, 1);
359 passed = received >= 0 && retryOwner->descriptorOwnerCount() == 1 && posix_close(received) == 0 &&
360 retryOwner->descriptorOwnerCount() == 0 && closePair(fixture) && passed;
361 return passed;
362}
363
364bool emptyPayloadAndCloseDrain(PosixSubsystem* subsystem, StreamFixture& fixture) {
365 fixture.sockets[0] = fixture.sockets[1] = -1;
366 if (posix_socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fixture.sockets)) {
367 return false;
368 }
369
370 FileDescriptor::OpenFileDescriptionLease empty = addSource(subsystem, SourceDescriptor);
371 int source = SourceDescriptor;
372 prepareSend(fixture, fixture.sendPayload, 0, &source, 1);
373 bool passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == -1 &&
374 SocketRights::inFlightForTest() == 0 && empty->descriptorOwnerCount() == 1 &&
375 posix_close(SourceDescriptor) == 0 && empty->descriptorOwnerCount() == 0;
376 fixture.sendMessage = {};
377 fixture.sendVector = {fixture.sendPayload, 0};
378 fixture.sendMessage.msg_iov = &fixture.sendVector;
379 fixture.sendMessage.msg_iovlen = 1;
380 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 0 && passed;
381 prepareReceive(fixture, 1, sizeof(fixture.receiveControl));
382 passed = posix_recvmsg(fixture.sockets[1], &fixture.receiveMessage, 0) == -1 && passed;
383 passed = closePair(fixture) && passed;
384
385 if (posix_socketpair(AF_UNIX, SOCK_STREAM, 0, fixture.sockets)) {
386 return false;
387 }
388 FileDescriptor::OpenFileDescriptionLease closeOwner = addSource(subsystem, SourceDescriptor);
389 fixture.sendPayload[0] = 'c';
390 prepareSend(fixture, fixture.sendPayload, 1, &source, 1);
391 passed = posix_sendmsg(fixture.sockets[0], &fixture.sendMessage, 0) == 1 &&
392 posix_close(SourceDescriptor) == 0 && closeOwner->descriptorOwnerCount() == 1 &&
393 posix_close(fixture.sockets[1]) == 0 && passed;
394 fixture.sockets[1] = -1;
395 passed = closeOwner->descriptorOwnerCount() == 0 && SocketRights::inFlightForTest() == 0 &&
396 closePair(fixture) && passed;
397 return passed;
398}
399
400int runStreamWorker(void* parameter) {
401 StreamContext* context = reinterpret_cast<StreamContext*>(parameter);
402 PosixSubsystem* subsystem = static_cast<PosixSubsystem*>(
403 Processor::information().getCurrentThread()->getParent()->getSubsystem());
404 const size_t pageSize = PhysicalMemoryManager::getPageSize();
405 uintptr_t mappingAddress = 0;
406 if (!context->process->allocateUserRange(Process::UserRegion::Normal, pageSize, mappingAddress)) {
407 context->completed = true;
408 return 1;
409 }
410
411 uintptr_t mappedAddress = mappingAddress;
413 mappedAddress, pageSize, MemoryMappedObject::Read | MemoryMappedObject::Write);
414 if (!mapping || mappedAddress != mappingAddress || sizeof(StreamFixture) > pageSize) {
415 if (mapping) {
416 MemoryMapManager::instance().remove(mappedAddress, pageSize);
417 }
418 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
419 context->completed = true;
420 return 1;
421 }
422
423 StreamFixture* fixture = reinterpret_cast<StreamFixture*>(mappingAddress);
424 ByteSet(fixture, 0, sizeof(*fixture));
425 bool passed = orderingAndSenderClose(subsystem, *fixture);
426 passed = splitIovecMarker(subsystem, *fixture) && passed;
427 passed = plainReadAndTruncation(subsystem, *fixture) && passed;
428 passed = multipleControlsAndFaultRetry(subsystem, *fixture) && passed;
429 passed = sendRetryDoesNotDuplicate(subsystem, *fixture) && passed;
430 passed = emptyPayloadAndCloseDrain(subsystem, *fixture) && passed;
431
432 MemoryMapManager::instance().remove(mappingAddress, pageSize);
433 context->process->freeUserRange(Process::UserRegion::Normal, mappingAddress, pageSize);
434 context->result = passed;
435 context->completed = true;
436 return 0;
437}
438} // namespace
439
440bool runHostedScmStreamRegressions(Process* kernelProcess) {
441 bool passed = SocketRights::inFlightForTest() == 0;
442
444 auto* priorView = VFS::instance().mountView();
445 VFS::HostedRootViewScope fixture;
446 UnixFilesystem* filesystem = new UnixFilesystem;
447 if (!fixture.open(filesystem)) {
448 delete filesystem;
449 return false;
450 }
451 Process* process =
452 new PosixProcess(kernelProcess, true, Process::FilesystemContextMode::Deferred);
453 process->setSubsystem(new PosixSubsystem);
454 const bool contextInstalled = fixture.installContext(*process);
455 StreamContext context(process);
456 Thread* worker = new Thread(process, runStreamWorker, &context, nullptr, false, true, true);
457 worker->setName("hosted AF_UNIX stream SCM_RIGHTS");
458 const bool started = contextInstalled && worker->start();
459 const bool joined = started && worker->joinForCompletion();
460 if (!started) {
461 delete worker;
462 }
463
464 passed = started && joined && context.completed && context.result && passed;
465 delete process;
466
467 const bool rootRestored = fixture.close();
468 if (!rootRestored)
469 FATAL("Hosted filesystem fixture retained owners after teardown");
470 passed = rootRestored && VFS::instance().getRootFilesystem() == priorRoot &&
471 VFS::instance().mountView() == priorView && passed;
472 delete filesystem;
473 passed = SocketRights::inFlightForTest() == 0 && passed;
474
475 if (!passed) {
476 ERROR(
477 "HOSTED-SYSCALL-TEST: FAIL scm-rights-stream: ordering, one-shot delivery, "
478 "truncation, or lifecycle drain regressed");
479 return false;
480 }
481
482 NOTICE("HOSTED-SYSCALL-TEST: PASS scm-rights-stream");
483 return true;
484}
Memory-mapped file interface.
OpenFileDescriptionLease acquireOpenFileDescription() const
size_t fd
Descriptor number.
MemoryMappedObject * mapAnon(uintptr_t &address, size_t length, MemoryMappedObject::Permissions perms)
size_t remove(uintptr_t base, size_t length)
static MemoryMapManager & instance()
void addFileDescriptor(size_t fd, FileDescriptor *pFd)
static ProcessorInformation & information()
Filesystem * getRootFilesystem() const
Definition VFS.cc:631
static VFS & instance()
Definition VFS.cc:291