mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 04:07:45 +00:00
Kernel: Make Thread refcounted
Similar to Process, we need to make Thread refcounted. This will solve problems that will appear once we schedule threads on more than one processor. This allows us to hold onto threads without necessarily holding the scheduler lock for the entire duration.
This commit is contained in:
parent
079486ed7e
commit
838d9fa251
14 changed files with 136 additions and 90 deletions
|
@ -36,8 +36,10 @@ namespace Kernel {
|
|||
pid_t Process::sys$fork(RegisterState& regs)
|
||||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
Thread* child_first_thread = nullptr;
|
||||
auto* child = new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_is_kernel_process, m_cwd, m_executable, m_tty, this);
|
||||
RefPtr<Thread> child_first_thread;
|
||||
auto child = adopt(*new Process(child_first_thread, m_name, m_uid, m_gid, m_pid, m_is_kernel_process, m_cwd, m_executable, m_tty, this));
|
||||
if (!child_first_thread)
|
||||
return -ENOMEM;
|
||||
child->m_root_directory = m_root_directory;
|
||||
child->m_root_directory_relative_to_global_root = m_root_directory_relative_to_global_root;
|
||||
child->m_promises = m_promises;
|
||||
|
@ -92,6 +94,7 @@ pid_t Process::sys$fork(RegisterState& regs)
|
|||
{
|
||||
ScopedSpinLock lock(g_processes_lock);
|
||||
g_processes->prepend(child);
|
||||
child->ref(); // This reference will be dropped by Process::reap
|
||||
}
|
||||
|
||||
child_first_thread->set_affinity(Thread::current()->affinity());
|
||||
|
|
|
@ -40,8 +40,12 @@ int Process::sys$donate(pid_t tid)
|
|||
REQUIRE_PROMISE(stdio);
|
||||
if (tid < 0)
|
||||
return -EINVAL;
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
|
||||
// We don't strictly need to grab the scheduler lock here, but it
|
||||
// will close a race where we can find the thread but it disappears
|
||||
// before we call Scheduler::donate_to.
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
auto thread = Thread::from_tid(tid);
|
||||
if (!thread || thread->pid() != pid())
|
||||
return -ESRCH;
|
||||
Scheduler::donate_to(thread, "sys$donate");
|
||||
|
@ -55,8 +59,11 @@ int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> us
|
|||
if (!copy_from_user(&desired_param, user_param))
|
||||
return -EFAULT;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
if (desired_param.sched_priority < THREAD_PRIORITY_MIN || desired_param.sched_priority > THREAD_PRIORITY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
auto* peer = Thread::current();
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
if (pid != 0)
|
||||
peer = Thread::from_tid(pid);
|
||||
|
||||
|
@ -66,9 +73,6 @@ int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> us
|
|||
if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid)
|
||||
return -EPERM;
|
||||
|
||||
if (desired_param.sched_priority < THREAD_PRIORITY_MIN || desired_param.sched_priority > THREAD_PRIORITY_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
peer->set_priority((u32)desired_param.sched_priority);
|
||||
return 0;
|
||||
}
|
||||
|
@ -76,22 +80,27 @@ int Process::sys$sched_setparam(int pid, Userspace<const struct sched_param*> us
|
|||
int Process::sys$sched_getparam(pid_t pid, Userspace<struct sched_param*> user_param)
|
||||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
InterruptDisabler disabler;
|
||||
auto* peer = Thread::current();
|
||||
if (pid != 0) {
|
||||
// FIXME: PID/TID BUG
|
||||
// The entire process is supposed to be affected.
|
||||
peer = Thread::from_tid(pid);
|
||||
int priority;
|
||||
{
|
||||
auto* peer = Thread::current();
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
if (pid != 0) {
|
||||
// FIXME: PID/TID BUG
|
||||
// The entire process is supposed to be affected.
|
||||
peer = Thread::from_tid(pid);
|
||||
}
|
||||
|
||||
if (!peer)
|
||||
return -ESRCH;
|
||||
|
||||
if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid)
|
||||
return -EPERM;
|
||||
|
||||
priority = (int)peer->priority();
|
||||
}
|
||||
|
||||
if (!peer)
|
||||
return -ESRCH;
|
||||
|
||||
if (!is_superuser() && m_euid != peer->process().m_uid && m_uid != peer->process().m_uid)
|
||||
return -EPERM;
|
||||
|
||||
struct sched_param param {
|
||||
(int)peer->priority()
|
||||
priority
|
||||
};
|
||||
if (!copy_to_user(user_param, ¶m))
|
||||
return -EFAULT;
|
||||
|
@ -103,8 +112,8 @@ int Process::sys$set_thread_boost(pid_t tid, int amount)
|
|||
REQUIRE_PROMISE(proc);
|
||||
if (amount < 0 || amount > 20)
|
||||
return -EINVAL;
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
ScopedSpinLock lock(g_scheduler_lock);
|
||||
auto thread = Thread::from_tid(tid);
|
||||
if (!thread)
|
||||
return -ESRCH;
|
||||
if (thread->state() == Thread::State::Dead || thread->state() == Thread::State::Dying)
|
||||
|
|
|
@ -102,8 +102,7 @@ void Process::sys$exit_thread(Userspace<void*> exit_value)
|
|||
int Process::sys$detach_thread(pid_t tid)
|
||||
{
|
||||
REQUIRE_PROMISE(thread);
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
auto thread = Thread::from_tid(tid);
|
||||
if (!thread || thread->pid() != pid())
|
||||
return -ESRCH;
|
||||
|
||||
|
@ -118,8 +117,7 @@ int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
|
|||
{
|
||||
REQUIRE_PROMISE(thread);
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
auto thread = Thread::from_tid(tid);
|
||||
if (!thread || thread->pid() != pid())
|
||||
return -ESRCH;
|
||||
|
||||
|
@ -134,20 +132,14 @@ int Process::sys$join_thread(pid_t tid, Userspace<void**> exit_value)
|
|||
KResult try_join_result(KSuccess);
|
||||
auto result = current_thread->block<Thread::JoinBlocker>(nullptr, *thread, try_join_result, joinee_exit_value);
|
||||
if (result == Thread::BlockResult::NotBlocked) {
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
if (try_join_result.is_error())
|
||||
return try_join_result.error();
|
||||
break;
|
||||
}
|
||||
if (result == Thread::BlockResult::InterruptedByDeath) {
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
break;
|
||||
}
|
||||
if (result == Thread::BlockResult::InterruptedByDeath)
|
||||
return 0; // we're not going to return back to user mode
|
||||
}
|
||||
|
||||
// NOTE: 'thread' is very possibly deleted at this point. Clear it just to be safe.
|
||||
thread = nullptr;
|
||||
|
||||
if (exit_value && !copy_to_user(exit_value, &joinee_exit_value))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
@ -164,8 +156,7 @@ int Process::sys$set_thread_name(pid_t tid, Userspace<const char*> user_name, si
|
|||
if (name.length() > max_thread_name_size)
|
||||
return -EINVAL;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
auto thread = Thread::from_tid(tid);
|
||||
if (!thread || thread->pid() != pid())
|
||||
return -ESRCH;
|
||||
|
||||
|
@ -179,15 +170,16 @@ int Process::sys$get_thread_name(pid_t tid, Userspace<char*> buffer, size_t buff
|
|||
if (buffer_size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
InterruptDisabler disabler;
|
||||
auto* thread = Thread::from_tid(tid);
|
||||
auto thread = Thread::from_tid(tid);
|
||||
if (!thread || thread->pid() != pid())
|
||||
return -ESRCH;
|
||||
|
||||
if (thread->name().length() + 1 > (size_t)buffer_size)
|
||||
// We must make a temporary copy here to avoid a race with sys$set_thread_name
|
||||
auto thread_name = thread->name();
|
||||
if (thread_name.length() + 1 > (size_t)buffer_size)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
if (!copy_to_user(buffer, thread->name().characters(), thread->name().length() + 1))
|
||||
if (!copy_to_user(buffer, thread_name.characters(), thread_name.length() + 1))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,9 @@ KResultOr<siginfo_t> Process::do_waitid(idtype_t idtype, int id, int options)
|
|||
return reap(*waitee_process);
|
||||
} else {
|
||||
// FIXME: PID/TID BUG
|
||||
auto* waitee_thread = Thread::from_tid(waitee_pid.value());
|
||||
// Make sure to hold the scheduler lock so that we operate on a consistent state
|
||||
ScopedSpinLock scheduler_lock(g_scheduler_lock);
|
||||
auto waitee_thread = Thread::from_tid(waitee_pid.value());
|
||||
if (!waitee_thread)
|
||||
return KResult(-ECHILD);
|
||||
ASSERT((options & WNOHANG) || waitee_thread->state() == Thread::State::Stopped);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue