mirror of
https://github.com/ish-app/ish.git
synced 2025-12-08 17:36:02 +00:00
202 lines
5.4 KiB
C
202 lines
5.4 KiB
C
#ifndef TASK_H
|
|
#define TASK_H
|
|
|
|
#include <pthread.h>
|
|
#include "emu/cpu.h"
|
|
#include "kernel/mm.h"
|
|
#include "kernel/fs.h"
|
|
#include "kernel/signal.h"
|
|
#include "kernel/resource.h"
|
|
#include "fs/sockrestart.h"
|
|
#include "util/list.h"
|
|
#include "util/timer.h"
|
|
#include "util/sync.h"
|
|
|
|
// everything here is private to the thread executing this task and needs no
|
|
// locking, unless otherwise specified
|
|
struct task {
|
|
struct cpu_state cpu;
|
|
struct mm *mm; // locked by general_lock
|
|
struct mem *mem; // pointer to mm.mem, for convenience
|
|
pthread_t thread;
|
|
uint64_t threadid;
|
|
|
|
struct tgroup *group; // immutable
|
|
struct list group_links;
|
|
pid_t_ pid, tgid; // immutable
|
|
uid_t_ uid, gid;
|
|
uid_t_ euid, egid;
|
|
uid_t_ suid, sgid;
|
|
#define MAX_GROUPS 32
|
|
unsigned ngroups;
|
|
uid_t_ groups[MAX_GROUPS];
|
|
char comm[16] __strncpy_safe; // locked by general_lock
|
|
bool did_exec; // for that one annoying setsid edge case
|
|
|
|
struct fdtable *files;
|
|
struct fs_info *fs;
|
|
|
|
// locked by sighand->lock
|
|
struct sighand *sighand;
|
|
sigset_t_ blocked;
|
|
sigset_t_ pending;
|
|
sigset_t_ waiting; // if nonzero, an ongoing call to sigtimedwait is waiting on these
|
|
struct list queue;
|
|
cond_t pause; // please don't signal this
|
|
// private
|
|
sigset_t_ saved_mask;
|
|
bool has_saved_mask;
|
|
|
|
struct {
|
|
// Locks all ptrace-related things
|
|
lock_t lock;
|
|
cond_t cond;
|
|
|
|
bool traced;
|
|
bool stopped;
|
|
int signal;
|
|
struct siginfo_ info;
|
|
int trap_event;
|
|
} ptrace;
|
|
|
|
// locked by pids_lock
|
|
struct task *parent;
|
|
struct list children;
|
|
struct list siblings;
|
|
|
|
addr_t clear_tid;
|
|
addr_t robust_list;
|
|
|
|
// locked by pids_lock
|
|
dword_t exit_code;
|
|
bool zombie;
|
|
bool exiting;
|
|
|
|
// this structure is allocated on the stack of the parent's clone() call
|
|
struct vfork_info {
|
|
bool done;
|
|
cond_t cond;
|
|
lock_t lock;
|
|
} *vfork;
|
|
int exit_signal;
|
|
|
|
// lock for anything that needs locking but is not covered by some other lock
|
|
// specifically: comm, mm
|
|
lock_t general_lock;
|
|
|
|
struct task_sockrestart sockrestart;
|
|
|
|
// current condition/lock, so it can be notified in case of a signal
|
|
cond_t *waiting_cond;
|
|
lock_t *waiting_lock;
|
|
lock_t waiting_cond_lock;
|
|
};
|
|
|
|
// current will always give the process that is currently executing
|
|
// if I have to stop using __thread, current will become a macro
|
|
extern __thread struct task *current;
|
|
|
|
static inline void task_set_mm(struct task *task, struct mm *mm) {
|
|
task->mm = mm;
|
|
task->mem = &task->mm->mem;
|
|
task->cpu.mmu = &task->mem->mmu;
|
|
}
|
|
|
|
// Creates a new process, initializes most fields from the parent. Specify
|
|
// parent as NULL to create the init process. Returns NULL if out of memory.
|
|
// Ends with an underscore because there's a mach function by the same name
|
|
struct task *task_create_(struct task *parent);
|
|
// Removes the process from the process table and frees it. Must be called with pids_lock.
|
|
void task_destroy(struct task *task);
|
|
|
|
// misc
|
|
void vfork_notify(struct task *task);
|
|
pid_t_ task_setsid(struct task *task);
|
|
void task_leave_session(struct task *task);
|
|
|
|
struct posix_timer {
|
|
struct timer *timer;
|
|
int_t timer_id;
|
|
struct tgroup *tgroup;
|
|
pid_t_ thread_pid;
|
|
int_t signal;
|
|
union sigval_ sig_value;
|
|
};
|
|
|
|
// struct thread_group is way too long to type comfortably
|
|
struct tgroup {
|
|
struct list threads; // locked by pids_lock, by majority vote
|
|
struct task *leader; // immutable
|
|
struct rusage_ rusage;
|
|
|
|
// locked by pids_lock
|
|
pid_t_ sid, pgid;
|
|
struct list session;
|
|
struct list pgroup;
|
|
|
|
bool stopped;
|
|
cond_t stopped_cond;
|
|
|
|
struct tty *tty;
|
|
struct timer *itimer;
|
|
#define TIMERS_MAX 16
|
|
struct posix_timer posix_timers[TIMERS_MAX];
|
|
|
|
struct rlimit_ limits[RLIMIT_NLIMITS_];
|
|
|
|
// From https://twitter.com/tblodt/status/957706819236904960
|
|
// > there are two distinct ways for a p̶r̶o̶c̶e̶s̶s̶ thread group to exit:
|
|
// >
|
|
// > - each thread calls exit
|
|
// > wait will return the exit code for the group leader
|
|
// >
|
|
// > - any thread calls exit_group
|
|
// > the SIGNAL_GROUP_EXIT flag will be set and wait will return the status passed to exit_group
|
|
//
|
|
// TODO locking
|
|
bool doing_group_exit;
|
|
dword_t group_exit_code;
|
|
|
|
struct rusage_ children_rusage;
|
|
cond_t child_exit;
|
|
|
|
dword_t personality;
|
|
|
|
// for everything in this struct not locked by something else
|
|
lock_t lock;
|
|
};
|
|
|
|
static inline bool task_is_leader(struct task *task) {
|
|
return task->group->leader == task;
|
|
}
|
|
|
|
struct pid {
|
|
dword_t id;
|
|
struct task *task;
|
|
struct list session;
|
|
struct list pgroup;
|
|
};
|
|
|
|
// synchronizes obtaining a pointer to a task and freeing that task
|
|
extern lock_t pids_lock;
|
|
// these functions must be called with pids_lock
|
|
struct pid *pid_get(dword_t pid);
|
|
struct task *pid_get_task(dword_t pid);
|
|
struct task *pid_get_task_zombie(dword_t id); // don't return null if the task exists as a zombie
|
|
|
|
#define MAX_PID (1 << 15) // oughta be enough
|
|
|
|
// TODO document
|
|
void task_start(struct task *task);
|
|
void task_run_current(void);
|
|
|
|
extern void (*exit_hook)(struct task *task, int code);
|
|
|
|
#define superuser() (current != NULL && current->euid == 0)
|
|
|
|
// Update the thread name to match the current task, in the format "comm-pid".
|
|
// Will ensure that the -pid part always fits, then will fit as much of comm as possible.
|
|
void update_thread_name(void);
|
|
|
|
#endif
|