Kernel: Barebones implementation sessions and process groups

This commit is contained in:
Bananymous 2023-08-22 11:35:40 +03:00
parent be5b81740e
commit ccc61cb10c
5 changed files with 140 additions and 69 deletions

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <BAN/Iteration.h>
#include <BAN/String.h> #include <BAN/String.h>
#include <BAN/StringView.h> #include <BAN/StringView.h>
#include <BAN/Vector.h> #include <BAN/Vector.h>
@ -45,11 +46,17 @@ namespace Kernel
void exit(int status, int signal); void exit(int status, int signal);
static void for_each_process(const BAN::Function<BAN::Iteration(Process&)>& callback);
void add_thread(Thread*); void add_thread(Thread*);
void on_thread_exit(Thread&); void on_thread_exit(Thread&);
pid_t sid() const { return m_sid; }
pid_t pgrp() const { return m_pgrp; }
pid_t pid() const { return m_pid; } pid_t pid() const { return m_pid; }
bool is_session_leader() const { return pid() == sid(); }
BAN::ErrorOr<long> sys_exit(int status); BAN::ErrorOr<long> sys_exit(int status);
BAN::ErrorOr<long> sys_gettermios(::termios*); BAN::ErrorOr<long> sys_gettermios(::termios*);
@ -111,7 +118,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*) const; BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*) const;
TTY& tty() { ASSERT(m_tty); return *m_tty; } TTY& tty() { ASSERT(m_controlling_terminal); return *m_controlling_terminal; }
static Process& current() { return Thread::current().process(); } static Process& current() { return Thread::current().process(); }
@ -121,8 +128,8 @@ namespace Kernel
const userspace_info_t& userspace_info() const { return m_userspace_info; } const userspace_info_t& userspace_info() const { return m_userspace_info; }
private: private:
Process(const Credentials&, pid_t); Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp);
static Process* create_process(const Credentials&); static Process* create_process(const Credentials&, pid_t parent, pid_t sid = 0, pid_t pgrp = 0);
static void register_process(Process*); static void register_process(Process*);
// Load an elf file to virtual address space of the current page table // Load an elf file to virtual address space of the current page table
@ -150,9 +157,13 @@ namespace Kernel
BAN::Vector<BAN::UniqPtr<VirtualRange>> m_mapped_ranges; BAN::Vector<BAN::UniqPtr<VirtualRange>> m_mapped_ranges;
pid_t m_sid;
pid_t m_pgrp;
const pid_t m_pid;
const pid_t m_parent;
mutable RecursiveSpinLock m_lock; mutable RecursiveSpinLock m_lock;
const pid_t m_pid = 0;
BAN::String m_working_directory; BAN::String m_working_directory;
BAN::Vector<Thread*> m_threads; BAN::Vector<Thread*> m_threads;
@ -167,7 +178,7 @@ namespace Kernel
ExitStatus m_exit_status; ExitStatus m_exit_status;
BAN::UniqPtr<PageTable> m_page_table; BAN::UniqPtr<PageTable> m_page_table;
BAN::RefPtr<TTY> m_tty; BAN::RefPtr<TTY> m_controlling_terminal;
friend class Thread; friend class Thread;
}; };

View File

@ -23,8 +23,8 @@ namespace Kernel
uint32_t height() const { return m_height; } uint32_t height() const { return m_height; }
uint32_t width() const { return m_width; } uint32_t width() const { return m_width; }
void set_foreground_process(pid_t pgid) { m_foreground_process = pgid; } void set_foreground_pgrp(pid_t pgrp) { m_foreground_pgrp = pgrp; }
pid_t foreground_process() const { return m_foreground_process; } pid_t foreground_pgrp() const { return m_foreground_pgrp; }
// for kprint // for kprint
static void putchar_current(uint8_t ch); static void putchar_current(uint8_t ch);
@ -97,7 +97,7 @@ namespace Kernel
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE }; TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
TerminalDriver::Color m_background { TerminalColor::BLACK }; TerminalDriver::Color m_background { TerminalColor::BLACK };
pid_t m_foreground_process { 0 }; pid_t m_foreground_pgrp { 0 };
termios m_termios; termios m_termios;

View File

