Skip to content

Commit 577eef2

Browse files
authored
Merge pull request #884 from Geertiebear/cancelable_syscalls
Changes for managarm cancelable syscalls
2 parents 271a112 + 078e61e commit 577eef2

File tree

6 files changed

+126
-42
lines changed

6 files changed

+126
-42
lines changed

sysdeps/managarm/generic/entry.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ namespace {
2828
thread_local unsigned __mlibc_gsf_nesting;
2929
thread_local void *__mlibc_cached_thread_page;
3030
thread_local HelHandle *cachedFileTable;
31+
thread_local HelHandle *cancelEvent;
3132

3233
// This construction is a bit weird: Even though the variables above
3334
// are thread_local we still protect their initialization with a pthread_once_t
@@ -45,6 +46,7 @@ void actuallyCacheInfos() {
4546
__mlibc_cached_thread_page = data.threadPage;
4647
cachedFileTable = data.fileTable;
4748
__mlibc_clk_tracker_page = data.clockTrackerPage;
49+
cancelEvent = data.cancelRequestEvent;
4850
}
4951
} // namespace
5052

@@ -104,6 +106,11 @@ HelHandle getHandleForFd(int fd) {
104106

105107
void clearCachedInfos() { has_cached_infos = PTHREAD_ONCE_INIT; }
106108

109+
void setCurrentRequestEvent(HelHandle event) {
110+
pthread_once(&has_cached_infos, &actuallyCacheInfos);
111+
__atomic_store_n(cancelEvent, event, __ATOMIC_RELEASE);
112+
}
113+
107114
extern char **environ;
108115

109116
extern "C" void

sysdeps/managarm/generic/file.cpp

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,10 @@ int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) {
17481748
if (!handle)
17491749
return EBADF;
17501750

1751+
HelHandle cancel_handle;
1752+
HEL_CHECK(helCreateOneshotEvent(&cancel_handle));
1753+
helix::UniqueDescriptor cancel_event{cancel_handle};
1754+
17511755
managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
17521756
req.set_req_type(managarm::fs::CntReqType::READ);
17531757
req.set_fd(fd);
@@ -1756,29 +1760,31 @@ int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) {
17561760
frg::string<MemoryAllocator> ser(getSysdepsAllocator());
17571761
req.SerializeToString(&ser);
17581762

1759-
auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSync(
1760-
handle,
1761-
helix_ng::offer(
1762-
helix_ng::sendBuffer(ser.data(), ser.size()),
1763-
helix_ng::imbueCredentials(),
1764-
helix_ng::recvInline(),
1765-
helix_ng::recvBuffer(data, max_size)
1766-
)
1767-
);
1763+
auto [offer, push_req, send_req, imbue_creds, recv_resp, recv_data] =
1764+
exchangeMsgsSyncCancellable(
1765+
handle,
1766+
cancel_handle,
1767+
helix_ng::offer(
1768+
helix_ng::sendBuffer(ser.data(), ser.size()),
1769+
helix_ng::pushDescriptor(cancel_event),
1770+
helix_ng::imbueCredentials(),
1771+
helix_ng::recvInline(),
1772+
helix_ng::recvBuffer(data, max_size)
1773+
)
1774+
);
17681775

17691776
HEL_CHECK(offer.error());
1777+
HEL_CHECK(push_req.error());
17701778
HEL_CHECK(send_req.error());
17711779
HEL_CHECK(imbue_creds.error());
17721780
HEL_CHECK(recv_resp.error());
17731781

17741782
managarm::fs::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
17751783
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
1776-
if (resp.error() != managarm::fs::Errors::SUCCESS)
1777-
return resp.error() | toErrno;
1778-
17791784
HEL_CHECK(recv_data.error());
1785+
17801786
*bytes_read = recv_data.actualLength();
1781-
return 0;
1787+
return resp.error() | toErrno;
17821788
}
17831789

