Compare commits

...

4 Commits

Author SHA1 Message Date
Bananymous 918657b658 Shell: do path resolution only if command doesn't contain '/' 2023-12-07 13:34:46 +02:00
Bananymous 9781cc5d16 Kernel: Remove obsolete Scheduler::is_valid_tid()
This function was used when processes could die at any point in time.
Now that processes can only die in known spots, we can be sure they
are not holding any locks. This allows much more performant locking.
2023-12-07 13:26:42 +02:00
Bananymous 6ed6fb6f78 Kernel: Make Inodes use the new lock
Also remove old lock from TTY since it can just use the one Inode
already has.
2023-12-07 13:19:12 +02:00
Bananymous 39170a437e Kernel: Implement RecursivePrioritySpinLock
This locks won't allow locking from userspace thread if there is
kernel thread waiting to lock this.
2023-12-07 13:18:21 +02:00
8 changed files with 105 additions and 55 deletions

View File

@ -121,9 +121,10 @@ namespace Kernel
virtual BAN::ErrorOr<void> chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual bool has_data_impl() const { dwarnln("nonblock not supported"); return true; }
private:
mutable RecursiveSpinLock m_lock;
protected:
mutable RecursivePrioritySpinLock m_lock;
private:
BAN::WeakPtr<SharedFileData> m_shared_region;
friend class FileBackedRegion;
};

View File

@ -29,8 +29,6 @@ namespace Kernel
Thread& current_thread();
static pid_t current_tid();
static bool is_valid_tid(pid_t tid);
[[noreturn]] void execute_current_thread();
[[noreturn]] void _execute_current_thread();
[[noreturn]] void delete_current_process_and_thread();

View File

@ -39,4 +39,24 @@ namespace Kernel
SpinLock m_lock;
};
}
class RecursivePrioritySpinLock
{
BAN_NON_COPYABLE(RecursivePrioritySpinLock);
BAN_NON_MOVABLE(RecursivePrioritySpinLock);
public:
RecursivePrioritySpinLock() = default;
void lock();
void unlock();
bool is_locked() const;
uint32_t lock_depth() const { return m_lock_depth; }
private:
pid_t m_locker = -1;
uint32_t m_queue_length = 0;
uint32_t m_lock_depth = 0;
SpinLock m_lock;
};
}

View File

@ -56,8 +56,6 @@ namespace Kernel
void do_backspace();
protected:
mutable Kernel::RecursiveSpinLock m_lock;
TerminalDriver::Color m_foreground { TerminalColor::BRIGHT_WHITE };
TerminalDriver::Color m_background { TerminalColor::BLACK };
termios m_termios;

View File

@ -378,26 +378,4 @@ namespace Kernel
}
}
bool Scheduler::is_valid_tid(pid_t tid)
{
CriticalScope _;
if (s_instance == nullptr)
return tid == 0;
for (auto& thread : s_instance->m_active_threads)
if (thread.thread->tid() == tid)
return true;
for (auto& thread : s_instance->m_sleeping_threads)
if (thread.thread->tid() == tid)
return true;
for (auto& thread : s_instance->m_blocking_threads)
if (thread.thread->tid() == tid)
return true;
return false;
}
}
}

View File

@ -13,7 +13,7 @@ namespace Kernel
{
CriticalScope _;
ASSERT(m_locker != tid);
if (m_locker == -1 || !Scheduler::is_valid_tid(m_locker))
if (m_locker == -1)
{
m_locker = tid;
break;
@ -48,7 +48,7 @@ namespace Kernel
m_lock_depth++;
break;
}
if (m_locker == -1 || !Scheduler::is_valid_tid(m_locker))
if (m_locker == -1)
{
m_locker = tid;
m_lock_depth = 1;
@ -80,4 +80,61 @@ namespace Kernel
return m_locker != -1;
}
void RecursivePrioritySpinLock::lock()
{
pid_t tid = Scheduler::current_tid();
bool has_priority = !Thread::current().is_userspace();
if (has_priority)
{
m_lock.lock();
m_queue_length++;
m_lock.unlock();
}
while (true)
{
m_lock.lock();
if (m_locker == tid)
{
m_lock_depth++;
break;
}
if (m_locker == -1 && (has_priority || m_queue_length == 0))
{
m_locker = tid;
m_lock_depth = 1;
break;
}
m_lock.unlock();
}
m_lock.unlock();
}
void RecursivePrioritySpinLock::unlock()
{
m_lock.lock();
ASSERT(m_lock_depth > 0);
ASSERT(m_locker == Scheduler::current_tid());
bool has_priority = !Thread::current().is_userspace();
if (has_priority)
m_queue_length--;
m_lock_depth--;
if (m_lock_depth == 0)
m_locker = -1;
m_lock.unlock();
}
bool RecursivePrioritySpinLock::is_locked() const
{
return m_locker != -1;
}
}

View File

@ -303,9 +303,13 @@ namespace Kernel
LockGuard _(m_lock);
while (!m_output.flush)
{
m_lock.unlock();
// FIXME: this is very hacky way to unlock lock temporarily
uint32_t depth = m_lock.lock_depth();
for (uint32_t i = 0; i < depth; i++)
m_lock.unlock();
bool eintr = Thread::current().block_or_eintr(m_output.semaphore);
m_lock.lock();
for (uint32_t i = 0; i < depth; i++)
m_lock.lock();
if (eintr)
return BAN::Error::from_errno(EINTR);
}

View File

@ -469,30 +469,24 @@ pid_t execute_command_no_wait(BAN::Vector<BAN::String>& args, int fd_in, int fd_
// do PATH resolution
BAN::String executable_file;
if (!args.front().empty() && args.front().front() != '.' && args.front().front() != '/')
if (!args.front().sv().contains('/'))
{
char* path_env_cstr = getenv("PATH");
if (path_env_cstr)
const char* path_env_cstr = getenv("PATH");
if (path_env_cstr == nullptr)
path_env_cstr = "";
auto path_env_list = MUST(BAN::StringView(path_env_cstr).split(':'));
for (auto path_env : path_env_list)
{
auto path_env_list = MUST(BAN::StringView(path_env_cstr).split(':'));
for (auto path_env : path_env_list)
{
BAN::String test_file = path_env;
MUST(test_file.push_back('/'));
MUST(test_file.append(args.front()));
BAN::String test_file = path_env;
MUST(test_file.push_back('/'));
MUST(test_file.append(args.front()));
struct stat st;
if (stat(test_file.data(), &st) == 0)
{
executable_file = BAN::move(test_file);
break;
}
}
if (executable_file.empty())
struct stat st;
if (stat(test_file.data(), &st) == 0)
{
fprintf(stderr, "command not found: %s\n", args.front().data());
return -1;
executable_file = BAN::move(test_file);
break;
}
}
}
@ -504,7 +498,7 @@ pid_t execute_command_no_wait(BAN::Vector<BAN::String>& args, int fd_in, int fd_
// Verify that the file exists is executable
{
struct stat st;
if (stat(executable_file.data(), &st) == -1)
if (executable_file.empty() || stat(executable_file.data(), &st) == -1)
{
fprintf(stderr, "command not found: %s\n", args.front().data());
return -1;