I need to implement virtual memory for one school project and I'm confused about something. If page fault occurs while working with stack (simple push for example), how and where am I going to save return address if I cannot push?
That's a very good question. Page faults cause an interrupt and how does that interrupt know where to return if it cannot preserve the return address?
On x86 architecture, TSS (task state segment) contains different stack pointers for different privilege levels. So if your user mode process runs out of stack, CPU privilege level is lowered and an exception is raised. That means as soon as you switch to the new privilege level, OS can start to use the new stack which resides in kernel memory and isn't subject to stack limits of the user process.
Here's what our development team did when faced with this same problem ...
We designed our in-house OS such that the page fault handler was not allowed to generate a page fault. Thus, the stack to which the page fault exception stack frame was pushed absolutely had to be guaranteed to be present in memory. Furthermore, any routine used by the page fault handler also by necessity had to be present in memory, as otherwise that could cause a page fault thereby violating the design.
Related
I am not quite sure about which work will be done by CPU and which will be done by the OS when a page fault occurs. That's why I'm asking the following questions.
Consider a single-core CPU, with several processes running. When a page fault occurs, the OS would try to fetch the required page from disk to RAM, which will cost a long time. During this time period, can the CPU keep on executing? Or the CPU has to wait until the required page is loaded into RAM?
If the CPU can keep on executing without waiting for the required page, then thrashing may occur when there are too many processes. At some moment, most of the instructions that the CPU executes will cause page faults, then the most of the time spent will be waiting for OS loading the pages from disk to RAM. That's why thrashing occurs. May I know if my understanding is correct?
Thanks in advance.
Update: this website describes thrashing very well.
The CPU doesn't know that it's "in" a page fault. CPUs aren't recursive!
When a 32-bit x86 CPU (for example) encounters a page fault, here's what it does (slightly simplified):
Set the value of CR2 to the address which caused the page fault.
Look at the Interrupt Descriptor Table and some other tables and find the address of the page fault handler (new CS, new EIP) and the kernel stack (new SS, new ESP).
Set the values of CS, EIP, SS, and ESP to the ones it just read.
Push the old SS, old ESP, EFLAGS, old CS and old EIP onto the stack.
Push the SS, ESP, EFLAGS, CS and EIP registers onto that stack.
Update the flags to say we're now in kernel mode.
That's all it does. Now, there is some data on the stack that the kernel uses when it wants to make the CPU go back to what it was doing before the page fault happened. But the kernel isn't obligated to use that data. It could go back somewhere entirely different, or it could never go back. It's up to the kernel. The CPU doesn't care.
A usual kernel will first save all the other registers (important!), look at the address, decide where to get the page, tell the disk to start fetching the page, make a note that the process is stopped because of a page fault, and then it will go and do something entirely different until the data comes back from the disk. It might run a different process, for example. If there are no processes left to run, it might turn off the CPU (yes, really).
Eventually the data comes back from the disk and the kernel sees that there's a process waiting for that data because of a page fault, and it updates the page table so the process can see the data, and it resets all the registers, including SS, ESP, EFLAGS, CS, and EIP. Now the CPU is doing whatever it was doing before.
The key point to notice is: the CPU only cares what's in its registers right now! It doesn't have a long-term memory. If you save the register values somewhere, you can make it stop doing whatever it was doing, and resume it later as if nothing ever happened. For example, there is absolutely no requirement that you have to return from function calls in the order they happened. The CPU doesn't care if you have a function that returns twice, for example (see setjmp), or if you have two coroutines and calling yield in one coroutine causes yield to return in the other one. You don't have to do things in stack order like you do in C.
In a cooperative multitasking OS the OS cannot initialize a context switch, so the CPU must wait for the page to be brought in.
Modern systems are preemptive multitasking systems. In this case the OS will most likely initiate a context switch and so other threads/processes will run on the CPU.
Thrashing is a concern when the amount of memory used far exceeds the capacity of the RAM. "Download more RAM" is a meme for a reason.
The CPU can keep on executing.
The CPU cannot, however, carry on execution of the thread that incurred the fault. That thread needs the fault to be resolved before the very next instruction can be executed. That is, it must block on the fault.
That many threads/processes may be blocked on fault handling is not in itself thrashing. Thrashing occurs when, in order to bring a page in, there are insufficient free page frames, so it is necessary to write a page out. But then, when the OS tries to find another thread to run, it picks the thread that owned a page it just wrote out, so it has to fault that page back in.
Thrashing is therefore a symptom of insufficient available real memory.
I was given this exact question on a quiz.
Question
Answer
Does the question make any sense? My understanding is that the OS schedules a process and manages what instructions it needs the processor to execute next. This is because the OS is liable to pull all sorts of memory management tricks, especially in main memory where fragmentation is a way of life. I remember that there is supposed to be a special register on the processor called the program counter. In light of the scheduler and memory management done by the OS I have trouble figuring out the purpose of this register unless it is just for the OS. Is the concept of the Stored Program Computer really relevant to how a modern computer operates?
Hardware fetches machine code from main memory, at the address in the program counter (which increments on its own as instructions execute, or is modified by executing a jump or call instruction).
Software has to load the code into RAM (main memory) and start the process with its program counter pointing into that memory.
And yes, if the OS wants to page that memory out to disk (or lazily load it in the first place), hardware will trigger a page fault when the CPU tries to fetch code from an unmapped page.
But no, the OS does not feed instructions to the CPU one at a time.
(Unless you're debugging a program by putting the CPU into "single step" mode when returning to user-space for that process, so it traps after executing one instruction. Like x86's trap flag, for example. Some ISAs only have software breakpoints, not HW support for single stepping.)
But anyway, the OS itself is made up of machine code that runs on the CPU. CPU hardware knows how to fetch and execute instructions from memory. An OS is just a fancy program that can load and manage other programs. (Remember, in a von Neumann architecture, code is data.)
Even the OS has to depend on the processing architecture. Memory today often is virtualized. That means the memory location seen by the program is not the real physical location, but is indirected by one or more tables describing the actual location and some attributes (e.g. read/write/execute allowed or not) for memory accesses. If the accessed virtual memory has not been loaded into main memory (these tables say so), an exception is generated, and the address of an exception handler is loaded into the program counter. This exception handler is by the OS and resides in main memory. So the program counter is quite relevant with today's computers, but the next instruction can be changed by exceptions (exceptions are also called for thread or process switching in preemptive multitasking systems) on the fly.
Does the question make any sense?
Yes. It makes sense to me. It is a bit imprecise, but the meanings of each of the alternatives are sufficiently distinct to be able to say that D) is the best answer.
(In theory, you could create a von Neumann computer which was able to execute instructions out of secondary storage, registers or even the internet ... but it would be highly impractical for various reasons.)
My understanding is that the OS schedules a process and manages what instructions it needs the processor to execute next. This is because the OS is liable to pull all sorts of memory management tricks, especially in main memory where fragmentation is a way of life.
Fragmentation of main memory is not actually relevant. A modern machine uses special hardware (and page tables) to deal with that. From the perspective of executing code (application or kernel) this is all hidden. The code uses virtual addresses, and the hardware maps them to physical addresses. (This is even true when dealing with page faults, though special care will be taken to ensure that the code and page table entries for the page fault handler are in RAM pages that are never swapped out.)
I remember that there is supposed to be a special register on the processor called the program counter. In light of the scheduler and memory management done by the OS I have trouble figuring out the purpose of this register unless it is just for the OS.
The PC is fundamental. It contains the virtual memory address of the next instruction that the CPU is to execute. For application code AND for OS kernel code. When you switch between the application and kernel code, the value in the PC is updated as part of the context switch.
Is the concept of the Stored Program Computer really relevant to how a modern computer operates?
Yes. Unless you are working on a special custom machine where (say) the program has been transformed into custom silicon.
I find that during TLB missing process, some architecture use hardware to handle it while some use the OS. But when it comes to page fault, most of them use the OS instead of hardware.
I tried to find the answer but didn't find any article explains why.
Could anyone help with this?
Thanks.
If the hardware could handle it on its own, it wouldn't need to fault.
The whole point is that the OS hasn't wired the page into the hardware page tables, e.g. because it's not actually in memory at all, or because the OS needs to catch an attempt to write so the OS can implement copy-on-write.
Page faults come in three categories:
valid (the process logically has the memory mapped, but the OS was lazy or playing tricks):
hard: the page needs to be paged in from disk, either from swap space or from a disk file (e.g. a memory mapped file, like a page of an executable or shared library). Usually the OS will schedule another task while waiting for I/O.
soft: no disk access required, just for example allocating + zeroing a new physical page to back a virtual page that user-space just tried to write. Or copy-on-write of a writeable page that multiple processes had mapped, but where changes by one shouldn't be visible to the other (like mmap(MAP_PRIVATE)). This turns a shared page into a private dirty page.
invalid: There wasn't even a logical mapping for that page. A POSIX OS like Linux will deliver SIGSEGV signal to the offending process/thread.
The hardware doesn't know which is which, all it knows was that a page walk didn't find a valid page-table entry for that virtual address, so it's time to let the OS decide what to do next. (i.e. raise a page-fault exception which runs the OS's page-fault handler.) valid/invalid are purely software/OS concepts.
These example reasons are not an exhaustive list. e.g. an OS might remove the hardware mapping for a page without actually paging it out, just to see if the process touches it again soon. (In which case it's just a cheap soft page fault. But if not, then it might actually page it out to disk. Or drop it if it's clean.)
For HW to be able to fully handle a page fault, we'd need data structures with a hardware-specified layout that somehow lets hardware know what to do in some possible situations. Unless you build a whole kernel into the CPU microcode, it's not possible to have it handle every page fault, especially not invalid ones which require reading the OS's process / task-management data structures and delivering a signal to user-space. Either to a signal handler if there is one, or killing the process.
And especially not hard page faults, where a multi-tasking OS will let some other process run while waiting for the disk to DMA the page(s) into memory, before wiring up the page tables for this process and letting it retry the faulting load or store instruction.
Can processes share a single stack?
I'm currently thinking yes and no. That they "share" stack but it need to copy and save the information already there elsewere before using it and return it when the first process is getting picked up by the CPU again. But I might be confusing this with registers in general.
Can someone help me shed some light on this?
Processes do not share CPU stacks.
While processes can potentially share memory using shared-memory facilities, processes do not share memory by default. Operating systems try to minimize the amount of sharing between processes as a way to ensure security.
Sharing CPU stack between processes A and B would be detrimental to security, because process A would be able to poke around "junk" left on the stack by process B, and vice versa. Hackers managed to exploit an indirect sharing on a much smaller scale to create a major security vulnerability (you can read more about Meltdown and Spectre here). Sharing CPU stacks would create a much bigger problem.
It goes without saying that an attempt to share stacks would require a degree of inter-process synchronization that would be prohibitive to overall performance. An ability to make independent operations on CPU stack is so critical to concurrency that threads inside the same process are allocated separate stacks, even though they already share all the memory allocated to the process, so security is not a concern. Sharing stacks would effectively kill concurrency, because maintaining a shared stack would require frequent exclusive access with lots of synchronization.
Some systems use an interrupt stack shared by all processes. Generally, there is one interrupt stack per processor.
User stacks (and there is usually one for each processor mode used by the system) are unique to each process (or thread).
The difference between the registers and the stack is that the latter can be anywhere in memory (it is indirectly referenced by appropriate registers) while the formers are fixed (there is only one set of architecturally visible registers).
The stack is part of the state of a program, just like it make no sense to mix program instruction, data and context together, mixing two stacks make no sense.
If program A pushes X it expects to pop X and not an eventual value pushed by program B meanwhile.
It's possible to make all program shares the same memory area for the stack but this is, in general, counterproductive.
As you correctly noted, the stack must be swapped in an out, thus, in the case of two program A and B, two additional memory areas are needed: one for saving the stack of A and one for the stack of B.
In the end, three memory areas are used instead of two.
There are cases where the swapping is necessary: when the shared is at a fixed location.
This is the case, in some degenerate form, of registers but other structure can have a fixed location.
One simple example are the page table entries, if a program A is used to generate two processes A1 and A2, most OSs will copy-on-write them.
Under this circumstances, the two processes end up sharing a lot of pages, even all but a few. For the OS may be easier to swap in and out the few different pages rather than make the page table (or part of it) point to two different locations.
In general, if we cannot afford to have multiple instances of a resource, we need to time-share it.
Since we can afford to have more than one instance of the stack, we prefer to not share it.
I am reading operating systems and having a doubt regarding page fault service time ?
Average memory access Time = prob. of no page fault (memory access time)
+
prob. of page fault (Page fault service time)
My doubt is that what does the page fault service time includes ?
According to me,
First address translation is there in TLB or Page table , but when entry is not found in page table, it means page fault occurred . So, i have to fetch from disk and all the entries get updated in the TLB and as well as page table.
Hence, page Fault service time = TLB time + page table time + page fetch from disk
Plz someone confirm it ?
What you are describing is academic Bulls____. There are so many factors that a simple equation like that does not describe the access time. Nonetheless, there are certain idiotic operating systems books that put out stuff like that to sound intellectual (and professors like it for exam questions).
What these idiots are trying to say is that a page reference will be in memory or not in memory with the two probabilities adding up to 1.0. This is entirely meaningless because the relative probabilities are dynamic. If other processes start using memory, the likelihood of a page fault increases and if other processes stop using memory, the probability declines.
Then you have memory access times. That is not constant either. Accessing a cached memory location is faster than a non-cached location. Accessing memory that is shared by multiple processors and interlocked is slower. This is not a constant either.
Then you have page fault service time. There are soft and hard page faults. A page fault on a demand zero page is different in time for one that has to be loaded from disk. Is the disk access cached or not cached? How much activity is there on the disk?
Oh, is the page table paged? If so, is the page fault on the page table or on the page itself? It could even be both.
Servicing a page fault:
The process enters the exception and interrupt handler.
The interrupt handler dispatches to the page fault handler.
The page fault handler has to find where the page is stored.
If the page is in memory (has been paged out but not written to disk), the handler just has to update the page table.
If the page is not in memory, the handler has to look up where the page is stored (this is system and type of memory specific).
The system has to allocate a physical page frame for the memory.
If this is a first reference to a demand zero page, there is no need to read from disk, just set everything to zero.
If the page is in a disk cache, get the page from that.
Otherwise read the page from disk to the page frame.
Reset the process's registers as appropriate.
Return to user mode
Restart the instruction causing the fault.
(All of the above have gross simplifications.)
The TLB has nothing really to do with this except that the servicing time is marginally faster if the page table entry in question is in the TLB.
Hence, page Fault service time = TLB time + page table time + page fetch from disk
Not at all.