kernel+libc: Add support for unnamed pipes
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
1a2fce5316
commit
efc6d03f23
@ -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
45
apps/ipc-test.cpp
Normal 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;
|
||||||
|
}
|
@ -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
62
kernel/src/fs/Pipe.cpp
Normal 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
134
kernel/src/fs/Pipe.h
Normal 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;
|
||||||
|
};
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user