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