@ -56,7 +56,7 @@ namespace Kernel
BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags) BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags)
{ {
if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_APPEND | O_TRUNC | O_CLOEXEC)) if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT))
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
int access_mask = O_EXEC | O_RDONLY | O_WRONLY | O_SEARCH; int access_mask = O_EXEC | O_RDONLY | O_WRONLY | O_SEARCH;

View File

@ -21,13 +21,43 @@ namespace Kernel
{ {
static BAN::Vector<Process*> s_processes; static BAN::Vector<Process*> s_processes;
static SpinLock s_process_lock; static RecursiveSpinLock s_process_lock;
Process* Process::create_process(const Credentials& credentials) void Process::for_each_process(const BAN::Function<BAN::Iteration(Process&)>& callback)
{ {
static pid_t s_next_pid = 1; LockGuard _(s_process_lock);
auto* process = new Process(credentials, s_next_pid++);
for (auto* process : s_processes)
{
auto ret = callback(*process);
if (ret == BAN::Iteration::Break)
return;
ASSERT(ret == BAN::Iteration::Continue);
}
}
Process* Process::create_process(const Credentials& credentials, pid_t parent, pid_t sid, pid_t pgrp)
{
static pid_t s_next_id = 1;
pid_t pid;
{
CriticalScope _;
pid = s_next_id;
if (sid == 0 && pgrp == 0)
{
sid = s_next_id;
pgrp = s_next_id;
}
s_next_id++;
}
ASSERT(sid > 0);
ASSERT(pgrp > 0);
auto* process = new Process(credentials, pid, parent, sid, pgrp);
ASSERT(process); ASSERT(process);
return process; return process;
} }
@ -42,7 +72,7 @@ namespace Kernel
Process* Process::create_kernel(entry_t entry, void* data) Process* Process::create_kernel(entry_t entry, void* data)
{ {
auto* process = create_process({ 0, 0, 0, 0 }); auto* process = create_process({ 0, 0, 0, 0 }, 0);
MUST(process->m_working_directory.push_back('/')); MUST(process->m_working_directory.push_back('/'));
auto* thread = MUST(Thread::create_kernel(entry, data, process)); auto* thread = MUST(Thread::create_kernel(entry, data, process));
process->add_thread(thread); process->add_thread(thread);
@ -54,7 +84,7 @@ namespace Kernel
{ {
auto elf = TRY(load_elf_for_exec(credentials, path, "/"sv, {})); auto elf = TRY(load_elf_for_exec(credentials, path, "/"sv, {}));
auto* process = create_process(credentials); auto* process = create_process(credentials, 0);
MUST(process->m_working_directory.push_back('/')); MUST(process->m_working_directory.push_back('/'));
process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));; process->m_page_table = BAN::UniqPtr<PageTable>::adopt(MUST(PageTable::create_userspace()));;
@ -95,11 +125,13 @@ namespace Kernel
return process; return process;
} }
Process::Process(const Credentials& credentials, pid_t pid) Process::Process(const Credentials& credentials, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp)
: m_credentials(credentials) : m_credentials(credentials)
, m_open_file_descriptors(m_credentials) , m_open_file_descriptors(m_credentials)
, m_sid(sid)
, m_pgrp(pgrp)
, m_pid(pid) , m_pid(pid)
, m_tty(TTY::current()) , m_parent(parent)
{ {
for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++) for (size_t i = 0; i < sizeof(m_signal_handlers) / sizeof(*m_signal_handlers); i++)
m_signal_handlers[i] = (vaddr_t)SIG_DFL; m_signal_handlers[i] = (vaddr_t)SIG_DFL;
@ -148,9 +180,6 @@ namespace Kernel
// NOTE: We must clear allocators while the page table is still alive // NOTE: We must clear allocators while the page table is still alive
m_fixed_width_allocators.clear(); m_fixed_width_allocators.clear();
m_general_allocator.clear(); m_general_allocator.clear();
if (m_tty && m_tty->foreground_process() == pid())
m_tty->set_foreground_process(0);
} }
void Process::on_thread_exit(Thread& thread) void Process::on_thread_exit(Thread& thread)
@ -198,10 +227,11 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_gettermios(::termios* termios) BAN::ErrorOr<long> Process::sys_gettermios(::termios* termios)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
if (!m_tty)
if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY); return BAN::Error::from_errno(ENOTTY);
Kernel::termios ktermios = m_tty->get_termios(); Kernel::termios ktermios = m_controlling_terminal->get_termios();
termios->c_lflag = 0; termios->c_lflag = 0;
if (ktermios.canonical) if (ktermios.canonical)
termios->c_lflag |= ICANON; termios->c_lflag |= ICANON;
@ -214,14 +244,15 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_settermios(const ::termios* termios) BAN::ErrorOr<long> Process::sys_settermios(const ::termios* termios)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
if (!m_tty)
if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY); return BAN::Error::from_errno(ENOTTY);
Kernel::termios ktermios; Kernel::termios ktermios;
ktermios.echo = termios->c_lflag & ECHO; ktermios.echo = termios->c_lflag & ECHO;
ktermios.canonical = termios->c_lflag & ICANON; ktermios.canonical = termios->c_lflag & ICANON;
m_tty->set_termios(ktermios); m_controlling_terminal->set_termios(ktermios);
return 0; return 0;
} }
@ -325,8 +356,8 @@ namespace Kernel
if (m_general_allocator) if (m_general_allocator)
general_allocator = TRY(m_general_allocator->clone(*page_table)); general_allocator = TRY(m_general_allocator->clone(*page_table));
Process* forked = create_process(m_credentials); Process* forked = create_process(m_credentials, m_pid, m_sid, m_pgrp);
forked->m_tty = m_tty; forked->m_controlling_terminal = m_controlling_terminal;
forked->m_working_directory = BAN::move(working_directory); forked->m_working_directory = BAN::move(working_directory);
forked->m_page_table = BAN::move(page_table); forked->m_page_table = BAN::move(page_table);
forked->m_open_file_descriptors = BAN::move(open_file_descriptors); forked->m_open_file_descriptors = BAN::move(open_file_descriptors);
@ -455,12 +486,17 @@ namespace Kernel
if (options) if (options)
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
{ for_each_process(
LockGuard _(s_process_lock); [&](Process& process)
for (auto* process : s_processes) {
if (process->pid() == pid) if (process.pid() == pid)
target = process; {
} target = &process;
return BAN::Iteration::Break;
}
return BAN::Iteration::Continue;
}
);
if (target == nullptr) if (target == nullptr)
return BAN::Error::from_errno(ECHILD); return BAN::Error::from_errno(ECHILD);
@ -555,7 +591,14 @@ namespace Kernel
flags &= ~O_CREAT; flags &= ~O_CREAT;
} }
return TRY(m_open_file_descriptors.open(absolute_path, flags)); int fd = TRY(m_open_file_descriptors.open(absolute_path, flags));
auto inode = MUST(m_open_file_descriptors.inode_of(fd));
// Open controlling terminal
if ((flags & O_TTY_INIT) && !(flags & O_NOCTTY) && inode->is_tty() && is_session_leader() && !m_controlling_terminal)
m_controlling_terminal = (TTY*)inode.ptr();
return fd;
} }
BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags, mode_t mode) BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags, mode_t mode)
@ -791,14 +834,18 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_termid(char* buffer) const BAN::ErrorOr<long> Process::sys_termid(char* buffer) const
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
if (!m_tty)
auto& tty = m_controlling_terminal;
if (!tty)
buffer[0] = '\0'; buffer[0] = '\0';
else else
{ {
ASSERT(minor(m_tty->rdev()) < 10); ASSERT(minor(tty->rdev()) < 10);
strcpy(buffer, "/dev/tty0"); strcpy(buffer, "/dev/tty0");
buffer[8] += minor(m_tty->rdev()); buffer[8] += minor(tty->rdev());
} }
return 0; return 0;
} }
@ -834,7 +881,7 @@ namespace Kernel
BAN::ErrorOr<long> Process::sys_kill(pid_t pid, int signal) BAN::ErrorOr<long> Process::sys_kill(pid_t pid, int signal)
{ {
if (pid <= 0) if (pid == 0 || pid == -1)
return BAN::Error::from_errno(ENOTSUP); return BAN::Error::from_errno(ENOTSUP);
if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX)) if (signal != 0 && (signal < _SIGMIN || signal > _SIGMAX))
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
@ -842,19 +889,26 @@ namespace Kernel
if (pid == Process::current().pid()) if (pid == Process::current().pid())
return Process::current().sys_raise(signal); return Process::current().sys_raise(signal);
LockGuard process_guard(s_process_lock); bool found = false;
for (auto* process : s_processes) for_each_process(
{ [&](Process& process)
if (process->pid() == pid)
{ {
if (signal == 0) if (pid == process.pid() || -pid == process.pid())
return 0; {
CriticalScope _; found = true;
process->m_signal_pending_mask |= 1ull << signal; if (signal)
return 0; {
CriticalScope _;
process.m_signal_pending_mask |= 1 << signal;
}
return (pid > 0) ? BAN::Iteration::Break : BAN::Iteration::Continue;
}
return BAN::Iteration::Continue;
} }
} );
if (found)
return 0;
return BAN::Error::from_errno(ESRCH); return BAN::Error::from_errno(ESRCH);
} }
@ -869,31 +923,37 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_tcsetpgrp(int fd, pid_t pgid) BAN::ErrorOr<long> Process::sys_tcsetpgrp(int fd, pid_t pgrp)
{ {
LockGuard _(m_lock); LockGuard _(m_lock);
// FIXME: validate the inode if (!m_controlling_terminal)
return BAN::Error::from_errno(ENOTTY);
bool valid_pgrp = false;
for_each_process(
[&](Process& process)
{
if (process.sid() == sid() && process.pgrp() == pgrp)
{
valid_pgrp = true;
return BAN::Iteration::Break;
}
return BAN::Iteration::Continue;
}
);
if (!valid_pgrp)
return BAN::Error::from_errno(EPERM);
auto inode = TRY(m_open_file_descriptors.inode_of(fd)); auto inode = TRY(m_open_file_descriptors.inode_of(fd));
if (!inode->is_tty()) if (!inode->is_tty())
return BAN::Error::from_errno(ENOTTY); return BAN::Error::from_errno(ENOTTY);
if ((TTY*)inode.ptr() != m_controlling_terminal.ptr())
return BAN::Error::from_errno(ENOTTY);
// FIXME: use process groups instead of process ids ((TTY*)inode.ptr())->set_foreground_pgrp(pgrp);
// FIXME: return values return 0;
LockGuard process_guard(s_process_lock);
for (auto* process : s_processes)
{
if (process->pid() == pgid)
{
if (!process->is_userspace())
return BAN::Error::from_errno(EINVAL);
((TTY*)inode.ptr())->set_foreground_process(pgid);
return 0;
}
}
return BAN::Error::from_errno(EPERM);
} }
BAN::ErrorOr<long> Process::sys_setuid(uid_t uid) BAN::ErrorOr<long> Process::sys_setuid(uid_t uid)

