Hello!
I'm in the process of rewriting my virtual memory manager and have run into a hang-up.
Each address space is composed of a page-directory and a bitmap describing allocated pages. Each address-space shares the page tables that identity-map low memory, kernel data+code, kernel ELF sections, etc. Memory is allocated on a first-fit basis, so it's reasonable for an allocation to be fulfilled in a globally shared page table.
If a process allocates memory within one of these globally-shared-tables, then every process will then receive the updated state in the shared page tables. However, only the process that fulfilled the allocation would have the memory marked in its allocation bitmap.
I was banging my head against this for a few days after seeing mismatched states between a process's page-tables and allocation bitmap until I realized what was going on. For now, on task switch, I iterate the shared tables and ensure nothing is out-of-sync, and panic if it is.
I'm trying to come up with a clean way to signal allocations to a shared table, so that every process that shares the table can mark the pages as allocated in its bitmap. A few ideas:
- Each VAS never allocates memory within a shared table unless specifically requested. This seems like punting the problem until future-me needs some shared buffer between processes.
- Within the shared kernel memory, maintain a linked-list of VAS's that refer to shared page tables. Whenever an allocation is fulfilled within a shared page table, iterate each VAS, map in the VAS structure somewhere, and update its allocation bitmap. This seems to require quite a lot of state about which page tables are shared by which VAS. This update could alternatively be performed on a task switch, or when a mismatched allocation state is detected between the page tables and allocation bitmap.
- Within the shared kernel memory, maintain a pointer to the "latest" VAS containing modifications to the shared kernel tables. When an allocation is fulfilled in a shared page table, update the pointer to the VAS that fulfilled the allocation. On task switch (or w/e), update the allocation state to match that of the "latest" VAS's shared tables. This seems fine, but seems to be special-casing the shared kernel memory. It'd be nice if the approach worked for general-purpose IPC shared-memory.
I'm sure this is trod-ground and am curious if anyone has an approach they can share. Thanks!
[Solved] Keeping shared memory in-sync
-
- Member
- Posts: 77
- Joined: Fri May 20, 2016 2:29 pm
- Location: London, UK
- GitHub: https://github.com/codyd51
- Contact:
[Solved] Keeping shared memory in-sync
Last edited by codyd51 on Sat Jul 04, 2020 4:58 pm, edited 1 time in total.
-
- Member
- Posts: 425
- Joined: Tue Apr 03, 2018 2:44 am
Re: Keeping shared memory in-sync
If you have shared tables in kernel space, why bother tracking those per-process?codyd51 wrote:Hello!
I'm in the process of rewriting my virtual memory manager and have run into a hang-up.
Each address space is composed of a page-directory and a bitmap describing allocated pages. Each address-space shares the page tables that identity-map low memory, kernel data+code, kernel ELF sections, etc. Memory is allocated on a first-fit basis, so it's reasonable for an allocation to be fulfilled in a globally shared page table.
If a process allocates memory within one of these globally-shared-tables, then every process will then receive the updated state in the shared page tables. However, only the process that fulfilled the allocation would have the memory marked in its allocation bitmap.
I was banging my head against this for a few days after seeing mismatched states between a process's page-tables and allocation bitmap until I realized what was going on. For now, on task switch, I iterate the shared tables and ensure nothing is out-of-sync, and panic if it is.
I'm trying to come up with a clean way to signal allocations to a shared table, so that every process that shares the table can mark the pages as allocated in its bitmap. A few ideas:
Instead, use your per-process bitmap purely per process user mapping, and perhaps have a shared bitmap for kernel mappings. That way, you just need to manage a single shared bitmap, but you will have to partition your bitmap handling between user and kernel mappings.
-
- Member
- Posts: 77
- Joined: Fri May 20, 2016 2:29 pm
- Location: London, UK
- GitHub: https://github.com/codyd51
- Contact:
Re: Keeping shared memory in-sync
This is a really good idea! I tried it out, and it works nicely. I've marked this post as solved. Thanks for the thought-timethewrongchristian wrote:Instead, use your per-process bitmap purely per process user mapping, and perhaps have a shared bitmap for kernel mappings.
I'll need to watch out for a few things, like an allocation crossing over from the shared-mapping into a unique-mapping, and being careful when to allocate in each map, but it's all solvable in a straightforward way.
Code: Select all
static address_space_page_bitmap_t* _vmm_bitmap_for_addr(vmm_page_directory_t* vmm_dir, uint32_t page_addr) {
if (page_addr < _first_page_outside_shared_kernel_tables) {
return _vmm_state_bitmap(boot_info_get()->vmm_kernel);
}
return _vmm_state_bitmap(vmm_dir);
}