kernel+libc: Add support for unnamed pipes
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-05-10 22:48:31 +02:00
parent 1a2fce5316
commit efc6d03f23
Signed by: apio
GPG Key ID: B8A7D06E42258954
13 changed files with 286 additions and 10 deletions

View File

@ -23,3 +23,4 @@ luna_app(stat.cpp stat)
luna_app(uname.cpp uname) luna_app(uname.cpp uname)
luna_app(base64.cpp base64) luna_app(base64.cpp base64)
luna_app(login.cpp login) luna_app(login.cpp login)
luna_app(ipc-test.cpp ipc-test)

45
apps/ipc-test.cpp Normal file
View File

@ -0,0 +1,45 @@
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main()
{
int pfds[2];
if (pipe(pfds) < 0)
{
perror("pipe");
return 1;
}
pid_t child = fork();
if (child == 0)
{
close(pfds[1]);
char buffer[4096];
size_t nread = read(pfds[0], buffer, sizeof(buffer) - 1);
buffer[nread] = 0;
close(pfds[0]);
puts(buffer);
return 0;
}
else if (child == -1)
{
perror("fork");
return 1;
}
close(pfds[0]);
const char* string = "Hello from a child process who just received this message from its parent!";
write(pfds[1], string, strlen(string));
close(pfds[1]);
wait(NULL);
return 0;
}

View File

@ -39,6 +39,7 @@ set(SOURCES
src/sys/link.cpp src/sys/link.cpp
src/sys/uname.cpp src/sys/uname.cpp
src/fs/VFS.cpp src/fs/VFS.cpp
src/fs/Pipe.cpp
src/fs/tmpfs/FileSystem.cpp src/fs/tmpfs/FileSystem.cpp
src/fs/devices/DeviceRegistry.cpp src/fs/devices/DeviceRegistry.cpp
src/fs/devices/NullDevice.cpp src/fs/devices/NullDevice.cpp

62
kernel/src/fs/Pipe.cpp Normal file
View File

@ -0,0 +1,62 @@
#include "fs/Pipe.h"
#include "thread/Scheduler.h"
Result<void> Pipe::create(SharedPtr<VFS::Inode>& rpipe, SharedPtr<VFS::Inode>& wpipe)
{
auto pipe = TRY(make_shared<Pipe>());
auto writer = TRY(make_shared<PipeWriter>());
auto reader = TRY(make_shared<PipeReader>());
auto auth = Scheduler::current()->auth;
pipe->m_writer = writer.ptr();
pipe->m_reader = reader.ptr();
writer->m_pipe = reader->m_pipe = pipe;
writer->chown(auth.euid, auth.egid);
reader->chown(auth.euid, auth.egid);
rpipe = reader;
wpipe = writer;
return {};
}
Result<usize> Pipe::read(u8* buf, usize, usize length)
{
if (length > m_data_buffer.size()) length = m_data_buffer.size();
memcpy(buf, m_data_buffer.data(), length);
memmove(m_data_buffer.data(), m_data_buffer.data() + length, m_data_buffer.size() - length);
TRY(m_data_buffer.try_resize(m_data_buffer.size() - length));
return length;
}
Result<usize> Pipe::write(const u8* buf, usize, usize length)
{
if (!m_reader) return length;
u8* slice = TRY(m_data_buffer.slice_at_end(length));
memcpy(slice, buf, length);
return length;
}
bool Pipe::blocking() const
{
return !m_data_buffer.size() && m_writer;
}
PipeWriter::~PipeWriter()
{
m_pipe->m_writer = nullptr;
}
PipeReader::~PipeReader()
{
m_pipe->m_reader = nullptr;
}

134
kernel/src/fs/Pipe.h Normal file
View File

@ -0,0 +1,134 @@
#pragma once
#include "fs/VFS.h"
#include <luna/Buffer.h>
class PipeInodeBase;
class PipeReader;
class PipeWriter;
class Pipe
{
public:
static Result<void> create(SharedPtr<VFS::Inode>& rpipe, SharedPtr<VFS::Inode>& wpipe);
Result<usize> read(u8* buf, usize, usize length);
Result<usize> write(const u8* buf, usize, usize length);
bool blocking() const;
private:
Buffer m_data_buffer;
PipeWriter* m_writer;
PipeReader* m_reader;
friend class PipeInodeBase;
friend class PipeReader;
friend class PipeWriter;
};
class PipeInodeBase : public VFS::FileInode
{
public:
Result<void> truncate(usize) override
{
return err(ENOTSUP);
}
bool blocking() const override
{
return m_pipe->blocking();
}
usize size() const override
{
return m_pipe->m_data_buffer.size();
}
void did_link() override
{
}
void did_unlink() override
{
}
Result<void> chmod(mode_t) override
{
return err(ENOTSUP);
}
Result<void> chown(u32 uid, u32 gid) override
{
m_uid = uid;
m_gid = gid;
return {};
}
usize inode_number() const override
{
return 0;
}
VFS::FileSystem* fs() const override
{
return nullptr;
}
virtual ~PipeInodeBase() = default;
friend class Pipe;
protected:
SharedPtr<Pipe> m_pipe;
u32 m_uid { 0 };
u32 m_gid { 0 };
};
class PipeWriter : public PipeInodeBase
{
public:
Result<usize> read(u8*, usize, usize) const override
{
// A FileDescriptor pointing to a PipeWriter should never be opened for reading.
check(false);
}
Result<usize> write(const u8* buf, usize offset, usize length) override
{
return m_pipe->write(buf, offset, length);
}
mode_t mode() const override
{
return 0200;
}
~PipeWriter();
friend class Pipe;
};
class PipeReader : public PipeInodeBase
{
public:
Result<usize> read(u8* buf, usize offset, usize length) const override
{
return m_pipe->read(buf, offset, length);
}
Result<usize> write(const u8*, usize, usize) override
{
// A FileDescriptor pointing to a PipeReader should never be opened for writing.
check(false);
}
mode_t mode() const override
{
return 0400;
}
~PipeReader();
friend class Pipe;
};

View File

@ -81,7 +81,7 @@ namespace VFS
virtual Result<void> chown(u32 uid, u32 gid) = 0; virtual Result<void> chown(u32 uid, u32 gid) = 0;
// Generic VFS-related methods // Generic VFS-related methods
virtual FileSystem& fs() const = 0; virtual FileSystem* fs() const = 0;
virtual ~Inode() = default; virtual ~Inode() = default;

View File

@ -50,9 +50,9 @@ namespace TmpFS
m_inode_number = inum; m_inode_number = inum;
} }
VFS::FileSystem& fs() const override VFS::FileSystem* fs() const override
{ {
return *m_fs; return m_fs;
} }
usize inode_number() const override usize inode_number() const override
@ -138,9 +138,9 @@ namespace TmpFS
m_device = device; m_device = device;
} }
VFS::FileSystem& fs() const override VFS::FileSystem* fs() const override
{ {
return *m_fs; return m_fs;
} }
usize inode_number() const override usize inode_number() const override
@ -305,9 +305,9 @@ namespace TmpFS
return {}; return {};
} }
VFS::FileSystem& fs() const override VFS::FileSystem* fs() const override
{ {
return *m_fs; return m_fs;
} }
usize inode_number() const override usize inode_number() const override

