forked from Bananymous/banan-os
Kernel/LibC: Add basic pipe() syscall and command
You can now create pipes :)
This commit is contained in:
parent
22caacd2a9
commit
4eb95c963d
|
@ -20,6 +20,7 @@ set(KERNEL_SOURCES
|
|||
kernel/Font.cpp
|
||||
kernel/FS/Ext2.cpp
|
||||
kernel/FS/Inode.cpp
|
||||
kernel/FS/Pipe.cpp
|
||||
kernel/FS/VirtualFileSystem.cpp
|
||||
kernel/Input/PS2Controller.cpp
|
||||
kernel/Input/PS2Keyboard.cpp
|
||||
|
|
|
@ -76,6 +76,7 @@ namespace Kernel
|
|||
virtual dev_t rdev() const = 0;
|
||||
|
||||
virtual bool is_device() const { return false; }
|
||||
virtual bool is_pipe() const { return false; }
|
||||
|
||||
virtual BAN::StringView name() const = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/Semaphore.h>
|
||||
#include <kernel/SpinLock.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
class Pipe : public Inode
|
||||
{
|
||||
public:
|
||||
static BAN::ErrorOr<BAN::RefPtr<Inode>> create(const Credentials&);
|
||||
|
||||
virtual bool is_pipe() const override { return true; }
|
||||
void clone_writing();
|
||||
void close_writing();
|
||||
|
||||
virtual ino_t ino() const override { return 0; } // FIXME
|
||||
virtual Mode mode() const override { return { Mode::IFIFO | Mode::IRUSR | Mode::IWUSR }; }
|
||||
virtual nlink_t nlink() const override { return 1; }
|
||||
virtual uid_t uid() const override { return m_uid; }
|
||||
virtual gid_t gid() const override { return m_gid; }
|
||||
virtual off_t size() const override { return 0; }
|
||||
virtual timespec atime() const override { return m_atime; }
|
||||
virtual timespec mtime() const override { return m_mtime; }
|
||||
virtual timespec ctime() const override { return m_ctime; }
|
||||
virtual blksize_t blksize() const override { return 4096; }
|
||||
virtual blkcnt_t blocks() const override { return 0; }
|
||||
virtual dev_t dev() const override { return 0; } // FIXME
|
||||
virtual dev_t rdev() const override { return 0; } // FIXME
|
||||
|
||||
virtual BAN::StringView name() const override { return ""sv; }
|
||||
|
||||
virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override;
|
||||
virtual BAN::ErrorOr<size_t> write(size_t, const void*, size_t) override;
|
||||
|
||||
private:
|
||||
Pipe(const Credentials&);
|
||||
|
||||
private:
|
||||
const uid_t m_uid;
|
||||
const gid_t m_gid;
|
||||
timespec m_atime {};
|
||||
timespec m_mtime {};
|
||||
timespec m_ctime {};
|
||||
BAN::Vector<uint8_t> m_buffer;
|
||||
SpinLock m_lock;
|
||||
Semaphore m_semaphore;
|
||||
|
||||
uint32_t m_writing_count { 1 };
|
||||
};
|
||||
|
||||
}
|
|
@ -84,6 +84,8 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> sys_write(int fd, const void* buffer, size_t count);
|
||||
BAN::ErrorOr<long> sys_creat(BAN::StringView name, mode_t);
|
||||
|
||||
BAN::ErrorOr<long> sys_pipe(int fildes[2]);
|
||||
|
||||
BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence);
|
||||
BAN::ErrorOr<long> sys_tell(int fd);
|
||||
|
||||
|
@ -136,6 +138,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> validate_fd(int);
|
||||
OpenFileDescription& open_file_description(int);
|
||||
BAN::ErrorOr<int> get_free_fd();
|
||||
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]);
|
||||
|
||||
|
||||
struct ExitStatus
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
#include <kernel/FS/Pipe.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/RTC.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> Pipe::create(const Credentials& credentials)
|
||||
{
|
||||
Pipe* pipe = new Pipe(credentials);
|
||||
if (pipe == nullptr)
|
||||
return BAN::Error::from_errno(ENOMEM);
|
||||
return BAN::RefPtr<Inode>::adopt(pipe);
|
||||
}
|
||||
|
||||
Pipe::Pipe(const Credentials& credentials)
|
||||
: m_uid(credentials.euid())
|
||||
, m_gid(credentials.egid())
|
||||
{
|
||||
uint64_t current_time = BAN::to_unix_time(RTC::get_current_time());
|
||||
m_atime = { .tv_sec = current_time, .tv_nsec = 0 };
|
||||
m_mtime = { .tv_sec = current_time, .tv_nsec = 0 };
|
||||
m_ctime = { .tv_sec = current_time, .tv_nsec = 0 };
|
||||
}
|
||||
|
||||
void Pipe::clone_writing()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
ASSERT(m_writing_count > 0);
|
||||
m_writing_count++;
|
||||
}
|
||||
|
||||
void Pipe::close_writing()
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
ASSERT(m_writing_count > 0);
|
||||
m_writing_count--;
|
||||
if (m_writing_count == 0)
|
||||
m_semaphore.unblock();
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Pipe::read(size_t, void* buffer, size_t count)
|
||||
{
|
||||
m_lock.lock();
|
||||
while (m_buffer.empty())
|
||||
{
|
||||
if (m_writing_count == 0)
|
||||
return 0;
|
||||
m_lock.unlock();
|
||||
m_semaphore.block();
|
||||
m_lock.lock();
|
||||
}
|
||||
|
||||
size_t to_copy = BAN::Math::min<size_t>(count, m_buffer.size());
|
||||
memcpy(buffer, m_buffer.data(), to_copy);
|
||||
|
||||
memmove(m_buffer.data(), m_buffer.data() + to_copy, m_buffer.size() - to_copy);
|
||||
MUST(m_buffer.resize(m_buffer.size() - to_copy));
|
||||
|
||||
uint64_t current_time = BAN::to_unix_time(RTC::get_current_time());
|
||||
m_atime = { .tv_sec = current_time, .tv_nsec = 0 };
|
||||
|
||||
m_semaphore.unblock();
|
||||
|
||||
m_lock.unlock();
|
||||
|
||||
return to_copy;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Pipe::write(size_t, const void* buffer, size_t count)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
size_t old_size = m_buffer.size();
|
||||
|
||||
TRY(m_buffer.resize(old_size + count));
|
||||
memcpy(m_buffer.data() + old_size, buffer, count);
|
||||
|
||||
uint64_t current_time = BAN::to_unix_time(RTC::get_current_time());
|
||||
m_mtime = { .tv_sec = current_time, .tv_nsec = 0 };
|
||||
m_ctime = { .tv_sec = current_time, .tv_nsec = 0 };
|
||||
|
||||
m_semaphore.unblock();
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#include <BAN/StringView.h>
|
||||
#include <kernel/CriticalScope.h>
|
||||
#include <kernel/FS/Pipe.h>
|
||||
#include <kernel/FS/VirtualFileSystem.h>
|
||||
#include <kernel/LockGuard.h>
|
||||
#include <kernel/Memory/Heap.h>
|
||||
|
@ -277,6 +278,14 @@ namespace Kernel
|
|||
forked->m_working_directory = m_working_directory;
|
||||
|
||||
forked->m_open_files = m_open_files;
|
||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||
{
|
||||
if (validate_fd(fd).is_error())
|
||||
continue;
|
||||
auto& openfd = open_file_description(fd);
|
||||
if (openfd.flags & O_WRONLY && openfd.inode->is_pipe())
|
||||
((Pipe*)openfd.inode.ptr())->clone_writing();
|
||||
}
|
||||
|
||||
forked->m_userspace_info = m_userspace_info;
|
||||
|
||||
|
@ -325,7 +334,7 @@ namespace Kernel
|
|||
|
||||
LockGuard lock_guard(m_lock);
|
||||
|
||||
for (int fd = 0; fd < m_open_files.size(); fd++)
|
||||
for (int fd = 0; fd < (int)m_open_files.size(); fd++)
|
||||
{
|
||||
if (validate_fd(fd).is_error())
|
||||
continue;
|
||||
|
@ -538,6 +547,8 @@ namespace Kernel
|
|||
LockGuard _(m_lock);
|
||||
TRY(validate_fd(fd));
|
||||
auto& open_file_description = this->open_file_description(fd);
|
||||
if (open_file_description.flags & O_WRONLY && open_file_description.inode->is_pipe())
|
||||
((Pipe*)open_file_description.inode.ptr())->close_writing();
|
||||
open_file_description.inode = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
@ -590,6 +601,29 @@ namespace Kernel
|
|||
return nwrite;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_pipe(int fildes[2])
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
||||
auto pipe = TRY(Pipe::create(m_credentials));
|
||||
|
||||
TRY(get_free_fd_pair(fildes));
|
||||
|
||||
auto& openfd_read = m_open_files[fildes[0]];
|
||||
openfd_read.inode = pipe;
|
||||
openfd_read.flags = O_RDONLY;
|
||||
openfd_read.offset = 0;
|
||||
openfd_read.path.clear();
|
||||
|
||||
auto& openfd_write = m_open_files[fildes[1]];
|
||||
openfd_write.inode = pipe;
|
||||
openfd_write.flags = O_WRONLY;
|
||||
openfd_write.offset = 0;
|
||||
openfd_write.path.clear();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence)
|
||||
{
|
||||
LockGuard _(m_lock);
|
||||
|
@ -1089,4 +1123,27 @@ namespace Kernel
|
|||
return m_open_files.size() - 1;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::get_free_fd_pair(int fds[2])
|
||||
{
|
||||
ASSERT(m_lock.is_locked());
|
||||
int found = 0;
|
||||
for (size_t fd = 0; fd < m_open_files.size(); fd++)
|
||||
{
|
||||
if (!m_open_files[fd].inode)
|
||||
{
|
||||
fds[found++] = fd;
|
||||
if (found >= 2)
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
while (found < 2)
|
||||
{
|
||||
TRY(m_open_files.push_back({}));
|
||||
fds[found++] = m_open_files.size() - 1;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
|
@ -132,6 +132,9 @@ namespace Kernel
|
|||
case SYS_CLOCK_GETTIME:
|
||||
ret = Process::current().sys_clock_gettime((clockid_t)arg1, (timespec*)arg2);
|
||||
break;
|
||||
case SYS_PIPE:
|
||||
ret = Process::current().sys_pipe((int*)arg1);
|
||||
break;
|
||||
default:
|
||||
dwarnln("Unknown syscall {}", syscall);
|
||||
break;
|
||||
|
|
|
@ -39,6 +39,7 @@ __BEGIN_DECLS
|
|||
#define SYS_GET_PWD 32
|
||||
#define SYS_SET_PWD 33
|
||||
#define SYS_CLOCK_GETTIME 34
|
||||
#define SYS_PIPE 35
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -251,6 +251,12 @@ long syscall(long syscall, ...)
|
|||
ret = Kernel::syscall(SYS_CLOCK_GETTIME, clock_id, (uintptr_t)tp);
|
||||
break;
|
||||
}
|
||||
case SYS_PIPE:
|
||||
{
|
||||
int* fildes = va_arg(args, int*);
|
||||
ret = Kernel::syscall(SYS_PIPE, (uintptr_t)fildes);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
puts("LibC: Unhandeled syscall");
|
||||
ret = -ENOSYS;
|
||||
|
@ -365,6 +371,11 @@ pid_t fork(void)
|
|||
return syscall(SYS_FORK);
|
||||
}
|
||||
|
||||
int pipe(int fildes[2])
|
||||
{
|
||||
return syscall(SYS_PIPE, fildes);
|
||||
}
|
||||
|
||||
unsigned int sleep(unsigned int seconds)
|
||||
{
|
||||
return syscall(SYS_SLEEP, seconds);
|
||||
|
|
Loading…
Reference in New Issue