Snail OS 0.03 device目录则是利用信号量和锁实现同步和互斥的实战

利用信号量可以实现锁,锁能够使得临界区代码被线程独占,而进程阻塞和唤醒在环形缓冲区上的使用能够有限度的实现同步,而利用信号量能够实现设备驱动程序和硬盘中断服务程序之间的同步。

// console.h
#ifndef __CONSOLE_H
#define __CONSOLE_H

void console_init(void);
void console_acquire(void);
void console_release(void);
void console_put_str(char* str);
void console_put_int(unsigned int i);

#endif
// console.c

#include "console.h"
#include "string.h"
#include "thread.h"

static struct lock console_lock;

void console_init(void) {
	lock_init(&console_lock);
}

void console_acquire(void) {
	lock_acquire(&console_lock);
}

void console_release(void) {
	lock_release(&console_lock);
}

void console_put_str(char* str) {
	console_acquire();
	put_str_red(str);
	console_release();
}

void console_put_int(unsigned int i) {
	console_acquire();
	put_str_red(i2a(i, 16));
	console_release();
}

 

// ioqueue.h
#ifndef __IOQUEUE_H
#define __IOQUEUE_H
#include "thread.h"
#include "sync.h"

struct ioqueue {
	struct lock lock;
	struct task* producer;
	struct task* consumer;
	int* buf;
	unsigned int head;
	unsigned int tail;
};

struct ioqueue main_ioq;

void ioqueue_init(struct ioqueue* ioq);
unsigned int next_pos(int pos);
bool ioq_full(struct ioqueue* ioq);
bool ioq_empty(struct ioqueue* ioq);
void ioq_wait(struct task** waiter);
void wakeup(struct task** waiter);
int ioq_getint(struct ioqueue* ioq);
void ioq_putint(struct ioqueue* ioq, int data);

#endif
// ioqueue.c
#include "ioqueue.h"
#include "thread.h"
#include "debug.h"
#include "intr_status_op.h"
#include "global.h"
#include "memory.h"

void ioqueue_init(struct ioqueue* ioq) {
	lock_init(&ioq->lock);
	ioq->producer = ioq->consumer = NULL;
	ioq->head = ioq->tail = 0;
	ioq->buf = get_kernel_pages(1);
}

unsigned int next_pos(int pos) {
	return (pos + 1) % 1024;
}

bool ioq_full(struct ioqueue* ioq) {
	ASSERT(intr_get_status() == INTR_OFF);
	return next_pos(ioq->head) == ioq->tail;
}

bool ioq_empty(struct ioqueue* ioq) {
	ASSERT(intr_get_status() == INTR_OFF);
	return ioq->head == ioq->tail;
}

void ioq_wait(struct task** waiter) {
	ASSERT(*waiter != NULL && waiter != NULL);
	*waiter = running_thread();
	thread_block(BLOCKED);
}

void wakeup(struct task** waiter) {
	ASSERT(*waiter != NULL);
	thread_unblock(*waiter);
	*waiter = NULL;
}

int ioq_getint(struct ioqueue* ioq) {
	ASSERT(intr_get_status() == INTR_OFF);
	while(ioq_empty(ioq)) {
		lock_acquire(&ioq->lock);
		ioq_wait(&ioq->consumer);
		lock_release(&ioq->lock);
	}
	int data = ioq->buf[ioq->tail];
	ioq->tail = next_pos(ioq->tail);
	if(ioq->producer != NULL) {
		wakeup(&ioq->producer);
	}
	return data;
}

void ioq_putint(struct ioqueue* ioq, int data) {
	ASSERT(intr_get_status() == INTR_OFF);
	while(ioq_full(ioq)) {
		lock_acquire(&ioq->lock);
		ioq_wait(&ioq->producer);
		lock_release(&ioq->lock);
	}
	ioq->buf[ioq->head] = data;
	ioq->head = next_pos(ioq->head);
	thread_unblock(main_thread);	
	if(ioq->consumer != NULL) {
		wakeup(&ioq->consumer);
	}
}

 

// ide.h
#ifndef __IDE_H
#define __IDE_H
#include "global.h"
#include "thread.h"
#include "sync.h"

struct partition {
	char name[32];
	unsigned int start_lba, sec_cnt;
	struct disk* disk_;
	struct super_block* sb;
};

struct disk {
	char name[32];
	unsigned char dev_no;
	struct partition prim_parts[4];
	struct partition logic_parts[8];
};

extern void insw(unsigned short port, void* buf, unsigned int word_cnt);
extern void outsw(unsigned short port, void* buf, unsigned int word_cnt);

void hd_init(void);
void select_hd(struct disk* hd);
void select_lba(struct disk* hd, unsigned int lba, unsigned char sec_cnt);
void hd_cmd(struct disk* hd, unsigned char cmd);
void read_sectors(struct disk* hd, void* buf, unsigned char sec_cnt);
void write_sectors(struct disk* hd, void* buf, unsigned char sec_cnt);
bool fake_busy_wait(struct disk* hd);
void hd_read(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt);
void hd_write(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt);
			 
void hd_read_sub(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt);
void hd_write_sub(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt);
			 
			 

unsigned short portbase;
struct lock hd_lock;
bool expecting_intr;
struct semaphore hd_done;
struct disk hds[2];

#endif

 

// ide.c
#include "hd.h"
#include "string.h"
#include "debug.h"
#include "intr.h"

/*
unsigned short portbase;
struct lock hd_lock;
bool expecting_intr;
struct semaphore hd_done;

struct partition {
	char name[32];
	unsigned int start_lba, sec_cnt;
	struct disk* disk_;
	struct super_block* sb;
};

struct disk {
	char name[32];
	unsigned char dev_no;
	struct partition prim_parts[4];
	struct partition logic_parts[8];
};
*/