View File

@ -1,4 +1,5 @@
#include "Log.h" #include "Log.h"
#include "fs/Pipe.h"
#include "fs/VFS.h" #include "fs/VFS.h"
#include "memory/MemoryManager.h" #include "memory/MemoryManager.h"
#include "sys/Syscall.h" #include "sys/Syscall.h"
@ -166,3 +167,26 @@ Result<u64> sys_dup2(Registers*, SyscallArgs args)
return (u64)newfd; return (u64)newfd;
} }
Result<u64> sys_pipe(Registers*, SyscallArgs args)
{
int* pfds = (int*)args[0];
Thread* current = Scheduler::current();
int rfd = TRY(current->allocate_fd(0));
int wfd = TRY(current->allocate_fd(rfd + 1));
if (!MemoryManager::copy_to_user_typed(pfds, &rfd)) return err(EFAULT);
if (!MemoryManager::copy_to_user_typed(pfds + 1, &wfd)) return err(EFAULT);
SharedPtr<VFS::Inode> rpipe;
SharedPtr<VFS::Inode> wpipe;
TRY(Pipe::create(rpipe, wpipe));
current->fd_table[rfd] = FileDescriptor { rpipe, 0, O_RDONLY };
current->fd_table[wfd] = FileDescriptor { wpipe, 0, O_WRONLY };
return 0;
}

View File

@ -27,7 +27,7 @@ Result<u64> sys_mknod(Registers*, SyscallArgs args)
auto parent = TRY(VFS::resolve_path(dirname.chars(), current->auth, current->current_directory)); auto parent = TRY(VFS::resolve_path(dirname.chars(), current->auth, current->current_directory));
if (!VFS::can_write(parent, current->auth)) return err(EACCES); if (!VFS::can_write(parent, current->auth)) return err(EACCES);
auto inode = TRY(parent->fs().create_device_inode(maj, min)); auto inode = TRY(parent->fs()->create_device_inode(maj, min));
TRY(parent->add_entry(inode, basename.chars())); TRY(parent->add_entry(inode, basename.chars()));
TRY(inode->chmod(mode)); TRY(inode->chmod(mode));

View File

@ -59,7 +59,7 @@ Result<u64> sys_openat(Registers*, SyscallArgs args)
if (flags & O_TMPFILE) if (flags & O_TMPFILE)
{ {
if (inode->type() != VFS::InodeType::Directory) return err(EINVAL); if (inode->type() != VFS::InodeType::Directory) return err(EINVAL);
inode = TRY(inode->fs().create_file_inode()); inode = TRY(inode->fs()->create_file_inode());
inode->chmod(mode); inode->chmod(mode);
inode->chown(current->auth.euid, current->auth.egid); inode->chown(current->auth.euid, current->auth.egid);
} }

View File

@ -127,6 +127,9 @@ extern "C"
/* Set the current network hostname. */ /* Set the current network hostname. */
int sethostname(const char* buf, size_t len); int sethostname(const char* buf, size_t len);
/* Create a pipe for inter-process communication. */
int pipe(int pfds[2]);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -399,4 +399,10 @@ extern "C"
long rc = syscall(SYS_sethostname, buf, len); long rc = syscall(SYS_sethostname, buf, len);
__errno_return(rc, int); __errno_return(rc, int);
} }
int pipe(int pfds[2])
{
long rc = syscall(SYS_pipe, (int*)pfds);
__errno_return(rc, int);
}
} }

View File

@ -4,7 +4,7 @@
_e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(openat) _e(close) _e(read) _e(getpid) _e(write) \ _e(exit) _e(clock_gettime) _e(mmap) _e(munmap) _e(usleep) _e(openat) _e(close) _e(read) _e(getpid) _e(write) \
_e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \ _e(lseek) _e(mkdir) _e(execve) _e(mknod) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) \
_e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(chmod) _e(chown) \ _e(geteuid) _e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(chmod) _e(chown) \
_e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(ioctl) _e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe)
enum Syscalls enum Syscalls
{ {