Applications, kernel and hardware simulator in NachOS = one UNIX process
Three important sections: NachOS kernel → Machine (simulates all hardware) → User application
How does NachOS do CPU scheduling? We have scheduler and threads.
Scheduler
Maintains a ready queue of threads
It is invoked whenever the current thread gives up (non-preemptive)
Three important code:
ReadyToRun(thread): adds to the ready queue
FindNextToRun(): returns the thread at the front of ready queue
Run(thread): switch from one thread to another (including context switching)
Thread
List of states:
READY
RUNNING
BLOCKED (equivalent to waiting)
JUST_CREATED (temporary, useless)
List of functions:
Fork(function, arg, flag): Turns the function into a process and calls ReadyToRun().
Yield(): Finds the next thread to run using FindNextToRun(). If another thread is found, then turn to current thread to READY and Run() the new thread.
Sleep(): Set status to BLOCKED, find another thread to run. This is called by the blocking semaphores!
Finish(): End of execution. Mark this thread for termination. Call Sleep() and never wake up.
Lab 2
Timers
They are used to trigger an interrupt (preemptive)
TimerInterruptHandler(): Executes whenever associated timer expires and interrupt is triggrered.
TimerExpired(): Executes whenever timer expires, and calls the TimerInterruptHandler() function.
TimeOfNextInterrupt(): Returns an integer denoting the number of time ticks. Used to schedule an interrupt using the timer → relative time.
Interrupt
There is also a pending list for interrupts that are pending
Schedule(): Insert a new interrupt to the pending list (which is sorted)
OneTick(): Function to process a single tick. Increase the number of tick. Calls CheckIfDue(), and if it returns True, calls Yield()
CheckIfDue(): Checks if the pendingInterrupt at the head of the pending list should be triggered. If yes, runs TimerExpired()
YieldOnReturn(): Called by TimerInterruptHandler(). Force OneTick() to trigger a context switch
Lab 3
Remember that a thread will never run until you bind it to a certain function using Fork.
There are three different synchronisation primitives in NachOS: Semaphores, Locks, and Condition variables
Semaphores
P(): equivalent to Wait() → waits until the value of semaphore is > 0
If the value is zero (no resource is available), then the calling thread is appended to the waiting queue (like list L) and is put to sleep.
V(): equivalent to Signal() → increment the semaphore value and wakes up the first thread in the waiting queue and put it in the ready list.
Locks
A lock can either be FREE or BUSY. We have a queue for the lock. We can either Acquire() it or Release() it.
Condition Variables
They require a lock.
lock->Acquire();while (!condition) { cond->Wait(lock);}// condition is true here, and lock is held... critical section ...lock->Release();
Wait(lock): Releases the lock. Relinquishes CPU until signaled (put into the waiting queue and sleep). After waking up, re-acquire the lock.
Signal(lock): Wakes up the first thread in the waiting queue → done by the producer, not by the same process. The same process should just release the lock.
Broadcast(lock): Wakes up all threads in the waiting queue.
Lab 4
There are two things: TLB and IPT (Inverted Page Table)
Translate()
Calculate the virtual page number
Look up VPN in TLB
If lookup is successful, calculate the physical address
If lookup fails, call updateTLB and then Translate again
updateTLB()
Calls vpnToPhyPage, which checks the IPT
If vpn is found in the IPT, update the TLB by calling insertToTLB
Otherwise, page fault. Perform paging adn then update the TLB
PageOutPageIn()
Determine the victim frame using LRU
Page out the victim page (write to the swap file / backing store)