diff --git a/kernel/include/kernel/Epoll.h b/kernel/include/kernel/Epoll.h index 6a9e9ea8..a56157aa 100644 --- a/kernel/include/kernel/Epoll.h +++ b/kernel/include/kernel/Epoll.h @@ -2,6 +2,7 @@ #include #include +#include #include @@ -90,6 +91,7 @@ namespace Kernel }; private: + Mutex m_mutex; ThreadBlocker m_thread_blocker; SpinLock m_ready_lock; BAN::HashMap, uint32_t> m_ready_events; diff --git a/kernel/include/kernel/FS/EventFD.h b/kernel/include/kernel/FS/EventFD.h index 89c97cc5..9e027ea6 100644 --- a/kernel/include/kernel/FS/EventFD.h +++ b/kernel/include/kernel/FS/EventFD.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Kernel { @@ -44,8 +45,9 @@ namespace Kernel private: const bool m_is_semaphore; - uint64_t m_value; + BAN::Atomic m_value; + Mutex m_mutex; ThreadBlocker m_thread_blocker; }; diff --git a/kernel/include/kernel/FS/Ext2/Inode.h b/kernel/include/kernel/FS/Ext2/Inode.h index a80fa5eb..5f813c85 100644 --- a/kernel/include/kernel/FS/Ext2/Inode.h +++ b/kernel/include/kernel/FS/Ext2/Inode.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Kernel { @@ -110,6 +111,9 @@ namespace Kernel Ext2::Inode m_inode; const uint32_t m_ino; + // TODO: try to reduce locking or replace this with rwlock(?) + Mutex m_lock; + friend class Ext2FS; friend class BAN::RefPtr; }; diff --git a/kernel/include/kernel/FS/Inode.h b/kernel/include/kernel/FS/Inode.h index 944d2d2f..5d6d9afa 100644 --- a/kernel/include/kernel/FS/Inode.h +++ b/kernel/include/kernel/FS/Inode.h @@ -10,7 +10,6 @@ #include #include -#include #include #include @@ -183,11 +182,10 @@ namespace Kernel virtual BAN::ErrorOr ioctl_impl(int, void*) { return BAN::Error::from_errno(ENOTSUP); } - protected: - mutable PriorityMutex m_mutex; - private: + SpinLock m_shared_region_lock; BAN::WeakPtr m_shared_region; + SpinLock m_epoll_lock; BAN::LinkedList m_epolls; friend class Epoll; diff --git a/kernel/include/kernel/FS/Pipe.h b/kernel/include/kernel/FS/Pipe.h index a4ad4b1b..10c441ba 100644 --- a/kernel/include/kernel/FS/Pipe.h +++ b/kernel/include/kernel/FS/Pipe.h @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include @@ -53,6 +53,8 @@ namespace Kernel timespec m_atime {}; timespec m_mtime {}; timespec m_ctime {}; + + Mutex m_mutex; ThreadBlocker m_thread_blocker; BAN::UniqPtr m_buffer; diff --git a/kernel/include/kernel/FS/TmpFS/Inode.h b/kernel/include/kernel/FS/TmpFS/Inode.h index 4508f0f3..051984b6 100644 --- a/kernel/include/kernel/FS/TmpFS/Inode.h +++ b/kernel/include/kernel/FS/TmpFS/Inode.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Kernel { @@ -53,22 +54,25 @@ namespace Kernel virtual BAN::ErrorOr fsync_impl() override { return {}; } void sync(); - virtual BAN::ErrorOr prepare_unlink() { return {}; }; + virtual BAN::ErrorOr prepare_unlink_no_lock() { return {}; }; void free_all_blocks(); - void free_indirect_blocks(size_t block, uint32_t depth); + void free_indirect_blocks_no_lock(size_t block, uint32_t depth); BAN::Optional block_index(size_t data_block_index); - BAN::Optional block_index_from_indirect(size_t block, size_t index, uint32_t depth); + BAN::Optional block_index_from_indirect_no_lock(size_t block, size_t index, uint32_t depth); BAN::ErrorOr block_index_with_allocation(size_t data_block_index); - BAN::ErrorOr block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth); + BAN::ErrorOr block_index_from_indirect_with_allocation_no_lock(size_t& block, size_t index, uint32_t depth); protected: TmpFileSystem& m_fs; TmpInodeInfo m_inode_info; const ino_t m_ino; + // TODO: try to reduce locking or replace this with rwlock(?) + Mutex m_lock; + // has to be able to increase link count friend class TmpDirectoryInode; }; @@ -149,7 +153,7 @@ namespace Kernel protected: TmpDirectoryInode(TmpFileSystem&, ino_t, const TmpInodeInfo&); - virtual BAN::ErrorOr prepare_unlink() override; + virtual BAN::ErrorOr prepare_unlink_no_lock() override; protected: virtual BAN::ErrorOr> find_inode_impl(BAN::StringView) override final; diff --git a/kernel/include/kernel/Lock/SpinLockAsMutex.h b/kernel/include/kernel/Lock/SpinLockAsMutex.h index 5f7f3552..d93b6882 100644 --- a/kernel/include/kernel/Lock/SpinLockAsMutex.h +++ b/kernel/include/kernel/Lock/SpinLockAsMutex.h @@ -46,7 +46,7 @@ namespace Kernel uint32_t lock_depth() const override { return m_lock_depth; } private: - SpinLock& m_lock; + Lock& m_lock; uint32_t m_lock_depth { 0 }; InterruptState m_state; const pid_t m_locker; diff --git a/kernel/include/kernel/Networking/TCPSocket.h b/kernel/include/kernel/Networking/TCPSocket.h index 23fc803b..46952dc2 100644 --- a/kernel/include/kernel/Networking/TCPSocket.h +++ b/kernel/include/kernel/Networking/TCPSocket.h @@ -181,6 +181,7 @@ namespace Kernel uint64_t m_time_wait_start_ms { 0 }; + mutable Mutex m_mutex; ThreadBlocker m_thread_blocker; RecvWindowInfo m_recv_window; diff --git a/kernel/include/kernel/Networking/UDPSocket.h b/kernel/include/kernel/Networking/UDPSocket.h index aa5706d9..f2e8360c 100644 --- a/kernel/include/kernel/Networking/UDPSocket.h +++ b/kernel/include/kernel/Networking/UDPSocket.h @@ -66,9 +66,12 @@ namespace Kernel SpinLock m_packet_lock; ThreadBlocker m_packet_thread_blocker; + SpinLock m_peer_address_lock; sockaddr_storage m_peer_address {}; socklen_t m_peer_address_len { 0 }; + Mutex m_bind_lock; + friend class BAN::RefPtr; }; diff --git a/kernel/include/kernel/Networking/UNIX/Socket.h b/kernel/include/kernel/Networking/UNIX/Socket.h index 0423b39e..88143e11 100644 --- a/kernel/include/kernel/Networking/UNIX/Socket.h +++ b/kernel/include/kernel/Networking/UNIX/Socket.h @@ -43,15 +43,16 @@ namespace Kernel UnixDomainSocket(Socket::Type, const Socket::Info&); ~UnixDomainSocket(); - bool is_bound() const { return !m_bound_file.canonical_path.empty(); } - bool is_bound_to_unused() const { return !m_bound_file.inode; } + bool is_bound() const; + bool is_bound_to_unused() const; + BAN::ErrorOr bind_to_unused_if_not_bound(); bool is_streaming() const; private: struct ConnectionInfo { - bool listening { false }; + BAN::Atomic listening { false }; BAN::Atomic connection_done { false }; mutable BAN::Atomic target_closed { false }; BAN::WeakPtr connection; @@ -62,6 +63,7 @@ namespace Kernel struct ConnectionlessInfo { + SpinLock lock; BAN::String peer_address; }; @@ -76,7 +78,9 @@ namespace Kernel BAN::ErrorOr add_packet(const msghdr&, PacketInfo&&, bool dont_block); private: - const Socket::Type m_socket_type; + const Socket::Type m_socket_type; + + mutable Mutex m_bind_mutex; VirtualFileSystem::File m_bound_file; BAN::Variant m_info; diff --git a/kernel/include/kernel/Terminal/PseudoTerminal.h b/kernel/include/kernel/Terminal/PseudoTerminal.h index c3566308..d39ef521 100644 --- a/kernel/include/kernel/Terminal/PseudoTerminal.h +++ b/kernel/include/kernel/Terminal/PseudoTerminal.h @@ -67,7 +67,7 @@ namespace Kernel bool putchar_impl(uint8_t ch) override; bool can_write_impl() const override; - bool has_hungup_impl() const override { return !m_master.valid(); } + bool has_hungup_impl() const override { return master_has_closed(); } private: PseudoTerminalSlave(BAN::String&& name, uint32_t number, mode_t, uid_t, gid_t); diff --git a/kernel/include/kernel/Terminal/TTY.h b/kernel/include/kernel/Terminal/TTY.h index 1fdfb9d0..bd83b2a9 100644 --- a/kernel/include/kernel/Terminal/TTY.h +++ b/kernel/include/kernel/Terminal/TTY.h @@ -46,12 +46,14 @@ namespace Kernel static void keyboard_task(void*); static void initialize_devices(); + + bool should_receive_input() const { return m_tty_ctrl.receive_input; } + void on_key_event(LibInput::RawKeyEvent); void on_key_event(LibInput::KeyEvent); void handle_input_byte(uint8_t); - void get_termios(termios* termios) { *termios = m_termios; } - // FIXME: validate termios - BAN::ErrorOr set_termios(const termios* termios) { m_termios = *termios; return {}; } + void get_termios(termios*); + BAN::ErrorOr set_termios(const termios*); virtual bool is_tty() const override { return true; } @@ -85,9 +87,6 @@ namespace Kernel bool putchar(uint8_t ch); void do_backspace(); - protected: - termios m_termios; - private: const dev_t m_rdev; @@ -95,23 +94,27 @@ namespace Kernel struct tty_ctrl_t { - bool draw_graphics { true }; - bool receive_input { true }; - ThreadBlocker thread_blocker; + BAN::Atomic draw_graphics { true }; + BAN::Atomic receive_input { true }; }; tty_ctrl_t m_tty_ctrl; struct Buffer { BAN::UniqPtr buffer; - bool flush { false }; + BAN::Atomic flush { false }; ThreadBlocker thread_blocker; }; Buffer m_output; winsize m_winsize {}; + SpinLock m_termios_lock; + termios m_termios; + protected: + Mutex m_mutex; + RecursiveSpinLock m_write_lock; ThreadBlocker m_write_blocker; }; diff --git a/kernel/include/kernel/USB/HID/Joystick.h b/kernel/include/kernel/USB/HID/Joystick.h index 1fd2d498..0c12de4d 100644 --- a/kernel/include/kernel/USB/HID/Joystick.h +++ b/kernel/include/kernel/USB/HID/Joystick.h @@ -62,8 +62,8 @@ namespace Kernel Mutex m_command_mutex; BAN::Atomic m_has_initialized_leds { false }; - uint8_t m_led_state { 0b0001 }; - uint8_t m_rumble_strength { 0x00 }; + BAN::Atomic m_led_state { 0b0001 }; + BAN::Atomic m_rumble_strength { 0x00 }; friend class BAN::RefPtr; }; diff --git a/kernel/kernel/ACPI/BatterySystem.cpp b/kernel/kernel/ACPI/BatterySystem.cpp index b1c44421..460d58af 100644 --- a/kernel/kernel/ACPI/BatterySystem.cpp +++ b/kernel/kernel/ACPI/BatterySystem.cpp @@ -57,7 +57,7 @@ namespace Kernel::ACPI m_last_value = target_conv.value().as.integer.value; } - auto target_str = TRY(BAN::String::formatted("{}", m_last_value)); + auto target_str = TRY(BAN::String::formatted("{}", m_last_value.load())); if (static_cast(offset) >= target_str.size()) return 0; @@ -67,8 +67,8 @@ namespace Kernel::ACPI return ncopy; } - BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); } - BAN::ErrorOr truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); } + BAN::ErrorOr write_impl(off_t, BAN::ConstByteSpan) override { return BAN::Error::from_errno(EINVAL); } + BAN::ErrorOr truncate_impl(size_t) override { return BAN::Error::from_errno(EINVAL); } bool can_read_impl() const override { return true; } bool can_write_impl() const override { return false; } @@ -90,8 +90,8 @@ namespace Kernel::ACPI AML::NameString m_method_name; size_t m_result_index; - uint64_t m_last_read_ms = 0; - uint64_t m_last_value = 0; + BAN::Atomic m_last_read_ms = 0; + BAN::Atomic m_last_value = 0; }; BAN::ErrorOr BatterySystem::initialize(AML::Namespace& acpi_namespace) diff --git a/kernel/kernel/Epoll.cpp b/kernel/kernel/Epoll.cpp index dd9de2ea..27867704 100644 --- a/kernel/kernel/Epoll.cpp +++ b/kernel/kernel/Epoll.cpp @@ -153,8 +153,6 @@ namespace Kernel REMOVE_IT(); { - LockGuard inode_locker(inode->m_mutex); - #define CHECK_EVENT_BIT(mask, func) \ if ((events & mask) && !inode->func()) \ events &= ~mask; diff --git a/kernel/kernel/FS/EventFD.cpp b/kernel/kernel/FS/EventFD.cpp index 3fc50a60..8b38d673 100644 --- a/kernel/kernel/FS/EventFD.cpp +++ b/kernel/kernel/FS/EventFD.cpp @@ -1,4 +1,5 @@ #include +#include #include @@ -18,16 +19,20 @@ namespace Kernel if (buffer.size() < sizeof(uint64_t)) return BAN::Error::from_errno(EINVAL); + LockGuard _(m_mutex); + while (m_value == 0) TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); - const uint64_t read_value = m_is_semaphore ? 1 : m_value; + const uint64_t read_value = m_is_semaphore ? 1 : m_value.load(); m_value -= read_value; buffer.as() = read_value; epoll_notify(EPOLLOUT); + m_thread_blocker.unblock(); + return sizeof(uint64_t); } @@ -40,6 +45,8 @@ namespace Kernel if (write_value == UINT64_MAX) return BAN::Error::from_errno(EINVAL); + LockGuard _(m_mutex); + while (m_value + write_value < m_value) TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); @@ -48,6 +55,8 @@ namespace Kernel if (m_value > 0) epoll_notify(EPOLLIN); + m_thread_blocker.unblock(); + return sizeof(uint64_t); } diff --git a/kernel/kernel/FS/Ext2/Inode.cpp b/kernel/kernel/FS/Ext2/Inode.cpp index 72e6ed14..1aa6709a 100644 --- a/kernel/kernel/FS/Ext2/Inode.cpp +++ b/kernel/kernel/FS/Ext2/Inode.cpp @@ -61,6 +61,8 @@ namespace Kernel const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t indices_per_fs_block = blksize() / sizeof(uint32_t); + LockGuard _(m_lock); + if (block == 0 && !allocate) return BAN::Optional(); @@ -115,6 +117,8 @@ namespace Kernel const uint32_t inode_blocks_per_fs_block = blksize() / 512; const uint32_t indices_per_block = blksize() / sizeof(uint32_t); + LockGuard _(m_lock); + if (data_block_index < 12) { if (m_inode.block[data_block_index] != 0) @@ -152,6 +156,9 @@ namespace Kernel BAN::ErrorOr Ext2Inode::link_target_impl() { ASSERT(mode().iflnk()); + + LockGuard _(m_lock); + if (m_inode.size < sizeof(m_inode.block)) { BAN::String result; @@ -168,6 +175,9 @@ namespace Kernel BAN::ErrorOr Ext2Inode::set_link_target_impl(BAN::StringView target) { ASSERT(mode().iflnk()); + + LockGuard _(m_lock); + if (target.size() < sizeof(m_inode.block)) { if (m_inode.size >= sizeof(m_inode.block)) @@ -194,10 +204,12 @@ namespace Kernel if (static_cast>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset)) return BAN::Error::from_errno(EOVERFLOW); + LockGuard _0(m_lock); + if (static_cast>(offset) >= m_inode.size) return 0; - ScopedSync _(*this); + ScopedSync _1(*this); uint32_t count = buffer.size(); if (offset + buffer.size() > m_inode.size) @@ -240,6 +252,8 @@ namespace Kernel if (static_cast>(offset) >= UINT32_MAX || buffer.size() >= UINT32_MAX || buffer.size() >= (size_t)(UINT32_MAX - offset)) return BAN::Error::from_errno(EOVERFLOW); + LockGuard _0(m_lock); + if (m_inode.size < offset + buffer.size()) TRY(truncate_impl(offset + buffer.size())); @@ -300,6 +314,8 @@ namespace Kernel BAN::ErrorOr Ext2Inode::truncate_impl(size_t new_size) { + LockGuard _(m_lock); + if (m_inode.size == new_size) return {}; @@ -320,6 +336,10 @@ namespace Kernel BAN::ErrorOr Ext2Inode::chmod_impl(mode_t mode) { ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); + + // TODO: this could be atomic + LockGuard _(m_lock); + if (m_inode.mode == mode) return {}; @@ -337,6 +357,9 @@ namespace Kernel BAN::ErrorOr Ext2Inode::chown_impl(uid_t uid, gid_t gid) { + // TODO: this could be atomic + LockGuard _(m_lock); + if (m_inode.uid == uid && m_inode.gid == gid) return {}; @@ -357,6 +380,9 @@ namespace Kernel BAN::ErrorOr Ext2Inode::utimens_impl(const timespec times[2]) { + // TODO: this could be atomic + LockGuard _(m_lock); + const uint32_t old_times[2] { m_inode.atime, m_inode.mtime, @@ -379,6 +405,7 @@ namespace Kernel BAN::ErrorOr Ext2Inode::fsync_impl() { + LockGuard _(m_lock); for (size_t i = 0; i < max_used_data_block_count(); i++) if (const auto fs_block = TRY(fs_block_of_data_block_index(i, false)); fs_block.has_value()) TRY(m_fs.sync_block(fs_block.value())); @@ -389,6 +416,8 @@ namespace Kernel { ASSERT(block); + LockGuard _(m_lock); + if (depth == 0) { TRY(m_fs.release_block(block)); @@ -413,6 +442,8 @@ namespace Kernel BAN::ErrorOr Ext2Inode::cleanup_data_blocks() { + LockGuard _(m_lock); + if (mode().iflnk() && (size_t)size() < sizeof(m_inode.block)) goto done; @@ -451,6 +482,8 @@ done: ASSERT(mode().ifdir()); ASSERT(offset >= 0); + LockGuard _(m_lock); + if (static_cast>(offset) >= max_used_data_block_count()) return 0; @@ -552,6 +585,8 @@ done: { ASSERT(this->mode().ifdir()); + LockGuard _(m_lock); + if (!find_inode_impl(name).is_error()) return BAN::Error::from_errno(EEXIST); @@ -586,6 +621,8 @@ done: ASSERT(this->mode().ifdir()); ASSERT(Mode(mode).ifdir()); + LockGuard _(m_lock); + if (!find_inode_impl(name).is_error()) return BAN::Error::from_errno(EEXIST); @@ -619,6 +656,8 @@ done: ASSERT(!inode->mode().ifdir()); ASSERT(&m_fs == inode->filesystem()); + LockGuard _(m_lock); + if (!find_inode_impl(name).is_error()) return BAN::Error::from_errno(EEXIST); @@ -636,16 +675,17 @@ done: auto* ext2_parent = static_cast(old_parent.ptr()); - // FIXME: possible deadlock :) - LockGuard _(ext2_parent->m_mutex); + // FIXME: is this a possible deadlock? + LockGuard _0(ext2_parent->m_lock); + LockGuard _1(m_lock); auto old_inode = TRY(ext2_parent->find_inode_impl(old_name)); auto* ext2_inode = static_cast(old_inode.ptr()); - if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error()) + if (auto find_result = find_inode_impl(new_name); find_result.is_error()) { - if (replace_or_error.error().get_error_code() != ENOENT) - return replace_or_error.release_error(); + if (find_result.error().get_error_code() != ENOENT) + return find_result.release_error(); } else { @@ -667,6 +707,8 @@ done: if (name.size() > 255) return BAN::Error::from_errno(ENAMETOOLONG); + LockGuard _(m_lock); + if (m_inode.flags & Ext2::Enum::INDEX_FL) { dwarnln("file creation to indexed directory not supported"); @@ -770,6 +812,8 @@ needs_new_block: auto block_buffer = TRY(m_fs.get_block_buffer()); + LockGuard _(m_lock); + // Confirm that this doesn't contain anything else than '.' or '..' for (uint32_t i = 0; i < max_used_data_block_count(); i++) { @@ -800,14 +844,17 @@ needs_new_block: BAN::ErrorOr Ext2Inode::cleanup_default_links() { ASSERT(mode().ifdir()); + + auto block_buffer = TRY(m_fs.get_block_buffer()); + + LockGuard _(m_lock); + if (m_inode.flags & Ext2::Enum::INDEX_FL) { dwarnln("deletion of indexed directory is not supported"); return BAN::Error::from_errno(ENOTSUP); } - auto block_buffer = TRY(m_fs.get_block_buffer()); - for (uint32_t i = 0; i < max_used_data_block_count(); i++) { const auto block_index = TRY(fs_block_of_data_block_index(i, false)); @@ -857,14 +904,17 @@ needs_new_block: BAN::ErrorOr Ext2Inode::remove_inode_from_directory(BAN::StringView name, bool cleanup_directory) { ASSERT(mode().ifdir()); + + auto block_buffer = TRY(m_fs.get_block_buffer()); + + LockGuard _(m_lock); + if (m_inode.flags & Ext2::Enum::INDEX_FL) { dwarnln("deletion from indexed directory is not supported"); return BAN::Error::from_errno(ENOTSUP); } - auto block_buffer = TRY(m_fs.get_block_buffer()); - for (uint32_t i = 0; i < max_used_data_block_count(); i++) { const auto block_index = TRY(fs_block_of_data_block_index(i, false)); @@ -925,6 +975,8 @@ needs_new_block: auto block_buffer = TRY(m_fs.get_block_buffer()); TRY(m_fs.read_block(inode_location.block, block_buffer)); + + LockGuard _(m_lock); if (memcmp(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode))) { memcpy(block_buffer.data() + inode_location.offset, &m_inode, sizeof(Ext2::Inode)); @@ -940,6 +992,7 @@ needs_new_block: auto block_buffer = TRY(m_fs.get_block_buffer()); + LockGuard _(m_lock); for (uint32_t i = 0; i < max_used_data_block_count(); i++) { const auto block_index = TRY(fs_block_of_data_block_index(i, false)); diff --git a/kernel/kernel/FS/Inode.cpp b/kernel/kernel/FS/Inode.cpp index 06119d06..2a346ac3 100644 --- a/kernel/kernel/FS/Inode.cpp +++ b/kernel/kernel/FS/Inode.cpp @@ -62,7 +62,6 @@ namespace Kernel BAN::ErrorOr> Inode::find_inode(BAN::StringView name) { - LockGuard _(m_mutex); if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); return find_inode_impl(name); @@ -70,7 +69,6 @@ namespace Kernel BAN::ErrorOr Inode::list_next_inodes(off_t offset, struct dirent* list, size_t list_len) { - LockGuard _(m_mutex); if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); return list_next_inodes_impl(offset, list, list_len); @@ -78,7 +76,6 @@ namespace Kernel BAN::ErrorOr Inode::create_file(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid) { - LockGuard _(m_mutex); if (!this->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); if (Mode(mode).ifdir()) @@ -90,7 +87,6 @@ namespace Kernel BAN::ErrorOr Inode::create_directory(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid) { - LockGuard _(m_mutex); if (!this->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); if (!Mode(mode).ifdir()) @@ -102,7 +98,6 @@ namespace Kernel BAN::ErrorOr Inode::link_inode(BAN::StringView name, BAN::RefPtr inode) { - LockGuard _(m_mutex); if (!this->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); if (inode->mode().ifdir()) @@ -116,7 +111,6 @@ namespace Kernel BAN::ErrorOr Inode::rename_inode(BAN::RefPtr old_parent, BAN::StringView old_name, BAN::StringView new_name) { - LockGuard _(m_mutex); if (!this->mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); if (!old_parent->mode().ifdir()) @@ -130,7 +124,6 @@ namespace Kernel BAN::ErrorOr Inode::unlink(BAN::StringView name) { - LockGuard _(m_mutex); if (!mode().ifdir()) return BAN::Error::from_errno(ENOTDIR); if (name == "."_sv || name == ".."_sv) @@ -142,7 +135,6 @@ namespace Kernel BAN::ErrorOr Inode::link_target() { - LockGuard _(m_mutex); if (!mode().iflnk()) return BAN::Error::from_errno(EINVAL); return link_target_impl(); @@ -150,7 +142,6 @@ namespace Kernel BAN::ErrorOr Inode::set_link_target(BAN::StringView target) { - LockGuard _(m_mutex); if (!mode().iflnk()) return BAN::Error::from_errno(EINVAL); if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) @@ -160,7 +151,6 @@ namespace Kernel BAN::ErrorOr Inode::accept(sockaddr* address, socklen_t* address_len, int flags) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return accept_impl(address, address_len, flags); @@ -168,7 +158,6 @@ namespace Kernel BAN::ErrorOr Inode::bind(const sockaddr* address, socklen_t address_len) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return bind_impl(address, address_len); @@ -176,7 +165,6 @@ namespace Kernel BAN::ErrorOr Inode::connect(const sockaddr* address, socklen_t address_len) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return connect_impl(address, address_len); @@ -184,7 +172,6 @@ namespace Kernel BAN::ErrorOr Inode::listen(int backlog) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return listen_impl(backlog); @@ -192,7 +179,6 @@ namespace Kernel BAN::ErrorOr Inode::recvmsg(msghdr& message, int flags) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return recvmsg_impl(message, flags); @@ -200,7 +186,6 @@ namespace Kernel BAN::ErrorOr Inode::sendmsg(const msghdr& message, int flags) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return sendmsg_impl(message, flags); @@ -208,7 +193,6 @@ namespace Kernel BAN::ErrorOr Inode::getsockname(sockaddr* address, socklen_t* address_len) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return getsockname_impl(address, address_len); @@ -216,7 +200,6 @@ namespace Kernel BAN::ErrorOr Inode::getpeername(sockaddr* address, socklen_t* address_len) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return getpeername_impl(address, address_len); @@ -224,7 +207,6 @@ namespace Kernel BAN::ErrorOr Inode::getsockopt(int level, int option, void* value, socklen_t* value_len) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return getsockopt_impl(level, option, value, value_len); @@ -232,7 +214,6 @@ namespace Kernel BAN::ErrorOr Inode::setsockopt(int level, int option, const void* value, socklen_t value_len) { - LockGuard _(m_mutex); if (!mode().ifsock()) return BAN::Error::from_errno(ENOTSOCK); return setsockopt_impl(level, option, value, value_len); @@ -240,7 +221,6 @@ namespace Kernel BAN::ErrorOr Inode::read(off_t offset, BAN::ByteSpan buffer) { - LockGuard _(m_mutex); if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); return read_impl(offset, buffer); @@ -248,7 +228,6 @@ namespace Kernel BAN::ErrorOr Inode::write(off_t offset, BAN::ConstByteSpan buffer) { - LockGuard _(m_mutex); if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) @@ -258,7 +237,6 @@ namespace Kernel BAN::ErrorOr Inode::truncate(size_t size) { - LockGuard _(m_mutex); if (mode().ifdir()) return BAN::Error::from_errno(EISDIR); if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) @@ -269,7 +247,6 @@ namespace Kernel BAN::ErrorOr Inode::chmod(mode_t mode) { ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); - LockGuard _(m_mutex); if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) return BAN::Error::from_errno(EROFS); return chmod_impl(mode); @@ -277,7 +254,6 @@ namespace Kernel BAN::ErrorOr Inode::chown(uid_t uid, gid_t gid) { - LockGuard _(m_mutex); if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) return BAN::Error::from_errno(EROFS); return chown_impl(uid, gid); @@ -285,7 +261,6 @@ namespace Kernel BAN::ErrorOr Inode::utimens(const timespec times[2]) { - LockGuard _(m_mutex); if (auto* fs = filesystem(); fs && (fs->flag() & ST_RDONLY)) return BAN::Error::from_errno(EROFS); return utimens_impl(times); @@ -293,40 +268,32 @@ namespace Kernel BAN::ErrorOr Inode::fsync() { - LockGuard _(m_mutex); - if (auto shared = m_shared_region.lock()) - for (size_t i = 0; i < shared->pages.size(); i++) - shared->sync(i); + // TODO: should we sync shared data? return fsync_impl(); } bool Inode::can_read() const { - LockGuard _(m_mutex); return can_read_impl(); } bool Inode::can_write() const { - LockGuard _(m_mutex); return can_write_impl(); } bool Inode::has_error() const { - LockGuard _(m_mutex); return has_error_impl(); } bool Inode::has_hungup() const { - LockGuard _(m_mutex); return has_hungup_impl(); } BAN::ErrorOr Inode::ioctl(int request, void* arg) { - LockGuard _(m_mutex); return ioctl_impl(request, arg); } diff --git a/kernel/kernel/FS/Pipe.cpp b/kernel/kernel/FS/Pipe.cpp index 52a142be..f7ce65f3 100644 --- a/kernel/kernel/FS/Pipe.cpp +++ b/kernel/kernel/FS/Pipe.cpp @@ -73,6 +73,8 @@ namespace Kernel BAN::ErrorOr Pipe::read_impl(off_t, BAN::ByteSpan buffer) { + LockGuard _(m_mutex); + while (m_buffer->empty()) { if (m_writing_count == 0) @@ -95,6 +97,8 @@ namespace Kernel BAN::ErrorOr Pipe::write_impl(off_t, BAN::ConstByteSpan buffer) { + LockGuard _(m_mutex); + while (m_buffer->full()) { if (m_reading_count == 0) diff --git a/kernel/kernel/FS/TmpFS/Inode.cpp b/kernel/kernel/FS/TmpFS/Inode.cpp index d76a5621..5ca0b2a7 100644 --- a/kernel/kernel/FS/TmpFS/Inode.cpp +++ b/kernel/kernel/FS/TmpFS/Inode.cpp @@ -94,6 +94,7 @@ namespace Kernel BAN::ErrorOr TmpInode::chmod_impl(mode_t new_mode) { + // FIXME: make this atomic ASSERT(!(new_mode & Inode::Mode::TYPE_MASK)); m_inode_info.mode &= Inode::Mode::TYPE_MASK; m_inode_info.mode |= new_mode; @@ -102,6 +103,7 @@ namespace Kernel BAN::ErrorOr TmpInode::chown_impl(uid_t new_uid, gid_t new_gid) { + // FIXME: make this atomic m_inode_info.uid = new_uid; m_inode_info.gid = new_gid; return {}; @@ -109,6 +111,7 @@ namespace Kernel BAN::ErrorOr TmpInode::utimens_impl(const timespec times[2]) { + // FIXME: make this atomic if (times[0].tv_nsec != UTIME_OMIT) m_inode_info.atime = times[0]; if (times[1].tv_nsec != UTIME_OMIT) @@ -123,23 +126,24 @@ namespace Kernel void TmpInode::free_all_blocks() { + LockGuard _(m_lock); if (mode().iflnk() && m_inode_info.size <= sizeof(TmpInodeInfo::block)) goto free_all_blocks_done; for (size_t i = 0; i < TmpInodeInfo::direct_block_count; i++) if (m_inode_info.block[i]) m_fs.free_block(m_inode_info.block[i]); if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 0]) - free_indirect_blocks(block, 1); + free_indirect_blocks_no_lock(block, 1); if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 1]) - free_indirect_blocks(block, 2); + free_indirect_blocks_no_lock(block, 2); if (size_t block = m_inode_info.block[TmpInodeInfo::direct_block_count + 2]) - free_indirect_blocks(block, 3); + free_indirect_blocks_no_lock(block, 3); free_all_blocks_done: for (auto& block : m_inode_info.block) block = 0; } - void TmpInode::free_indirect_blocks(size_t block, uint32_t depth) + void TmpInode::free_indirect_blocks_no_lock(size_t block, uint32_t depth) { ASSERT(block != 0); @@ -160,7 +164,7 @@ namespace Kernel if (next_block == 0) continue; - free_indirect_blocks(next_block, depth - 1); + free_indirect_blocks_no_lock(next_block, depth - 1); } m_fs.free_block(block); @@ -168,6 +172,8 @@ namespace Kernel BAN::Optional TmpInode::block_index(size_t data_block_index) { + LockGuard _(m_lock); + if (data_block_index < TmpInodeInfo::direct_block_count) { if (m_inode_info.block[data_block_index] == 0) @@ -179,20 +185,20 @@ namespace Kernel const size_t indices_per_block = blksize() / sizeof(size_t); if (data_block_index < indices_per_block) - return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1); + return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1); data_block_index -= indices_per_block; if (data_block_index < indices_per_block * indices_per_block) - return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2); + return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2); data_block_index -= indices_per_block * indices_per_block; if (data_block_index < indices_per_block * indices_per_block * indices_per_block) - return block_index_from_indirect(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3); + return block_index_from_indirect_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3); ASSERT_NOT_REACHED(); } - BAN::Optional TmpInode::block_index_from_indirect(size_t block, size_t index, uint32_t depth) + BAN::Optional TmpInode::block_index_from_indirect_no_lock(size_t block, size_t index, uint32_t depth) { if (block == 0) return {}; @@ -215,11 +221,13 @@ namespace Kernel if (depth == 1) return next_block; - return block_index_from_indirect(next_block, index, depth - 1); + return block_index_from_indirect_no_lock(next_block, index, depth - 1); } BAN::ErrorOr TmpInode::block_index_with_allocation(size_t data_block_index) { + LockGuard _(m_lock); + if (data_block_index < TmpInodeInfo::direct_block_count) { if (m_inode_info.block[data_block_index] == 0) @@ -234,20 +242,20 @@ namespace Kernel const size_t indices_per_block = blksize() / sizeof(size_t); if (data_block_index < indices_per_block) - return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1); + return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 0], data_block_index, 1); data_block_index -= indices_per_block; if (data_block_index < indices_per_block * indices_per_block) - return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2); + return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 1], data_block_index, 2); data_block_index -= indices_per_block * indices_per_block; if (data_block_index < indices_per_block * indices_per_block * indices_per_block) - return block_index_from_indirect_with_allocation(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3); + return block_index_from_indirect_with_allocation_no_lock(m_inode_info.block[TmpInodeInfo::direct_block_count + 2], data_block_index, 3); ASSERT_NOT_REACHED(); } - BAN::ErrorOr TmpInode::block_index_from_indirect_with_allocation(size_t& block, size_t index, uint32_t depth) + BAN::ErrorOr TmpInode::block_index_from_indirect_with_allocation_no_lock(size_t& block, size_t index, uint32_t depth) { if (block == 0) { @@ -280,7 +288,7 @@ namespace Kernel if (depth == 1) return next_block; - return block_index_from_indirect_with_allocation(next_block, index, depth - 1); + return block_index_from_indirect_with_allocation_no_lock(next_block, index, depth - 1); } /* FILE INODE */ @@ -309,6 +317,8 @@ namespace Kernel BAN::ErrorOr TmpFileInode::read_impl(off_t offset, BAN::ByteSpan out_buffer) { + LockGuard _(m_lock); + if (offset >= size() || out_buffer.size() == 0) return 0; @@ -339,7 +349,12 @@ namespace Kernel BAN::ErrorOr TmpFileInode::write_impl(off_t offset, BAN::ConstByteSpan in_buffer) { - // FIXME: handle overflow + if (offset < 0) + return BAN::Error::from_errno(EINVAL); + if (BAN::Math::will_addition_overflow(offset, in_buffer.size())) + return BAN::Error::from_errno(EOVERFLOW); + + LockGuard _(m_lock); if (offset + in_buffer.size() > (size_t)size()) TRY(truncate_impl(offset + in_buffer.size())); @@ -370,6 +385,7 @@ namespace Kernel { // FIXME: if size is decreased, we should probably free // unused blocks + // FIXME: make this atomic m_inode_info.size = new_size; return {}; @@ -427,6 +443,8 @@ namespace Kernel BAN::ErrorOr TmpSymlinkInode::set_link_target_impl(BAN::StringView new_target) { + LockGuard _(m_lock); + free_all_blocks(); m_inode_info.size = 0; @@ -455,6 +473,8 @@ namespace Kernel BAN::ErrorOr TmpSymlinkInode::link_target_impl() { + LockGuard _(m_lock); + BAN::String result; TRY(result.resize(size())); @@ -522,7 +542,7 @@ namespace Kernel { } - BAN::ErrorOr TmpDirectoryInode::prepare_unlink() + BAN::ErrorOr TmpDirectoryInode::prepare_unlink_no_lock() { ino_t dot_ino = 0; ino_t dotdot_ino = 0; @@ -564,15 +584,15 @@ namespace Kernel BAN::ErrorOr> TmpDirectoryInode::find_inode_impl(BAN::StringView name) { - ino_t result = 0; + LockGuard _(m_lock); + ino_t result = 0; for_each_valid_entry([&](TmpDirectoryEntry& entry) { if (entry.name_sv() != name) return BAN::Iteration::Continue; result = entry.ino; return BAN::Iteration::Break; }); - if (result == 0) return BAN::Error::from_errno(ENOENT); @@ -588,6 +608,8 @@ namespace Kernel return BAN::Error::from_errno(ENOBUFS); } + LockGuard _(m_lock); + auto block_index = this->block_index(data_block_index); // if we reach a non-allocated block, it marks the end @@ -664,6 +686,8 @@ namespace Kernel ASSERT(!inode->mode().ifdir()); ASSERT(&m_fs == inode->filesystem()); + LockGuard _(m_lock); + if (!find_inode_impl(name).is_error()) return BAN::Error::from_errno(EEXIST); @@ -680,16 +704,17 @@ namespace Kernel auto* tmp_parent = static_cast(old_parent.ptr()); - // FIXME: possible deadlock :) - LockGuard _(tmp_parent->m_mutex); + // FIXME: is this a possible deadlock? + LockGuard _0(tmp_parent->m_lock); + LockGuard _1(m_lock); auto old_inode = TRY(tmp_parent->find_inode_impl(old_name)); auto* tmp_inode = static_cast(old_inode.ptr()); - if (auto replace_or_error = find_inode_impl(new_name); replace_or_error.is_error()) + if (auto find_result = find_inode_impl(new_name); find_result.is_error()) { - if (replace_or_error.error().get_error_code() != ENOENT) - return replace_or_error.release_error(); + if (find_result.error().get_error_code() != ENOENT) + return find_result.release_error(); } else { @@ -711,15 +736,15 @@ namespace Kernel BAN::ErrorOr TmpDirectoryInode::unlink_inode(BAN::StringView name, bool cleanup) { - ino_t entry_ino = 0; + LockGuard _(m_lock); + ino_t entry_ino = 0; for_each_valid_entry([&](TmpDirectoryEntry& entry) { if (entry.name_sv() != name) return BAN::Iteration::Continue; entry_ino = entry.ino; return BAN::Iteration::Break; }); - if (entry_ino == 0) return BAN::Error::from_errno(ENOENT); @@ -728,7 +753,7 @@ namespace Kernel ASSERT(inode->nlink() > 0); if (cleanup) - TRY(inode->prepare_unlink()); + TRY(inode->prepare_unlink_no_lock()); inode->m_inode_info.nlink--; if (inode->nlink() == 0) @@ -749,6 +774,8 @@ namespace Kernel { static constexpr size_t directory_entry_alignment = sizeof(TmpDirectoryEntry); + LockGuard _(m_lock); + auto find_result = find_inode_impl(name); if (!find_result.is_error()) return BAN::Error::from_errno(EEXIST); diff --git a/kernel/kernel/FS/USTARModule.cpp b/kernel/kernel/FS/USTARModule.cpp index a5be5103..4f2c959e 100644 --- a/kernel/kernel/FS/USTARModule.cpp +++ b/kernel/kernel/FS/USTARModule.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/kernel/kernel/Input/InputDevice.cpp b/kernel/kernel/Input/InputDevice.cpp index 74fd90a8..ad64bbb1 100644 --- a/kernel/kernel/Input/InputDevice.cpp +++ b/kernel/kernel/Input/InputDevice.cpp @@ -13,12 +13,15 @@ namespace Kernel { + static SpinLock s_keyboard_lock; static BAN::Vector> s_keyboards; static BAN::RefPtr s_keyboard_device; + static SpinLock s_mouse_lock; static BAN::Vector> s_mice; static BAN::RefPtr s_mouse_device; + static SpinLock s_joystick_lock; static BAN::Vector> s_joysticks; static const char* get_name_format(InputDevice::Type type) @@ -40,20 +43,29 @@ namespace Kernel switch (type) { case InputDevice::Type::Keyboard: + { + SpinLockGuard _(s_keyboard_lock); for (size_t i = 0; i < s_keyboards.size(); i++) if (!s_keyboards[i].valid()) return makedev(DeviceNumber::Keyboard, i + 1); return makedev(DeviceNumber::Keyboard, s_keyboards.size() + 1); + } case InputDevice::Type::Mouse: + { + SpinLockGuard _(s_mouse_lock); for (size_t i = 0; i < s_mice.size(); i++) if (!s_mice[i].valid()) return makedev(DeviceNumber::Mouse, i + 1); return makedev(DeviceNumber::Mouse, s_mice.size() + 1); + } case InputDevice::Type::Joystick: + { + SpinLockGuard _(s_joystick_lock); for (size_t i = 0; i < s_joysticks.size(); i++) if (!s_joysticks[i].valid()) return makedev(DeviceNumber::Joystick, i + 1); return makedev(DeviceNumber::Joystick, s_joysticks.size() + 1); + } } ASSERT_NOT_REACHED(); } @@ -84,20 +96,29 @@ namespace Kernel switch (m_type) { case Type::Keyboard: + { + SpinLockGuard _(s_keyboard_lock); if (s_keyboards.size() < minor(m_rdev)) MUST(s_keyboards.resize(minor(m_rdev))); s_keyboards[minor(m_rdev) - 1] = MUST(get_weak_ptr()); break; + } case Type::Mouse: + { + SpinLockGuard _(s_mouse_lock); if (s_mice.size() < minor(m_rdev)) MUST(s_mice.resize(minor(m_rdev))); s_mice[minor(m_rdev) - 1] = MUST(get_weak_ptr()); break; + } case Type::Joystick: + { + SpinLockGuard _(s_joystick_lock); if (s_joysticks.size() < minor(m_rdev)) MUST(s_joysticks.resize(minor(m_rdev))); s_joysticks[minor(m_rdev) - 1] = MUST(get_weak_ptr()); break; + } } } @@ -256,6 +277,8 @@ namespace Kernel void KeyboardDevice::notify() { epoll_notify(EPOLLIN); + + SpinLockGuard _(s_keyboard_lock); m_thread_blocker.unblock(); } @@ -264,6 +287,7 @@ namespace Kernel if (buffer.size() < sizeof(LibInput::RawKeyEvent)) return BAN::Error::from_errno(ENOBUFS); + SpinLockGuard keyboard_guard(s_keyboard_lock); for (;;) { for (auto& weak_keyboard : s_keyboards) @@ -277,13 +301,14 @@ namespace Kernel return bytes; } - // FIXME: race condition as notify doesn't lock mutex - TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); + SpinLockGuardAsMutex smutex(keyboard_guard); + TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex)); } } bool KeyboardDevice::can_read_impl() const { + SpinLockGuard _(s_keyboard_lock); for (auto& weak_keyboard : s_keyboards) if (auto keyboard = weak_keyboard.lock()) if (keyboard->can_read()) @@ -308,6 +333,8 @@ namespace Kernel void MouseDevice::notify() { epoll_notify(EPOLLIN); + + SpinLockGuard _(s_mouse_lock); m_thread_blocker.unblock(); } @@ -316,6 +343,7 @@ namespace Kernel if (buffer.size() < sizeof(LibInput::MouseEvent)) return BAN::Error::from_errno(ENOBUFS); + SpinLockGuard mouse_guard(s_mouse_lock); for (;;) { for (auto& weak_mouse : s_mice) @@ -329,13 +357,14 @@ namespace Kernel return bytes; } - // FIXME: race condition as notify doesn't lock mutex - TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &m_mutex)); + SpinLockGuardAsMutex smutex(mouse_guard); + TRY(Thread::current().block_or_eintr_indefinite(m_thread_blocker, &smutex)); } } bool MouseDevice::can_read_impl() const { + SpinLockGuard _(s_mouse_lock); for (auto& weak_mouse : s_mice) if (auto mouse = weak_mouse.lock()) if (mouse->can_read()) diff --git a/kernel/kernel/Memory/FileBackedRegion.cpp b/kernel/kernel/Memory/FileBackedRegion.cpp index d29a07ac..3e2518bf 100644 --- a/kernel/kernel/Memory/FileBackedRegion.cpp +++ b/kernel/kernel/Memory/FileBackedRegion.cpp @@ -35,7 +35,7 @@ namespace Kernel if (type == Type::PRIVATE) TRY(region->m_dirty_pages.resize(BAN::Math::div_round_up(size, PAGE_SIZE))); - LockGuard _(inode->m_mutex); + SpinLockGuard _(inode->m_shared_region_lock); if (!(region->m_shared_data = inode->m_shared_region.lock())) { auto shared_data = TRY(BAN::RefPtr::create()); diff --git a/kernel/kernel/Networking/TCPSocket.cpp b/kernel/kernel/Networking/TCPSocket.cpp index b3f66c09..9c8161f8 100644 --- a/kernel/kernel/Networking/TCPSocket.cpp +++ b/kernel/kernel/Networking/TCPSocket.cpp @@ -66,6 +66,8 @@ namespace Kernel BAN::ErrorOr TCPSocket::accept_impl(sockaddr* address, socklen_t* address_len, int flags) { + LockGuard _(m_mutex); + if (m_state != State::Listen) return BAN::Error::from_errno(EINVAL); @@ -171,6 +173,8 @@ namespace Kernel BAN::ErrorOr TCPSocket::listen_impl(int backlog) { + LockGuard _(m_mutex); + if (!is_bound()) return BAN::Error::from_errno(EDESTADDRREQ); if (m_connection_info.has_value()) @@ -185,6 +189,8 @@ namespace Kernel BAN::ErrorOr TCPSocket::bind_impl(const sockaddr* address, socklen_t address_len) { + LockGuard _(m_mutex); + if (is_bound()) return BAN::Error::from_errno(EINVAL); return m_network_layer.bind_socket_to_address(this, address, address_len); @@ -204,6 +210,8 @@ namespace Kernel message.msg_controllen = 0; } + LockGuard _(m_mutex); + if (!m_has_connected) return BAN::Error::from_errno(ENOTCONN); @@ -261,6 +269,8 @@ namespace Kernel if (CMSG_FIRSTHDR(&message)) dwarnln("ignoring sendmsg control message"); + LockGuard _(m_mutex); + if (!m_has_connected) return BAN::Error::from_errno(ENOTCONN); @@ -291,6 +301,7 @@ namespace Kernel BAN::ErrorOr TCPSocket::getpeername_impl(sockaddr* address, socklen_t* address_len) { + LockGuard _(m_mutex); if (!m_has_connected && m_state != State::Established) return BAN::Error::from_errno(ENOTCONN); ASSERT(m_connection_info.has_value()); @@ -302,6 +313,8 @@ namespace Kernel BAN::ErrorOr TCPSocket::getsockopt_impl(int level, int option, void* value, socklen_t* value_len) { + LockGuard _(m_mutex); + int result; switch (level) @@ -351,6 +364,8 @@ namespace Kernel BAN::ErrorOr TCPSocket::setsockopt_impl(int level, int option, const void* value, socklen_t value_len) { + LockGuard _(m_mutex); + switch (level) { case SOL_SOCKET: @@ -401,6 +416,7 @@ namespace Kernel bool TCPSocket::can_read_impl() const { + LockGuard _(m_mutex); if (m_has_connected && !m_has_sent_zero && m_state != State::Established && m_state != State::Listen) return true; if (m_state == State::Listen) @@ -410,6 +426,7 @@ namespace Kernel bool TCPSocket::can_write_impl() const { + LockGuard _(m_mutex); if (m_state != State::Established) return false; return !m_send_window.buffer->full(); @@ -417,6 +434,7 @@ namespace Kernel bool TCPSocket::has_hungup_impl() const { + LockGuard _(m_mutex); return m_has_connected && m_state != State::Established; } diff --git a/kernel/kernel/Networking/UDPSocket.cpp b/kernel/kernel/Networking/UDPSocket.cpp index 27e2ce4b..327a8287 100644 --- a/kernel/kernel/Networking/UDPSocket.cpp +++ b/kernel/kernel/Networking/UDPSocket.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -58,9 +59,6 @@ namespace Kernel void UDPSocket::receive_packet(BAN::ConstByteSpan packet, const sockaddr* sender, socklen_t sender_len) { - (void)sender_len; - - //auto& header = packet.as(); auto payload = packet.slice(sizeof(UDPHeader)); SpinLockGuard _(m_packet_lock); @@ -95,6 +93,8 @@ namespace Kernel { if (address_len > static_cast(sizeof(m_peer_address))) address_len = sizeof(m_peer_address); + + SpinLockGuard _(m_peer_address_lock); memcpy(&m_peer_address, address, address_len); m_peer_address_len = address_len; return {}; @@ -102,6 +102,7 @@ namespace Kernel BAN::ErrorOr UDPSocket::bind_impl(const sockaddr* address, socklen_t address_len) { + LockGuard _(m_bind_lock); if (is_bound()) return BAN::Error::from_errno(EINVAL); return m_network_layer.bind_socket_to_address(this, address, address_len); @@ -183,8 +184,11 @@ namespace Kernel if (CMSG_FIRSTHDR(&message)) dwarnln("ignoring sendmsg control message"); - if (!is_bound()) - TRY(m_network_layer.bind_socket_with_target(this, static_cast(message.msg_name), message.msg_namelen)); + { + LockGuard _(m_bind_lock); + if (!is_bound()) + TRY(m_network_layer.bind_socket_with_target(this, static_cast(message.msg_name), message.msg_namelen)); + } const size_t total_send_size = [&message]() -> size_t { @@ -208,6 +212,7 @@ namespace Kernel socklen_t address_len; if (!message.msg_name || message.msg_namelen == 0) { + SpinLockGuard _(m_peer_address_lock); if (m_peer_address_len == 0) return BAN::Error::from_errno(EDESTADDRREQ); address = reinterpret_cast(&m_peer_address); diff --git a/kernel/kernel/Networking/UNIX/Socket.cpp b/kernel/kernel/Networking/UNIX/Socket.cpp index 3a624b1d..ffa2efb9 100644 --- a/kernel/kernel/Networking/UNIX/Socket.cpp +++ b/kernel/kernel/Networking/UNIX/Socket.cpp @@ -88,6 +88,26 @@ namespace Kernel } } + bool UnixDomainSocket::is_bound() const + { + LockGuard _(m_bind_mutex); + return !m_bound_file.canonical_path.empty(); + } + + bool UnixDomainSocket::is_bound_to_unused() const + { + LockGuard _(m_bind_mutex); + return !m_bound_file.inode; + } + + BAN::ErrorOr UnixDomainSocket::bind_to_unused_if_not_bound() + { + LockGuard _(m_bind_mutex); + if (!is_bound()) + TRY(m_bound_file.canonical_path.push_back('X')); + return {}; + } + BAN::ErrorOr UnixDomainSocket::make_socket_pair(UnixDomainSocket& other) { if (!m_info.has() || !other.m_info.has()) @@ -106,15 +126,15 @@ namespace Kernel { if (!m_info.has()) return BAN::Error::from_errno(EOPNOTSUPP); - auto& connection_info = m_info.get(); - if (!connection_info.listening) - return BAN::Error::from_errno(EINVAL); - BAN::RefPtr pending; { + auto& connection_info = m_info.get(); + LockGuard _(connection_info.pending_lock); + if (!connection_info.listening) + return BAN::Error::from_errno(EINVAL); while (connection_info.pending_connections.empty()) TRY(Thread::current().block_or_eintr_indefinite(connection_info.pending_thread_blocker, &connection_info.pending_lock)); @@ -154,8 +174,6 @@ namespace Kernel BAN::ErrorOr UnixDomainSocket::connect_impl(const sockaddr* address, socklen_t address_len) { const auto sun_path = TRY(validate_sockaddr_un(address, address_len)); - if (!is_bound()) - TRY(m_bound_file.canonical_path.push_back('X')); auto absolute_path = TRY(Process::current().absolute_path_of(sun_path)); auto file = TRY(VirtualFileSystem::get().file_from_absolute_path( @@ -180,9 +198,12 @@ namespace Kernel if (m_socket_type != target->m_socket_type) return BAN::Error::from_errno(EPROTOTYPE); + TRY(bind_to_unused_if_not_bound()); + if (m_info.has()) { auto& connectionless_info = m_info.get(); + SpinLockGuard _(connectionless_info.lock); connectionless_info.peer_address = BAN::move(file.canonical_path); return {}; } @@ -192,7 +213,6 @@ namespace Kernel return BAN::Error::from_errno(ECONNREFUSED); if (connection_info.listening) return BAN::Error::from_errno(EOPNOTSUPP); - connection_info.connection_done = false; for (;;) @@ -222,23 +242,25 @@ namespace Kernel BAN::ErrorOr UnixDomainSocket::listen_impl(int backlog) { backlog = BAN::Math::clamp(backlog, 1, SOMAXCONN); + if (!is_bound()) return BAN::Error::from_errno(EDESTADDRREQ); if (!m_info.has()) return BAN::Error::from_errno(EOPNOTSUPP); + auto& connection_info = m_info.get(); + + LockGuard _(connection_info.pending_lock); if (connection_info.connection) return BAN::Error::from_errno(EINVAL); TRY(connection_info.pending_connections.reserve(backlog)); connection_info.listening = true; + return {}; } BAN::ErrorOr UnixDomainSocket::bind_impl(const sockaddr* address, socklen_t address_len) { - if (is_bound()) - return BAN::Error::from_errno(EINVAL); - const auto sun_path = TRY(validate_sockaddr_un(address, address_len)); if (sun_path.empty()) return BAN::Error::from_errno(EINVAL); @@ -261,10 +283,15 @@ namespace Kernel O_RDWR )); - LockGuard _(s_bound_socket_lock); + LockGuard _0(m_bind_mutex); + if (is_bound()) + return BAN::Error::from_errno(EINVAL); + + LockGuard _1(s_bound_socket_lock); if (s_bound_sockets.contains(file.inode)) return BAN::Error::from_errno(EADDRINUSE); TRY(s_bound_sockets.emplace(file.inode, TRY(get_weak_ptr()))); + m_bound_file = BAN::move(file); return {}; @@ -679,6 +706,7 @@ namespace Kernel { if (!m_info.has()) return BAN::Error::from_errno(ENOTCONN); + auto connection = m_info.get().connection.lock(); if (!connection) return BAN::Error::from_errno(ENOTCONN); @@ -687,7 +715,11 @@ namespace Kernel .sun_family = AF_UNIX, .sun_path = {}, }; - strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data()); + + { + LockGuard _(m_bind_mutex); + strcpy(sa_un.sun_path, connection->m_bound_file.canonical_path.data()); + } const size_t to_copy = BAN::Math::min(sizeof(sockaddr_un), *address_len); memcpy(address, &sa_un, to_copy); diff --git a/kernel/kernel/OpenFileDescriptorSet.cpp b/kernel/kernel/OpenFileDescriptorSet.cpp index 88c621eb..ec57d051 100644 --- a/kernel/kernel/OpenFileDescriptorSet.cpp +++ b/kernel/kernel/OpenFileDescriptorSet.cpp @@ -699,9 +699,9 @@ namespace Kernel size_t nread; { - LockGuard _(inode->m_mutex); if (!inode->can_read() && inode->has_hungup()) return 0; + // FIXME: race condition, pass flags to read if (is_nonblock && !inode->can_read()) return BAN::Error::from_errno(EAGAIN); nread = TRY(inode->read(offset, buffer)); @@ -753,7 +753,6 @@ namespace Kernel size_t nwrite; { - LockGuard _(inode->m_mutex); if (inode->has_error()) { Thread::current().add_signal(SIGPIPE, {}); @@ -761,6 +760,7 @@ namespace Kernel } if (is_nonblock && !inode->can_write()) return BAN::Error::from_errno(EAGAIN); + // FIXME: race condition, pass flags to write nwrite = TRY(inode->write(offset, buffer)); } @@ -818,7 +818,6 @@ namespace Kernel is_nonblock = !!(open_file->status_flags & O_NONBLOCK); } - LockGuard _(inode->m_mutex); if (is_nonblock && !inode->can_read()) return BAN::Error::from_errno(EAGAIN); return inode->recvmsg(message, flags); @@ -839,7 +838,6 @@ namespace Kernel is_nonblock = !!(open_file->status_flags & O_NONBLOCK); } - LockGuard _(inode->m_mutex); if (inode->has_hungup()) { if (!(flags & MSG_NOSIGNAL)) diff --git a/kernel/kernel/Random.cpp b/kernel/kernel/Random.cpp index 5dc391a3..c33bf95e 100644 --- a/kernel/kernel/Random.cpp +++ b/kernel/kernel/Random.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -9,6 +10,7 @@ namespace Kernel // Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator + static SpinLock s_rand_lock; static uint64_t s_rand_seed = 0x4d595df4d0f33173; static constexpr uint64_t s_rand_multiplier = 6364136223846793005; static constexpr uint64_t s_rand_increment = 1442695040888963407; @@ -46,7 +48,9 @@ namespace Kernel uint32_t Random::get_u32() { - auto rotr32 = [](uint32_t x, unsigned r) { return x >> r | x << (-r & 31); }; + constexpr auto rotr32 = [](uint32_t x, unsigned r) { return x >> r | x << (-r & 31); }; + + SpinLockGuard _(s_rand_lock); uint64_t x = s_rand_seed; unsigned count = (unsigned)(x >> 59); diff --git a/kernel/kernel/Terminal/PseudoTerminal.cpp b/kernel/kernel/Terminal/PseudoTerminal.cpp index 2cbb2b5e..1f37b2b2 100644 --- a/kernel/kernel/Terminal/PseudoTerminal.cpp +++ b/kernel/kernel/Terminal/PseudoTerminal.cpp @@ -144,6 +144,7 @@ namespace Kernel auto slave = m_slave.lock(); if (!slave) return BAN::Error::from_errno(EIO); + LockGuard _(slave->m_mutex); for (size_t i = 0; i < buffer.size(); i++) slave->handle_input_byte(buffer[i]); return buffer.size(); @@ -160,8 +161,11 @@ namespace Kernel switch (request) { case FIONREAD: + { + SpinLockGuard _(m_buffer_lock); *static_cast(argument) = m_buffer_size; return 0; + } case TIOCGWINSZ: case TIOCSWINSZ: if (auto slave = m_slave.lock()) diff --git a/kernel/kernel/Terminal/TTY.cpp b/kernel/kernel/Terminal/TTY.cpp index 9797dc14..38da8ff3 100644 --- a/kernel/kernel/Terminal/TTY.cpp +++ b/kernel/kernel/Terminal/TTY.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -71,8 +72,8 @@ namespace Kernel TTY::TTY(termios termios, mode_t mode, uid_t uid, gid_t gid) : CharacterDevice(mode, uid, gid) - , m_termios(termios) , m_rdev(next_tty_rdev()) + , m_termios(termios) { m_output.buffer = MUST(ByteRingBuffer::create(PAGE_SIZE)); } @@ -94,21 +95,16 @@ namespace Kernel if (flags & ~(TTY_FLAG_ENABLE_INPUT | TTY_FLAG_ENABLE_OUTPUT)) return BAN::Error::from_errno(EINVAL); - LockGuard _(m_mutex); - switch (command) { case TTY_CMD_SET: - if ((flags & TTY_FLAG_ENABLE_INPUT) && !m_tty_ctrl.receive_input) - { + if (flags & TTY_FLAG_ENABLE_INPUT) m_tty_ctrl.receive_input = true; - m_tty_ctrl.thread_blocker.unblock(); - } if (flags & TTY_FLAG_ENABLE_OUTPUT) m_tty_ctrl.draw_graphics = true; break; case TTY_CMD_UNSET: - if ((flags & TTY_FLAG_ENABLE_INPUT) && m_tty_ctrl.receive_input) + if (flags & TTY_FLAG_ENABLE_INPUT) m_tty_ctrl.receive_input = false; if (flags & TTY_FLAG_ENABLE_OUTPUT) m_tty_ctrl.draw_graphics = false; @@ -133,16 +129,8 @@ namespace Kernel while (true) { - { - LockGuard _(TTY::current()->m_mutex); - while (!TTY::current()->m_tty_ctrl.receive_input) - TTY::current()->m_tty_ctrl.thread_blocker.block_indefinite(&TTY::current()->m_mutex); - } - while (TTY::current()->m_tty_ctrl.receive_input) { - LockGuard _(keyboard_inode->m_mutex); - if (!keyboard_inode->can_read()) { SystemTimer::get().sleep_ms(1); @@ -160,19 +148,15 @@ namespace Kernel void TTY::initialize_devices() { - static bool initialized = false; - ASSERT(!initialized); - auto* thread = MUST(Thread::create_kernel(&TTY::keyboard_task, nullptr)); MUST(Processor::scheduler().add_thread(thread)); DevFileSystem::get().add_inode("tty", MUST(DevTTY::create(0666, 0, 0))); - - initialized = true; } BAN::ErrorOr TTY::chmod_impl(mode_t mode) { + // FIXME: make this atomic ASSERT((mode & Inode::Mode::TYPE_MASK) == 0); m_inode_info.mode &= Inode::Mode::TYPE_MASK; m_inode_info.mode |= mode; @@ -181,6 +165,7 @@ namespace Kernel BAN::ErrorOr TTY::chown_impl(uid_t uid, gid_t gid) { + // FIXME: make this atomic m_inode_info.uid = uid; m_inode_info.gid = gid; return {}; @@ -188,6 +173,7 @@ namespace Kernel void TTY::update_winsize(unsigned short cols, unsigned short rows) { + // FIXME: make this atomic m_winsize.ws_col = cols; m_winsize.ws_row = rows; (void)Process::kill(-m_foreground_pgrp, SIGWINCH); @@ -211,12 +197,14 @@ namespace Kernel } case TIOCGWINSZ: { + // FIXME: make this atomic auto* winsize = static_cast(argument); *winsize = m_winsize; return 0; } case TIOCSWINSZ: { + // FIXME: make this atomic const auto* winsize = static_cast(argument); m_winsize = *winsize; (void)Process::kill(-m_foreground_pgrp, SIGWINCH); @@ -226,10 +214,13 @@ namespace Kernel return BAN::Error::from_errno(ENOTSUP); } + void TTY::on_key_event(LibInput::RawKeyEvent event) + { + on_key_event(LibInput::KeyboardLayout::get().key_event_from_raw(event)); + } + void TTY::on_key_event(LibInput::KeyEvent event) { - LockGuard _(m_mutex); - if (event.released()) return; @@ -237,35 +228,55 @@ namespace Kernel if (ansi_c_str == nullptr) return; + LockGuard _(m_mutex); while (*ansi_c_str) handle_input_byte(*ansi_c_str++); after_write(); } + void TTY::get_termios(termios* termios) + { + SpinLockGuard _(m_termios_lock); + *termios = m_termios; + } + + BAN::ErrorOr TTY::set_termios(const termios* termios) + { + // FIXME: do some validation + + SpinLockGuard _(m_termios_lock); + m_termios = *termios; + return {}; + } + void TTY::handle_input_byte(uint8_t ch) { if (ch == _POSIX_VDISABLE) return; - LockGuard _(m_mutex); + LockGuard _0(m_mutex); - if ((m_termios.c_iflag & ISTRIP)) + termios termios; + get_termios(&termios); + + + if ((termios.c_iflag & ISTRIP)) ch &= 0x7F; - if ((m_termios.c_iflag & IGNCR) && ch == CR) + if ((termios.c_iflag & IGNCR) && ch == CR) return; - if ((m_termios.c_iflag & ICRNL) && ch == CR) + if ((termios.c_iflag & ICRNL) && ch == CR) ch = NL; - else if ((m_termios.c_iflag & INLCR) && ch == NL) + else if ((termios.c_iflag & INLCR) && ch == NL) ch = CR; - if (m_termios.c_lflag & ISIG) + if (termios.c_lflag & ISIG) { int sig = -1; - if (ch == m_termios.c_cc[VINTR]) + if (ch == termios.c_cc[VINTR]) sig = SIGINT; - if (ch == m_termios.c_cc[VQUIT]) + if (ch == termios.c_cc[VQUIT]) sig = SIGQUIT; - if (ch == m_termios.c_cc[VSUSP]) + if (ch == termios.c_cc[VSUSP]) sig = SIGTSTP; if (sig != -1) { @@ -279,30 +290,30 @@ namespace Kernel bool should_flush = false; bool force_echo = false; - if (!(m_termios.c_lflag & ICANON)) + if (!(termios.c_lflag & ICANON)) should_flush = true; else { - if (ch == m_termios.c_cc[VERASE] && (m_termios.c_lflag & ECHOE)) + if (ch == termios.c_cc[VERASE] && (termios.c_lflag & ECHOE)) return do_backspace(); - if (ch == m_termios.c_cc[VKILL] && (m_termios.c_lflag & ECHOK)) + if (ch == termios.c_cc[VKILL] && (termios.c_lflag & ECHOK)) { while (!m_output.buffer->empty() && m_output.buffer->back() != '\n') do_backspace(); return; } - if (ch == m_termios.c_cc[VEOF]) + if (ch == termios.c_cc[VEOF]) { should_append = false; should_flush = true; } - if (ch == NL || ch == CR || ch == m_termios.c_cc[VEOL]) + if (ch == NL || ch == CR || ch == termios.c_cc[VEOL]) { should_flush = true; - force_echo = !!(m_termios.c_lflag & ECHONL); + force_echo = !!(termios.c_lflag & ECHONL); } } @@ -311,7 +322,7 @@ namespace Kernel if (should_append && !m_output.buffer->full()) m_output.buffer->push({ &ch, 1 }); - if (should_append && (force_echo || (m_termios.c_lflag & ECHO))) + if (should_append && (force_echo || (termios.c_lflag & ECHO))) { if ((ch <= 31 || ch == 127) && ch != '\n') { @@ -380,14 +391,18 @@ namespace Kernel bool TTY::putchar(uint8_t ch) { - SpinLockGuard _(m_write_lock); if (!m_tty_ctrl.draw_graphics) return true; - if (m_termios.c_oflag & OPOST) + + termios termios; + get_termios(&termios); + + SpinLockGuard _1(m_write_lock); + if (termios.c_oflag & OPOST) { - if ((m_termios.c_oflag & ONLCR) && ch == NL) + if ((termios.c_oflag & ONLCR) && ch == NL) return putchar_impl(CR) && putchar_impl(NL); - if ((m_termios.c_oflag & OCRNL) && ch == CR) + if ((termios.c_oflag & OCRNL) && ch == CR) return putchar_impl(NL); } return putchar_impl(ch); @@ -395,6 +410,7 @@ namespace Kernel BAN::ErrorOr TTY::read_impl(off_t, BAN::ByteSpan buffer) { + LockGuard _(m_mutex); while (!m_output.flush) TRY(Thread::current().block_or_eintr_indefinite(m_output.thread_blocker, &m_mutex)); @@ -428,24 +444,24 @@ namespace Kernel BAN::ErrorOr TTY::write_impl(off_t, BAN::ConstByteSpan buffer) { - while (!can_write_impl()) + SpinLockGuard write_guard(m_write_lock); + + while (!can_write()) { if (master_has_closed()) return BAN::Error::from_errno(EIO); - TRY(Thread::current().block_or_eintr_indefinite(m_write_blocker, &m_mutex)); + + SpinLockGuardAsMutex smutex(write_guard); + TRY(Thread::current().block_or_eintr_indefinite(m_write_blocker, &smutex)); } size_t written = 0; + for (; written < buffer.size(); written++) + if (!putchar(buffer[written])) + break; + after_write(); - { - SpinLockGuard _(m_write_lock); - for (; written < buffer.size(); written++) - if (!putchar(buffer[written])) - break; - after_write(); - } - - if (can_write_impl()) + if (can_write()) epoll_notify(EPOLLOUT); return written; diff --git a/kernel/kernel/Terminal/TerminalDriver.cpp b/kernel/kernel/Terminal/TerminalDriver.cpp index 11316c21..5c1c3ec8 100644 --- a/kernel/kernel/Terminal/TerminalDriver.cpp +++ b/kernel/kernel/Terminal/TerminalDriver.cpp @@ -23,6 +23,7 @@ namespace Kernel g_terminal_driver = TRY(TextModeTerminalDriver::create_from_boot_info()); break; } + return {}; }