17841790
int sys_readv(int fd, const struct iovec *iovs, int iovc, ssize_t *bytes_read) {

sysdeps/managarm/generic/fork-exec.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,20 +57,33 @@ int sys_futex_wake(int *pointer) {
5757
int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) {
5858
SignalGuard sguard;
5959

60+
if (ru) {
61+
mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog;
62+
return ENOSYS;
63+
}
64+
65+
HelHandle cancel_handle;
66+
HEL_CHECK(helCreateOneshotEvent(&cancel_handle));
67+
helix::UniqueDescriptor cancel_event{cancel_handle};
68+
6069
managarm::posix::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
6170
req.set_request_type(managarm::posix::CntReqType::WAIT);
6271
req.set_pid(pid);
6372
req.set_flags(flags);
6473

65-
auto [offer, send_head, recv_resp] = exchangeMsgsSync(
74+
auto [offer, send_head, push_descriptor, recv_resp] = exchangeMsgsSyncCancellable(
6675
getPosixLane(),
76+
cancel_handle,
6777
helix_ng::offer(
68-
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()), helix_ng::recvInline()
78+
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
79+
helix_ng::pushDescriptor(cancel_event),
80+
helix_ng::recvInline()
6981
)
7082
);
7183

7284
HEL_CHECK(offer.error());
7385
HEL_CHECK(send_head.error());
86+
HEL_CHECK(push_descriptor.error());
7487
HEL_CHECK(recv_resp.error());
7588

7689
managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());

sysdeps/managarm/include/bits/errors.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ inline int operator|(managarm::fs::Errors e, ToErrno) {
7676
return ENOTSOCK;
7777
case managarm::fs::Errors::INTERNAL_ERROR:
7878
return EIO;
79+
case managarm::fs::Errors::INTERRUPTED:
80+
return EINTR;
7981
}
8082

8183
mlibc::panicLogger() << "unhandled managarm::fs::Errors " << static_cast<int32_t>(e)
@@ -145,6 +147,8 @@ inline int operator|(managarm::posix::Errors e, ToErrno) {
145147
return EISCONN;
146148
case managarm::posix::Errors::UNSUPPORTED_SOCKET_TYPE:
147149
return ESOCKTNOSUPPORT;
150+
case managarm::posix::Errors::INTERRUPTED:
151+
return EINTR;
148152
}
149153

150154
mlibc::panicLogger() << "unhandled managarm::posix::Errors " << static_cast<int32_t>(e)

sysdeps/managarm/include/mlibc/posix-pipe.hpp

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
#define MLIBC_POSIX_PIPE
33

44
#include <cstddef>
5-
#include <signal.h>
6-
#include <stdint.h>
75
#include <string.h>
86

97
#include <hel-syscalls.h>
108
#include <hel.h>
119

10+
#include <bits/ensure.h>
11+
#include <frg/optional.hpp>
12+
#include <mlibc/allocator.hpp>
13+
#include <mlibc/debug.hpp>
14+
1215
struct SignalGuard {
1316
SignalGuard();
1417

@@ -121,24 +124,26 @@ struct Queue {
121124

122125
void trim() {}
123126

124-
ElementHandle dequeueSingle() {
127+
frg::optional<ElementHandle> dequeueSingleUnlessCancelled() {
125128
while (true) {
126129
__ensure(_retrieveIndex != _nextIndex);
127130

128-
bool done;
129-
_waitProgressFutex(&done);
131+
auto progress = _waitProgressFutex();
130132

131133
auto n = _numberOf(_retrieveIndex);
132134
__ensure(_refCount[n]);
133135

134-
if (done) {
136+
if (progress == FutexProgress::DONE) {
135137
retire(n);
136138

137139
_lastProgress = 0;
138140
_retrieveIndex = ((_retrieveIndex + 1) & kHelHeadMask);
139141
continue;
140142
}
141143

144+
if (progress == FutexProgress::CANCELLED)
145+
return frg::null_opt;
146+
142147
// Dequeue the next element.
143148
auto ptr = (char *)_chunks[n] + sizeof(HelChunk) + _lastProgress;
144149
auto element = reinterpret_cast<HelElement *>(ptr);
@@ -148,6 +153,14 @@ struct Queue {
148153
}
149154
}
150155

156+
ElementHandle dequeueSingle() {
157+
while (true) {
158+
auto result = dequeueSingleUnlessCancelled();
159+
if (result)
160+
return *result;
161+
}
162+
}
163+
151164
void retire(int n) {
152165
__ensure(_refCount[n]);
153166
if (_refCount[n]-- > 1)
@@ -175,18 +188,21 @@ struct Queue {
175188
HEL_CHECK(helFutexWake(&_queue->headFutex));
176189
}
177190

178-
void _waitProgressFutex(bool *done) {
191+
enum class FutexProgress {
192+
DONE,
193+
PROGRESS,
194+
CANCELLED,
195+
};
196+
197+
FutexProgress _waitProgressFutex() {
179198
while (true) {
180199
auto futex = __atomic_load_n(&_retrieveChunk()->progressFutex, __ATOMIC_ACQUIRE);
181200
__ensure(!(futex & ~(kHelProgressMask | kHelProgressWaiters | kHelProgressDone)));
182201
do {
183-
if (_lastProgress != (futex & kHelProgressMask)) {
184-
*done = false;
185-
return;
186-
} else if (futex & kHelProgressDone) {
187-
*done = true;
188-
return;
189-
}
202+
if (_lastProgress != (futex & kHelProgressMask))
203+
return FutexProgress::PROGRESS;
204+
else if (futex & kHelProgressDone)
205+
return FutexProgress::DONE;
190206

191207
if (futex & kHelProgressWaiters)
192208
break; // Waiters bit is already set (in a previous iteration).
@@ -199,9 +215,14 @@ struct Queue {
199215
__ATOMIC_ACQUIRE
200216
));
201217

202-
HEL_CHECK(helFutexWait(
218+
int err = helFutexWait(
203219
&_retrieveChunk()->progressFutex, _lastProgress | kHelProgressWaiters, -1
204-
));
220+
);
221+
222+
if (err == kHelErrCancelled)
223+
return FutexProgress::CANCELLED;
224+
225+
HEL_CHECK(err);
205226
}
206227
}
207228

@@ -261,6 +282,7 @@ inline HelHandleResult *parseHandle(ElementHandle &element) {
261282
HelHandle getPosixLane();
262283
HelHandle *cacheFileTable();
263284
HelHandle getHandleForFd(int fd);
285+
void setCurrentRequestEvent(HelHandle event);
264286
void clearCachedInfos();
265287

266288
extern thread_local Queue globalQueue;
@@ -287,4 +309,26 @@ auto exchangeMsgsSync(HelHandle descriptor, Args &&...args) {
287309
return results;
288310
}
289311

312+
template <typename... Args>
313+
auto exchangeMsgsSyncCancellable(HelHandle descriptor, HelHandle event, Args &&...args) {
314+
auto results = helix_ng::createResultsTuple(args...);
315+
auto actions = helix_ng::chainActionArrays(args...);
316+
317+
setCurrentRequestEvent(event);
318+
HEL_CHECK(
319+
helSubmitAsync(descriptor, actions.data(), actions.size(), globalQueue.getQueue(), 0, 0)
320+
);
321+
322+
auto element = globalQueue.dequeueSingle();
323+
void *ptr = element.data();
324+
325+
[&]<size_t... p>(std::index_sequence<p...>) {
326+
(results.template get<p>().parse(ptr, element), ...);
327+
}(std::make_index_sequence<std::tuple_size_v<decltype(results)>>{});
328+
329+
setCurrentRequestEvent(kHelNullHandle);
330+
331+
return results;
332+
}
333+
290334
#endif // MLIBC_POSIX_PIPE

sysdeps/managarm/rtld-generic/support.cpp

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,10 @@ struct Queue {
143143
__ATOMIC_ACQUIRE
144144
));
145145

146-
HEL_CHECK(helFutexWait(&_chunk->progressFutex, _lastProgress | kHelProgressWaiters, -1)
147-
);
146+
int err = helFutexWait(&_chunk->progressFutex, _lastProgress | kHelProgressWaiters, -1);
147+
if (err == kHelErrCancelled)
148+
continue;
149+
HEL_CHECK(err);
148150
}
149151
}
150152

@@ -302,7 +304,10 @@ int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) {
302304
int sys_read(int fd, void *data, size_t length, ssize_t *bytes_read) {
303305
cacheFileTable();
304306
auto lane = fileTable[fd];
305-
HelAction actions[5];
307+
HelAction actions[6];
308+
309+
HelHandle cancel_handle;
310+
HEL_CHECK(helCreateOneshotEvent(&cancel_handle));
306311

307312
managarm::fs::CntRequest<MemoryAllocator> req(getAllocator());
308313
req.set_req_type(managarm::fs::CntReqType::READ);
@@ -319,25 +324,30 @@ int sys_read(int fd, void *data, size_t length, ssize_t *bytes_read) {
319324
actions[1].flags = kHelItemChain;
320325
actions[1].buffer = ser.data();
321326
actions[1].length = ser.size();
322-
actions[2].type = kHelActionImbueCredentials;
323-
actions[2].handle = kHelThisThread;
327+
actions[2].type = kHelActionPushDescriptor;
328+
actions[2].handle = cancel_handle;
324329
actions[2].flags = kHelItemChain;
325-
actions[3].type = kHelActionRecvInline;
330+
actions[3].type = kHelActionImbueCredentials;
331+
actions[3].handle = kHelThisThread;
326332
actions[3].flags = kHelItemChain;
327-
actions[4].type = kHelActionRecvToBuffer;
328-
actions[4].flags = 0;
329-
actions[4].buffer = data;
330-
actions[4].length = length;
331-
HEL_CHECK(helSubmitAsync(lane, actions, 5, globalQueue->getHandle(), 0, 0));
333+
actions[4].type = kHelActionRecvInline;
334+
actions[4].flags = kHelItemChain;
335+
actions[5].type = kHelActionRecvToBuffer;
336+
actions[5].flags = 0;
337+
actions[5].buffer = data;
338+
actions[5].length = length;
339+
HEL_CHECK(helSubmitAsync(lane, actions, 6, globalQueue->getHandle(), 0, 0));
332340

333341
auto element = globalQueue->dequeueSingle();
334342
auto offer = parseHandle(element);
335343
auto send_req = parseSimple(element);
344+
auto push_desc = parseSimple(element);
336345
auto imbue_creds = parseSimple(element);
337346
auto recv_resp = parseInline(element);
338347
auto recv_data = parseLength(element);
339348
HEL_CHECK(offer->error);
340349
HEL_CHECK(send_req->error);
350+
HEL_CHECK(push_desc->error);
341351
HEL_CHECK(imbue_creds->error);
342352
HEL_CHECK(recv_resp->error);
343353
HEL_CHECK(recv_data->error);

0 commit comments

Comments
 (0)