How to change the preemption rate in xv6? - operating-system

I need to achieve the following:
Process preemption should be done in every time quantum (measured in clock ticks) instead of every clock tick
In order to achieve this, I have modified the yield() function in proc.c
void
yield(void)
{
struct proc *p = myproc();
acquire(&ptable.lock); //DOC: yieldlock
p->state = RUNNABLE;
p->timeslice--;
if(!p->timeslice)
sched();
release(&ptable.lock);
}
I have added the field int timeslice in struct proc. I timeslice is initialized in scheduler(), every time a process is scheduled
void
scheduler(void)
{
struct proc *p;
struct cpu *c = mycpu();
c->proc = 0;
for(;;){
// Enable interrupts on this processor.
sti();
// Loop over process table looking for process to run.
acquire(&ptable.lock);
for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){
if(p->state != RUNNABLE)
continue;
// Switch to chosen process. It is the process's job
// to release ptable.lock and then reacquire it
// before jumping back to us.
c->proc = p;
switchuvm(p);
p->state = RUNNING;
p->timeslice = QUANTA;
swtch(&(c->scheduler), p->context);
switchkvm();
// Process is done running for now.
// It should have changed its p->state before coming back.
c->proc = 0;
}
release(&ptable.lock);
}
}
But I am getting the following error in xv6 shell
xv6...
cpu1: starting 1
cpu0: starting 0
sb: size 1000 nblocks 941 ninodes 200 nlog 30 logstart 2 inodestart 32 bmap start 58
unexpected trap 14 from cpu 1 eip 801059d2 (cr2=0x3920)
lapicid 1: panic: trap
80105cdf 801059c9 0 0 0 0 0 0 0 0
Please help me fix the error. Thanks in advance ...

You should not change the process state if you don't call sched().
void
yield(void)
{
acquire(&ptable.lock);
struct proc *p = myproc();
p->timeslice--;
if(!p->timeslice ) {
acquire(&ptable.lock);
p->state = RUNNABLE;
sched();
}
release(&ptable.lock);
}
Note:
In code above, you might acquire and release the process table in the if body, but I'm not sure that it's save to change p->timeslice if process table is not locked.

Related

dht11 sensor only retuning unexpected number of pulse often

I am trying to make a simple water pump controller using a dth11 to make the pump turn on more frequently when the temperature is higher. i have it working but every 4th or 5th time i call measure on the dht11 sensor i get an error saying "InvalidPulseCount: Expected 82 but got 0 pulses" or "InvalidPulseCount: Got more than 82 pulses". I have added try block that is stopping the program from crashing but would really like to figure out why it is happening. I also had to edit the dht.py lib to have 82 instead of 84 as the default expected pulses because that was what was commonly returned.
here is my main.py file
from machine import Pin
from time import sleep_ms
import dht
import I2C_LCD_driver
sensor = dht.DHT11(Pin(28))
lcd = I2C_LCD_driver.lcd()
pump = Pin(7, machine.Pin.OUT)
counter = 0
pumpTime = 30
normalTime = 60
hotTime = 30
lowTemp = 19
# sensor variables only updated every 3 loops
lastMesure = 1
temp = 0
humid = 0
first = True
while True:
# sensor.messure can only be called ever 3 seconds
# start at 1 and set to zero in the first loop for our first messurement
lastMesure += -1
if lastMesure <= 0:
try:
sensor.measure()
lastMesure = 3
temp = round((sensor.temperature), 0)
humid = sensor.humidity
except:
print("something went wrong")
print("Counter: {:.0f} pumpping:{:0.f}".format(counter, pump.value()))
print("Temp: {:.0f}℃ HUMIDITY: {:.0F}% ".format(temp, humid))
# if the pump is running
if pump.value() == 1:
if counter >= pumpTime: # if it has been the set pump run time
pump.value(0) # turn off pump
counter = 0 # reset counter
else:
counter += 1
else:
# check current temp
# if warmer then {lowTemp} check for {hotTime} else check for {normalTime}
if (temp > lowTemp and counter >= hotTime) or counter >= normalTime:
pump.value(1) # turn on pump
counter = 0 # reset counter
else:
counter += 1
# print current data to the screen
lcd.lcd_clear()
lcd.lcd_display_string("T: {:.0f}C H:{:.0f}%".format(temp, humid), 1)
if pump.value() == 1:
status = f'Pumping {pumpTime - counter}s'
lcd.lcd_display_string(status, 2);
else:
lcd.lcd_display_string("Pump off ", 2)
sleep_ms(1000)
here is a picture of my breadboard set up. I have run it both with and without a 1k pull up resistor on the data pin

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.

stm32f429, spi dr register not write data

code_1
code_2
register on debug
logic analyzer
void SPI_SendData(SPI_RegDef_t *pSPIx,uint8_t *pTxBuffer , uint32_t Len)
{
while(Len > 0)
{
// 1 . wait until TXE is set ,
while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG) == FLAG_RESET);
// 2. check the DFF bit in CR1
if( (pSPIx->CR1 & (1 << SPI_CR1_DFF) ) )
{
// 16 BIT DFF
pSPIx->DR = *((uint16_t*)pTxBuffer); // dereferencing(typecasting );
Len--;
Len--;
(uint16_t*)pTxBuffer++; // typecasting this pointer to uint16 type and incrementing by 2.
/* The buffer is a uint8_t pointer type. When using the 16-bit data frame,
* we pick up 16-bits of data, increment pointer by 2 bytes,*/
}else
{
// 8 BIT DFF
pSPIx->DR = *pTxBuffer;
Len--;
pTxBuffer++;
/*
*(( uint8_t*)&hspi->Instance->DR) = (*pData);
pData += sizeof(uint8_t);
hspi->TxXferCount--;
*/
}
}
}
i see, MOSI always send 255 on logic analyzer but wrong data.
(uint16_t*)pTxBuffer++; increments the pointer by 1 byte, not two that you say you hope it will in the comment.
If you want to do it by converting to halfword pointer and incrementing, then you need to do something like:
pTxBuffer = (uint8_t*)(((uint16_t*)pTxBuffer) + 1);
But that is just a silly way of saying pTxBuffer += 2;
Really it doesn't make sense to have the if inside the loop, because the value of the DFF bit doesn't change unless you write to it, and you don't. I suggest you write one loop over words and one loop over bytes and have the if at the top level.

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)

How to ensure recv() to have all data send() in tcp

I am implementing the recvall() function to be sure that the data is completely sent. Also I modified the send() function to sendall() like this:
int sendall (int consocket, char* buf, int* len)
{
int total = 0;
int bytesleft = *len; // how many we have left to send
int n;
while(total < *len) {
n = send(consocket, buf+total, bytesleft, 0);
if (n == -1) { break; }
total += n;
bytesleft -= n;
*len = total; // return number actually sent here
return n==-1?-1:0; // return -1 on failure, 0 on success
}
}
How can I implement recvall()? Say I sent from the server a struct of 14 bytes and I check in the client and get 12 bytes.. now in an unreliable situation how should I manage to get the other two bytes... I have spent time trying... any help welcomed.
You may loop over a select with an appropriate timeout . Select will wait until new data is received or until time is elapsed or an error occurs. This gives you a greater control than just blocing on a recv.