提交 36f59e13 创建 作者: 赵鹏翀's avatar 赵鹏翀

Initial commit

上级
#!/usr/bin/python
#!/usr/bin/python
import sys
import copy
P_NULL = 0
P_NEW = 1
P_READY = 2
P_RUNNING = 4
P_WAITING = 8
P_EXIT = 16
S_STATE = 0
S_TIME = 1
HZ = 100
graph_title = r"""
-----===< COOL GRAPHIC OF SCHEDULER >===-----
[Symbol] [Meaning]
~~~~~~~~~~~~~~~~~~~~~~~~~~~
number PID or tick
"-" New or Exit
"#" Running
"|" Ready
":" Waiting
/ Running with
"+" -| Ready
\and/or Waiting
-----===< !!!!!!!!!!!!!!!!!!!!!!!!! >===-----
"""
usage = """
Usage:
%s /path/to/process.log [PID1] [PID2] ... [-x PID1 [PID2] ... ] [-m] [-g]
Example:
# Include process 6, 7, 8 and 9 in statistics only. (Unit: tick)
%s /path/to/process.log 6 7 8 9
# Exclude process 0 and 1 from statistics. (Unit: tick)
%s /path/to/process.log -x 0 1
# Include process 6 and 7 only and print a COOL "graphic"! (Unit: millisecond)
%s /path/to/process.log 6 7 -m -g
# Include all processes and print a COOL "graphic"! (Unit: tick)
%s /path/to/process.log -g
"""
class MyError(Exception):
pass
class DuplicateNew(MyError):
def __init__(self, pid):
args = "More than one 'N' for process %d." % pid
MyError.__init__(self, args)
class UnknownState(MyError):
def __init__(self, state):
args = "Unknown state '%s' found." % state
MyError.__init__(self, args)
class BadTime(MyError):
def __init__(self, time):
args = "The time '%d' is bad. It should >= previous line's time." % time
MyError.__init__(self, args)
class TaskHasExited(MyError):
def __init__(self, state):
args = "The process has exited. Why it enter '%s' state again?" % state
MyError.__init__(self, args)
class BadFormat(MyError):
def __init__(self):
args = "Bad log format"
MyError.__init__(self, args)
class RepeatState(MyError):
def __init__(self, pid):
args = "Previous state of process %d is identical with this line." % (pid)
MyError.__init__(self, args)
class SameLine(MyError):
def __init__(self):
args = "It is a clone of previous line."
MyError.__init__(self, args)
class NoNew(MyError):
def __init__(self, pid, state):
args = "The first state of process %d is '%s'. Why not 'N'?" % (pid, state)
MyError.__init__(self, args)
class statistics:
def __init__(self, pool, include, exclude):
if include:
self.pool = process_pool()
for process in pool:
if process.getpid() in include:
self.pool.add(process)
else:
self.pool = copy.copy(pool)
if exclude:
for pid in exclude:
if self.pool.get_process(pid):
self.pool.remove(pid)
def list_pid(self):
l = []
for process in self.pool:
l.append(process.getpid())
return l
def average_turnaround(self):
if len(self.pool) == 0:
return 0
sum = 0
for process in self.pool:
sum += process.turnaround_time()
return float(sum) / len(self.pool)
def average_waiting(self):
if len(self.pool) == 0:
return 0
sum = 0
for process in self.pool:
sum += process.waiting_time()
return float(sum) / len(self.pool)
def begin_time(self):
begin = 0xEFFFFF
for p in self.pool:
if p.begin_time() < begin:
begin = p.begin_time()
return begin
def end_time(self):
end = 0
for p in self.pool:
if p.end_time() > end:
end = p.end_time()
return end
def throughput(self):
return len(self.pool) * HZ / float(self.end_time() - self.begin_time())
def print_graphic(self):
begin = self.begin_time()
end = self.end_time()
print graph_title
for i in range(begin, end+1):
line = "%5d " % i
for p in self.pool:
state = p.get_state(i)
if state & P_NEW:
line += "-"
elif state == P_READY or state == P_READY | P_WAITING:
line += "|"
elif state == P_RUNNING:
line += "#"
elif state == P_WAITING:
line += ":"
elif state & P_EXIT:
line += "-"
elif state == P_NULL:
line += " "
elif state & P_RUNNING:
line += "+"
else:
assert False
if p.get_state(i-1) != state and state != P_NULL:
line += "%-3d" % p.getpid()
else:
line += " "
print line
class process_pool:
def __init__(self):
self.list = []
def get_process(self, pid):
for process in self.list:
if process.getpid() == pid:
return process
return None
def remove(self, pid):
for process in self.list:
if process.getpid() == pid:
self.list.remove(process)
def new(self, pid, time):
p = self.get_process(pid)
if p:
if pid != 0:
raise DuplicateNew(pid)
else:
p.states=[(P_NEW, time)]
else:
p = process(pid, time)
self.list.append(p)
return p
def add(self, p):
self.list.append(p)
def __len__(self):
return len(self.list)
def __iter__(self):
return iter(self.list)
class process:
def __init__(self, pid, time):
self.pid = pid
self.states = [(P_NEW, time)]
def getpid(self):
return self.pid
def change_state(self, state, time):
last_state, last_time = self.states[-1]
if state == P_NEW:
raise DuplicateNew(pid)
if time < last_time:
raise BadTime(time)
if last_state == P_EXIT:
raise TaskHasExited(state)
if last_state == state and self.pid != 0: # task 0 can have duplicate state
raise RepeatState(self.pid)
self.states.append((state, time))
def get_state(self, time):
rval = P_NULL
combo = P_NULL
if self.begin_time() <= time <= self.end_time():
for state, s_time in self.states:
if s_time < time:
rval = state
elif s_time == time:
combo |= state
else:
break
if combo:
rval = combo
return rval
def turnaround_time(self):
return self.states[-1][S_TIME] - self.states[0][S_TIME]
def waiting_time(self):
return self.state_last_time(P_READY)
def cpu_time(self):
return self.state_last_time(P_RUNNING)
def io_time(self):
return self.state_last_time(P_WAITING)
def state_last_time(self, state):
time = 0
state_begin = 0
for s,t in self.states:
if s == state:
state_begin = t
elif state_begin != 0:
assert state_begin <= t
time += t - state_begin
state_begin = 0
return time
def begin_time(self):
return self.states[0][S_TIME]
def end_time(self):
return self.states[-1][S_TIME]
# Enter point
if len(sys.argv) < 2:
print usage.replace("%s", sys.argv[0])
sys.exit(0)
# parse arguments
include = []
exclude = []
unit_ms = False
graphic = False
ex_mark = False
try:
for arg in sys.argv[2:]:
if arg == '-m':
unit_ms = True
continue
if arg == '-g':
graphic = True
continue
if not ex_mark:
if arg == '-x':
ex_mark = True
else:
include.append(int(arg))
else:
exclude.append(int(arg))
except ValueError:
print "Bad argument '%s'" % arg
sys.exit(-1)
# parse log file and construct processes
processes = process_pool()
f = open(sys.argv[1], "r")
# Patch process 0's New & Run state
processes.new(0, 40).change_state(P_RUNNING, 40)
try:
prev_time = 0
prev_line = ""
for lineno, line in enumerate(f):
if line == prev_line:
raise SameLine
prev_line = line
fields = line.split("\t")
if len(fields) != 3:
raise BadFormat
pid = int(fields[0])
s = fields[1].upper()
time = int(fields[2])
if time < prev_time:
raise BadTime(time)
prev_time = time
p = processes.get_process(pid)
state = P_NULL
if s == 'N':
processes.new(pid, time)
elif s == 'J':
state = P_READY
elif s == 'R':
state = P_RUNNING
elif s == 'W':
state = P_WAITING
elif s == 'E':
state = P_EXIT
else:
raise UnknownState(s)
if state != P_NULL:
if not p:
raise NoNew(pid, s)
p.change_state(state, time)
except MyError, err:
print "Error at line %d: %s" % (lineno+1, err)
sys.exit(0)
# Stats
stats = statistics(processes, include, exclude)
att = stats.average_turnaround()
awt = stats.average_waiting()
if unit_ms:
unit = "ms"
att *= 1000/HZ
awt *= 1000/HZ
else:
unit = "tick"
print "(Unit: %s)" % unit
print "Process Turnaround Waiting CPU Burst I/O Burst"
for pid in stats.list_pid():
p = processes.get_process(pid)
tt = p.turnaround_time()
wt = p.waiting_time()
cpu = p.cpu_time()
io = p.io_time()
if unit_ms:
print "%7d %10d %7d %9d %9d" % (pid, tt*1000/HZ, wt*1000/HZ, cpu*1000/HZ, io*1000/HZ)
else:
print "%7d %10d %7d %9d %9d" % (pid, tt, wt, cpu, io)
print "Average: %10.2f %7.2f" % (att, awt)
print "Throughout: %.2f/s" % (stats.throughput())
if graphic:
stats.print_graphic()
#define __LIBRARY__
#define __LIBRARY__
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFFER_SIZE 10 /* 缓冲区数量 */
#define NUM 25 /* 产品总数 */
#define __NR_sem_open 87
#define __NR_sem_wait 88
#define __NR_sem_post 89
#define __NR_sem_unlink 90
typedef void sem_t; /* 下面用到sem_t*的,其实质都是指针,故在此将sem_t*类型定义为void*类型,
就不用在此重新定义sem_t的结构体,因此也方便了对结构体的管理:如果在
此重新定义此结构体,内核中也已经定义了此结构体,如需对其修改,则同时
需要修改此处和内存处两处的结构体 */
_syscall2(int, sem_open, const char*, name, unsigned int, value)
_syscall1(int, sem_wait, sem_t *, sem)
_syscall1(int, sem_post, sem_t *, sem)
_syscall1(int, sem_unlink, const char *, name)
int main()
{
/* 注意: 在应用程序中不能使用断点等调试功能 */
int i, j;
int consumeNum = 0; /* 消费者消费的产品号 */
int produceNum = 0; /* 生产者生产的产品号 */
int consume_pos = 0; /* 消费者从共享缓冲区中取出产品消费的位置 */
int produce_pos = 0; /* 生产者生产产品向共享缓冲区放入的位置 */
sem_t *empty, *full, *mutex;
FILE *fp = NULL;
pid_t producer_pid, consumer_pid;
/* 创建empty、full、mutex三个信号量 */
empty = (sem_t*)sem_open("empty", BUFFER_SIZE);
full = (sem_t*)sem_open("full", 0);
mutex = (sem_t*)sem_open("mutex", 1);
/* 用文件建立一个共享缓冲区 */
fp=fopen("filebuffer.txt", "wb+");
/* 创建生产者进程 */
if( !fork() )
{
producer_pid = getpid();
printf("Producer pid=%d create success!\n", producer_pid);
for( i = 0 ; i < NUM; i++)
{
sem_wait(empty);
sem_wait(mutex);
produceNum = i;
/* 移动文件的游标,向其中放入产品 */
fseek(fp, produce_pos * sizeof(int), SEEK_SET);
fwrite(&produceNum, sizeof(int), 1, fp);
fflush(fp);
/* 输出生产产品的信息 */
printf("Producer pid=%d : %02d at %d\n", producer_pid, produceNum, produce_pos);
fflush(stdout);
/* 生产者的游标向后移动一个位置 */
produce_pos = (produce_pos + 1) % BUFFER_SIZE;
sem_post(mutex);
sem_post(full);
sleep(2);
}
exit(0);
}
/* 创建消费者进程 */
if( !fork() )
{
consumer_pid = getpid();
printf("\t\t\tConsumer pid=%d create success!\n", consumer_pid);
for( j = 0; j < NUM; j++ )
{
sem_wait(full);
sem_wait(mutex);
/* 移动文件的游标,取出其中的产品 */
fseek(fp, consume_pos * sizeof(int), SEEK_SET);
fread(&consumeNum, sizeof(int), 1, fp);
fflush(fp);
/* 输出消费产品的信息 */
printf("\t\t\tConsumer pid=%d: %02d at %d\n", consumer_pid, consumeNum, consume_pos);
fflush(stdout);
/* 消费者的游标向后移动一个位置 */
consume_pos = (consume_pos + 1) % BUFFER_SIZE;
sem_post(mutex);
sem_post(empty);
if(j<4) sleep(8);
else sleep(1);
}
exit(0);
}
waitpid(producer_pid, NULL, 0); /* 等待生产者进程结束 */
waitpid(consumer_pid, NULL, 0); /* 等待消费者进程结束 */
/* 关闭所有信号量 */
sem_unlink("empty");
sem_unlink("full");
sem_unlink("mutex");
/* 关闭文件 */
fclose(fp);
return 0;
}
#define __LIBRARY__
#define __LIBRARY__
#include <unistd.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <signal.h>
#include <string.h>
#define SEM_MAX 20 // 最大信号量个数
#define NAME_MAX 16 // 信号量名称的最大长度
// 定义任务队列链表
typedef struct _item
{
struct task_struct* task; // 当前任务指针
struct _item* next; // 下一个链表项的指针
}item;
// 定义信号量结构体
typedef struct _sem_t
{
char sem_name[NAME_MAX]; // 信号量的名称
int value; // 可用资源的数量
int used; // 信号量的引用计数,为0表示未使用,大于0表示已使用
item* wait; // 阻塞在信号量下的等待的任务
}sem_t;
sem_t sem_array[SEM_MAX]; // 系统中存放信号量的结构体数组
// 将任务插入任务等待队列的队尾
void wait_task(struct task_struct* task, sem_t* sem)
{
item** end;
item* new_item;
// 查找任务队列尾部的最后一个任务
for(end = &sem->wait; *end != NULL; end = &(*end)->next)
;
// 新建item节点,将新建节点插入到任务链表item的尾部
new_item = (item*)malloc(sizeof(item));
new_item->task = task;
new_item->next = NULL;
*end = new_item;
return;
}
// 在已有信号量中查找信号量
int find_sem(const char* name)
{
int i;
for(i = 0; i < SEM_MAX; i++)
{
// 如果在已有信号量中存在当前信号量,则返回当前信号量在信号量数组中的偏移量
if(sem_array[i].used > 0 && 0 == strcmp(sem_array[i].sem_name, name))
{
return i;
}
}
// 已有信号量中没有当前信号,返回-1
return -1;
}
// 将用户输入的user_name传递到内核,再返回内核中kernel_name的地址
char* get_name(const char* user_name)
{
static char kernel_name[NAME_MAX]={};
char temp;
int i = 0;
while((temp = get_fs_byte(user_name + i)) != '\0')
{ // get_fs_byte()函数的作用是在内核空间取得用户空间的数据
kernel_name[i] = temp;
i++;
}
kernel_name[i] = '\0';
return kernel_name;
}
// 创建信号量
sem_t* sys_sem_open(const char* name, unsigned int value)
{
int i = 0;
char* kernel_name;
cli(); // 关中断
kernel_name = get_name(name); /* kernel_name指向了get_name()函数内定义的static变量kernel_name指向的内存 */
// 如果在已有信号量中找到当前信号量,则返回信号量数组中的当前信号量
if (-1 != (i = find_sem(kernel_name)))
{
sem_array[i].used++;
sti(); // 开中断
return &sem_array[i];
}
// 在已有信号中未找到当前信号量,则创建新的信号量
for (i = 0; i < SEM_MAX; i++)
{
if(0 == sem_array[i].used)
{
strcpy(sem_array[i].sem_name, kernel_name);
sem_array[i].value = value;
sem_array[i].used++;
sem_array[i].wait->next = NULL; // 初始化信号量任务队列
sti(); // 开中断
return &sem_array[i];
}
}
sti(); // 开中断
return &sem_array[SEM_MAX];
}
// 等待信号量
int sys_sem_wait(sem_t* sem)
{
cli(); // 关中断
sem->value--;
if(sem->value < 0)
{
wait_task(current, sem);
current->state = TASK_UNINTERRUPTIBLE;
RECORD_TASK_STATE(current->pid, TS_WAIT, jiffies);
schedule();
}
sti(); // 开中断
return 0;
}
// 释放信号量
int sys_sem_post(sem_t* sem)
{
struct task_struct* p;
item* first;
cli(); // 关中断
sem->value++;
if(sem->value <= 0 && sem->wait != NULL)
{
first = sem->wait;
p = first->task;
p->state = TASK_RUNNING;
RECORD_TASK_STATE(p->pid, TS_READY, jiffies);
sem->wait = first->next;
free(first);
}
sti(); //开中断
return 0;
}
// 关闭信号量
int sys_sem_unlink(const char *name)
{
int locate = 0;
char* kernel_name;
cli(); // 关中断
kernel_name = get_name(name); /* Tempname指向了get_name()函数内定义的static变量tempname指向的内存 */
if (-1 != (locate = find_sem(kernel_name))) //已有信号量中存在当前信号量
{
// 多个进程使用当前信号量,则信号量计数值减1
sem_array[locate].used--;
sti(); // 开中断
return 0;
}
sti(); // 开中断
return -1;
}
#include<linux/sched.h>
#include<linux/sched.h>
#include<sys/stat.h>
static char logbuf[1024];
int fprintk( int fd, const char * fmt, ... )
{
va_list args;
int i;
struct file * file;
struct m_inode * inode;
va_start (args, fmt);
i = vsprintf (logbuf, fmt, args);
va_end (args);
if( fd<3 )
{
__asm__ ("push %%fs\n\t"
"push %%ds\n\t"
"pop %%fs\n\t"
"pushl %0\n\t"
"pushl $_logbuf\n\t"
"pushl %1\n\t"
"call _sys_write\n\t"
"addl $8,%%esp\n\t"
"popl %0\n\t"
"pop %%fs"
::"r" (i),"r" (fd):"ax", "dx");
}
else
{
if( !( file=task[0]->filp[fd] ) )
return 0;
inode=file->f_inode;
__asm__ ("push %%fs\n\t"
"push %%ds\n\t"
"pop %%fs\n\t"
"pushl %0\n\t"
"pushl $_logbuf\n\t"
"pushl %1\n\t"
"pushl %2\n\t"
"call _file_write\n\t"
"addl $12,%%esp\n\t"
"popl %0\n\t"
"pop %%fs"
::"r" (i), "r" (file), "r" (inode) );
}
return i;// ַ
}
int physical_mem()
int physical_mem()
{
int i, free=0; /* free表示空闲页的总数 */
__asm("cli");
/* PAGING_PAGES 是在本文件第 137 行处定义,表示分页后的物理内存页数。*/
/* mem_map[] 是在第 152 行定义的内存映射字节图(1 字节代表 1 页内存),
每个页面对应的字节用于标志页面当前被引用(占用)次数。*/
for(i=0 ; i<PAGING_PAGES ; i++)
{
if (0 == mem_map[i])
{
free++;
}
}
printk("Page Count : %d\n", PAGING_PAGES);
printk("Memory Count : %d * 4096 = %d Byte\n\n", PAGING_PAGES, PAGING_PAGES * 4096);
printk("Free Page Count : %d\n", free);
printk("Used Page Count : %d\n", PAGING_PAGES - free);
__asm("sti");
return 0;
}
#define __LIBRARY__
#define __LIBRARY__
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#define BUFFER_SIZE 10 /* 缓冲区数量 */
#define NUM 25 /* 产品总数 */
#define __NR_sem_open 87
#define __NR_sem_wait 88
#define __NR_sem_post 89
#define __NR_sem_unlink 90
typedef void sem_t; /* 下面用到sem_t*的,其实质都是指针,故在此将sem_t*类型定义为void*类型,
就不用在此重新定义sem_t的结构体,因此也方便了对结构体的管理:如果在
此重新定义此结构体,内核中也已经定义了此结构体,如需对其修改,则同时
需要修改此处和内存处两处的结构体 */
_syscall2(int, sem_open, const char*, name, unsigned int, value)
_syscall1(int, sem_wait, sem_t *, sem)
_syscall1(int, sem_post, sem_t *, sem)
_syscall1(int, sem_unlink, const char *, name)
int main()
{
/* 注意: 在应用程序中不能使用断点等调试功能 */
int i, j;
int consumeNum = 0; /* 消费者消费的产品号 */
int produceNum = 0; /* 生产者生产的产品号 */
int consume_pos = 0; /* 消费者从共享缓冲区中取出产品消费的位置 */
int produce_pos = 0; /* 生产者生产产品向共享缓冲区放入的位置 */
sem_t *empty, *full, *mutex;
FILE *fp = NULL;
pid_t producer_pid, consumer_pid;
/* 创建empty、full、mutex三个信号量 */
empty = (sem_t*)sem_open("empty", BUFFER_SIZE);
full = (sem_t*)sem_open("full", 0);
mutex = (sem_t*)sem_open("mutex", 1);
/* 用文件建立一个共享缓冲区 */
fp=fopen("filebuffer.txt", "wb+");
/* 创建生产者进程 */
if( !fork() )
{
producer_pid = getpid();
printf("producer pid=%d create success!\n", producer_pid);
for( i = 0 ; i < NUM; i++)
{
sem_wait(empty);
sem_wait(mutex);
produceNum = i;
/* 移动文件的游标,向其中放入产品 */
fseek(fp, produce_pos * sizeof(int), SEEK_SET);
fwrite(&produceNum, sizeof(int), 1, fp);
fflush(fp);
/* 输出生产产品的信息 */
printf("Producer pid=%d : %02d at %d\n", producer_pid, produceNum, produce_pos);
fflush(stdout);
/* 生产者的游标向后移动一个位置 */
produce_pos = (produce_pos + 1) % BUFFER_SIZE;
sem_post(mutex);
sem_post(full);
sleep(2);
}
exit(0);
}
/* 创建消费者进程 */
if( !fork() )
{
consumer_pid = getpid();
printf("\t\t\tconsumer pid=%d create success!\n", consumer_pid);
for( j = 0; j < NUM; j++ )
{
sem_wait(full);
sem_wait(mutex);
/* 移动文件的游标,取出其中的产品 */
fseek(fp, consume_pos * sizeof(int), SEEK_SET);
fread(&consumeNum, sizeof(int), 1, fp);
fflush(fp);
/* 输出消费产品的信息 */
printf("\t\t\tConsumer pid=%d: %02d at %d\n", consumer_pid, consumeNum, consume_pos);
fflush(stdout);
/* 消费者的游标向后移动一个位置 */
consume_pos = (consume_pos + 1) % BUFFER_SIZE;
sem_post(mutex);
sem_post(empty);
if(j<4) sleep(8);
else sleep(1);
}
exit(0);
}
waitpid(producer_pid, NULL, 0); /* 等待生产者进程结束 */
waitpid(consumer_pid, NULL, 0); /* 等待消费者进程结束 */
/* 关闭所有信号量 */
sem_unlink("empty");
sem_unlink("full");
sem_unlink("mutex");
/* 关闭文件 */
fclose(fp);
return 0;
}
#define __LIBRARY__
#define __LIBRARY__
#include <unistd.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <signal.h>
#include <string.h>
#define ENOMEM 12
#define EINVAL 22
int vector[20]={0};
#define SEM_MAX 20 // 最大信号量个数
#define NAME_MAX 16 // 信号量名称的最大长度
// 定义任务队列链表
typedef struct _item
{
struct task_struct* task; // 当前任务指针
struct _item* next; // 下一个链表项的指针
}item;
// 定义信号量结构体
typedef struct _sem_t
{
char sem_name[NAME_MAX]; // 信号量的名称
int value; // 可用资源的数量
int used; // 信号量的引用计数,为0表示未使用,大于0表示已使用
item* wait; // 阻塞在信号量下的等待的任务
}sem_t;
sem_t sem_array[SEM_MAX]; // 系统中存放信号量的结构体数组
// 将任务插入任务等待队列的队尾
void wait_task(struct task_struct* task, sem_t* sem)
{
item** end;
item* new_item;
// 查找任务队列尾部的最后一个任务
for(end = &sem->wait; *end != NULL; end = &(*end)->next)
;
// 新建item节点,将新建节点插入到任务链表item的尾部
new_item = (item*)malloc(sizeof(item));
new_item->task = task;
new_item->next = NULL;
*end = new_item;
return;
}
// 在已有信号量中查找信号量
int find_sem(const char* name)
{
int i;
for(i = 0; i < SEM_MAX; i++)
{
// 如果在已有信号量中存在当前信号量,则返回当前信号量在信号量数组中的偏移量
if(sem_array[i].used > 0 && 0 == strcmp(sem_array[i].sem_name, name))
{
return i;
}
}
// 已有信号量中没有当前信号,返回-1
return -1;
}
// 将用户输入的user_name传递到内核,再返回内核中kernel_name的地址
char* get_name(const char* user_name)
{
static char kernel_name[NAME_MAX]={};
char temp;
int i = 0;
while((temp = get_fs_byte(user_name + i)) != '\0')
{ // get_fs_byte()函数的作用是在内核空间取得用户空间的数据
kernel_name[i] = temp;
i++;
}
kernel_name[i] = '\0';
return kernel_name;
}
// 创建信号量
sem_t* sys_sem_open(const char* name, unsigned int value)
{
int i = 0;
char* kernel_name;
cli(); // 关中断
kernel_name = get_name(name); /* kernel_name指向了get_name()函数内定义的static变量kernel_name指向的内存 */
// 如果在已有信号量中找到当前信号量,则返回信号量数组中的当前信号量
if (-1 != (i = find_sem(kernel_name)))
{
sem_array[i].used++;
sti(); // 开中断
return &sem_array[i];
}
// 在已有信号中未找到当前信号量,则创建新的信号量
for (i = 0; i < SEM_MAX; i++)
{
if(0 == sem_array[i].used)
{
strcpy(sem_array[i].sem_name, kernel_name);
sem_array[i].value = value;
sem_array[i].used++;
sem_array[i].wait->next = NULL; // 初始化信号量任务队列
sti(); // 开中断
return &sem_array[i];
}
}
sti(); // 开中断
return &sem_array[SEM_MAX];
}
// 等待信号量
int sys_sem_wait(sem_t* sem)
{
cli(); // 关中断
sem->value--;
if(sem->value < 0)
{
wait_task(current, sem);
current->state = TASK_UNINTERRUPTIBLE;
RECORD_TASK_STATE(current->pid, TS_WAIT, jiffies);
schedule();
}
sti(); // 开中断
return 0;
}
// 释放信号量
int sys_sem_post(sem_t* sem)
{
struct task_struct* p;
item* first;
cli(); // 关中断
sem->value++;
if(sem->value <= 0 && sem->wait != NULL)
{
first = sem->wait;
p = first->task;
p->state = TASK_RUNNING;
RECORD_TASK_STATE(p->pid, TS_READY, jiffies);
sem->wait = first->next;
free(first);
}
sti(); //开中断
return 0;
}
// 关闭信号量
int sys_sem_unlink(const char *name)
{
int locate = 0;
char* kernel_name;
cli(); // 关中断
kernel_name = get_name(name); /* Tempname指向了get_name()函数内定义的static变量tempname指向的内存 */
if (-1 != (locate = find_sem(kernel_name))) //已有信号量中存在当前信号量
{
// 多个进程使用当前信号量,则信号量计数值减一
sem_array[locate].used--;
sti(); // 开中断
return 0;
}
sti(); // 开中断
return -1;
}
/* 新建/打开一页共享内存,并返回该页共享内存的shmid(该块共享内存在操作系统内部的id)。*/
int sys_shmget(int key, int size)
{
int free = 0;
if(vector[key] != 0)
{
return vector[key];
}
if(size > 4096)
return -EINVAL;
free = get_free_page(); // get_free_page()返回的是申请的空闲页面的地址
if(!free)
{
return -ENOMEM;
}
vector[key] = free;
return vector[key];
}
/* 将shmid指定的共享页面映射到当前进程的虚拟地址空间中,并将其首地址返回。 */
void* sys_shmat(int shmid, const void *shmaddr)
{
if(!shmid)
return NULL;
put_page(shmid, current->start_code + current->brk);
return (void*)current->brk;
}
extern void calc_mem();
extern void calc_mem();
int sys_table_mapping()
{
unsigned long index_of_dir, index_of_table;
unsigned long entry;
unsigned long page_table_base;
unsigned long page_dir_base = 0;
__asm("cli");
calc_mem(); // 显示内存空闲页面数。
// 首先打印输出页目录信息。格式为:Page Directory(页目录的物理页框号 | 所在线性地址)
fprintk(1,"Page Directory(PFN:0x0 | LA:0x00000000)\n");
// 第一层循环,遍历页目录中的所有 PDE
for(index_of_dir = 0; index_of_dir < 1024; index_of_dir++)
{
entry = ((unsigned long*)page_dir_base)[index_of_dir];
if(!(entry & 1)) /* 跳过无效的 PDE */
continue;
// 输出 PDE 信息,格式如下:
// PDE: 下标 -> Page Table(页表的物理页框号 | 所在的线性地址)
fprintk(1,"\tPDE: 0x%X -> Page Table(PFN:0x%X | LA:0x%08X)\n", index_of_dir, entry >> 12, 0xFFFFF000 & entry);
/* 页目录项的高20位即为页表的物理地址,页表的物理地址即为页表的逻辑地址 */
page_table_base = 0xFFFFF000 & entry;
/* 第二层循环,遍历页表中的所有 PTE */
for(index_of_table = 0; index_of_table < 1024; index_of_table++)
{
entry = ((unsigned long*)page_table_base)[index_of_table];
if(!(entry & 1)) /* 跳过无效的 PTE */
continue;
// 输出 PTE 信息,格式如下:
// PTE: 下标 -> Physical Page(物理页框号 | 所在的线性地址)
fprintk(1,"\t\tPTE: 0x%X -> Physical Page(PFN:0x%X | LA:0x%08X)\n", index_of_table,
entry >> 12, (index_of_dir << 22) | (index_of_table << 12));
}
}
__asm("sti");
return 0;
}
#include <stdio.h>
#include <windows.h>
#define MAX_SIZE 1000
#define ALLOC_MIN_SIZE 10//最小分配空间大小.
#define RED FOREGROUND_RED
#define GREEN FOREGROUND_GREEN
#define BLUE FOREGROUND_BLUE
typedef struct Bound{
union {
struct Bound * preLink;//头部域前驱
struct Bound * upLink;//尾部域,指向结点头部
};
int tag;//0标示空闲,1表示占用
int size;//仅仅表示 可用空间,不包括 头部 和 尾部空间
struct Bound * nextLink;//头部后继指针.
}*Space;
#define FOOT_LOC(p) ((p)+(p->size)-1)//尾部域位置
void initSpace(Space * freeSpace,Space * pav){
//有2个空间是为了 查找空间的邻接点,防止出界用的。
*freeSpace = (Space)malloc((MAX_SIZE+2)*sizeof(struct Bound));
Space head = *freeSpace;
head->tag = 1;//设置边界已占用
head++;//指向第一个节点..
head->tag = 0;//设置节点空闲.
head->preLink = head->nextLink = head;//循环双链表..
head->size = MAX_SIZE;
*pav = head;//设置头指针
Space foot = FOOT_LOC(head);
foot->tag = 0;
foot->upLink = head;
foot++;
foot->tag = 1;//设置 边界 已占用
}
Space userSpace[MAX_SIZE] = {NULL};//用户空间数组.
int usCount = 0;
Space allocBoundTag(Space * pav,int size){
Space p = * pav;
for (;p != NULL && p->size < size && p->nextLink != *pav ; p = p->nextLink) ;
if (p == NULL || p->size < size ){
return NULL;
}
*pav = p->nextLink;
if (p->size - size > ALLOC_MIN_SIZE){//从高位截取p,不破坏指针间的关系.
p->size -= size;
Space foot = FOOT_LOC(p);
foot->upLink = p;
foot->tag = 0;
p = foot + 1;
p->size = size;
foot = FOOT_LOC(p);
p->tag = foot->tag = 1;
foot->upLink = p;
}
else{//分配后剩余空间小于 ALLOC_MIN_SIZE
if (p = *pav){//只剩下一个空间了,清空指针
*pav = NULL;
p->tag = 1;
}
else{//直接分配 p->size个空间出去
Space foot = FOOT_LOC(p);
foot->tag =p->tag = 1;
p->preLink->nextLink = p->nextLink;
p->nextLink->preLink = p->preLink;
}
}
userSpace[usCount] = p;
usCount++;
return p;
}
//回收空间,合并 邻接空闲空间.
void reclaimBoundTag(Space * pav,Space sp){
Space pre = NULL;//前一个空间
Space next = NULL;//后一个空间..
Space foot = NULL;
int pTag = -1;
int nTag = -1;
int i = 0;
if(*pav != NULL)
{
pre = (sp -1)->upLink;//前一个空间
pTag = pre->tag;
next = sp + sp->size;//后一个空间..
nTag = next->tag;
}
if ((*pav != NULL && pTag == 1 && nTag == 1) || *pav == NULL){//前后都被占用,直接插入在表头.
Space foot = FOOT_LOC(sp);
foot->tag = sp->tag = 0;
if (*pav == NULL){
*pav = sp->preLink = sp->nextLink = sp;
}
else{
sp->nextLink = *pav;
sp->preLink = (*pav)->preLink;
(*pav)->preLink = sp;
sp->preLink->nextLink = sp;
*pav = sp;//将头指针指向刚释放的空间
}
}
else if(pTag == 0 && nTag == 1){//前面的可以合并..
pre->size += sp->size;
foot = FOOT_LOC(pre);
foot->tag = 0;
foot->upLink = pre;
}
else if(pTag == 1 && nTag == 0){//后面的可以合并
if(*pav == next)
{
*pav = sp;
}
sp->preLink = next->preLink;
sp->nextLink = next->nextLink;
next->preLink->nextLink = sp;
next->nextLink->preLink = sp;
sp->size += next->size;
foot = FOOT_LOC(sp);
sp->tag = foot->tag = 0;
foot->upLink = sp;
}
else{//前后都可以合并
if(*pav == next)
{
*pav = pre;
}
pre->size += sp->size + next->size;
pre->nextLink = next->nextLink;
next->nextLink->preLink = pre;
foot = FOOT_LOC(pre);
foot->upLink = pre;
}
//设置用户空间
for (i = 0; i < usCount; i++){
if (sp == userSpace[i]){
userSpace[i] = NULL;
}
}
}
/* 设置字体颜色 */
void SetColor(int color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | color);
}
void print(Space s){
printf("0x%0x %6d\t%10d 0x%0x 0x%0x\n",s,s->size,s->tag, s->preLink,s->nextLink);
}
void printSpace(Space pav){
SetColor(RED|GREEN|BLUE);
printf("空间首地址 空间大小 块标志(0:空闲,1:占用) 前驱地址 后继地址\n");
SetColor(GREEN);
int i = 0;
Space p = NULL, us = NULL;
if (pav != NULL)
{
p = pav;
print(p);
for (p = p->nextLink; p != pav; p = p->nextLink){
print(p);
i++;
}
}
for (i = 0; i < usCount; i++){
us = userSpace[i];
if (us){
printf("0x%0x %6d\t%10d\t\n",us, us->size, us->tag);
}
}
}
int main(int argc, char* argv[])
{
Space freeSpace = NULL,pav = NULL;
initSpace(&freeSpace,&pav);
int item = 0, i = 0;
unsigned long start = 0;
unsigned long joblength;
Space us = NULL;
while(1)
{
SetColor(RED|BLUE|GREEN);
printf("选择功能项:(0-退出 1-分配内存 2-回收内存 3-显示内存):");
scanf("%d",&item);
switch(item)
{
case 0:
exit(0);
case 1:
SetColor(RED|GREEN);
printf("所需内存长度:");
scanf("%*c%ld",&joblength);
allocBoundTag(&pav,joblength);
break;
case 2:
SetColor(RED|BLUE);
printf("输入要回收分区的首地址:");
scanf("%x",&start);
for (i = 0; i < usCount; i++){
us = userSpace[i];
if ((unsigned long)us == start){
reclaimBoundTag(&pav, us);
break;
}
}
if(i == usCount)
{
SetColor(RED);
printf("输入要回收分区的首地址不符合要求\n");
}
if(pav->size == MAX_SIZE)
{
usCount = 0;
}
break;
case 3:
printSpace(pav);
break;
default:
printf("没有该选项\n");
}
}
return 0;
}
\ No newline at end of file
#include <stdio.h>
#include <math.h>
#include <windows.h>
#define RED FOREGROUND_RED
#define GREEN FOREGROUND_GREEN
#define BLUE FOREGROUND_BLUE
#define M 10 /* 可利用空间总容量(2的幂次),子表的个数为M+1 */
#define N 100 /* 占用块个数的最大值 */
//伙伴系统可利用空间表的结构
typedef struct _Node{
struct _Node *llink; //指向前驱节点
int bflag; //块标志,0:空闲,1:占用
int bsize; //块大小,值为2的幂次k
struct _Node *rlink; //头部域,指向后继节点
}Node;
//可利用空间表的头结点
typedef struct HeadNode{
int nodesize; //链表的空闲块大小
Node *first; //链表的表头指针
}FreeList[M+1];
Node* start; // 全局变量start为整个生成空间的首地址
/* avail[0...M]为可利用空间表,n为申请分配量。若有不小于n的空闲块,
则分配相应的存储块,并返回首地址;否则,返回NULL */
Node* AllocBuddy(FreeList *avail, unsigned long n)
{
int i, k;
Node *pa, *pi, *pre, *suc;
//查找满足分配要求的子表即空闲块大小大于n的表
for(k = 0; k <= M && ((*avail)[k].nodesize <= n || !(*avail)[k].first); ++k)
;
if(k>M) // 分配失败返回NULL
{
printf("内存分配失败!\n");
return NULL;
}
else{ //进行分配
pa = (*avail)[k].first; //指向可分配表的第一个节点
pre = pa->llink; //分别指向前驱和后继
suc = pa->rlink;
if(pa == suc) //分配后该子表变成空表
(*avail)[k].first = NULL;
else{ //从子表删去*pa节点
pre->rlink = suc;
suc->llink = pre;
(*avail)[k].first = suc;
}
/* 将剩余块插入相应子表 */
for(i = 1; (*avail)[k-i].nodesize >= n+1; ++i)
{
pi = pa + (int)pow(2,k-i);
pi->rlink = pi;
pi->llink = pi;
pi->bflag = 0;
pi->bsize = k-i;
(*avail)[k-i].first = pi;
}
pa->bflag = 1;
pa->bsize = k - (--i);
}
return pa;
}
//返回相对起始地址为p,块大小为pow(2,k)的块的伙伴地址
Node* buddy(Node* n)
{
if((n-start)%(int)pow(2,n->bsize+1)==0) //p为前块
return n + (int)pow(2,n->bsize);
else //p为后块
return n - (int)pow(2,n->bsize);
}
// 伙伴系统的回收算法 将p所指的释放块回收到可利用空间表pav中
void Reclaim(FreeList *pav,Node* *p)
{
//
// 此处代TODO: 在此添加代码
//
}
/* 设置字体颜色 */
void SetColor(int color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
FOREGROUND_INTENSITY | color);
}
//输出所有可用空间表
void print_free(FreeList p)
{
int i;
Node* head;
//设置字体颜色为白色
SetColor(RED|BLUE|GREEN);
printf("可利用空间:\n");
printf(" 块的大小 块的首地址\t块标志(0:空闲 1:占用) 前驱地址 后继地址\n");
SetColor(GREEN);
for(i = 0; i <= M; i++)
{
if(p[i].first) //第i个可利用空间表不同
{
head = p[i].first; //head指向链表的第一个节点的头部域(首地址)
do
{
printf("\t%d\t 0x%x\t %10d 0x%x 0x%x\n",(int)pow(2,head->bsize), head, head->bflag, head->llink, head->rlink);
head = head->rlink;
}while(head != p[i].first);
}
}
printf("\n");
}
// 输出p数组所指的已分配空间
void print_used(Node* p[])
{
int i;
//设置字体颜色为白色
SetColor(RED|BLUE|GREEN);
printf("已利用空间:\n");
printf(" 占用块块号\t占用块的首地址\t块大小\t块标志(0:空闲 1:占用)\n");
SetColor(RED);
for(i = 0; i < N; i++)
if(p[i]) // 指针不为0(指向一个占用块)
printf("\t %d\t 0x%x\t %d\t %d\n",i, p[i],(int)pow(2,p[i]->bsize), p[i]->bflag);
printf("\n");
}
int main(int argc, char* argv[])
{
/* 注意:在应用程序中不能使用断点等调试功能 */
int i, j, item;
unsigned long joblength;
FreeList avail;
Node* used_block[N] = {NULL}; //used_block数组为占用块的首地址
//初始化可利用空间
for(i = 0; i <= M; i++)
{
avail[i].nodesize = (int)pow(2,i);
avail[i].first = NULL;
}
// 在最大链表中生成一个结点
start = avail[M].first = (Node*)malloc(avail[M].nodesize * sizeof(Node));
if(start) // 生成结点成功
{
start->llink = start->rlink = start; // 初始化该结点
start->bflag = 0;
start->bsize = M;
int color = 8;
i = 0;
while(1)
{
//设置字体颜色为白色
SetColor(RED|BLUE|GREEN);
printf("选择功能项:(0-退出 1-分配主存 2-回收主存 3-显示主存):");
scanf("%d",&item);
switch(item)
{
case 0:
exit(0);
case 1:
SetColor(RED|GREEN);
printf("输入作业所需长度:");
scanf("%ld",&joblength);
if(avail[M].first && (int)pow(2, avail[M].first->bsize) == 1024)
{
i = 0;
}
used_block[i] = AllocBuddy(&avail,joblength);
++i;
break;
case 2:
SetColor(RED|BLUE);
printf("输入要回收块的块号:");
scanf("%d",&j);
if(i > 0 && j < i)
{
Reclaim(&avail,&used_block[j]);
}
else
{
SetColor(RED);
if(i == 0)
{
printf("没有可回收的内存块,请分配后,再进行回收!\n");
}
else
{
printf("输入的块号不合法\n");
}
}
break;
case 3:
print_free(avail);
print_used(used_block);
break;
default:
printf("没有该选项\n");
}
}
}
}
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
//输出内存块页面序号
int OutputBlockofMemory(int *BlockofMemory, int BlockCount, int ReplacePage, int PageNum)
{
int i;
printf("访问页面 %d 后,", PageNum);
printf("内存中的页面号为:\t");
for(i = 0; i < BlockCount; i++)
{
if(BlockofMemory[i] < 0)
printf("# ");
else
printf("%d ", BlockofMemory[i]);
}
if(ReplacePage != -1)
printf("\t淘汰页面号为:%d", ReplacePage);
printf("\n");
return -1;
}
//输出页面引用串号
void OutputPageNumofRef(int* PageNumofRef, int PageNumRefCount)
{
int i = 0;
printf("页面引用串为:\t");
for(i = 0; i < PageNumRefCount; i++)
printf("%d ", PageNumofRef[i]);
printf("\n");
}
//内存块页面号清零
void ResetBlockofMemory(int *BlockofMemory, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
BlockofMemory[i] = -1;
}
//判断页是否在内存中,如果页在内存中,返回1,否则返回0;
int PageInBlockofMemory(int PageNum, int *BlockofMemory, int BlockCount)
{
int i;
for(i = 0; i < BlockCount; i++)
if(PageNum == BlockofMemory[i])
return 1;
return 0;
}
//下次访问次序
//参数j: 页面在内存块中的位置
//参数i: 页面号在页面号引用串中的位置
int DistanceOpt(int *BlockofMemory, int *PageNumofRef, int j, int i, int PageNumRefCount)
{
int k;
for(k = i + 1; k < PageNumRefCount; k++)
if(BlockofMemory[j] == PageNumofRef[k])
return k;
return PageNumRefCount;
}
//最佳页面置换算法
void Opt(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i, j, k;
int MaxIndex1, MaxIndex2;
int MissCount = 0;
int ReplacePage;
int EmptyBlockCount = BlockCount;
printf("**********最佳页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
MaxIndex1 = MaxIndex2 = 0;
//求出未来最长时间不被访问的页
for(j = 0; j < BlockCount; j++)
{
MaxIndex2 = DistanceOpt(BlockofMemory, PageNumofRef, j, i, PageNumRefCount);
if(MaxIndex1 < MaxIndex2)
{
MaxIndex1 = MaxIndex2;
k = j;
}
}
ReplacePage = BlockofMemory[k];
BlockofMemory[k] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
{
OutputBlockofMemory(BlockofMemory,BlockCount, -1, PageNumofRef[i]);
}
}
printf("缺页次数为: %d\n", MissCount);
printf("OPT缺页率为: %.3f\n", (float)MissCount / PageNumRefCount);
}
//先进先出页面置换算法
void Fifo(int *BlockofMemory,int *PageNumofRef,int BlockCount,int PageNumRefCount)
{
int i;
int ReplacePage;
int ReplaceIndex = 0;
int MissCount = 0;
int EmptyBlockCount = BlockCount;
printf("**********先进先出页面置换算法:**********\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef,PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
if(EmptyBlockCount > 0)
{
BlockofMemory[BlockCount - EmptyBlockCount] = PageNumofRef[i];
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
EmptyBlockCount--;
}
else
{
ReplacePage = BlockofMemory[ReplaceIndex];
BlockofMemory[ReplaceIndex] = PageNumofRef[i];
ReplaceIndex = (ReplaceIndex + 1) % BlockCount;
OutputBlockofMemory(BlockofMemory, BlockCount, ReplacePage, PageNumofRef[i]);
}
}
else
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
}
printf("缺页次数为:%d\n", MissCount);
printf("FIFO缺页率为:%.3f\n", (float)MissCount / PageNumRefCount);
}
int main()
{
int *BlockofMemory; //内存物理块
const int BlockCount = 5;
int PageNumofRef[] = {7,0,1,2,0,3,0,4,2,3,0,1,1,7,0,1,0,3}; //页面号引用串
int PageNumRefCount = sizeof(PageNumofRef) / sizeof(PageNumofRef[0]);
BlockofMemory = (int*)malloc(BlockCount * sizeof(int));
if(BlockofMemory == (int*)NULL)
{
printf("内存分配出错\n");
exit(1);
}
ResetBlockofMemory(BlockofMemory, BlockCount);
Opt(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
ResetBlockofMemory(BlockofMemory,BlockCount);
Fifo(BlockofMemory, PageNumofRef, BlockCount, PageNumRefCount);
free(BlockofMemory);
return 0;
}
//最近最久未使用页面置换算法
//最近最久未使用页面置换算法
void Lru(int *BlockofMemory, int *PageNumofRef, int BlockCount, int PageNumRefCount)
{
int i;
int MissCount = 0;
printf("************最近最久未使用页面置换算法:************\n");
//输出页面引用串号
OutputPageNumofRef(PageNumofRef, PageNumRefCount);
for(i = 0; i < PageNumRefCount; i++)
{
if(!PageInBlockofMemory(PageNumofRef[i], BlockofMemory, BlockCount)) //页不在内存中
{
MissCount++;
//
// 在此添加代码,实现 LRU 页面置换算法
//
}
else
OutputBlockofMemory(BlockofMemory, BlockCount, -1, PageNumofRef[i]);
}
printf("缺页次数为:%d\n", MissCount);
printf("LRU缺页率为:%.3f\n", (float)MissCount / PageNumRefCount);
}
#include <asm/segment.h>
#include <asm/segment.h>
#include <linux/sched.h>
#define SIZE 1024 //缓冲区大小
char psbuffer[SIZE]; //定义缓冲区来存放结点信息
/* 将整型数据转换为字符数据并赋值给psbuffer */
void itoa(int num, int* j)
{
char buffer[16] = {}; //定义一个缓冲区来临时存放将整型num转换成的反向的字符串
int i = 0;
if (num == 0)
{
psbuffer[*j] = '0';
(*j)++;
psbuffer[*j] = '\t';
(*j)++;
return;
}
if (num<0)
{
psbuffer[*j] = '-';
(*j)++;
num = -num;
}
//将整型数据num转换成反向字符串,保存到buffer中
//i同时表示num转换成的字符的个数
for(i = 0; num != 0; i++)
{
buffer[i] = (char)(num % 10 + '0'); //将num的个位数转换成字符数据放到buffer中
num = num / 10; //去掉个位数
}
//反向将buffer中的字符放入到psbuffer中
//数组下标是此0开始计数的,所以首先需要将i减1
for(--i; i >= 0; i--)
{
psbuffer[*j] = buffer[i];
(*j) ++;
}
psbuffer[*j] = '\t'; //此处加制表符是为来显示时将数据对齐,以便于查看
(*j)++;
}
/* 向数组psbuffer中添加标题 */
/* 参数j为在psbuffer中写数据的偏移位置 */
void addTitle(char* title, int* j)
{
//这里也可以使用strcat,但是由于*j的值还需要来记录偏移的位置,这样就
//还需要使用strlen来计算*title的长度,效率可能会降低许多,
//同时代码量也不会比下面使用的代码量少
for( ; *title; (*j)++, *title++)
psbuffer[*j] = *title; //逐字节的将标题添加到psbuffer中
psbuffer[*j] = '\t'; //此处加制表符是为来显示时将数据对齐,以便于查看
(*j) ++;
}
/* 读取系统中的信息放到psbuffer数组中,并再读取psbuffer中的数据写入到用户
空间的buf中。读取位置从f_pos指向的位置开始,每次最多读count个字节,并根据
实际读到的字节数调整f_pos的值,最后返回实际读到的字节数*/
int psread(int dev,char * buf,int count,off_t * f_pos)
{
struct task_struct * p;
int i, j = 0; //变量j为在psbuffer中写数据的位置偏移量
//第一次从psbuffers数组的起始位置0开始,读取完毕后第二次再进入到此函数就
//不会再为psbuffer赋值,直接执行后面的for循环体
if(!(*f_pos))
{
memset(psbuffer, 0, SIZE); //将psbuffer数组初始化为0
//添加psinfo节点的标题
addTitle("pid", &j);
addTitle("state", &j);
addTitle("father", &j);
addTitle("counter", &j);
addTitle("start_time", &j);
psbuffer[j] = '\n';
j++;
//遍历当前的进程,为psinfo节点赋值
//NR_TASKS为系统最大的任务数的宏定义
for(i = 0; i < NR_TASKS; i++)
{
p = task[i];
if(p == NULL)continue;
//添加psinfo节点下的数据
itoa( p->pid, &j);
itoa( p->state, &j);
itoa( p->father, &j);
itoa( p->counter, &j);
itoa( p->start_time, &j);
psbuffer[j] = '\n';
j++;
}
}
//将数组psbuffer中的信息读取到用户空间的buf位置处
for(i = 0; i < count; i++, (*f_pos)++)
{
if(psbuffer[*f_pos] == '\0')
break;
//put_fs_byte函数是将一字节存放在 fs 段中指定内存地址处。
//其第一个参数是char类型,第二个参数是char*类型
put_fs_byte(psbuffer[*f_pos], &buf[i]);
}
return i;
}
/* 定义控制台应用程序的入口点 */
/* 定义控制台应用程序的入口点 */
#include <stdio.h>
#define PHYSICAL_BLOCK_SIZE 1024
#define LOGICAL_BLOCK_SIZE 1024
#define NAME_LEN 14
#define START_PARTITION_TABLE 0x1be
//分区表结构
struct par_table_entry {
char boot_indicator; //导入指示器,绝大多数情况都是0
char start_chs_val[3]; //起始柱面磁头扇区值,3个字节分别对应柱面号、磁头号、扇区号
char par_type; //分区类型
char end_chs_val[3]; //终止柱面磁头扇区值
int start_sector; //起始盘块号
int par_size; //分区大小
};
// 超级块结构体
struct super_block
{
unsigned short s_ninodes; // 节点数。
unsigned short s_nzones; // 逻辑块数。
unsigned short s_imap_blocks; // i 节点位图所占用的数据块数。
unsigned short s_zmap_blocks; // 逻辑块位图所占用的数据块数。
unsigned short s_firstdatazone; // 第一个数据逻辑块号。
unsigned short s_log_zone_size; // log(数据块数/逻辑块)。(以2 为底)。
unsigned long s_max_size; // 文件最大长度。
unsigned short s_magic; // 文件系统魔数。
};
// i节点结构体
struct d_inode
{
unsigned short i_mode; // 文件类型和属性(rwx 位)。
unsigned short i_uid; // 用户id(文件拥有者标识符)。
unsigned long i_size; // 文件大小(字节数)。
unsigned long i_time; // 修改时间(自1970.1.1:0 算起,秒)。
unsigned char i_gid; // 组id(文件拥有者所在的组)。
unsigned char i_nlinks; // 链接数(多少个文件目录项指向该i 节点)。
unsigned short i_zone[9]; // 直接(0-6)、间接(7)或双重间接(8)逻辑块号。
// zone 是区的意思,可译成区段,或逻辑块。
};
//目录项结构
struct dir_entry{
unsigned short inode; //i节点号
char name[NAME_LEN]; //文件名
};
struct super_block sblock; //超级块
struct par_table_entry pte[4]; //分区表数组
FILE* fd; //文件指针
char physical_block[PHYSICAL_BLOCK_SIZE]; //存储物理块
char logical_block[LOGICAL_BLOCK_SIZE]; //存储逻辑块
char *inode_bitmap; //i节点位图指针
//char *logical_bitmap; //逻辑块位图指针,本实例未使用
//读取一个物理块
void get_physical_block(int block_num)
{
//减1是因为物理盘块是从1开始计数
fseek(fd, (block_num - 1) * PHYSICAL_BLOCK_SIZE, SEEK_SET);
fread(physical_block, PHYSICAL_BLOCK_SIZE, 1, fd);
}
//读取第一个分区的一个逻辑块
void get_partition_logical_block(int block_num)
{
//block_num前面加的1表示在第一个分区前还有一个主引导记录(MBR)块,
//后面加的1是因为物理盘块是从1开始计数的,而逻辑块是从0开始计数的
get_physical_block(1 + block_num + 1);
memcpy(logical_block, physical_block, LOGICAL_BLOCK_SIZE);
}
//读取分区表
void get_partition_table()
{
int i = 0;
//分区表有4个16字节的表项组成,第一个表项的起始地址为START_PARTITION_TABLE
get_physical_block( 1 ); //分区表在物理盘块的第1块
memcpy(pte, &physical_block[START_PARTITION_TABLE], sizeof(pte));
for(i = 0; i < 4; i++)
{
printf("**************pattition table%d****************\n", i+1);
printf("Boot Indicator:%d\n", pte[i].boot_indicator);
printf("start CHS value:0x%04x\n", pte[i].start_chs_val);
printf("partition type:%ld\n", pte[i].par_type);
printf("end CHS value:0x%04x\n", pte[i].end_chs_val);
printf("start sector:%d\n", pte[i].start_sector);
printf("partition size:%d\n", pte[i].par_size);
}
}
//读取第一个分区的超级块
void get_super_block()
{
get_partition_logical_block( 1 );
memcpy(&sblock, logical_block, sizeof(sblock));
printf("**************super block****************\n");
printf("ninodes:%d\n", sblock.s_ninodes);
printf("nzones:%d\n", sblock.s_nzones);
printf("imap_blocks:%d\n", sblock.s_imap_blocks);
printf("zmap_blocks:%d\n", sblock.s_zmap_blocks);
printf("firstdatazone:0x%04x\n", sblock.s_firstdatazone);
printf("log_zone_size:%d\n", sblock.s_log_zone_size);
printf("max_size:0x%x = %dByte\n", sblock.s_max_size,sblock.s_max_size);
printf("magic:0x%x\n", sblock.s_magic);
}
//加载i节点位图
void load_inode_bitmap()
{
inode_bitmap = (char*)malloc(sblock.s_imap_blocks * LOGICAL_BLOCK_SIZE);
int i = 0;
for(i = 0; i < sblock.s_imap_blocks; i++)
{
//i节点位图前有1个引导块和一个超级块
get_partition_logical_block(1 + 1 + i);
memcpy(&inode_bitmap[i * LOGICAL_BLOCK_SIZE], &logical_block, LOGICAL_BLOCK_SIZE);
}
}
//根据i节点位图判断其对应的i节点是否有效
//参数inode_id为i节点的id
//有效返回1,无效返回0
int is_inode_valid(unsigned short inode_id)
{
if(inode_id > sblock.s_ninodes)
return 0;
char byte = inode_bitmap[(inode_id - 1) / 8]; //inode_id减1是因为i节点是从1开始计数的
return (byte >> (7 - (inode_id - 1) % 8) ) & 0x1; //取一个字节中的某位与1做位运算
}
//根据i节点id读取i节点
void get_inode(unsigned short inode_id, struct d_inode* inode)
{
//一个引导块,一个超级块,sblock.s_imap_blocks个i节点位图,sblock.s_zmap_blocks个逻辑块位图
//一个i节点占32个字节,一个盘块有LOGICAL_BLOCK_SIZE/32个节点,所以inode_id/(LOGICAL_BLOCK_SIZE/32)
//减1是因为i节点号是从1开始计数的,而逻辑块号是从0开始计数的
//inode_blocknum是i节点在逻辑块中的偏移块数
int inode_blocknum = 1 + 1 + sblock.s_imap_blocks + sblock.s_zmap_blocks + (inode_id - 1) / (LOGICAL_BLOCK_SIZE/32) ;
get_partition_logical_block(inode_blocknum);
memcpy((char*)inode, &logical_block[((inode_id - 1) % sizeof(struct d_inode)) * sizeof(struct d_inode)], sizeof(struct d_inode));
}
//递归打印i节点下的目录
void print_inode(unsigned short id, int tab_count, const char* name)
{
int i, m, n;
struct d_inode inode;
struct dir_entry dir;
//如果i节点号对应在i节点位图相应位的值为1,说明此i节点已使用
//否则说明此i节点无用或已被删除,则直接返回
if(is_inode_valid(id) != 1)
return;
get_inode(id, &inode);
tab_count++;
unsigned short mode = inode.i_mode >> 12; //高4位存放的是文件类型
//如果是目录文件
if(mode == 4)
{
//打印tab键,为了使目录有层次感
for(i=0; i<tab_count; i++)
{
printf("\t");
}
printf("%s\n", name);
//循环读取i节点中的i_zones[]数组
for(m = 0; m<7; m++)
{
//如果数组数据为0,则跳过
if(inode.i_zone[m] == 0)
continue;
//一个逻辑块最多存储64个目录项,循环读取64个目录项
//其中前两项分别为 . 和 ..
for(n = 0; n < 64; n++)
{
get_partition_logical_block(inode.i_zone[m]);
//将逻辑块中的数据拷贝到目录项结构体
memcpy((char*)&dir, &logical_block[n * sizeof(dir)], sizeof(dir));
//如果是 .和..则继续循环
if(n == 0 || n == 1)
continue;
//如果目录项中没有内容了则不再读取
if(dir.inode == 0)
break;
//递归打印子目录
print_inode(dir.inode, tab_count, dir.name);
}
}
}
//如果是常规文件
else if(mode == 8)
{
for(i=0; i<tab_count; i++)
{
printf("\t");
}
printf("%s\n", name);
}
//如果块设备文件、字符设备文件等其他类型文件,请读者尝试自己实现
}
int main(int argc, char* argv[])
{
int bit;
struct d_inode* inode = (struct d_inode*)malloc(sizeof(struct d_inode));
char* path = "C:\\minix\\harddisk.img";
fd = fopen(path, "rb");
if(fd==NULL)
printf("open file failed!\n");
//读取分区表
get_partition_table();
//读取超级块
get_super_block();
//加载i节点逻辑块位图
load_inode_bitmap();
//i节点位图的第一位对应文件系统的根节点
//如果第一位为1,则打印根节点
bit = is_inode_valid(1);
if(bit == 1)
print_inode(1, -1, "\\");
else
printf("root node lost!\n");
return 0;
}
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论