LoGin 1496ba7b24
进程管理模块重构完成 (#380)
* 添加新版pcb的数据结构 (#273)

* 将pcb中的内容分类,分别加锁 (#305)

* 进程管理重构:完成fork的主体逻辑 (#309)

1.完成fork的主体逻辑
2.将文件系统接到新的pcb上
3.经过思考,暂时弃用signal机制,待进程管理重构完成后,重写signal机制.原因是原本的signal机制太烂了

* chdir getcwd pid pgid ppid (#310)


---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* 删除旧的fork以及signal的代码,并调整fork/vfork/execve系统调用 (#325)

1.删除旧的fork
2.删除signal相关代码,等进程管理重构结束之后,再重新写.
3.调整了fork/vfork/execve系统调用

* 实现切换进程的代码 (#331)



* 实现切换进程的代码

* Patch modify preempt (#332)

* 修改设置preempt的代码

* 删除rust的list和refcount

* 为每个核心初始化idle进程 (#333)

* 为每个核心初始化idle进程

* 完成了新的内核线程机制 (#335)

* 调度器的pcb替换为新的Arc<ProcessControlBlock>,把调度器队列锁从 RwSpinLock 替换为了 SpinLock (#336)

* 把调度器的pcb替换为新的Arc<ProcessControlBlock>

* 把调度器队列锁从 RwSpinLock 替换为了 SpinLock ,修改了签名以通过编译

* 修正一些双重加锁、细节问题

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* github workflow自动检查代码是否格式化

* cache toolchain yml

* 调整rust版本的waitqueue中的pcb为新版的pcb (#343)

* 解决设置rust workspace带来的“工具链不一致”的问题 (#344)


* 解决设置rust workspace带来的“工具链不一致”的问题

更改workflow

* 调整pcb的sched_info和rwlock,以避免调度器死锁问题 (#341)

* 调整pcb的sched_info和rwlock,以避免调度器死锁问题

* 修改为在 WriterGuard 中维护 Irq_guard

* 修正了 write_irqsave方法

* 优化了代码

* 把 set state 操作从 wakup 移动到 sched_enqueue 中

* 修正为在 wakeup 中设置 running ,以保留 set_state 的私有性

* 移除了 process_wakeup

* 实现进程退出的逻辑 (#340)

实现进程退出的逻辑

* 标志进程sleep

* 修复wakeup的问题

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* rust 重构 completion (#350)

* 完成了completion的基本结构,待完善上级调用

* 用SpinLock保护结构体并发安全

* 修改原子变量为u32,修复符号错误

* irq guard

* 修改为具有内部可变性的结构体

* temp fix

* 修复了由于进程持有自旋锁导致的不被调度的问题

* 对 complete 系列方法上锁,保护 done 数据并发安全

* 移除了未使用的依赖

* 重写显示刷新驱动 (#363)

* 重构显示刷新驱动

* Patch refactor process management (#366)

* 维护进程树

* 维护进程树

* 更改代码结构

* 新建进程时,设置cwd

* 调整adopt childern函数,降低开销

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* waitqueue兼容C部分 (#351)

* PATH

* safe init

* waitqueue兼容C部分

* waitqueue兼容C部分

* 删除semaphore.c,在ps2_keyboard中使用waitqueue

* 删除semaphore.c,在ps2_keyboard中使用waitqueue

* current_pcb的C兼容

* current_pcb的C兼容

* current_pcb的C兼容

* fmt

* current_pcb的兼容

* 针对修改

* 调整代码

* fmt

* 删除pcb的set flags

* 更改函数名

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* merge master

* Patch debug process management refactor (#372)

* 能够调通,执行完textui_init

* 能跑到initial kernel thread

* fmt

* 能够正常初始化所有服务(尚未能切换到用户程序)

* 删除部分无用的extern

* 存在问题:ap处理器启动后,bsp的smp_init函数return之后就出错了,怀疑是栈损坏

* 解决smp启动由于未换栈导致的内存访问错误

* debug

* 1

* 1

* lock no preempt

* 调通

* 优化代码,删除一些调试日志

* fix

* 使用rust重写wait4 (#377)

* 维护进程树

* 维护进程树

* 更改代码结构

* 新建进程时,设置cwd

* 调整adopt childern函数,降低开销

* wait4

* 删除c_sys_wait4

* 使用userbuffer保护裸指针

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>

* 消除warning

* 1. 修正未设置cpu executing的问题

* 修正kthread机制可能存在的内存泄露问题

* 删除pcb文档

* 删除C的tss struct

---------

Co-authored-by: Bullet <93781792+GP-Bullet@users.noreply.github.com>
Co-authored-by: Chiichen <39649411+Chiichen@users.noreply.github.com>
Co-authored-by: hanjiezhou <zhouhanjie@dragonos.org>
Co-authored-by: GnoCiYeH <118462160+GnoCiYeH@users.noreply.github.com>
Co-authored-by: houmkh <1119644616@qq.com>
2023-09-15 14:58:19 +08:00

395 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <stdlib.h>
#include <libsystem/syscall.h>
#include <stddef.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#define PAGE_4K_SHIFT 12
#define PAGE_2M_SHIFT 21
#define PAGE_1G_SHIFT 30
#define PAGE_GDT_SHIFT 39
// 不同大小的页的容量
#define PAGE_4K_SIZE (1UL << PAGE_4K_SHIFT)
#define PAGE_2M_SIZE (1UL << PAGE_2M_SHIFT)
#define PAGE_1G_SIZE (1UL << PAGE_1G_SHIFT)
// 屏蔽低于x的数值
#define PAGE_4K_MASK (~(PAGE_4K_SIZE - 1))
#define PAGE_2M_MASK (~(PAGE_2M_SIZE - 1))
// 将addr按照x的上边界对齐
#define PAGE_4K_ALIGN(addr) (((unsigned long)(addr) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
#define PAGE_2M_ALIGN(addr) (((unsigned long)(addr) + PAGE_2M_SIZE - 1) & PAGE_2M_MASK)
#define ALIGN_UP16(x) (((x) + 15) & ~15)
#define PAGE_ALIGN_UP(x) (((x) + PAGE_4K_SIZE - 1) & PAGE_4K_MASK)
/**
* @brief 显式链表的结点
*
*/
typedef struct malloc_mem_chunk_t
{
uint64_t length; // 整个块所占用的内存区域的大小
struct malloc_mem_chunk_t *prev; // 上一个结点的指针
struct malloc_mem_chunk_t *next; // 下一个结点的指针
} malloc_mem_chunk_t;
static uint64_t brk_base_addr = 0; // 堆区域的内存基地址
static uint64_t brk_max_addr = 0; // 堆区域的内存最大地址
static uint64_t brk_managed_addr = 0; // 堆区域已经被管理的地址
// 空闲链表
// 按start_addr升序排序
static malloc_mem_chunk_t *malloc_free_list = NULL;
static malloc_mem_chunk_t *malloc_free_list_end = NULL; // 空闲链表的末尾结点
static uint64_t count_last_free_size = 0; // 统计距离上一次回收内存已经free了多少内存
/**
* @brief 将块插入空闲链表
*
* @param ck 待插入的块
*/
static void malloc_insert_free_list(malloc_mem_chunk_t *ck);
/**
* @brief 当堆顶空闲空间大于2个页的空间的时候释放1个页
*
*/
static void release_brk();
/**
* @brief 在链表中检索符合要求的空闲块best fit
*
* @param size 块的大小
* @return malloc_mem_chunk_t*
*/
static malloc_mem_chunk_t *malloc_query_free_chunk_bf(uint64_t size)
{
// 在满足best fit的前提下尽可能的使分配的内存在低地址
// 使得总的堆内存可以更快被释放
if (malloc_free_list == NULL)
{
return NULL;
}
malloc_mem_chunk_t *ptr = malloc_free_list;
malloc_mem_chunk_t *best = NULL;
// printf("query size=%d", size);
while (ptr != NULL)
{
// printf("ptr->length=%#010lx\n", ptr->length);
if (ptr->length == size)
{
best = ptr;
break;
}
if (ptr->length > size)
{
if (best == NULL)
best = ptr;
else if (best->length > ptr->length)
best = ptr;
}
ptr = ptr->next;
}
return best;
}
/**
* @brief 在链表中检索符合要求的空闲块first fit
*
* @param size
* @return malloc_mem_chunk_t*
*/
static malloc_mem_chunk_t *malloc_query_free_chunk_ff(uint64_t size)
{
if (malloc_free_list == NULL)
return NULL;
malloc_mem_chunk_t *ptr = malloc_free_list;
while (ptr)
{
if (ptr->length >= size)
{
return ptr;
}
ptr = ptr->next;
}
return NULL;
}
/**
* @brief 扩容malloc管理的内存区域
*
* @param size 扩大的内存大小
*/
static int malloc_enlarge(int64_t size)
{
if (brk_base_addr == 0) // 第一次调用,需要初始化
{
brk_base_addr = sbrk(0);
// printf("brk_base_addr=%#018lx\n", brk_base_addr);
brk_managed_addr = brk_base_addr;
brk_max_addr = sbrk(0);
}
int64_t free_space = brk_max_addr - brk_managed_addr;
// printf("size=%ld\tfree_space=%ld\n", size, free_space);
if (free_space < size) // 现有堆空间不足
{
if (sbrk(PAGE_ALIGN_UP(size - free_space)) != (void *)(-1))
brk_max_addr = sbrk((0));
else
{
put_string("malloc_enlarge(): no_mem\n", COLOR_YELLOW, COLOR_BLACK);
return -ENOMEM;
}
// printf("brk max addr = %#018lx\n", brk_max_addr);
}
// 扩展管理的堆空间
// 在新分配的内存的底部放置header
malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)brk_managed_addr;
memset(new_ck, 0, sizeof(malloc_mem_chunk_t));
new_ck->length = brk_max_addr - brk_managed_addr;
// printf("new_ck->start_addr=%#018lx\tbrk_max_addr=%#018lx\tbrk_managed_addr=%#018lx\n", (uint64_t)new_ck, brk_max_addr, brk_managed_addr);
new_ck->prev = NULL;
new_ck->next = NULL;
brk_managed_addr = brk_max_addr;
malloc_insert_free_list(new_ck);
return 0;
}
/**
* @brief 合并空闲块
*
*/
static void malloc_merge_free_chunk()
{
if (malloc_free_list == NULL)
return;
malloc_mem_chunk_t *ptr = malloc_free_list->next;
while (ptr != NULL)
{
// 内存块连续
if (((uint64_t)(ptr->prev) + ptr->prev->length == (uint64_t)ptr))
{
// printf("merged %#018lx and %#018lx\n", (uint64_t)ptr, (uint64_t)(ptr->prev));
// 将ptr与前面的空闲块合并
ptr->prev->length += ptr->length;
ptr->prev->next = ptr->next;
if (ptr->next == NULL)
malloc_free_list_end = ptr->prev;
else
ptr->next->prev = ptr->prev;
// 由于内存组成结构的原因不需要free掉header
ptr = ptr->prev;
}
ptr = ptr->next;
}
}
/**
* @brief 将块插入空闲链表
*
* @param ck 待插入的块
*/
static void malloc_insert_free_list(malloc_mem_chunk_t *ck)
{
if (malloc_free_list == NULL) // 空闲链表为空
{
malloc_free_list = ck;
malloc_free_list_end = ck;
ck->prev = ck->next = NULL;
return;
}
else
{
malloc_mem_chunk_t *ptr = malloc_free_list;
while (ptr != NULL)
{
if ((uint64_t)ptr < (uint64_t)ck)
{
if (ptr->next == NULL) // 当前是最后一个项
{
ptr->next = ck;
ck->next = NULL;
ck->prev = ptr;
malloc_free_list_end = ck;
break;
}
else if ((uint64_t)(ptr->next) > (uint64_t)ck)
{
ck->prev = ptr;
ck->next = ptr->next;
ptr->next = ck;
ck->next->prev = ck;
break;
}
}
else // 在ptr之前插入
{
if (ptr->prev == NULL) // 是第一个项
{
malloc_free_list = ck;
ck->prev = NULL;
ck->next = ptr;
ptr->prev = ck;
break;
}
else
{
ck->prev = ptr->prev;
ck->next = ptr;
ck->prev->next = ck;
ptr->prev = ck;
break;
}
}
ptr = ptr->next;
}
}
}
/**
* @brief 获取一块堆内存
*
* @param size 内存大小
* @return void* 内存空间的指针
*
* 分配内存的时候结点的prev next指针所占用的空间被当做空闲空间分配出去
*/
void *malloc(ssize_t size)
{
// printf("malloc\n");
// 计算需要分配的块的大小
if (size + sizeof(uint64_t) <= sizeof(malloc_mem_chunk_t))
size = sizeof(malloc_mem_chunk_t);
else
size += sizeof(uint64_t);
// 采用best fit
malloc_mem_chunk_t *ck = malloc_query_free_chunk_bf(size);
if (ck == NULL) // 没有空闲块
{
// printf("no free blocks\n");
// 尝试合并空闲块
malloc_merge_free_chunk();
ck = malloc_query_free_chunk_bf(size);
// 找到了合适的块
if (ck)
goto found;
// printf("before enlarge\n");
// 找不到合适的块,扩容堆区域
if (malloc_enlarge(size) == -ENOMEM)
return (void *)-ENOMEM; // 内存不足
malloc_merge_free_chunk(); // 扩容后运行合并,否则会导致碎片
// 扩容后再次尝试获取
ck = malloc_query_free_chunk_bf(size);
}
found:;
// printf("ck = %#018lx\n", (uint64_t)ck);
if (ck == NULL)
return (void *)-ENOMEM;
// printf("ck->prev=%#018lx ck->next=%#018lx\n", ck->prev, ck->next);
// 分配空闲块
// 从空闲链表取出
if (ck->prev == NULL) // 当前是链表的第一个块
{
malloc_free_list = ck->next;
}
else
ck->prev->next = ck->next;
if (ck->next != NULL) // 当前不是最后一个块
ck->next->prev = ck->prev;
else
malloc_free_list_end = ck->prev;
// 当前块剩余的空间还能容纳多一个结点的空间,则分裂当前块
if ((int64_t)(ck->length) - size > sizeof(malloc_mem_chunk_t))
{
// printf("seperate\n");
malloc_mem_chunk_t *new_ck = (malloc_mem_chunk_t *)(((uint64_t)ck) + size);
new_ck->length = ck->length - size;
new_ck->prev = new_ck->next = NULL;
// printf("new_ck=%#018lx, new_ck->length=%#010lx\n", (uint64_t)new_ck, new_ck->length);
ck->length = size;
malloc_insert_free_list(new_ck);
}
// printf("malloc done: %#018lx, length=%#018lx\n", ((uint64_t)ck + sizeof(uint64_t)), ck->length);
// 此时链表结点的指针的空间被分配出去
return (void *)((uint64_t)ck + sizeof(uint64_t));
}
/**
* @brief 当堆顶空闲空间大于2个页的空间的时候释放1个页
*
*/
static void release_brk()
{
// 先检测最顶上的块
// 由于块按照开始地址排列,因此找最后一个块
if (malloc_free_list_end == NULL)
{
printf("release(): free list end is null. \n");
return;
}
if ((uint64_t)malloc_free_list_end + malloc_free_list_end->length == brk_max_addr && (uint64_t)malloc_free_list_end <= brk_max_addr - (PAGE_2M_SIZE << 1))
{
int64_t delta = ((brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK) - PAGE_2M_SIZE;
// printf("(brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK=%#018lx\n ", (brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK);
// printf("PAGE_2M_SIZE=%#018lx\n", PAGE_2M_SIZE);
// printf("tdfghgbdfggkmfn=%#018lx\n ", (brk_max_addr - (uint64_t)malloc_free_list_end) & PAGE_2M_MASK - PAGE_2M_SIZE);
// printf("delta=%#018lx\n ", delta);
if (delta <= 0) // 不用释放内存
return;
sbrk(-delta);
brk_max_addr = sbrk(0);
brk_managed_addr = brk_max_addr;
malloc_free_list_end->length = brk_max_addr - (uint64_t)malloc_free_list_end;
}
}
/**
* @brief 释放一块堆内存
*
* @param ptr 堆内存的指针
*/
void free(void *ptr)
{
// 找到结点此时prev和next都处于未初始化的状态
malloc_mem_chunk_t *ck = (malloc_mem_chunk_t *)((uint64_t)ptr - sizeof(uint64_t));
// printf("free(): addr = %#018lx\t len=%#018lx\n", (uint64_t)ck, ck->length);
count_last_free_size += ck->length;
malloc_insert_free_list(ck);
if (count_last_free_size > PAGE_2M_SIZE)
{
count_last_free_size = 0;
malloc_merge_free_chunk();
release_brk();
}
}