mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 01:07:35 +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:
parent
f5744a6f2f
commit
7bdf54c837
7 changed files with 53 additions and 46 deletions
|
@ -822,9 +822,9 @@ Optional<KBuffer> procfs$all(InodeIdentifier)
|
|||
}
|
||||
|
||||
process_object.add("pid", process.pid().value());
|
||||
process_object.add("pgid", process.tty() ? process.tty()->pgid() : 0);
|
||||
process_object.add("pgp", process.pgid());
|
||||
process_object.add("sid", process.sid());
|
||||
process_object.add("pgid", process.tty() ? process.tty()->pgid().value() : 0);
|
||||
process_object.add("pgp", process.pgid().value());
|
||||
process_object.add("sid", process.sid().value());
|
||||
process_object.add("uid", process.uid());
|
||||
process_object.add("gid", process.gid());
|
||||
process_object.add("ppid", process.ppid().value());
|
||||
|
|
|
@ -100,7 +100,8 @@ ProcessID Process::allocate_pid()
|
|||
// Overflow is UB, and negative PIDs wreck havoc.
|
||||
// TODO: Handle PID overflow
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -153,11 +153,14 @@ public:
|
|||
const PageDirectory& page_directory() const { return *m_page_directory; }
|
||||
|
||||
static RefPtr<Process> from_pid(ProcessID);
|
||||
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
|
||||
|
||||
const String& name() const { return m_name; }
|
||||
ProcessID pid() const { return m_pid; }
|
||||
pid_t sid() const { return m_sid; }
|
||||
pid_t pgid() const { return m_pgid; }
|
||||
SessionID sid() const { return m_sid; }
|
||||
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; }
|
||||
uid_t euid() const { return m_euid; }
|
||||
gid_t egid() const { return m_egid; }
|
||||
|
@ -179,7 +182,7 @@ public:
|
|||
template<typename Callback>
|
||||
static void for_each(Callback);
|
||||
template<typename Callback>
|
||||
static void for_each_in_pgrp(pid_t, Callback);
|
||||
static void for_each_in_pgrp(ProcessGroupID, Callback);
|
||||
template<typename Callback>
|
||||
void for_each_child(Callback);
|
||||
template<typename Callback>
|
||||
|
@ -617,8 +620,8 @@ private:
|
|||
String m_name;
|
||||
|
||||
ProcessID m_pid { 0 };
|
||||
pid_t m_sid { 0 };
|
||||
pid_t m_pgid { 0 };
|
||||
SessionID m_sid { 0 };
|
||||
ProcessGroupID m_pgid { 0 };
|
||||
|
||||
uid_t m_euid { 0 };
|
||||
gid_t m_egid { 0 };
|
||||
|
@ -772,7 +775,7 @@ inline void Process::for_each_thread(Callback callback) const
|
|||
}
|
||||
|
||||
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();
|
||||
ScopedSpinLock lock(g_processes_lock);
|
||||
|
|
|
@ -52,7 +52,8 @@ KResult Process::do_killpg(pid_t pgrp, int signal)
|
|||
// Send the signal to all processes in the given group.
|
||||
if (pgrp == 0) {
|
||||
// Send the signal to our own pgrp.
|
||||
pgrp = pgid();
|
||||
// FIXME: PIF/PGID INCOMPLETE
|
||||
pgrp = pgid().value();
|
||||
}
|
||||
|
||||
bool group_was_empty = true;
|
||||
|
|
|
@ -33,14 +33,14 @@ pid_t Process::sys$getsid(pid_t pid)
|
|||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
if (pid == 0)
|
||||
return m_sid;
|
||||
return m_sid.value();
|
||||
ScopedSpinLock lock(g_processes_lock);
|
||||
auto process = Process::from_pid(pid);
|
||||
if (!process)
|
||||
return -ESRCH;
|
||||
if (m_sid != process->m_sid)
|
||||
return -EPERM;
|
||||
return process->m_sid;
|
||||
return process->m_sid.value();
|
||||
}
|
||||
|
||||
pid_t Process::sys$setsid()
|
||||
|
@ -48,44 +48,49 @@ pid_t Process::sys$setsid()
|
|||
REQUIRE_PROMISE(proc);
|
||||
InterruptDisabler disabler;
|
||||
bool found_process_with_same_pgid_as_my_pid = false;
|
||||
// FIXME: PID/PGID ISSUE?
|
||||
Process::for_each_in_pgrp(pid().value(), [&](auto&) {
|
||||
found_process_with_same_pgid_as_my_pid = true;
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
if (found_process_with_same_pgid_as_my_pid)
|
||||
return -EPERM;
|
||||
// Create a new Session and a new ProcessGroup.
|
||||
m_sid = m_pid.value();
|
||||
m_pgid = m_pid.value();
|
||||
m_tty = nullptr;
|
||||
return m_sid;
|
||||
return m_sid.value();
|
||||
}
|
||||
|
||||
pid_t Process::sys$getpgid(pid_t pid)
|
||||
{
|
||||
REQUIRE_PROMISE(proc);
|
||||
if (pid == 0)
|
||||
return m_pgid;
|
||||
return m_pgid.value();
|
||||
ScopedSpinLock lock(g_processes_lock); // FIXME: Use a ProcessHandle
|
||||
auto process = Process::from_pid(pid);
|
||||
if (!process)
|
||||
return -ESRCH;
|
||||
return process->m_pgid;
|
||||
return process->m_pgid.value();
|
||||
}
|
||||
|
||||
pid_t Process::sys$getpgrp()
|
||||
{
|
||||
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);
|
||||
auto group_leader = Process::from_pid(pgid);
|
||||
if (!group_leader)
|
||||
return -1;
|
||||
return group_leader->sid();
|
||||
|
||||
SessionID sid { -1 };
|
||||
Process::for_each_in_pgrp(pgid, [&](auto& process) {
|
||||
sid = process.sid();
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
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.
|
||||
return -ESRCH;
|
||||
}
|
||||
if (process->pid() == process->sid()) {
|
||||
if (process->is_session_leader()) {
|
||||
// The process indicated by the pid argument is a session leader.
|
||||
return -EPERM;
|
||||
}
|
||||
|
@ -116,10 +121,9 @@ int Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid)
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
// FIXME: PID/PGID INCOMPLETE
|
||||
pid_t new_pgid = specified_pgid ? specified_pgid : process->m_pid.value();
|
||||
pid_t current_sid = get_sid_from_pgid(process->m_pgid);
|
||||
pid_t new_sid = get_sid_from_pgid(new_pgid);
|
||||
ProcessGroupID new_pgid = specified_pgid ? ProcessGroupID(specified_pgid) : process->m_pid.value();
|
||||
SessionID current_sid = sid();
|
||||
SessionID new_sid = get_sid_from_pgid(new_pgid);
|
||||
if (current_sid != new_sid) {
|
||||
// Can't move a process between sessions.
|
||||
return -EPERM;
|
||||
|
|
|
@ -159,6 +159,7 @@ void TTY::emit(u8 ch)
|
|||
if (auto parent = Process::from_pid(m_process->ppid()))
|
||||
(void)parent->send_signal(SIGCHLD, m_process);
|
||||
}
|
||||
// TODO: Else send it to the session leader maybe?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +254,7 @@ void TTY::generate_signal(int signal)
|
|||
return;
|
||||
if (should_flush_on_signal())
|
||||
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?
|
||||
Process::for_each_in_pgrp(pgid(), [&](auto& process) {
|
||||
dbg() << tty_name() << ": Send signal " << signal << " to " << process;
|
||||
|
@ -291,7 +292,6 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
|||
{
|
||||
REQUIRE_PROMISE(tty);
|
||||
auto& current_process = *Process::current();
|
||||
pid_t pgid;
|
||||
termios* user_termios;
|
||||
winsize* user_winsize;
|
||||
|
||||
|
@ -304,23 +304,21 @@ int TTY::ioctl(FileDescription&, unsigned request, FlatPtr arg)
|
|||
#endif
|
||||
switch (request) {
|
||||
case TIOCGPGRP:
|
||||
return this->pgid();
|
||||
case TIOCSPGRP:
|
||||
pgid = static_cast<pid_t>(arg);
|
||||
return this->pgid().value();
|
||||
case TIOCSPGRP: {
|
||||
ProcessGroupID pgid = static_cast<pid_t>(arg);
|
||||
if (pgid <= 0)
|
||||
return -EINVAL;
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
auto process = Process::from_pid(pgid);
|
||||
if (!process)
|
||||
return -EPERM;
|
||||
if (pgid != process->pgid())
|
||||
return -EPERM;
|
||||
if (current_process.sid() != process->sid())
|
||||
return -EPERM;
|
||||
m_process = process->make_weak_ptr();
|
||||
}
|
||||
InterruptDisabler disabler;
|
||||
auto process = Process::from_pid(pgid.value());
|
||||
SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
|
||||
if (!new_sid || new_sid != current_process.sid())
|
||||
return -EPERM;
|
||||
if (process && pgid != process->pgid())
|
||||
return -EPERM;
|
||||
m_process = process ? process->make_weak_ptr() : WeakPtr<Process>();
|
||||
return 0;
|
||||
}
|
||||
case TCGETS: {
|
||||
user_termios = reinterpret_cast<termios*>(arg);
|
||||
if (!current_process.validate_write(user_termios, sizeof(termios)))
|
||||
|
@ -395,7 +393,7 @@ void TTY::hang_up()
|
|||
generate_signal(SIGHUP);
|
||||
}
|
||||
|
||||
pid_t TTY::pgid() const
|
||||
ProcessGroupID TTY::pgid() const
|
||||
{
|
||||
return m_process ? m_process->pgid() : 0;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
unsigned short rows() const { return m_rows; }
|
||||
unsigned short columns() const { return m_columns; }
|
||||
|
||||
pid_t pgid() const;
|
||||
ProcessGroupID pgid() const;
|
||||
|
||||
void set_termios(const termios&);
|
||||
bool should_generate_signals() const { return m_termios.c_lflag & ISIG; }
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue