Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

uses pthreads over spinlocks and also little revise of structures used in the code #638

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 77 additions & 77 deletions kernel/bio.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,51 @@
// so do not keep them longer than necessary.



#include "types.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "riscv.h"
#include "defs.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include "fs.h"
#include "buf.h"

struct {
struct spinlock lock;
#include "virtio_disk.h"

#define NBUF 8

struct buf {
uint32_t dev;
uint32_t blockno;
bool valid;
int refcnt;
pthread_mutex_t lock;
uint8_t data[BLOCK_SIZE];
struct buf* next;
struct buf* prev;
};

struct buf_cache {
pthread_mutex_t lock;
struct buf buf[NBUF];

// Linked list of all buffers, through prev/next.
// Sorted by how recently the buffer was used.
// head.next is most recent, head.prev is least.
struct buf head;
} bcache;
};

void
binit(void)
{
struct buf *b;
static struct buf_cache bcache;

initlock(&bcache.lock, "bcache");
void buf_cache_init(void) {
pthread_mutex_init(&bcache.lock, NULL);

// Create linked list of buffers
bcache.head.prev = &bcache.head;
bcache.head.next = &bcache.head;
for(b = bcache.buf; b < bcache.buf+NBUF; b++){
for (size_t i = 0; i < NBUF; i++) {
struct buf* b = &bcache.buf[i];
pthread_mutex_init(&b->lock, NULL);
b->next = bcache.head.next;
b->prev = &bcache.head;
initsleeplock(&b->lock, "buffer");
bcache.head.next->prev = b;
bcache.head.next = b;
}
Expand All @@ -55,99 +67,87 @@ binit(void)
// Look through buffer cache for block on device dev.
// If not found, allocate a buffer.
// In either case, return locked buffer.
static struct buf*
bget(uint dev, uint blockno)
{
struct buf *b;
static struct buf* bget(uint32_t dev, uint32_t blockno) {
pthread_mutex_lock(&bcache.lock);

acquire(&bcache.lock);

// Is the block already cached?
for(b = bcache.head.next; b != &bcache.head; b = b->next){
if(b->dev == dev && b->blockno == blockno){
// Check if the block is already cached.
struct buf* b;
for (b = bcache.head.next; b != &bcache.head; b = b->next) {
if (b->dev == dev && b->blockno == blockno) {
b->refcnt++;
release(&bcache.lock);
acquiresleep(&b->lock);
pthread_mutex_unlock(&bcache.lock);
pthread_mutex_lock(&b->lock);
return b;
}
}

// Not cached.
// Block is not cached.
// Recycle the least recently used (LRU) unused buffer.
for(b = bcache.head.prev; b != &bcache.head; b = b->prev){
if(b->refcnt == 0) {
for (b = bcache.head.prev; b != &bcache.head; b = b->prev) {
if (b->refcnt == 0) {
b->dev = dev;
b->blockno = blockno;
b->valid = 0;
b->valid = false;
b->refcnt = 1;
release(&bcache.lock);
acquiresleep(&b->lock);
pthread_mutex_unlock(&bcache.lock);
pthread_mutex_lock(&b->lock);
return b;
}
}
panic("bget: no buffers");

// All buffers are in use.
pthread_mutex_unlock(&bcache.lock);
return NULL;
}



// Return a locked buf with the contents of the indicated block.
struct buf*
bread(uint dev, uint blockno)
{
struct buf *b;

b = bget(dev, blockno);
if(!b->valid) {
virtio_disk_rw(b, 0);
b->valid = 1;
// If no buffer is available or if the read from the disk fails, return NULL.
struct buf* bread(uint32_t dev, uint32_t blockno) {
struct buf* b = bget(dev, blockno);
if (b == NULL) {
return NULL;
}

if (!b->valid) {
if (!virtio_disk_rw(b, 0)) {
pthread_mutex_unlock(&b->lock);
return NULL;
}
b->valid = true;
}

return b;
}

// Write b's contents to disk. Must be locked.
void
bwrite(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("bwrite");
virtio_disk_rw(b, 1);
// Return true if successful, false otherwise.
bool bwrite(struct buf* b) {
if (!pthread_mutex_trylock(&b->lock)) {
return false;
}

bool success = virtio_disk_rw(b, 1);
pthread_mutex_unlock(&b->lock);
return success;
}

// Release a locked buffer.
// Move to the head of the most-recently-used list.
void
brelse(struct buf *b)
{
if(!holdingsleep(&b->lock))
panic("brelse");

releasesleep(&b->lock);

acquire(&bcache.lock);
void brelse(struct buf* b) {
pthread_mutex_lock(&bcache.lock);
b->refcnt--;
if (b->refcnt == 0) {
// no one is waiting for it.
// Move to the head of the most-recently-used list.
b->next->prev = b->prev;
b->prev->next = b->next;
b->next = bcache.head.next;
b->prev = &bcache.head;
bcache.head.next->prev = b;
bcache.head.next = b;
}

release(&bcache.lock);
}

void
bpin(struct buf *b) {
acquire(&bcache.lock);
b->refcnt++;
release(&bcache.lock);
pthread_mutex_unlock(&bcache.lock);
pthread_mutex_unlock(&b->lock);
}

void
bunpin(struct buf *b) {
acquire(&bcache.lock);
b->refcnt--;
release(&bcache.lock);
}