View File

@ -29,7 +29,7 @@ namespace Kernel
static dev_t next_tty_rdev() static dev_t next_tty_rdev()
{ {
static dev_t major = DevFileSystem::get().get_next_rdev(); static dev_t major = DevFileSystem::get().get_next_rdev();
static dev_t minor = 1; static dev_t minor = 0;
return makedev(major, minor++); return makedev(major, minor++);
} }
@ -75,17 +75,17 @@ namespace Kernel
ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event)); ASSERT(MUST(Process::current().sys_read(fd, &event, sizeof(event))) == sizeof(event));
TTY& current_tty = *TTY::current(); TTY& current_tty = *TTY::current();
if (current_tty.m_foreground_process && if (current_tty.m_foreground_pgrp &&
event.pressed() && event.pressed() &&
event.ctrl() && event.ctrl() &&
!event.shift() !event.shift()
&& event.key == Input::Key::C && event.key == Input::Key::C
) )
{ {
if (auto ret = Process::sys_kill(current_tty.m_foreground_process, SIGINT); ret.is_error()) if (auto ret = Process::sys_kill(-current_tty.m_foreground_pgrp, SIGINT); ret.is_error())
dwarnln("TTY: {}", ret.error()); dwarnln("TTY: {}", ret.error());
} }
else else
current_tty.on_key(event); current_tty.on_key(event);
} }
}, nullptr }, nullptr