void hd_init(void) {
	portbase = 0x1f0;
	expecting_intr = false;
	lock_init(&hd_lock);
	sema_init(&hd_done, 0);
	strcpy_(hds[0].name, "hd0");
	strcpy_(hds[1].name, "hd1");
	hds[0].dev_no = 0;
	hds[1].dev_no = 1;
}

void select_hd(struct disk* hd) {
	unsigned char dev = 0xa0 + 0x40;
	portbase = 0x1f0;
	if(hd->dev_no == 1) {
		portbase = 0x170;
		dev += 0x10;
	}
	out((portbase + 6), dev);
}

void select_lba(struct disk* hd, unsigned int lba, unsigned char sec_cnt) {
	unsigned char dev = 0xa0 + 0x40;
	portbase = 0x1f0;
	if(hd->dev_no == 1) {
		portbase = 0x170;
		dev += 0x10;
	}
	out((portbase + 2), sec_cnt);
	out((portbase + 3), lba);
	out((portbase + 4), lba >> 8);
	out((portbase + 5), lba >> 16);
	out((portbase + 6), dev + ((lba >> 24) & 0x0f));
}

void hd_cmd(struct disk* hd, unsigned char cmd) {
	portbase = 0x1f0;
	if(hd->dev_no == 1) {
		portbase = 0x170;
	}
	expecting_intr = true;
	out((portbase + 7), cmd);
}

void read_sectors(struct disk* hd, void* buf, unsigned char sec_cnt) {
	unsigned int size;
	portbase = 0x1f0;
	if(hd->dev_no == 1) {
		portbase = 0x170;
	}
	if(!sec_cnt) {
		size = (256 << 9);
	} else {
		size = (sec_cnt << 9);
	}
	insw((portbase + 0), buf, (size >> 1));
}

void write_sectors(struct disk* hd, void* buf, unsigned char sec_cnt) {
	unsigned int size;
	portbase = 0x1f0;
	if(hd->dev_no == 1) {
		portbase = 0x170;
	}
	if(!sec_cnt) {
		size = (256 << 9);
	} else {
		size = (sec_cnt << 9);
	}
	outsw((portbase + 0), buf, (size >> 1));
}

bool fake_busy_wait(struct disk* hd) {
	portbase = 0x1f0;
	if(hd->dev_no == 1) {
		portbase = 0x170;
	}
	unsigned int i = 30000;
	for(; i >= 0; i -= 10) {
		if(!(in((portbase + 7)) & 0x80)) {
			return (in((portbase + 7)) & 0x08);
		} else {
			mtime_sleep(10);
		}
	}
	return false;
}

void hd_read(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt)
{
	lock_acquire(&hd_lock);
	select_hd(hd);
	unsigned int per_sec, done_sec = 0;
	while(done_sec < sec_cnt) {
		if((done_sec + 256) <= sec_cnt) {
			per_sec = 256;
		} else {
			per_sec = sec_cnt - done_sec;
		}
		select_lba(hd, lba + done_sec, per_sec);
	
		hd_cmd(hd, 0x20);
		sema_down(&hd_done);
		if(!fake_busy_wait(hd)) {
			PANIC("read hard disk failed!...");
		}
		read_sectors(hd, (void*)((unsigned int)buf + (done_sec << 9)), per_sec);
		done_sec += per_sec;
	}
	lock_release(&hd_lock);
}
	
void hd_write(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt)
{
	lock_acquire(&hd_lock);
	select_hd(hd);
	unsigned int per_sec, done_sec = 0;
	while(done_sec < sec_cnt) {
		if((done_sec + 256) <= sec_cnt) {
			per_sec = 256;
		} else {
			per_sec = sec_cnt - done_sec;
		}
		select_lba(hd, lba + done_sec, per_sec);
	
		hd_cmd(hd, 0x30);
		if(!fake_busy_wait(hd)) {
			PANIC("read hard disk failed!...");
		}
		write_sectors(hd, (void*)((unsigned int)buf + (done_sec << 9)), per_sec);
		sema_down(&hd_done);
		done_sec += per_sec;
	}
	lock_release(&hd_lock);
}
	
void hd_read_sub(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt)
{
	lock_acquire(&hd_lock);
	select_hd(hd);
	unsigned int per_sec = 1, done_sec = 0;
	while(done_sec < sec_cnt) {
		select_lba(hd, lba++, per_sec);	
		hd_cmd(hd, 0x20);
		
		sema_down(&hd_done);
		if(!fake_busy_wait(hd)) {
			PANIC("read hard disk failed!...");
		}
		read_sectors(hd, (void*)((unsigned int)buf + (done_sec << 9)), per_sec);
		done_sec += per_sec;
	}
	lock_release(&hd_lock);
}
	
void hd_write_sub(struct disk* hd, unsigned int lba, void* buf,
			 unsigned int sec_cnt)
{
	lock_acquire(&hd_lock);
	select_hd(hd);
	unsigned int per_sec = 1, done_sec = 0;
	while(done_sec < sec_cnt) {
		select_lba(hd, lba + done_sec, per_sec);
		hd_cmd(hd, 0x30);
		
		if(!fake_busy_wait(hd)) {
			PANIC("read hard disk failed!...");
		}
		write_sectors(hd, (void*)((unsigned int)buf + (done_sec << 9)), per_sec);
		sema_down(&hd_done);
		done_sec += per_sec;
	}
	lock_release(&hd_lock);
}
	










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_39410618

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值