mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 13:27:34 +00:00
Add primitive FIFO and hook it up to sys$pipe().
It's now possible to do this in bash: cat kernel.map | fgrep List This is very cool! :^)
This commit is contained in:
parent
18e3ddf605
commit
f1404aa948
13 changed files with 305 additions and 22 deletions
|
@ -43,7 +43,7 @@ ssize_t Console::write(const byte* data, size_t size)
|
|||
return 0;
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
putChar(data[i]);
|
||||
return 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
void Console::putChar(char ch)
|
||||
|
|
87
Kernel/FIFO.cpp
Normal file
87
Kernel/FIFO.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include "FIFO.h"
|
||||
#include <AK/StdLib.h>
|
||||
|
||||
//#define FIFO_DEBUG
|
||||
|
||||
RetainPtr<FIFO> FIFO::create()
|
||||
{
|
||||
return adopt(*new FIFO);
|
||||
}
|
||||
|
||||
FIFO::FIFO()
|
||||
{
|
||||
}
|
||||
|
||||
void FIFO::open(Direction direction)
|
||||
{
|
||||
if (direction == Reader) {
|
||||
++m_readers;
|
||||
#ifdef FIFO_DEBUG
|
||||
kprintf("open reader (%u)\n", m_readers);
|
||||
#endif
|
||||
} else if (direction == Writer) {
|
||||
++m_writers;
|
||||
#ifdef FIFO_DEBUG
|
||||
kprintf("open writer (%u)\n", m_writers);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void FIFO::close(Direction direction)
|
||||
{
|
||||
if (direction == Reader) {
|
||||
#ifdef FIFO_DEBUG
|
||||
kprintf("close reader (%u - 1)\n", m_readers);
|
||||
#endif
|
||||
ASSERT(m_readers);
|
||||
--m_readers;
|
||||
} else if (direction == Writer) {
|
||||
#ifdef FIFO_DEBUG
|
||||
kprintf("close writer (%u - 1)\n", m_writers);
|
||||
#endif
|
||||
ASSERT(m_writers);
|
||||
--m_writers;
|
||||
}
|
||||
}
|
||||
|
||||
bool FIFO::can_read() const
|
||||
{
|
||||
return !m_queue.isEmpty() || !m_writers;
|
||||
}
|
||||
|
||||
bool FIFO::can_write() const
|
||||
{
|
||||
#ifdef FIFO_DEBUG
|
||||
dbgprintf("can_write? size(%u) < capacity(%u) || !readers(%u)\n", m_queue.size(), m_queue.capacity(), m_readers);
|
||||
#endif
|
||||
return m_queue.size() < m_queue.capacity() || !m_readers;
|
||||
}
|
||||
|
||||
ssize_t FIFO::read(byte* buffer, size_t size)
|
||||
{
|
||||
if (!m_writers && m_queue.isEmpty())
|
||||
return 0;
|
||||
#ifdef FIFO_DEBUG
|
||||
dbgprintf("fifo: read(%u)\n",size);
|
||||
#endif
|
||||
size_t nread = min(size, m_queue.size());
|
||||
for (size_t i = 0; i < nread; ++i)
|
||||
buffer[i] = m_queue.dequeue();
|
||||
#ifdef FIFO_DEBUG
|
||||
dbgprintf(" -> read (%c) %u\n", buffer[0], nread);
|
||||
#endif
|
||||
return nread;
|
||||
}
|
||||
|
||||
ssize_t FIFO::write(const byte* buffer, size_t size)
|
||||
{
|
||||
if (!m_readers)
|
||||
return 0;
|
||||
#ifdef FIFO_DEBUG
|
||||
dbgprintf("fifo: write(%p, %u)\n", buffer, size);
|
||||
#endif
|
||||
size_t nwritten = min(size, m_queue.capacity() - m_queue.size());
|
||||
for (size_t i = 0; i < nwritten; ++i)
|
||||
m_queue.enqueue(buffer[i]);
|
||||
return nwritten;
|
||||
}
|
31
Kernel/FIFO.h
Normal file
31
Kernel/FIFO.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/CircularQueue.h>
|
||||
#include <AK/Retainable.h>
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <VirtualFileSystem/UnixTypes.h>
|
||||
|
||||
class FIFO : public Retainable<FIFO> {
|
||||
public:
|
||||
enum Direction {
|
||||
Neither, Reader, Writer
|
||||
};
|
||||
|
||||
static RetainPtr<FIFO> create();
|
||||
|
||||
void open(Direction);
|
||||
void close(Direction);
|
||||
|
||||
Unix::ssize_t write(const byte*, Unix::size_t);
|
||||
Unix::ssize_t read(byte*, Unix::size_t);
|
||||
|
||||
bool can_read() const;
|
||||
bool can_write() const;
|
||||
|
||||
private:
|
||||
FIFO();
|
||||
|
||||
unsigned m_writers { 0 };
|
||||
unsigned m_readers { 0 };
|
||||
CircularQueue<byte, 16> m_queue;
|
||||
};
|
|
@ -19,6 +19,7 @@ KERNEL_OBJS = \
|
|||
RTC.o \
|
||||
TTY.o \
|
||||
VirtualConsole.o \
|
||||
FIFO.o \
|
||||
Scheduler.o
|
||||
|
||||
VFS_OBJS = \
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <LibC/signal_numbers.h>
|
||||
#include "Syscall.h"
|
||||
#include "Scheduler.h"
|
||||
#include "FIFO.h"
|
||||
|
||||
//#define DEBUG_IO
|
||||
//#define TASK_DEBUG
|
||||
|
@ -982,7 +983,42 @@ ssize_t Process::sys$write(int fd, const void* data, size_t size)
|
|||
auto* descriptor = file_descriptor(fd);
|
||||
if (!descriptor)
|
||||
return -EBADF;
|
||||
auto nwritten = descriptor->write((const byte*)data, size);
|
||||
ssize_t nwritten = 0;
|
||||
if (descriptor->isBlocking()) {
|
||||
while (nwritten < (ssize_t)size) {
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf("while %u < %u\n", nwritten, size);
|
||||
#endif
|
||||
if (!descriptor->can_write()) {
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf("block write on %d\n", fd);
|
||||
#endif
|
||||
m_blocked_fd = fd;
|
||||
block(BlockedWrite);
|
||||
Scheduler::yield();
|
||||
}
|
||||
ssize_t rc = descriptor->write((const byte*)data + nwritten, size - nwritten);
|
||||
#ifdef IO_DEBUG
|
||||
dbgprintf(" -> write returned %d\n", rc);
|
||||
#endif
|
||||
if (rc < 0) {
|
||||
// FIXME: Support returning partial nwritten with errno.
|
||||
ASSERT(nwritten == 0);
|
||||
return rc;
|
||||
}
|
||||
if (rc == 0)
|
||||
break;
|
||||
if (has_unmasked_pending_signals()) {
|
||||
block(BlockedSignal);
|
||||
Scheduler::yield();
|
||||
if (nwritten == 0)
|
||||
return -EINTR;
|
||||
}
|
||||
nwritten += rc;
|
||||
}
|
||||
} else {
|
||||
nwritten = descriptor->write((const byte*)data, size);
|
||||
}
|
||||
if (has_unmasked_pending_signals()) {
|
||||
block(BlockedSignal);
|
||||
Scheduler::yield();
|
||||
|
@ -1174,10 +1210,34 @@ int Process::sys$open(const char* path, int options)
|
|||
return fd;
|
||||
}
|
||||
|
||||
int Process::alloc_fd()
|
||||
{
|
||||
int fd = -1;
|
||||
for (int i = 0; i < (int)m_max_open_file_descriptors; ++i) {
|
||||
if (!m_file_descriptors[i]) {
|
||||
fd = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int Process::sys$pipe(int* pipefd)
|
||||
{
|
||||
VALIDATE_USER_WRITE(pipefd, sizeof(int) * 2);
|
||||
ASSERT_NOT_REACHED();
|
||||
if (number_of_open_file_descriptors() + 2 > max_open_file_descriptors())
|
||||
return -EMFILE;
|
||||
auto fifo = FIFO::create();
|
||||
|
||||
int reader_fd = alloc_fd();
|
||||
m_file_descriptors[reader_fd] = FileDescriptor::create_pipe_reader(*fifo);
|
||||
pipefd[0] = reader_fd;
|
||||
|
||||
int writer_fd = alloc_fd();
|
||||
m_file_descriptors[writer_fd] = FileDescriptor::create_pipe_writer(*fifo);
|
||||
pipefd[1] = writer_fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Process::sys$killpg(int pgrp, int signum)
|
||||
|
@ -1353,12 +1413,15 @@ void Process::unblock()
|
|||
m_state = Process::Runnable;
|
||||
}
|
||||
|
||||
void Process::block(Process::State state)
|
||||
void Process::block(Process::State new_state)
|
||||
{
|
||||
ASSERT(current->state() == Process::Running);
|
||||
if (state() != Process::Running) {
|
||||
kprintf("Process::block: %s(%u) block(%u/%s) with state=%u/%s\n", name().characters(), pid(), new_state, toString(new_state), state(), toString(state()));
|
||||
}
|
||||
ASSERT(state() == Process::Running);
|
||||
system.nblocked++;
|
||||
m_was_interrupted_while_blocked = false;
|
||||
set_state(state);
|
||||
set_state(new_state);
|
||||
}
|
||||
|
||||
void block(Process::State state)
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
BlockedSleep,
|
||||
BlockedWait,
|
||||
BlockedRead,
|
||||
BlockedWrite,
|
||||
BlockedSignal,
|
||||
};
|
||||
|
||||
|
@ -226,6 +227,8 @@ private:
|
|||
int do_exec(const String& path, Vector<String>&& arguments, Vector<String>&& environment);
|
||||
void push_value_on_stack(dword);
|
||||
|
||||
int alloc_fd();
|
||||
|
||||
PageDirectory* m_page_directory { nullptr };
|
||||
|
||||
Process* m_prev { nullptr };
|
||||
|
@ -257,6 +260,7 @@ private:
|
|||
pid_t m_waitee { -1 };
|
||||
int m_waitee_status { 0 };
|
||||
int m_fdBlockedOnRead { -1 };
|
||||
int m_blocked_fd { -1 };
|
||||
size_t m_max_open_file_descriptors { 16 };
|
||||
SignalActionData m_signal_action_data[32];
|
||||
dword m_pending_signals { 0 };
|
||||
|
@ -337,6 +341,7 @@ static inline const char* toString(Process::State state)
|
|||
case Process::BlockedSleep: return "Sleep";
|
||||
case Process::BlockedWait: return "Wait";
|
||||
case Process::BlockedRead: return "Read";
|
||||
case Process::BlockedWrite: return "Write";
|
||||
case Process::BlockedSignal: return "Signal";
|
||||
case Process::BeingInspected: return "Inspect";
|
||||
}
|
||||
|
|
|
@ -57,6 +57,13 @@ bool Scheduler::pick_next()
|
|||
return true;
|
||||
}
|
||||
|
||||
if (process.state() == Process::BlockedWrite) {
|
||||
ASSERT(process.m_blocked_fd != -1);
|
||||
if (process.m_file_descriptors[process.m_blocked_fd]->can_write())
|
||||
process.unblock();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (process.state() == Process::Skip1SchedulerPass) {
|
||||
process.set_state(Process::Skip0SchedulerPasses);
|
||||
return true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue