1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 06:47:34 +00:00

Kernel: PID/PGID typing

This compiles, and fixes two bugs:
- setpgid() confusion (see previous commit)
- tcsetpgrp() now allows to set a non-empty process group even if
  the group leader has already died. This makes Serenity slightly
  more POSIX-compatible.
This commit is contained in:
Ben Wiederhake 2020-08-08 22:04:20 +02:00 committed by Andreas Kling
parent f5744a6f2f
commit 7bdf54c837
7 changed files with 53 additions and 46 deletions

View file

@ -822,9 +822,9 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
} }
process_object.add("pid", process.pid().value()); process_object.add("pid", process.pid().value());
process_object.add("pgid", process.tty() ? process.tty()->pgid() : 0); process_object.add("pgid", process.tty() ? process.tty()->pgid().value() : 0);
process_object.add("pgp", process.pgid()); process_object.add("pgp", process.pgid().value());
process_object.add("sid", process.sid()); process_object.add("sid", process.sid().value());
process_object.add("uid", process.uid()); process_object.add("uid", process.uid());
process_object.add("gid", process.gid()); process_object.add("gid", process.gid());
process_object.add("ppid", process.ppid().value()); process_object.add("ppid", process.ppid().value());

View file

@ -100,7 +100,8 @@ ProcessID Process::allocate_pid()
// Overflow is UB, and negative PIDs wreck havoc. // Overflow is UB, and negative PIDs wreck havoc.
// TODO: Handle PID overflow // TODO: Handle PID overflow
// For example: Use an Atomic<u32>, mask the most significant bit, // For example: Use an Atomic<u32>, mask the most significant bit,
// retry if PID is already taken as a PID, taken as a TID, or zero. // retry if PID is already taken as a PID, taken as a TID,
// takes as a PGID, taken as a SID, or zero.
return next_pid.fetch_add(1, AK::MemoryOrder::memory_order_acq_rel); return next_pid.fetch_add(1, AK::MemoryOrder::memory_order_acq_rel);
} }

View file

@ -153,11 +153,14 @@ public:
const PageDirectory& page_directory() const { return *m_page_directory; } const PageDirectory& page_directory() const { return *m_page_directory; }
static RefPtr<Process> from_pid(ProcessID); static RefPtr<Process> from_pid(ProcessID);
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
const String& name() const { return m_name; } const String& name() const { return m_name; }
ProcessID pid() const { return m_pid; } ProcessID pid() const { return m_pid; }
pid_t sid() const { return m_sid; } SessionID sid() const { return m_sid; }
pid_t pgid() const { return m_pgid; } bool is_session_leader() const { return m_sid.value() == m_pid.value(); }
ProcessGroupID pgid() const { return m_pgid; }
bool is_group_leader() const { return m_pgid.value() == m_pid.value(); }
const FixedArray<gid_t>& extra_gids() const { return m_extra_gids; } const FixedArray<gid_t>& extra_gids() const { return m_extra_gids; }
uid_t euid() const { return m_euid; } uid_t euid() const { return m_euid; }
gid_t egid() const { return m_egid; } gid_t egid() const { return m_egid; }
@ -179,7 +182,7 @@ public:
template<typename Callback> template<typename Callback>
static void for_each(Callback); static void for_each(Callback);
template<typename Callback> template<typename Callback>
static void for_each_in_pgrp(pid_t, Callback); static void for_each_in_pgrp(ProcessGroupID, Callback);
template<typename Callback> template<typename Callback>
void for_each_child(Callback); void for_each_child(Callback);
template<typename Callback> template<typename Callback>
@ -617,8 +620,8 @@ private:
String m_name; String m_name;
ProcessID m_pid { 0 }; ProcessID m_pid { 0 };
pid_t m_sid { 0 }; SessionID m_sid { 0 };
pid_t m_pgid { 0 }; ProcessGroupID m_pgid { 0 };
uid_t m_euid { 0 }; uid_t m_euid { 0 };
gid_t m_egid { 0 }; gid_t m_egid { 0 };
@ -772,7 +775,7 @@ inline void Process::for_each_thread(Callback callback) const
} }
template<typename Callback> template<typename Callback>
inline void Process::for_each_in_pgrp(pid_t pgid, Callback callback) inline void Process::for_each_in_pgrp(ProcessGroupID pgid, Callback callback)
{ {
ASSERT_INTERRUPTS_DISABLED(); ASSERT_INTERRUPTS_DISABLED();
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);

View file

@ -52,7 +52,8 @@ KResult Process::do_killpg(pid_t pgrp, int signal)
// Send the signal to all processes in the given group. // Send the signal to all processes in the given group.
if (pgrp == 0) { if (pgrp == 0) {
// Send the signal to our own pgrp. // Send the signal to our own pgrp.
pgrp = pgid(); // FIXME: PIF/PGID INCOMPLETE
pgrp = pgid().value();
} }
bool group_was_empty = true; bool group_was_empty = true;

View file

@ -33,14 +33,14 @@ pid_t Process::sys$getsid(pid_t pid)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (pid == 0) if (pid == 0)
return m_sid; return m_sid.value();
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return -ESRCH;
if (m_sid != process->m_sid) if (m_sid != process->m_sid)
return -EPERM; return -EPERM;
return process->m_sid; return process->m_sid.value();
} }
pid_t Process::sys$setsid() pid_t Process::sys$setsid()
@ -48,44 +48,49 @@ pid_t Process::sys$setsid()
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
InterruptDisabler disabler; InterruptDisabler disabler;
bool found_process_with_same_pgid_as_my_pid = false; bool found_process_with_same_pgid_as_my_pid = false;
// FIXME: PID/PGID ISSUE?
Process::for_each_in_pgrp(pid().value(), [&](auto&) { Process::for_each_in_pgrp(pid().value(), [&](auto&) {
found_process_with_same_pgid_as_my_pid = true; found_process_with_same_pgid_as_my_pid = true;
return IterationDecision::Break; return IterationDecision::Break;
}); });
if (found_process_with_same_pgid_as_my_pid) if (found_process_with_same_pgid_as_my_pid)
return -EPERM; return -EPERM;
// Create a new Session and a new ProcessGroup.
m_sid = m_pid.value(); m_sid = m_pid.value();
m_pgid = m_pid.value(); m_pgid = m_pid.value();
m_tty = nullptr; m_tty = nullptr;
return m_sid; return m_sid.value();
} }
pid_t Process::sys$getpgid(pid_t pid) pid_t Process::sys$getpgid(pid_t pid)
{ {
REQUIRE_PROMISE(proc); REQUIRE_PROMISE(proc);
if (pid == 0) if (pid == 0)
return m_pgid; return m_pgid.value();
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
auto process = Process::from_pid(pid); auto process = Process::from_pid(pid);
if (!process) if (!process)
return -ESRCH; return -ESRCH;
return process->m_pgid; return process->m_pgid.value();
} }
pid_t Process::sys$getpgrp() pid_t Process::sys$getpgrp()
{ {
REQUIRE_PROMISE(stdio); REQUIRE_PROMISE(stdio);
return m_pgid; return m_pgid.value();
} }
static pid_t get_sid_from_pgid(pid_t pgid) SessionID Process::get_sid_from_pgid(ProcessGroupID pgid)
{ {
// FIXME: This xor sys$setsid() uses the wrong locking mechanism.
ScopedSpinLock lock(g_processes_lock); ScopedSpinLock lock(g_processes_lock);
auto group_leader = Process::from_pid(pgid);
if (!group_leader) SessionID sid { -1 };
return -1; Process::for_each_in_pgrp(pgid, [&](auto& process) {
return group_leader->sid(); sid = process.sid();
return IterationDecision::Break;
});
return sid;
} }
int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid) int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
@ -105,7 +110,7 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
// of the calling process or of a child process of the calling process. // of the calling process or of a child process of the calling process.
return -ESRCH; return -ESRCH;
} }
if (process->pid() == process->sid()) { if (process->is_session_leader()) {
// The process indicated by the pid argument is a session leader. // The process indicated by the pid argument is a session leader.
return -EPERM; return -EPERM;
} }
@ -116,10 +121,9 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
return -EPERM; return -EPERM;
} }
// FIXME: PID/PGID INCOMPLETE ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->m_pid.value();
pid_t new_pgid = specified_pgid ? specified_pgid : process->m_pid.value(); SessionID current_sid = sid();
pid_t current_sid = get_sid_from_pgid(process->m_pgid); SessionID new_sid = get_sid_from_pgid(new_pgid);
pid_t new_sid = get_sid_from_pgid(new_pgid);
if (current_sid != new_sid) { if (current_sid != new_sid) {
// Can't move a process between sessions. // Can't move a process between sessions.
return -EPERM; return -EPERM;

View file

@ -159,6 +159,7 @@ void TTY::emit(u8 ch)
if (auto parent = Process::from_pid(m_process->ppid())) if (auto parent = Process::from_pid(m_process->ppid()))
(void)parent->send_signal(SIGCHLD, m_process); (void)parent->send_signal(SIGCHLD, m_process);
} }
// TODO: Else send it to the session leader maybe?
return; return;
} }
} }
@ -253,7 +254,7 @@ void TTY::generate_signal(int signal)
return; return;
if (should_flush_on_signal()) if (should_flush_on_signal())
flush_input(); flush_input();
dbg() << tty_name() << ": Send signal " << signal << " to everyone in pgrp " << pgid(); dbg() << tty_name() << ": Send signal " << signal << " to everyone in pgrp " << pgid().value();
InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead? InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
Process::for_each_in_pgrp(pgid(), [&](auto& process) { Process::for_each_in_pgrp(pgid(), [&](auto& process) {
dbg() << tty_name() << ": Send signal " << signal << " to " << process; dbg() << tty_name() << ": Send signal " << signal << " to " << process;
@ -291,7 +292,6 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
{ {
REQUIRE_PROMISE(tty); REQUIRE_PROMISE(tty);
auto& current_process = *Process::current(); auto& current_process = *Process::current();
pid_t pgid;
termios* user_termios; termios* user_termios;
winsize* user_winsize; winsize* user_winsize;
@ -304,23 +304,21 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
#endif #endif
switch (request) { switch (request) {
case TIOCGPGRP: case TIOCGPGRP:
return this->pgid(); return this->pgid().value();
case TIOCSPGRP: case TIOCSPGRP: {
pgid = static_cast<pid_t>(arg); ProcessGroupID pgid = static_cast<pid_t>(arg);
if (pgid <= 0) if (pgid <= 0)
return -EINVAL; return -EINVAL;
{ InterruptDisabler disabler;
InterruptDisabler disabler; auto process = Process::from_pid(pgid.value());
auto process = Process::from_pid(pgid); SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
if (!process) if (!new_sid || new_sid != current_process.sid())
return -EPERM; return -EPERM;
if (pgid != process->pgid()) if (process && pgid != process->pgid())
return -EPERM; return -EPERM;
if (current_process.sid() != process->sid()) m_process = process ? process->make_weak_ptr() : WeakPtr<Process>();
return -EPERM;
m_process = process->make_weak_ptr();
}
return 0; return 0;
}
case TCGETS: { case TCGETS: {
user_termios = reinterpret_cast<termios*>(arg); user_termios = reinterpret_cast<termios*>(arg);
if (!current_process.validate_write(user_termios, sizeof(termios))) if (!current_process.validate_write(user_termios, sizeof(termios)))
@ -395,7 +393,7 @@ void TTY::hang_up()
generate_signal(SIGHUP); generate_signal(SIGHUP);
} }
pid_t TTY::pgid() const ProcessGroupID TTY::pgid() const
{ {
return m_process ? m_process->pgid() : 0; return m_process ? m_process->pgid() : 0;
} }

View file

@ -50,7 +50,7 @@ public:
unsigned short rows() const { return m_rows; } unsigned short rows() const { return m_rows; }
unsigned short columns() const { return m_columns; } unsigned short columns() const { return m_columns; }
pid_t pgid() const; ProcessGroupID pgid() const;
void set_termios(const termios&); void set_termios(const termios&);
bool should_generate_signals() const { return m_termios.c_lflag & ISIG; } bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }