Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes for managarm cancelable syscalls #884

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions sysdeps/managarm/generic/file.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "mlibc/debug.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this LSP? In any case, this should be replaced with <>

#include <asm/ioctls.h>
#include <dirent.h>
#include <errno.h>
Expand Down Expand Up @@ -1555,12 +1556,14 @@ int sys_mknodat(int dirfd, const char *path, int mode, int dev) {
}

int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) {
SignalGuard sguard;

auto handle = getHandleForFd(fd);
if (!handle)
return EBADF;

HelHandle cancel_handle;
HEL_CHECK(helCreateOneshotEvent(&cancel_handle));
helix::UniqueDescriptor cancel_event{cancel_handle};

managarm::fs::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
req.set_req_type(managarm::fs::CntReqType::READ);
req.set_fd(fd);
Expand All @@ -1569,18 +1572,21 @@ int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) {
frg::string<MemoryAllocator> ser(getSysdepsAllocator());
req.SerializeToString(&ser);

auto [offer, send_req, imbue_creds, recv_resp, recv_data] =
exchangeMsgsSync(
auto [offer, push_req, send_req, imbue_creds, recv_resp, recv_data] =
exchangeMsgsSyncCancellable(
handle,
cancel_handle,
helix_ng::offer(
helix_ng::sendBuffer(ser.data(), ser.size()),
helix_ng::pushDescriptor(cancel_event),
helix_ng::imbueCredentials(),
helix_ng::recvInline(),
helix_ng::recvBuffer(data, max_size)
)
);

HEL_CHECK(offer.error());
HEL_CHECK(push_req.error());
HEL_CHECK(send_req.error());
HEL_CHECK(imbue_creds.error());
HEL_CHECK(recv_resp.error());
Expand All @@ -1597,6 +1603,10 @@ int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) {
}else if(resp.error() == managarm::fs::Errors::END_OF_FILE) {
*bytes_read = 0;
return 0;
}else if(resp.error() == managarm::fs::Errors::INTERRUPTED) {
HEL_CHECK(recv_data.error());
*bytes_read = recv_data.actualLength();
return EINTR;
}else{
__ensure(resp.error() == managarm::fs::Errors::SUCCESS);
HEL_CHECK(recv_data.error());
Expand Down
22 changes: 18 additions & 4 deletions sysdeps/managarm/generic/fork-exec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,31 +60,42 @@ int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret
return ENOSYS;
}

SignalGuard sguard;
//SignalGuard sguard;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover I guess.


HelHandle cancel_handle;
HEL_CHECK(helCreateOneshotEvent(&cancel_handle));
helix::UniqueDescriptor cancel_event{cancel_handle};

managarm::posix::CntRequest<MemoryAllocator> req(getSysdepsAllocator());
req.set_request_type(managarm::posix::CntReqType::WAIT);
req.set_pid(pid);
req.set_flags(flags);

auto [offer, send_head, recv_resp] =
exchangeMsgsSync(
auto [offer, send_head, push_descriptor, recv_resp] =
exchangeMsgsSyncCancellable(
getPosixLane(),
cancel_handle,
helix_ng::offer(
helix_ng::sendBragiHeadOnly(req, getSysdepsAllocator()),
helix_ng::pushDescriptor(cancel_event),
helix_ng::recvInline()
)
);

HEL_CHECK(offer.error());
HEL_CHECK(send_head.error());
HEL_CHECK(push_descriptor.error());
HEL_CHECK(recv_resp.error());

managarm::posix::SvrResponse<MemoryAllocator> resp(getSysdepsAllocator());
resp.ParseFromArray(recv_resp.data(), recv_resp.length());
if(resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) {
return EINVAL;
}
if (resp.error() == managarm::posix::Errors::INTERRUPTED) {
mlibc::infoLogger() << "returning EINT" << frg::endlog;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we put this behind some debug flag?

return EINTR;
}
__ensure(resp.error() == managarm::posix::Errors::SUCCESS);
if(status)
*status = resp.mode();
Expand Down Expand Up @@ -115,7 +126,10 @@ int sys_sleep(time_t *secs, long *nanos) {
globalQueue.getQueue(), 0, &async_id));

auto element = globalQueue.dequeueSingle();
auto result = parseSimple(element);
if (!element) {
return EINTR;
}
auto result = parseSimple(*element);
HEL_CHECK(result->error);

*secs = 0;
Expand Down
2 changes: 1 addition & 1 deletion sysdeps/managarm/generic/ioctl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ int sys_ioctl(int fd, unsigned long request, void *arg, int *result) {

managarm::fs::GenericIoctlRequest<MemoryAllocator> req(getSysdepsAllocator());
req.set_command(request);
req.set_pgid((long int)param);
req.set_pgid(*param);

frg::string<MemoryAllocator> ser(getSysdepsAllocator());
req.SerializeToString(&ser);
Expand Down
77 changes: 61 additions & 16 deletions sysdeps/managarm/include/mlibc/posix-pipe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include <hel.h>
#include <hel-syscalls.h>

#include <frg/optional.hpp>
#include <mlibc/debug.hpp>

struct SignalGuard {
SignalGuard();

Expand Down Expand Up @@ -130,24 +133,29 @@ struct Queue {

void trim() { }

ElementHandle dequeueSingle() {
frg::optional<ElementHandle> dequeueSingle(bool ignoreCancel = true) {
while(true) {
__ensure(_retrieveIndex != _nextIndex);

bool done;
_waitProgressFutex(&done);
auto progress = _waitProgressFutex(ignoreCancel);

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

if(done) {
if(progress == FutexProgress::DONE) {
retire(n);

_lastProgress = 0;
_retrieveIndex = ((_retrieveIndex + 1) & kHelHeadMask);
continue;
}

if (progress == FutexProgress::CANCELLED) {
__ensure(!ignoreCancel);
mlibc::infoLogger() << "cancel detected" << frg::endlog;
return frg::null_opt;
}

// Dequeue the next element.
auto ptr = (char *)_chunks[n] + sizeof(HelChunk) + _lastProgress;
auto element = reinterpret_cast<HelElement *>(ptr);
Expand Down Expand Up @@ -190,27 +198,40 @@ struct Queue {
HEL_CHECK(helFutexWake(&_queue->headFutex));
}

void _waitProgressFutex(bool *done) {
enum class FutexProgress {
DONE,
IN_PROGRESS,
CANCELLED,
};

FutexProgress _waitProgressFutex(bool ignoreCancel) {
while(true) {
auto futex = __atomic_load_n(&_retrieveChunk()->progressFutex, __ATOMIC_ACQUIRE);
__ensure(!(futex & ~(kHelProgressMask | kHelProgressWaiters | kHelProgressDone)));
do {
if(_lastProgress != (futex & kHelProgressMask)) {
*done = false;
return;
}else if(futex & kHelProgressDone) {
*done = true;
return;
}
if(_lastProgress != (futex & kHelProgressMask))
return FutexProgress::IN_PROGRESS;
else if(futex & kHelProgressDone)
return FutexProgress::DONE;

if(futex & kHelProgressWaiters)
break; // Waiters bit is already set (in a previous iteration).
} while(!__atomic_compare_exchange_n(&_retrieveChunk()->progressFutex, &futex,
_lastProgress | kHelProgressWaiters,
false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE));

HEL_CHECK(helFutexWait(&_retrieveChunk()->progressFutex,
_lastProgress | kHelProgressWaiters, -1));
int err = helFutexWait(&_retrieveChunk()->progressFutex,
_lastProgress | kHelProgressWaiters, -1);
if (err == kHelErrCancelled) {
if (ignoreCancel) {
mlibc::infoLogger() << "ignoring cancel" << frg::endlog;
continue;
}

mlibc::infoLogger() << "woke up from futex wait" << frg::endlog;
return FutexProgress::CANCELLED;
}
HEL_CHECK(err);
}
}

Expand Down Expand Up @@ -287,14 +308,38 @@ auto exchangeMsgsSync(HelHandle descriptor, Args &&...args) {
actions.size(), globalQueue.getQueue(), 0, 0));

auto element = globalQueue.dequeueSingle();
void *ptr = element.data();
__ensure(element);
void *ptr = element->data();

[&]<size_t ...p>(std::index_sequence<p...>) {
(results.template get<p>().parse(ptr, element), ...);
(results.template get<p>().parse(ptr, *element), ...);
} (std::make_index_sequence<std::tuple_size_v<decltype(results)>>{});

return results;
}

template <typename ...Args>
auto exchangeMsgsSyncCancellable(HelHandle descriptor, HelHandle event,
Args &&...args) {
auto results = helix_ng::createResultsTuple(args...);
auto actions = helix_ng::chainActionArrays(args...);

HEL_CHECK(helSubmitAsync(descriptor, actions.data(),
actions.size(), globalQueue.getQueue(), 0, 0));

auto element = globalQueue.dequeueSingle(false);
if (!element) {
HEL_CHECK(helRaiseEvent(event));
element = globalQueue.dequeueSingle();
__ensure(element);
}
void *ptr = element->data();

[&]<size_t ...p>(std::index_sequence<p...>) {
(results.template get<p>().parse(ptr, *element), ...);
} (std::make_index_sequence<std::tuple_size_v<decltype(results)>>{});

return results;
}

#endif // MLIBC_POSIX_PIPE
33 changes: 22 additions & 11 deletions sysdeps/managarm/rtdl-generic/support.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ struct Queue {
_lastProgress | kHelProgressWaiters,
false, __ATOMIC_ACQUIRE, __ATOMIC_ACQUIRE));

HEL_CHECK(helFutexWait(&_chunk->progressFutex,
_lastProgress | kHelProgressWaiters, -1));
int err = helFutexWait(&_chunk->progressFutex,
_lastProgress | kHelProgressWaiters, -1);
if (err == kHelErrCancelled)
continue;
HEL_CHECK(err);
}
}

Expand Down Expand Up @@ -286,7 +289,10 @@ int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) {
int sys_read(int fd, void *data, size_t length, ssize_t *bytes_read) {
cacheFileTable();
auto lane = fileTable[fd];
HelAction actions[5];
HelAction actions[6];

HelHandle cancel_handle;
HEL_CHECK(helCreateOneshotEvent(&cancel_handle));

managarm::fs::CntRequest<MemoryAllocator> req(getAllocator());
req.set_req_type(managarm::fs::CntReqType::READ);
Expand All @@ -303,25 +309,30 @@ int sys_read(int fd, void *data, size_t length, ssize_t *bytes_read) {
actions[1].flags = kHelItemChain;
actions[1].buffer = ser.data();
actions[1].length = ser.size();
actions[2].type = kHelActionImbueCredentials;
actions[2].handle = kHelThisThread;
actions[2].type = kHelActionPushDescriptor;
actions[2].handle = cancel_handle;
actions[2].flags = kHelItemChain;
actions[3].type = kHelActionRecvInline;
actions[3].type = kHelActionImbueCredentials;
actions[3].handle = kHelThisThread;
actions[3].flags = kHelItemChain;
actions[4].type = kHelActionRecvToBuffer;
actions[4].flags = 0;
actions[4].buffer = data;
actions[4].length = length;
HEL_CHECK(helSubmitAsync(lane, actions, 5, globalQueue->getHandle(), 0, 0));
actions[4].type = kHelActionRecvInline;
actions[4].flags = kHelItemChain;
actions[5].type = kHelActionRecvToBuffer;
actions[5].flags = 0;
actions[5].buffer = data;
actions[5].length = length;
HEL_CHECK(helSubmitAsync(lane, actions, 6, globalQueue->getHandle(), 0, 0));

auto element = globalQueue->dequeueSingle();
auto offer = parseHandle(element);
auto send_req = parseSimple(element);
auto push_desc = parseSimple(element);
auto imbue_creds = parseSimple(element);
auto recv_resp = parseInline(element);
auto recv_data = parseLength(element);
HEL_CHECK(offer->error);
HEL_CHECK(send_req->error);
HEL_CHECK(push_desc->error);
HEL_CHECK(imbue_creds->error);
HEL_CHECK(recv_resp->error);
HEL_CHECK(recv_data->error);
Expand Down