diff --git a/sysdeps/managarm/generic/entry.cpp b/sysdeps/managarm/generic/entry.cpp index 6fdda27fa..6bc064695 100644 --- a/sysdeps/managarm/generic/entry.cpp +++ b/sysdeps/managarm/generic/entry.cpp @@ -31,6 +31,7 @@ namespace { thread_local unsigned __mlibc_gsf_nesting; thread_local void *__mlibc_cached_thread_page; thread_local HelHandle *cachedFileTable; +thread_local HelHandle *cancelEvent; // This construction is a bit weird: Even though the variables above // are thread_local we still protect their initialization with a pthread_once_t @@ -48,6 +49,7 @@ void actuallyCacheInfos() { __mlibc_cached_thread_page = data.threadPage; cachedFileTable = data.fileTable; __mlibc_clk_tracker_page = data.clockTrackerPage; + cancelEvent = data.cancelRequestEvent; } } // namespace @@ -107,6 +109,11 @@ HelHandle getHandleForFd(int fd) { void clearCachedInfos() { has_cached_infos = PTHREAD_ONCE_INIT; } +void setCurrentRequestEvent(HelHandle event) { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + __atomic_store_n(cancelEvent, event, __ATOMIC_RELEASE); +} + struct LibraryGuard { LibraryGuard(); }; diff --git a/sysdeps/managarm/generic/file.cpp b/sysdeps/managarm/generic/file.cpp index ce2bee856..2c9e64ae1 100644 --- a/sysdeps/managarm/generic/file.cpp +++ b/sysdeps/managarm/generic/file.cpp @@ -1,3 +1,4 @@ +#include "mlibc/debug.hpp" #include #include #include @@ -1628,12 +1629,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 req(getSysdepsAllocator()); req.set_req_type(managarm::fs::CntReqType::READ); req.set_fd(fd); @@ -1642,17 +1645,21 @@ int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) { frg::string ser(getSysdepsAllocator()); req.SerializeToString(&ser); - auto [offer, send_req, imbue_creds, recv_resp, recv_data] = exchangeMsgsSync( - handle, - helix_ng::offer( - helix_ng::sendBuffer(ser.data(), ser.size()), - helix_ng::imbueCredentials(), - helix_ng::recvInline(), - helix_ng::recvBuffer(data, max_size) - ) - ); + 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()); @@ -1673,6 +1680,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()); diff --git a/sysdeps/managarm/generic/fork-exec.cpp b/sysdeps/managarm/generic/fork-exec.cpp index 858b9dbed..a966213c6 100644 --- a/sysdeps/managarm/generic/fork-exec.cpp +++ b/sysdeps/managarm/generic/fork-exec.cpp @@ -54,22 +54,33 @@ int sys_futex_wake(int *pointer) { } int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret_pid) { - SignalGuard sguard; + if (ru) { + mlibc::infoLogger() << "mlibc: struct rusage in sys_waitpid is unsupported" << frg::endlog; + return ENOSYS; + } + + HelHandle cancel_handle; + HEL_CHECK(helCreateOneshotEvent(&cancel_handle)); + helix::UniqueDescriptor cancel_event{cancel_handle}; managarm::posix::CntRequest 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::recvInline() + 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 resp(getSysdepsAllocator()); @@ -77,6 +88,10 @@ int sys_waitpid(pid_t pid, int *status, int flags, struct rusage *ru, pid_t *ret if (resp.error() == managarm::posix::Errors::ILLEGAL_ARGUMENTS) { return EINVAL; } + if (resp.error() == managarm::posix::Errors::INTERRUPTED) { + mlibc::infoLogger() << "returning EINT" << frg::endlog; + return EINTR; + } __ensure(resp.error() == managarm::posix::Errors::SUCCESS); if (status) *status = resp.mode(); @@ -148,7 +163,10 @@ int sys_sleep(time_t *secs, long *nanos) { )); auto element = globalQueue.dequeueSingle(); - auto result = parseSimple(element); + if (!element) { + return EINTR; + } + auto result = parseSimple(*element); HEL_CHECK(result->error); *secs = 0; diff --git a/sysdeps/managarm/include/mlibc/posix-pipe.hpp b/sysdeps/managarm/include/mlibc/posix-pipe.hpp index 120e7388d..eb8657a28 100644 --- a/sysdeps/managarm/include/mlibc/posix-pipe.hpp +++ b/sysdeps/managarm/include/mlibc/posix-pipe.hpp @@ -9,6 +9,9 @@ #include #include +#include +#include + struct SignalGuard { SignalGuard(); @@ -121,17 +124,16 @@ struct Queue { void trim() {} - ElementHandle dequeueSingle() { + frg::optional 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; @@ -139,6 +141,12 @@ struct Queue { 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(ptr); @@ -175,18 +183,21 @@ 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). @@ -199,9 +210,17 @@ struct Queue { __ATOMIC_ACQUIRE )); - HEL_CHECK(helFutexWait( + int err = helFutexWait( &_retrieveChunk()->progressFutex, _lastProgress | kHelProgressWaiters, -1 - )); + ); + if (err == kHelErrCancelled) { + if (ignoreCancel) { + continue; + } + + return FutexProgress::CANCELLED; + } + HEL_CHECK(err); } } @@ -261,6 +280,7 @@ inline HelHandleResult *parseHandle(ElementHandle &element) { HelHandle getPosixLane(); HelHandle *cacheFileTable(); HelHandle getHandleForFd(int fd); +void setCurrentRequestEvent(HelHandle event); void clearCachedInfos(); extern thread_local Queue globalQueue; @@ -278,12 +298,39 @@ auto exchangeMsgsSync(HelHandle descriptor, Args &&...args) { ); auto element = globalQueue.dequeueSingle(); - void *ptr = element.data(); + __ensure(element); + void *ptr = element->data(); + + [&](std::index_sequence) { + (results.template get

().parse(ptr, *element), ...); + }(std::make_index_sequence>{}); + + return results; +} + +template +auto exchangeMsgsSyncCancellable(HelHandle descriptor, HelHandle event, Args &&...args) { + auto results = helix_ng::createResultsTuple(args...); + auto actions = helix_ng::chainActionArrays(args...); + + setCurrentRequestEvent(event); + HEL_CHECK( + helSubmitAsync(descriptor, actions.data(), actions.size(), globalQueue.getQueue(), 0, 0) + ); + + auto element = globalQueue.dequeueSingle(false); + if (!element) { + element = globalQueue.dequeueSingle(); + __ensure(element); + } + void *ptr = element->data(); [&](std::index_sequence) { - (results.template get

().parse(ptr, element), ...); + (results.template get

().parse(ptr, *element), ...); }(std::make_index_sequence>{}); + setCurrentRequestEvent(kHelNullHandle); + return results; } diff --git a/sysdeps/managarm/rtld-generic/support.cpp b/sysdeps/managarm/rtld-generic/support.cpp index cda3dfc17..df3855232 100644 --- a/sysdeps/managarm/rtld-generic/support.cpp +++ b/sysdeps/managarm/rtld-generic/support.cpp @@ -138,8 +138,10 @@ struct Queue { __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); } } @@ -297,7 +299,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 req(getAllocator()); req.set_req_type(managarm::fs::CntReqType::READ); @@ -314,25 +319,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);