由于仅作演示,因此尽量简化功能。要求一个进程只能有一个共享内存区。要求分配共享内存后不允许再用 sbrk
分配空间,共享内存区作为进程最高端的空间。只有解除共享内存映射后才可以继续用 sbrk
释放内存空间。
代码+数据→隔离页帧→堆栈→sbrk
分配空间→共享内存区(不允许 sbrk
操作)
代码+数据→隔离页帧→堆栈→sbrk
分配空间(允许 sbrk
操作)
共享内存区间有全局标识 0~15 共 16 个,每个共享内存区不超过 64 个页(64*4 = 256KB
)每个共享内存区有:
struct shm{
int allocated; //是否分配使用的标志
Int memsize; // page 对齐的
Void *pages[64]; //所分配的物理内存地址(内核虚地址)
}shms[16];
提供系统调用 shm_create(int size)
用于创建共享内存区,返回共享内存的 id
值,超出 256 KB 或者超过 16 个 shm
则返回 -1。
共享区间物理页帧分配:根据 size 大小分配若干页帧,每个页帧的虚地址填写到 shms[id].pages[i]
中。 设置 shms[id].allocated = 1
标识已分配使用。
提供系统调用 shm_free(int id)
将 shms[id].pages[]
里的若干页帧逐个用 kfree()
释放,设置 shms[id].allocated=0;
提供 shm_attch(int id)
,用于将共享内存映射到用户进程空间,返回用户态的起始地址指针。将进程 proc->sz
先调整到页边界,然后再扩展到 sz+size
空间(类似于 allocuvm()
操作),对于页表映射则逐个页映射到 shms[id].pages[]
中的各个页(pte
地址要通过 V2P 转换)。
提供 shm_deatt(int id)
,用于将共享内存空间释放。对于释放的高地址的若干个页帧, 逐个解除页表映射(参考 deallocuvm()
的操作)。
编写应用程序,先运行一个进程创建并映射指定 id
的共享内存,写入指定数据。然后再启动另一个进程映射该 id
的共享内存。
参照 Linux 的实现,在进程 proc
中添加一个成员用于记录消息队列。出于简化编程的目的,一个消息不管长度位多少,都用一个页帧大小来管理。另外还需要注意同步关系。