mariuszp wrote:
I have stumbled upon this theoretical problem with mapped files and copy-on-write. So far, my OS was uniprocessor, and I started work on SMP support. I have some practical issues such as 2 CPUs ending up on the same stack, but I noticed a much more difficult theoretical program.
Let's say a certain area of virtual memory has a file mapped to it. Thread A accessed the memory. This causes a page fault, the kernel sees it is a memory-mapped file area and:
1) Marks the page as present and allocates a frame for it.
2) Reads the file data into that page.
But if thread B, which shares memory with thread A, tries to access the page inbetween step 1 and 2, it will end up reading whatever garbage was on that page before the file was read! Disabling interrupts for the duration of the mapping works for uniprocessor systems, but will not work with multiple CPUs, when thread B runs on another CPU at the same time this mapping happens.
How can I prevent this race condition?
The first thing is to swap the 2 steps. So the page will still be marked as not-present if a fault occurs on the second core.
Further from that you will need to give your pages a state variable. In this do the following:
1) Mark page state as WAITING_TO_BE_LOADED - but leave the not-present bit clear
2) Set the thread state as WAITING_FOR_PAGE
3) Allocate a physical page and load the data into it
4) Set the present bit
5) Mark page state as READY
6) Set present bit (and send an IPI if necessary)
7) Wake up waiting pages.
Now if the 2nd thread faults during steps 1 to 3 it will see that the page is WAITING_TO_BE_LOADED and can be put in the WAITING _FOR_PAGE state and be woken up when the page is ready. If it faults during 4 to 7 the handler notice the PRESENT bit is now set and simply return for a retry.
I hope I got this mainly right. It's roughly what I do in my OS.