Monitor Implementation Using Semaphores - operating-system

So i'm facing a Problem Understanding Monitor Implementation Using Semaphores , i Understod that Conditions of monitor is used for Synchronization problems not the Critical Section one ,
Variables
semaphore mutex; // (initially = 1)
semaphore next; // (initially = 0)
int next_count = 0;
Each function F will be replaced by
wait(mutex);
...
body of F
...
if (next_count > 0)
signal(next);
else
signal(mutex);
Mutual exclusion within a monitor is ensured
i Can't understand that implementation well . why should i signal another process if it's waiting and not Just signal my self ?! .
and i can't understand the x.wait() and x.signal() codes at all
x.wait:
x_count++;
if (next_count > 0)
signal(next);
else
signal(mutex);
wait(x sem);
x_count--;
x.signal():
if (x_count > 0) {
next_count++;
signal(x_sem);
wait(next);
next_count--;
}
i'm trying to understand this topic i searched so much but it still isn't clear

Related

How does copyout() in xv6 avoid race condition in the page table?

// Copy from kernel to user.
// Copy len bytes from src to virtual address dstva in a given page table.
// Return 0 on success, -1 on error.
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
uint64 n, va0, pa0;
while(len > 0){
va0 = PGROUNDDOWN(dstva);
pa0 = walkaddr(pagetable, va0);
if(pa0 == 0)
return -1;
n = PGSIZE - (dstva - va0);
if(n > len)
n = len;
memmove((void *)(pa0 + (dstva - va0)), src, n);
len -= n;
src += n;
dstva = va0 + PGSIZE;
}
return 0;
}
The function used in xv6 kernel for copying out data from the kernel to user-space process accepts a pagetable as argument and uses that pagetable to access the physical address behind that user-space address. However, neither copyout() nor walkaddr() performs any locking operation on the page table. How are race conditions avoided in this case? Is it possible for the page table to change after getting the physical address and before the actual reading and cause issues? And how is it avoided in xv6?
If I am not wrong, the copyout() is invoked by the kernel in the
piperead() and pipewrite() located in pipewrite.c function. Prior to calling this
function the calling process's spinlock is already held.

Two Process Solution for Critical Section Problem- Algorithm 1

I have started learning Critical Section Problem and its various solutions. To explain my question, let me first give a brief background of it.
The general structure for a two Process Solution for Critical Section Problem- Algorithm 1 is:
turn = 0;
do
{
while (turn != 0) ; //if not P0's turn , wait indefinitely
// critical section of Process P0
turn = 1; //after P0 leaves critical section, lets P1 in
//remainder section
} while (1); //loop again
The problem with this Algorithm is that it doesn't support the necessary requirement of Progress. It forces the critical section to be owned in equal turns by P0 -> P1 -> P0 -> P1 -> ...
To get over this problem Algorithm 2 is used where variable turn is replaced by an array flag[]. The general structure of algorithm 2 is:
do
{
flag[0] = T ;
while (flag[1]);//if flag[1] is true wait indefinitely
// critical section of Process P0
flag [0] = F; //P0 indicated it no longer needs to be in critical section
//remainder section
} while (1); //loop again
Here, a process can execute its critical section repeatedly if it needs. (Although this algorithm too doesn't supports progress)
Now my question, why can't we use the variable turn inside the do-while loop in Algorithm 1 in the same way as we use the variable flag[] in ALgorithm 2? Below code will explain what I mean:
For process 0:
do
{
turn = 0;
while (turn != 0) ; //if not P0's turn , wait indefinitely
// critical section of Process P0
turn = 1; //after P0 leaves critical section, lets P1 in
//remainder section
} while (1); //loop again
For process 1:
do
{
turn = 1;
while (turn != 1) ; //if not P0's turn , wait indefinitely
// critical section of Process P0
turn = 0; //after P1 leaves critical section, lets P0 in
//remainder section
} while (1); //loop again
Wouldn't the above code allow a process to repeatedly execute its critical section, if needed and hence solve the problem in Algorithm 1?
I know there is something wrong here or else this solution would have been used generally, don't know just exactly what it is.
The critical section is no longer protected. Among the arbitrary scheduling sequences there is this one (one line = exclusive execution during this time by process X):
process action contents of 'turn' critical section entered (by process)
0 "turn = 1;" 1 no
0 "} while(1);" 1 no
1 "while (turn != 1);" 1 no
1 "// critical section P1" 1 yes (1)
0 "do{" 1 yes (1)
0 "turn = 0;" 0 yes (1)
0 "while (turn != 0);" 0 yes (1)
0 "// critical section P0" 0 collision!

which solution of critical section is fulfilled in this algorithm

initial value of flag is
flag[2] is false
Process P0
do {
flag[0] = true;while (flag[1]) ;
<CS>
flag [0] = false;
<RS>
} while (1);
Process P1
do {
flag[1] = true;while (flag[0]) ;
<CS>
flag [1] = false;
<RS>
} while (1);
i want to know that if both processes run at the same time then isn't progress condition false?
My reason is that it creates a deadlock b/w two processes to get into critical section.I also want to know is mutual exclusion is being fulfilled there?

How does Test and Set Instruction provide Bounded Waiting in below code?

In the below code how is bounded waiting condition satisfied ,I am unable to get the usage of these statements ,why have they applied the condition j!=i and j=(j+1)%n and then the condition mentioned inside if clause using (j==i),please clarify this ,according to me it should only check for waiting[j] , so as to confirm if any other process is waiting for lock or not ,I am unable to get the idea of working of this algorithm ,please explain it .
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = false;
do {
waiting[i] = true;
while (waiting[i] && test_and_set(&lock)) ;
waiting[i] = false;
/* critical section */
j = (i + 1) % n;
while ((j != i) && !waiting[j])
j = (j + 1) % n;
if (j == i)
lock = false;
else
waiting[j] = false;
/* remainder section */
} while (true);
Bounded waiting means no process should wait for a resource for infinite amount of time.
You have n processes, process i is currently executing, when it enters the critical section, it sets its waiting to false.
Now, what happens when process i has finished ?
Process i will look for an index j (process j) that is waiting to run in critical section. In other words, we are looking for a process that is waiting to enter the critical section that is different from the current process that ran in critical section.
if (i==j), then no such process exists, we set lock to false. Otherwise, we set the process that is waiting to run and prevent starvation. And this way you satisfy Bounded Waiting.
This is achieved because you do a circular search, you first check processes
i+1, i+2, .... n, 0, 1, ... ,(i-1)

Why flag[other processes] == true Petersen's Solution

I am recently studying Peterson's Solution to Critical Section problem.
Let i and j two processes entering critical section,
I am not understanding why we set flag[j] == true in While loop when
its i's turn to enter critical section.
do
{
flag[i] = true;
turn = j;
while(**flag[j] == true** && turn == j);
Critical Section
flag[i] = false;
}
while(true);
while(flag[j] == true && turn == j);
This line says that if the other process is executing its critical section, then the first process should keep on waiting till the second process sets its flag variable(shared variable) to false.
Only after the second process executes its critical section, and sets its flag variable(shared variable) to false, the first process would start executing its critical section.