Files
ladybird/Kernel/Syscalls/pipe.cpp
Andreas Kling 164c9617c3 Kernel: Only lock file descriptor table once in sys$pipe()
Instead of locking it twice, we now frontload all the work that doesn't
touch the fd table, and then only lock it towards the end of the
syscall.

The benefit here is simplicity. The downside is that we do a bit of
unnecessary work in the EMFILE error case, but we don't need to optimize
that case anyway.
2022-08-16 20:39:45 +02:00

56 lines
1.7 KiB
C++

/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <Kernel/FileSystem/FIFO.h>
#include <Kernel/Process.h>
namespace Kernel {
ErrorOr<FlatPtr> Process::sys$pipe(Userspace<int*> pipefd, int flags)
{
VERIFY_NO_PROCESS_BIG_LOCK(this)
TRY(require_promise(Pledge::stdio));
// Reject flags other than O_CLOEXEC, O_NONBLOCK
if ((flags & (O_CLOEXEC | O_NONBLOCK)) != flags)
return EINVAL;
u32 fd_flags = (flags & O_CLOEXEC) ? FD_CLOEXEC : 0;
auto fifo = TRY(FIFO::try_create(uid()));
auto reader_description = TRY(fifo->open_direction(FIFO::Direction::Reader));
auto writer_description = TRY(fifo->open_direction(FIFO::Direction::Writer));
reader_description->set_readable(true);
writer_description->set_writable(true);
if (flags & O_NONBLOCK) {
reader_description->set_blocking(false);
writer_description->set_blocking(false);
}
TRY(m_fds.with_exclusive([&](auto& fds) -> ErrorOr<void> {
auto reader_fd_allocation = TRY(fds.allocate());
auto writer_fd_allocation = TRY(fds.allocate());
fds[reader_fd_allocation.fd].set(move(reader_description), fd_flags);
fds[writer_fd_allocation.fd].set(move(writer_description), fd_flags);
int fds_for_userspace[2] = {
reader_fd_allocation.fd,
writer_fd_allocation.fd,
};
if (copy_to_user(pipefd, fds_for_userspace, sizeof(fds_for_userspace)).is_error()) {
fds[reader_fd_allocation.fd] = {};
fds[writer_fd_allocation.fd] = {};
return EFAULT;
}
return {};
}));
return 0;
}
}