/* Liens entre les processus */ /* Copyright (C) 2008 Emmanuel Varoquaux This file is part of XOS. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "idle.h" #include "proc_struct.h" #include #include #include #include #include #include #include #include #define HASH_TABLE_SIZE 37 /* Table des processus */ 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); } /* Cette fonction ne peut pas echouer des lors que PID_MAX est superieur a * (2 * NR_TASKS). En effet, il peut y avoir jusqu'a NR_TASKS processus et * NR_TASKS groupes de processus. */ 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; } } /* Liste */ 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--; } /* Arborescence */ 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; /* connection des fils, orphelins, a idle */ 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; } } /* Enleve un processus de l'arborescence des processus. * Le processus ne doit pas avoir de fils. */ void proc_tree_remove(struct proc_struct *proc) { struct proc_struct *p; /* deconnection du pere */ 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; } } /* Groupes de processus */ /* Un processus doit toujours avoir un groupe. Un groupe ne doit jamais etre * vide. Les fonctions ci-dessous sont atomiques : elles garantissent ces * proprietes. */ 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)); } /* Alloue un groupe vide. */ 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; } /* Libere un groupe vide. */ 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); } /* Ajoute un processus dans un groupe. */ 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; } /* Enleve un processus d'un groupe et libere le groupe s'il devient vide. */ 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; } /* Informations sur les processus */ /* pid_table est alloue avec kmalloc() et devra-t-etre libere par l'appelant. * size est le nombre d'elements dans le tableau (et non la taille de l'espace * memoire alloue au tableau lui-meme. */ 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); }