Kernel: Remove the ConsoleManagement singleton

We don't really need it, and the entire functionality can be organically
intergrated into the VirtualConsole class, to switch between the Virtual
consoles, and manage initialization of all consoles in the global array.
This commit is contained in:
Liav A. 2024-05-17 12:20:20 +03:00
parent 3dc86747f0
commit 68f81b1f8c
14 changed files with 125 additions and 178 deletions

View file

@ -39,7 +39,6 @@
#include <Kernel/Devices/PCISerialDevice.h>
#include <Kernel/Devices/SerialDevice.h>
#include <Kernel/Devices/Storage/StorageManagement.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/PTYMultiplexer.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/FileSystem/SysFS/Registry.h>
@ -410,7 +409,7 @@ void init_stage2(void*)
MUST(HIDManagement::initialize());
GraphicsManagement::the().initialize();
ConsoleManagement::the().initialize();
VirtualConsole::initialize_consoles();
SyncTask::spawn();
FinalizerTask::spawn();

View file

@ -356,7 +356,6 @@ set(KERNEL_SOURCES
Syscalls/waitid.cpp
Syscalls/inode_watcher.cpp
Syscalls/write.cpp
Devices/TTY/ConsoleManagement.cpp
Devices/TTY/MasterPTY.cpp
Devices/TTY/PTYMultiplexer.cpp
Devices/TTY/SlavePTY.cpp

View file

@ -5,7 +5,7 @@
*/
#include <Kernel/Devices/GPU/Console/ContiguousFramebufferConsole.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
namespace Kernel::Graphics {
@ -36,7 +36,7 @@ void ContiguousFramebufferConsole::set_resolution(size_t width, size_t height, s
// Just to start cleanly, we clean the entire framebuffer
memset(m_framebuffer_region->vaddr().as_ptr(), 0, pitch * height);
ConsoleManagement::the().resolution_was_changed();
VirtualConsole::resolution_was_changed();
}
}

View file

@ -6,7 +6,6 @@
*/
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
namespace Kernel::Graphics {

View file

@ -5,7 +5,7 @@
*/
#include <Kernel/Devices/GPU/VirtIO/Console.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/Tasks/WorkQueue.h>
namespace Kernel::Graphics::VirtIOGPU {
@ -36,7 +36,7 @@ void Console::set_resolution(size_t width, size_t height, size_t pitch)
// Just to start cleanly, we clean the entire framebuffer
memset(framebuffer_data(), 0, pitch * height);
ConsoleManagement::the().resolution_was_changed();
VirtualConsole::resolution_was_changed();
}
void Console::set_cursor(size_t x, size_t y)

View file

@ -12,7 +12,6 @@
#include <Kernel/API/KeyCode.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/HID/KeyboardDevice.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/Sections.h>
#include <Kernel/Tasks/Scheduler.h>
@ -29,16 +28,16 @@ void KeyboardDevice::handle_input_event(KeyEvent queued_event)
if (queued_event.is_press() && (m_modifiers == (Mod_Alt | Mod_Shift) || m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)) && queued_event.key == Key_F12) {
// Alt+Shift+F12 pressed, dump some kernel state to the debug console.
ConsoleManagement::the().switch_to_debug();
VirtualConsole::switch_to_debug_console();
Scheduler::dump_scheduler_state(m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift));
}
{
auto key = queued_event.key;
if (queued_event.is_press() && (m_modifiers & Mod_Alt) != 0 && key >= Key_1 && key < Key_1 + ConsoleManagement::s_max_virtual_consoles) {
if (queued_event.is_press() && (m_modifiers & Mod_Alt) != 0 && key >= Key_1 && key < Key_1 + VirtualConsole::s_max_virtual_consoles) {
// FIXME: Do something sanely here if we can't allocate a work queue?
MUST(g_io_work->try_queue([key]() {
ConsoleManagement::the().switch_to(key - Key_1);
VirtualConsole::switch_to(key - Key_1);
}));
}
}

View file

@ -12,7 +12,6 @@
#include <Kernel/Devices/HID/Management.h>
#include <Kernel/Devices/HID/PS2/KeyboardDevice.h>
#include <Kernel/Devices/HID/ScanCodeEvent.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Sections.h>
#include <Kernel/Tasks/Scheduler.h>
#include <Kernel/Tasks/WorkQueue.h>

View file

@ -1,96 +0,0 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Singleton.h>
#include <Kernel/Boot/CommandLine.h>
#include <Kernel/Debug.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/GPU/Management.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Library/Panic.h>
#include <Kernel/Sections.h>
namespace Kernel {
static Singleton<ConsoleManagement> s_the;
void ConsoleManagement::resolution_was_changed()
{
for (auto& console : m_consoles) {
console->refresh_after_resolution_change();
}
}
bool ConsoleManagement::is_initialized()
{
if (!s_the.is_initialized())
return false;
if (s_the->m_consoles.is_empty())
return false;
if (!s_the->m_active_console)
return false;
return true;
}
ConsoleManagement& ConsoleManagement::the()
{
return *s_the;
}
UNMAP_AFTER_INIT ConsoleManagement::ConsoleManagement()
{
}
UNMAP_AFTER_INIT void ConsoleManagement::initialize()
{
for (size_t index = 0; index < s_max_virtual_consoles; index++) {
// FIXME: Better determine the debug TTY we chose...
if (index == 1) {
VERIFY(DeviceManagement::the().is_console_device_attached());
m_consoles.append(VirtualConsole::create_with_preset_log(index, DeviceManagement::the().console_device().logbuffer()));
continue;
}
m_consoles.append(VirtualConsole::create(index));
}
// Note: By default the active console is the first one.
auto tty_number = kernel_command_line().switch_to_tty();
if (tty_number > m_consoles.size()) {
PANIC("Switch to tty value is invalid: {} ", tty_number);
}
m_active_console = m_consoles[tty_number];
SpinlockLocker lock(m_lock);
m_active_console->set_active(true);
if (!m_active_console->is_graphical())
m_active_console->clear();
}
void ConsoleManagement::switch_to(unsigned index)
{
SpinlockLocker lock(m_lock);
VERIFY(m_active_console);
VERIFY(index < m_consoles.size());
if (m_active_console->index() == index)
return;
bool was_graphical = m_active_console->is_graphical();
m_active_console->set_active(false);
m_active_console = m_consoles[index];
dbgln_if(VIRTUAL_CONSOLE_DEBUG, "Console: Switch to {}", index);
// Before setting current console to be "active", switch between graphical mode to "textual" mode
// if needed. This will ensure we clear the screen and also that WindowServer won't print anything
// in between.
if (m_active_console->is_graphical() && !was_graphical) {
m_active_console->set_active(true);
GraphicsManagement::the().activate_graphical_mode();
return;
} else if (!m_active_console->is_graphical() && was_graphical) {
GraphicsManagement::the().deactivate_graphical_mode();
}
m_active_console->set_active(true);
}
}

View file

@ -1,45 +0,0 @@
/*
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Types.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/Library/NonnullLockRefPtr.h>
namespace Kernel {
class ConsoleManagement {
friend class VirtualConsole;
public:
ConsoleManagement();
static constexpr size_t s_max_virtual_consoles = 6;
static bool is_initialized();
static ConsoleManagement& the();
void switch_to(unsigned);
void initialize();
void resolution_was_changed();
void switch_to_debug() { switch_to(1); }
NonnullLockRefPtr<VirtualConsole> first_tty() const { return m_consoles[0]; }
NonnullLockRefPtr<VirtualConsole> debug_tty() const { return m_consoles[1]; }
RecursiveSpinlock<LockRank::None>& tty_write_lock() { return m_tty_write_lock; }
private:
Vector<NonnullLockRefPtr<VirtualConsole>, s_max_virtual_consoles> m_consoles;
VirtualConsole* m_active_console { nullptr };
Spinlock<LockRank::None> m_lock {};
RecursiveSpinlock<LockRank::None> m_tty_write_lock {};
};
};

View file

@ -1,11 +1,12 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org>
* Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il>
* Copyright (c) 2021-2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Singleton.h>
#include <AK/StdLibExtras.h>
#include <Kernel/Arch/Delay.h>
#if ARCH(X86_64)
@ -13,17 +14,110 @@
#endif
#include <Kernel/Boot/CommandLine.h>
#include <Kernel/Devices/DeviceManagement.h>
#include <Kernel/Devices/GPU/DisplayConnector.h>
#include <Kernel/Devices/GPU/Management.h>
#include <Kernel/Devices/HID/Management.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/Heap/kmalloc.h>
#include <Kernel/Library/Panic.h>
#include <Kernel/Library/StdLib.h>
#include <Kernel/Locking/SpinlockProtected.h>
#include <Kernel/Sections.h>
#include <LibVT/Color.h>
namespace Kernel {
static Singleton<SpinlockProtected<RefPtr<VirtualConsole>, LockRank::None>> s_active_console;
static Singleton<SpinlockProtected<RefPtr<VirtualConsole>, LockRank::None>> s_debug_console;
static Singleton<SpinlockProtected<Array<RefPtr<VirtualConsole>, VirtualConsole::s_max_virtual_consoles>, LockRank::None>> s_consoles;
void VirtualConsole::resolution_was_changed()
{
s_consoles->with([](auto& consoles) {
for (auto& console : consoles) {
// NOTE: The resolution can change before any VirtualConsole is initialized.
if (console)
console->refresh_after_resolution_change();
}
});
}
bool VirtualConsole::emit_char_on_debug_console(char ch)
{
return s_debug_console->with([ch](auto& console) -> bool {
if (!console)
return false;
console->emit_char(ch);
return true;
});
}
UNMAP_AFTER_INIT void VirtualConsole::initialize_consoles()
{
s_consoles->with([](auto& consoles) {
for (size_t index = 0; index < consoles.size(); index++) {
// FIXME: Better determine the debug TTY we chose...
if (index == 1) {
VERIFY(DeviceManagement::the().is_console_device_attached());
consoles[index] = VirtualConsole::create_with_preset_log(index, DeviceManagement::the().console_device().logbuffer());
continue;
}
consoles[index] = VirtualConsole::create(index);
}
// Note: By default the active console is the first one.
auto tty_number = kernel_command_line().switch_to_tty();
if (tty_number > consoles.size()) {
PANIC("Switch to tty value is invalid: {} ", tty_number);
}
s_active_console->with([&](auto& active_console) {
active_console = consoles[tty_number];
active_console->set_active(true);
if (!active_console->is_graphical())
active_console->clear();
});
s_debug_console->with([&](auto& console) {
console = consoles[1];
});
});
}
void VirtualConsole::switch_to(unsigned index)
{
VERIFY(index < VirtualConsole::s_max_virtual_consoles);
dbgln_if(VIRTUAL_CONSOLE_DEBUG, "VirtualConsole: Switch to {}", index);
s_consoles->with([index](auto& consoles) {
s_active_console->with([&](auto& active_console) {
VERIFY(active_console);
if (active_console->index() == index)
return;
bool was_graphical = active_console->is_graphical();
active_console->set_active(false);
active_console = consoles[index];
// Before setting current console to be "active", switch between graphical mode to "textual" mode
// if needed. This will ensure we clear the screen and also that WindowServer won't print anything
// in between.
if (!active_console->is_graphical() && !was_graphical) {
active_console->set_active(true);
return;
}
if (active_console->is_graphical() && !was_graphical) {
active_console->set_active(true);
GraphicsManagement::the().activate_graphical_mode();
return;
}
VERIFY(!active_console->is_graphical() && was_graphical);
GraphicsManagement::the().deactivate_graphical_mode();
active_console->set_active(true);
});
});
}
ConsoleImpl::ConsoleImpl(VirtualConsole& client)
: Terminal(client)
{
@ -109,15 +203,15 @@ ErrorOr<NonnullOwnPtr<KString>> VirtualConsole::pseudo_name() const
return KString::formatted("tty:{}", m_index);
}
UNMAP_AFTER_INIT NonnullLockRefPtr<VirtualConsole> VirtualConsole::create(size_t index)
UNMAP_AFTER_INIT NonnullRefPtr<VirtualConsole> VirtualConsole::create(size_t index)
{
auto virtual_console_or_error = DeviceManagement::try_create_device<VirtualConsole>(index);
// FIXME: Find a way to propagate errors
VERIFY(!virtual_console_or_error.is_error());
return virtual_console_or_error.release_value();
return *virtual_console_or_error.release_value();
}
UNMAP_AFTER_INIT NonnullLockRefPtr<VirtualConsole> VirtualConsole::create_with_preset_log(size_t index, CircularQueue<char, 16384> const& log)
UNMAP_AFTER_INIT NonnullRefPtr<VirtualConsole> VirtualConsole::create_with_preset_log(size_t index, CircularQueue<char, 16384> const& log)
{
auto virtual_console = VirtualConsole::create(index);
// HACK: We have to go through the TTY layer for correct newline handling.
@ -126,7 +220,7 @@ UNMAP_AFTER_INIT NonnullLockRefPtr<VirtualConsole> VirtualConsole::create_with_p
for (auto ch : log) {
virtual_console->emit_char(ch);
}
return virtual_console;
return *virtual_console;
}
UNMAP_AFTER_INIT void VirtualConsole::initialize()
@ -283,7 +377,6 @@ void VirtualConsole::on_key_pressed(KeyEvent event)
ErrorOr<size_t> VirtualConsole::on_tty_write(UserOrKernelBuffer const& data, size_t size)
{
SpinlockLocker global_lock(ConsoleManagement::the().tty_write_lock());
auto result = data.read_buffered<512>(size, [&](ReadonlyBytes buffer) {
for (auto const& byte : buffer)
m_console_impl.on_input(byte);
@ -296,7 +389,6 @@ ErrorOr<size_t> VirtualConsole::on_tty_write(UserOrKernelBuffer const& data, siz
void VirtualConsole::set_active(bool active)
{
VERIFY(ConsoleManagement::the().m_lock.is_locked());
VERIFY(m_active != active);
m_active = active;
@ -508,5 +600,4 @@ void VirtualConsole::invalidate_cursor(size_t row)
{
m_lines[row].dirty = true;
}
}

View file

@ -21,7 +21,6 @@
namespace Kernel {
class ConsoleManagement;
class VirtualConsole;
// FIXME: This implementation has no knowledge about keeping terminal history...
class ConsoleImpl final : public VT::Terminal {
@ -46,7 +45,6 @@ private:
class VirtualConsole final : public TTY
, public KeyboardClient
, public VT::TerminalClient {
friend class ConsoleManagement;
friend class DeviceManagement;
friend class ConsoleImpl;
friend class VT::Terminal;
@ -68,15 +66,19 @@ public:
};
public:
static NonnullLockRefPtr<VirtualConsole> create(size_t index);
static NonnullLockRefPtr<VirtualConsole> create_with_preset_log(size_t index, CircularQueue<char, 16384> const&);
static constexpr size_t s_max_virtual_consoles = 6;
static void switch_to(unsigned index);
static void initialize_consoles();
static void switch_to_debug_console() { switch_to(1); }
static void resolution_was_changed();
static bool emit_char_on_debug_console(char ch);
static NonnullRefPtr<VirtualConsole> create(size_t index);
static NonnullRefPtr<VirtualConsole> create_with_preset_log(size_t index, CircularQueue<char, 16384> const&);
virtual ~VirtualConsole() override;
size_t index() const { return m_index; }
void refresh_after_resolution_change();
bool is_graphical() const { return m_graphical; }
void set_graphical(bool graphical);
@ -87,6 +89,8 @@ private:
// ^KeyboardClient
virtual void on_key_pressed(KeyEvent) override;
void refresh_after_resolution_change();
// ^TTY
virtual ErrorOr<NonnullOwnPtr<KString>> pseudo_name() const override;
virtual ErrorOr<size_t> on_tty_write(UserOrKernelBuffer const&, size_t) override;

View file

@ -13,7 +13,7 @@
#endif
#include <AK/StringView.h>
#include <Kernel/Arch/PowerState.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/FileSystem/FileSystem.h>
#include <Kernel/FileSystem/VirtualFileSystem.h>
#include <Kernel/Firmware/ACPI/Parser.h>
@ -84,7 +84,7 @@ ErrorOr<void> PowerStateSwitchTask::perform_shutdown(PowerStateSwitchTask::DoReb
if (alive_process_count != 0)
dbgln("We're not the last process alive; proper shutdown may fail!");
ConsoleManagement::the().switch_to_debug();
VirtualConsole::switch_to_debug_console();
dbgln("Locking all file systems...");
FileSystem::lock_all();

View file

@ -16,7 +16,7 @@
#include <Kernel/Devices/GPU/Management.h>
#include <Kernel/Devices/Generic/ConsoleDevice.h>
#include <Kernel/Devices/PCISerialDevice.h>
#include <Kernel/Devices/TTY/ConsoleManagement.h>
#include <Kernel/Devices/TTY/VirtualConsole.h>
#include <Kernel/Locking/Spinlock.h>
#include <Kernel/kstdio.h>
@ -79,10 +79,9 @@ static void console_out(char ch)
bochs_debug_output(ch);
#endif
}
if (ConsoleManagement::is_initialized()) {
ConsoleManagement::the().debug_tty()->emit_char(ch);
} else if (auto* boot_console = g_boot_console.load()) {
boot_console->write(ch, true);
if (!VirtualConsole::emit_char_on_debug_console(ch)) {
if (auto* boot_console = g_boot_console.load())
boot_console->write(ch, true);
}
}

View file

@ -792,7 +792,6 @@ executable("Kernel_bin") {
"Syscalls/utimensat.cpp",
"Syscalls/waitid.cpp",
"Syscalls/write.cpp",
"TTY/ConsoleManagement.cpp",
"TTY/MasterPTY.cpp",
"TTY/PTYMultiplexer.cpp",
"TTY/SlavePTY.cpp",