axf-os161 / kern / proc / pid.c
pid.c
Raw
#include <pid.h>
#include <proc_syscalls.h>
#include <syscall.h>
#include <lib.h>
#include <limits.h>
#include <types.h>
#include <kern/errno.h>
#include <machine/trapframe.h>
#include <thread.h>
#include <synch.h>
#include <addrspace.h>
#include <proc.h>
#include <current.h>
#include <spl.h>

// will need a lock
static struct pid_node *pid_head;

void pid_bootstrap(void)
{
    pid_list_lock = lock_create("pid_list_lock");
    if(pid_list_lock == NULL)
    {
        panic("could not create pid list lock!");
    }
}

static struct child_node * child_node_create(pid_t pid)
{
    struct child_node* new_node = kmalloc(sizeof(struct child_node));
    
    if (new_node == NULL) {
        return NULL;
    }
    
    new_node->pid = pid;
    new_node->next = NULL;
    return new_node;
}

static struct pid_node * pid_node_create(pid_t pid)
{
        struct pid_node * new_node = kmalloc(sizeof(struct pid_node));
        if (new_node == NULL) {
            return NULL;
        }

        new_node->pid_cv = cv_create("pid_cv");
        if (new_node->pid_cv == NULL) {
            kfree(new_node->pid_cv);
            return NULL;
        }

        new_node->pid = pid;
        new_node->next = NULL;
        new_node->parent_pid = INVALID_PID;
        new_node->finished = false;
        new_node->child_list = NULL;
        return new_node;

}

// This will require checks to see if it is safe to remove
int pid_remove(pid_t pid)
{
    lock_acquire(pid_list_lock);
    struct pid_node *last = NULL;
    struct pid_node *current = pid_head;

    while(current != NULL)
    {
        if(current->pid == pid)
        {
            if(last != NULL)
            {
                last->next = current->next;
            }

            while(current->child_list != NULL)
            {
                struct child_node *child = current->child_list;
                current->child_list = current->child_list->next;
                kfree(child);
            }

            if(current->parent_pid != INVALID_PID)
            {
                pid_remove_child(current->pid, current->parent_pid);
            }

            cv_destroy(current->pid_cv);
            kfree(current);

            lock_release(pid_list_lock);
            return 0;
        }

        last = current;
        current = current->next;
    }

    // node with pid not found
    lock_release(pid_list_lock);
    return -1;
}

int pid_insert_kern(pid_t * pid)
{
    KASSERT(pid_head == NULL);

    struct pid_node *kern_node = pid_node_create(PID_KERN);
    if (kern_node == NULL) {
        return ENOMEM;
    }

    pid_head = kern_node;
    *pid = kern_node->pid;

    return 0;
}

int pid_insert(pid_t * pid)
{
    // while(!pid_list_lock->lk_free);
    lock_acquire(pid_list_lock);
    struct pid_node *search_node = pid_head;
    struct pid_node *new_node;
    struct pid_node *search_node_last = search_node;
    uint16_t linked_list_entries = 1;
    
    while(search_node != NULL)
    {
        if(linked_list_entries >= PID_MAX)
        {
            lock_release(pid_list_lock);
            return ENPROC;
        }

        // insert at tail if reached end of list
        if(search_node->next == NULL)
        {
            new_node = pid_node_create(search_node->pid + 1);
            if (new_node == NULL) {
                lock_release(pid_list_lock);
                return ENOMEM;
            }

            search_node->next = new_node;
            *pid = new_node->pid;
            lock_release(pid_list_lock);
            return 0;
        }
        // Insert between nodes if space
        else if (search_node->pid - search_node_last->pid > 1)
        {
            new_node = pid_node_create(search_node_last->pid + 1);
            if (new_node == NULL) {
                lock_release(pid_list_lock);
                return ENOMEM;
            }

            new_node->next = search_node;
            search_node_last->next = new_node;
            *pid = new_node->pid;
            lock_release(pid_list_lock);
            return 0;
        }

        search_node_last = search_node;
        search_node = search_node->next;

        linked_list_entries++;
    }

    lock_release(pid_list_lock);
    return ENOMEM;
}

struct pid_node* pid_get_node(pid_t pid)
{
    KASSERT(lock_do_i_hold(pid_list_lock));

    struct pid_node *search_node = pid_head;

    while(search_node != NULL)
    {
        if(search_node->pid == pid)
        {
            return search_node;
        }

        search_node = search_node->next;
    }

    return NULL;
}

int pid_assign_parent(pid_t child_pid, pid_t parent_pid)
{
    KASSERT(lock_do_i_hold(pid_list_lock));
    struct pid_node *current = pid_head;

    while(current != NULL)
    {
        if(current->pid == child_pid)
        {
            current->parent_pid = parent_pid;
            return 0;
        }
        current = current->next;
    }
    return -1;
}

int pid_assign_child(pid_t child_pid, pid_t parent_pid)
{
    KASSERT(lock_do_i_hold(pid_list_lock));

    struct pid_node *parent = pid_get_node(parent_pid);

    if(parent == NULL)
    {
        return -1;
    }

    // Insert at head if empty
    if(parent->child_list == NULL)
    {
            parent->child_list = child_node_create(child_pid);
            
            if (parent->child_list == NULL) {
                return ENOMEM;
            }

            return 0;
    }

    struct child_node *search_node = parent->child_list;

    while(search_node != NULL)
    {
        // insert at tail
        if(search_node->next == NULL)
        {
            search_node->next = child_node_create(child_pid);
            if (search_node->next == NULL) {
                return ENOMEM;
            }

            return 0;
        }

        search_node = search_node->next;
    }

    return -1;
}

int pid_remove_child(pid_t child_pid, pid_t parent_pid)
{
    KASSERT(lock_do_i_hold(pid_list_lock));

    struct pid_node *parent = pid_get_node(parent_pid);

    if(parent == NULL)
    {
        return -1;
    }

    if(parent->child_list == NULL)
    {
        return -1;
    }

    struct child_node *search_node = parent->child_list;
    struct child_node *last_node = NULL;
    struct pid_node *child;

    while(search_node != NULL)
    {
        if(search_node->pid == child_pid)
        {
            if(last_node != NULL)
            {
                last_node->next = search_node->next;
            }
            else
            {
                parent->child_list = search_node->next;
            }

            child = pid_get_node(search_node->pid);
            if(child!= NULL)
            {
                child->parent_pid = INVALID_PID;
            }
            kfree(search_node);
            return 0;
        }

        last_node = search_node;
        search_node = search_node->next;
    }

    return -1;
}

bool pid_is_child(pid_t child_pid, pid_t parent_pid)
{
    struct pid_node *parent = pid_head;

    while(parent != NULL)
    {
        if(parent->pid == parent_pid)
        {
            break;
        }
        parent = parent->next;
    }

    if(parent->pid != parent_pid)
    {
        return false;
    }

    struct child_node *search_node = parent->child_list;

    while(search_node != NULL)
    {
        // insert at tail
        if(search_node->pid == child_pid)
        {
            return true;
        }

        search_node = search_node->next;
    }

    return false;
}