Kernel/LibC: Add basic pipe() syscall and command

You can now create pipes :)
This commit is contained in:
Bananymous
2023-07-06 22:16:26 +03:00
parent cdcb395640
commit 4cd72992c8
9 changed files with 220 additions and 1 deletions

88
kernel/kernel/FS/Pipe.cpp Normal file
View File

@@ -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;
}
}

View File

@@ -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 {};
}
}

View File

@@ -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;