#include "idle.h"
#include "proc_struct.h"
#include <vm.h>
#include <kmalloc.h>
#include <string_table.h>
#include <slab.h>
#include <cache_struct.h>
#include <errno.h>
#include <enums.h>
#include <stddef.h>
#define HASH_TABLE_SIZE 37
static struct proc_struct *proc_table[HASH_TABLE_SIZE];
static struct proc_group_struct *proc_group_table[HASH_TABLE_SIZE];
static inline unsigned int hash(int pid)
{
return pid % HASH_TABLE_SIZE;
}
void proc_table_init()
{
struct proc_struct **proc_table_entry;
struct proc_group_struct **proc_group_table_entry;
proc_table_entry = proc_table;
proc_group_table_entry = proc_group_table;
while (proc_table_entry < proc_table + HASH_TABLE_SIZE)
*proc_table_entry++ = NULL, *proc_group_table_entry++ = NULL;
idle->id = 0;
idle->proc_table_next = NULL;
proc_table[hash(0)] = idle;
}
struct proc_struct *get_proc(int pid)
{
struct proc_struct *p;
p = proc_table[hash(pid)];
while (p) {
if (p->id == pid)
return p;
p = p->proc_table_next;
}
return NULL;
}
struct proc_group_struct *get_proc_group(int pgid)
{
struct proc_group_struct *pg;
pg = proc_group_table[hash(pgid)];
while (pg) {
if (pg->id == pgid)
return pg;
pg = pg->proc_group_table_next;
}
return NULL;
}
static inline int exists(int pid)
{
return get_proc(pid) || get_proc_group(pid);
}
static int generate_pid()
{
static int next_pid = 1;
int pid;
do {
pid = next_pid;
next_pid < PID_MAX ? next_pid++ : (next_pid = 1);
}
while (exists(pid));
return pid;
}
void proc_table_add(struct proc_struct *proc)
{
unsigned int hash_code;
proc->id = generate_pid();
hash_code = hash(proc->id);
proc->proc_table_next = proc_table[hash_code];
proc_table[hash_code] = proc;
}
void proc_table_remove(struct proc_struct *proc)
{
unsigned int hash_code;
struct proc_struct *p;
hash_code = hash(proc->id);
p = proc_table[hash_code];
if (p == proc)
proc_table[hash_code] = proc->proc_table_next;
else {
while (p->proc_table_next != proc)
p = p->proc_table_next;
p->proc_table_next = proc->proc_table_next;
}
}
static void proc_group_table_add(struct proc_group_struct *proc_group, int pgid)
{
unsigned int hash_code;
proc_group->id = pgid;
hash_code = hash(proc_group->id);
proc_group->proc_group_table_next = proc_group_table[hash_code];
proc_group_table[hash_code] = proc_group;
}
static void proc_group_table_remove(struct proc_group_struct *proc_group)
{
unsigned int hash_code;
struct proc_group_struct *pg;
hash_code = hash(proc_group->id);
pg = proc_group_table[hash_code];
if (pg == proc_group)
proc_group_table[hash_code] = proc_group->proc_group_table_next;
else {
while (pg->proc_group_table_next != proc_group)
pg = pg->proc_group_table_next;
pg->proc_group_table_next = proc_group->proc_group_table_next;
}
}
struct proc_struct *proc_list_first;
static unsigned short proc_list_count;
void proc_list_init()
{
idle->proc_list_previous = NULL;
idle->proc_list_next = NULL;
proc_list_first = idle;
proc_list_count = 1;
}
void proc_list_add(struct proc_struct *proc)
{
proc->proc_list_previous = NULL;
proc->proc_list_next = proc_list_first;
proc_list_first = proc;
if (proc->proc_list_next)
proc->proc_list_next->proc_list_previous = proc;
proc_list_count++;
}
void proc_list_remove(struct proc_struct *proc)
{
if (proc->proc_list_previous)
proc->proc_list_previous->proc_list_next = proc->proc_list_next;
else
proc_list_first = proc->proc_list_next;
if (proc->proc_list_next)
proc->proc_list_next->proc_list_previous = proc->proc_list_previous;
proc_list_count--;
}
void proc_tree_init()
{
idle->parent = NULL;
idle->next_sibling = NULL;
idle->first_child = NULL;
}
void proc_tree_add(struct proc_struct *proc, struct proc_struct *parent)
{
proc->parent = parent;
proc->next_sibling = parent->first_child;
proc->first_child = NULL;
parent->first_child = proc;
}
void proc_tree_dishinerit_children(struct proc_struct *proc)
{
struct proc_struct *p;
if (proc->first_child) {
p = proc->first_child;
p->parent = idle;
while (p->next_sibling) {
p->next_sibling->parent = idle;
p = p->next_sibling;
}
p->next_sibling = idle->first_child;
idle->first_child = proc->first_child;
}
}
void proc_tree_remove(struct proc_struct *proc)
{
struct proc_struct *p;
if (proc == proc->parent->first_child)
proc->parent->first_child = proc->next_sibling;
else {
p = proc->parent->first_child;
while (p->next_sibling != proc)
p = p->next_sibling;
p->next_sibling = proc->next_sibling;
}
}
static struct proc_group_struct idle_group;
static struct cache_struct prog_group_cache;
void proc_group_init()
{
proc_group_table_add(&idle_group, 0);
idle->group = &idle_group;
idle->group_next = NULL;
idle_group.first_proc = idle;
kmem_cache_init(&prog_group_cache, sizeof (struct proc_group_struct));
}
static struct proc_group_struct *alloc_proc_group(int pgid)
{
struct proc_group_struct *proc_group;
if (!(proc_group = kmem_cache_alloc(&prog_group_cache)))
return NULL;
proc_group_table_add(proc_group, pgid);
proc_group->first_proc = NULL;
return proc_group;
}
static void free_proc_group(struct proc_group_struct *proc_group)
{
proc_group_table_remove(proc_group);
kmem_cache_free(&prog_group_cache, proc_group);
}
static void add_proc(struct proc_group_struct *proc_group, struct proc_struct *proc)
{
proc->group = proc_group;
proc->group_next = proc_group->first_proc;
proc_group->first_proc = proc;
}
static void remove_proc(struct proc_struct *proc)
{
struct proc_group_struct *proc_group;
struct proc_struct *p;
proc_group = proc->group;
if (proc_group->first_proc == proc) {
proc_group->first_proc = proc->group_next;
if (!proc_group->first_proc)
free_proc_group(proc_group);
}
else
for (p = proc_group->first_proc; p->group_next; p = p->group_next)
if (p->group_next == proc) {
p->group_next = proc->group_next;
return;
}
}
int proc_create_proc_group(struct proc_struct *proc)
{
struct proc_group_struct *proc_group;
if (!(proc_group = alloc_proc_group(proc->id)))
return -ENOMEM;
add_proc(proc_group, proc);
return 0;
}
void proc_group_add(struct proc_struct *proc, struct proc_group_struct *proc_group)
{
add_proc(proc_group, proc);
}
void proc_group_remove(struct proc_struct *proc)
{
remove_proc(proc);
}
void proc_change_set_proc_group(struct proc_struct *proc, struct proc_group_struct *proc_group)
{
remove_proc(proc);
add_proc(proc_group, proc);
}
int proc_change_create_proc_group(struct proc_struct *proc)
{
struct proc_group_struct *proc_group;
if (!(proc_group = alloc_proc_group(proc->id)))
return -ENOMEM;
remove_proc(proc);
add_proc(proc_group, proc);
return 0;
}
int is_orphan(const struct proc_struct *proc)
{
return proc->parent == idle;
}
int proc_get_pid_table(int **pid_table, unsigned int *size)
{
int *pid;
const struct proc_struct *p;
if (!(*pid_table = kmalloc(proc_list_count * sizeof (int))))
return -ENOMEM;
pid = *pid_table;
for (p = proc_list_first; p; p = p->proc_list_next)
*pid++ = p->id;
*size = proc_list_count;
return 0;
}
int proc_get_ppid_pid(int pid, int *ppid)
{
const struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -EINVAL;
*ppid = proc == idle ? 0 : proc->parent->id;
return 0;
}
int proc_get_pgid_pid(int pid, int *pgid)
{
const struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -EINVAL;
*pgid = proc->group->id;
return 0;
}
int proc_get_state_pid(int pid, int *state)
{
const struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -EINVAL;
*state = proc->state;
return 0;
}
int proc_get_cmdline_pid(int pid, struct string_table_struct *cmdline)
{
static const struct string_table_struct zombie_cmdline = {0, NULL, 0};
const struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -EINVAL;
return string_table_clone(proc->state != PS_ZOMBIE ? &proc->cmdline : &zombie_cmdline, cmdline);
}
int proc_get_wd_pid(int pid, struct file_struct **wd)
{
const struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -EINVAL;
*wd = proc == idle || proc->state != PS_ZOMBIE ? proc->wd : NULL;
return 0;
}
int proc_get_maps(int pid, struct map_info_struct **map_info_array, unsigned int *count)
{
const struct proc_struct *proc;
if (!(proc = get_proc(pid)))
return -EINVAL;
return vm_get_maps(&proc->vm, map_info_array, count);
}