diff --git a/sysdeps/managarm/generic/entry.cpp b/sysdeps/managarm/generic/entry.cpp index 3ff28d2cb3..24f1103e10 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 @@ -46,6 +47,7 @@ namespace { __mlibc_cached_thread_page = data.threadPage; cachedFileTable = data.fileTable; __mlibc_clk_tracker_page = data.clockTrackerPage; + cancelEvent = data.cancelRequestEvent; } } @@ -103,6 +105,11 @@ HelHandle getHandleForFd(int fd) { return cacheFileTable()[fd]; } +void setCurrentRequestEvent(HelHandle event) { + pthread_once(&has_cached_infos, &actuallyCacheInfos); + __atomic_store_n(cancelEvent, event, __ATOMIC_RELEASE); +} + void clearCachedInfos() { has_cached_infos = PTHREAD_ONCE_INIT; } diff --git a/sysdeps/managarm/generic/file.cpp b/sysdeps/managarm/generic/file.cpp index d605269abb..de638261b4 100644 --- a/sysdeps/managarm/generic/file.cpp +++ b/sysdeps/managarm/generic/file.cpp @@ -1,3 +1,4 @@ +#include "mlibc/debug.hpp" #include #include #include @@ -1593,12 +1594,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); @@ -1607,11 +1610,13 @@ 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( + 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) @@ -1619,6 +1624,7 @@ int sys_read(int fd, void *data, size_t max_size, ssize_t *bytes_read) { ); HEL_CHECK(offer.error()); + HEL_CHECK(push_req.error()); HEL_CHECK(send_req.error()); HEL_CHECK(imbue_creds.error()); HEL_CHECK(recv_resp.error()); @@ -1639,6 +1645,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 ee1bcd43a6..3cb75866c2 100644 --- a/sysdeps/managarm/generic/fork-exec.cpp +++ b/sysdeps/managarm/generic/fork-exec.cpp @@ -55,24 +55,36 @@ 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; + } + + //SignalGuard sguard; + + 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::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()); @@ -80,6 +92,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(); @@ -152,7 +168,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; diff --git a/sysdeps/managarm/include/mlibc/posix-pipe.hpp b/sysdeps/managarm/include/mlibc/posix-pipe.hpp index 4bcf1cba2c..43709420df 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(); @@ -130,17 +133,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; @@ -148,6 +150,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); @@ -190,18 +198,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). @@ -209,8 +220,18 @@ struct Queue { _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); } } @@ -271,6 +292,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; @@ -287,14 +309,40 @@ 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(); [&](std::index_sequence) { - (results.template get

().parse(ptr, element), ...); + (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), ...); + } (std::make_index_sequence>{}); + + setCurrentRequestEvent(kHelNullHandle); + + return results; +} #endif // MLIBC_POSIX_PIPE diff --git a/sysdeps/managarm/rtld-generic/support.cpp b/sysdeps/managarm/rtld-generic/support.cpp index 895bc3ee74..8cc1ac62da 100644 --- a/sysdeps/managarm/rtld-generic/support.cpp +++ b/sysdeps/managarm/rtld-generic/support.cpp @@ -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); } } @@ -288,7 +291,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); @@ -305,25 +311,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);