在借助linux0.11内核代码剖析,别人的实验代码,以及操作系统原理实现与实践下完成QAQ
process.c
|
main.c
内核状态下只能用printk,根据老师的代码增加fprintk函数,在github上有相关的resource,遂不再记录
因为要早早的开始记录日志文件,所以在进程0开始在用户态执行以后就打开日志文件,开启了多进程视图,这个时间点就在move_to_user_mode()之后,但是还要先挂载上文件系统才能记录。
关键代码如下setup((void *) &drive_info);
(void) open("/dev/tty0",O_RDWR,0); // 完成了文件系统加载
(void) dup(0);
(void) dup(0);
(void) open("/var/process.log",O_CREAT|O_TRUNC|O_WRONLY,0666);
fork.c
完成多进程日志记录最重要的就是找到内核中关于进程状态代码的切换点,然后添加相关代码完成记录。
fork首先是新建进程的地方,这个地方肯定要记录,真正实现进程创建的函数是copy_process()函数,完成pcb相关设置后将进程状态设置为就绪,即p->state = TASK_RUNNING,这里就要向日志文件写相关记录,分别是新建和记录(其实不难发现,所有应该添加的代码,都应该围绕p->state这种状态设置代码来完成)
fprintk(3, "%ld\t%c\t%ld\n", p->pid, 'N', jiffies); |
sched.c
sched.c是内核中有有关进程调度管理的程序,其中包括有关调度的基本函数sleep_on(),wakeup(),schedule()等。
要做出修改的函数有schedule(),sys_pause(),sleep_on(),interruptible_sleep_on(),wake_up()函数
为了方便直接贴出所有代码(懒)
void schedule(void)
{
int i,next,c;
struct task_struct ** p;
/* check alarm, wake up any interruptible tasks that have got a signal */
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p) {
if ((*p)->alarm && (*p)->alarm < jiffies) {
(*p)->signal |= (1<<(SIGALRM-1));
(*p)->alarm = 0;
}
if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
(*p)->state==TASK_INTERRUPTIBLE)
{
(*p)->state=TASK_RUNNING;
fprintk(3, "%d\tJ\t%d\n", (*p)->pid, jiffies);
}
}
/* this is the scheduler proper: */
while (1) {
c = -1;
next = 0;
i = NR_TASKS;
p = &task[NR_TASKS];
while (--i) {
if (!*--p)
continue;
if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
c = (*p)->counter, next = i;
}
if (c) break;
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p)
(*p)->counter = ((*p)->counter >> 1) +
(*p)->priority;
if(current->pid != task[next]->pid)
{
if(current->state == TASK_RUNNING)
fprintk(3, "%d\tJ\t%d\n", current->pid, jiffies);
fprintk(3, "%d\tR\t%d\n", task[next]->pid, jiffies);
}
}
switch_to(next);
}
int sys_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
if(current->pid != 0)
fprintk(3, "%d\tW\t%d\n", current->pid, jiffies);
schedule();
return 0;
}
void sleep_on(struct task_struct **p)
{
struct task_struct *tmp;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
tmp = *p;
*p = current;
current->state = TASK_UNINTERRUPTIBLE;
fprintk(3, "%d\tW\t%d\n", current->pid, jiffies);
schedule();
if (tmp)
{
tmp->state=0;
fprintk(3, "%d\tJ\t%d\n", tmp->pid, jiffies);
}
}
void interruptible_sleep_on(struct task_struct **p)
{
struct task_struct *tmp;
if (!p)
return;
if (current == &(init_task.task))
panic("task[0] trying to sleep");
tmp=*p;
*p=current;
repeat: current->state = TASK_INTERRUPTIBLE;
fprintk(3, "%d\tW\t%d\n", current->pid, jiffies);
schedule();
if (*p && *p != current) {
(**p).state=0;
fprintk(3, "%d\tJ\t%d\n", (*p)->pid, jiffies);
goto repeat;
}
*p=NULL;
if (tmp)
{
tmp->state=0;
fprintk(3, "%d\tJ\t%d\n", tmp->pid, jiffies);
}
}
void wake_up(struct task_struct **p)
{
if (p && *p) {
(**p).state=0;
fprintk(3, "%d\tJ\t%d\n", (*p)->pid, jiffies);
*p=NULL;
}
}
exit.c
修改do_exit和sys_waitpidint do_exit(long code)
{
int i;
free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
for (i=0 ; i<NR_TASKS ; i++)
if (task[i] && task[i]->father == current->pid) {
task[i]->father = 1;
if (task[i]->state == TASK_ZOMBIE)
/* assumption task[1] is always init */
(void) send_sig(SIGCHLD, task[1], 1);
}
for (i=0 ; i<NR_OPEN ; i++)
if (current->filp[i])
sys_close(i);
iput(current->pwd);
current->pwd=NULL;
iput(current->root);
current->root=NULL;
iput(current->executable);
current->executable=NULL;
if (current->leader && current->tty >= 0)
tty_table[current->tty].pgrp = 0;
if (last_task_used_math == current)
last_task_used_math = NULL;
if (current->leader)
kill_session();
current->state = TASK_ZOMBIE;
current->exit_code = code;
tell_father(current->father);
fprintk(3, "%d\tE\t%d\n", current->pid, jiffies);
schedule();
return (-1); /* just to suppress warnings */
}
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
{
int flag, code;
struct task_struct ** p;
verify_area(stat_addr,4);
repeat:
flag=0;
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
if (!*p || *p == current)
continue;
if ((*p)->father != current->pid)
continue;
if (pid>0) {
if ((*p)->pid != pid)
continue;
} else if (!pid) {
if ((*p)->pgrp != current->pgrp)
continue;
} else if (pid != -1) {
if ((*p)->pgrp != -pid)
continue;
}
switch ((*p)->state) {
case TASK_STOPPED:
if (!(options & WUNTRACED))
continue;
put_fs_long(0x7f,stat_addr);
return (*p)->pid;
case TASK_ZOMBIE:
current->cutime += (*p)->utime;
current->cstime += (*p)->stime;
flag = (*p)->pid;
code = (*p)->exit_code;
release(*p);
put_fs_long(code,stat_addr);
return flag;
default:
flag=1;
continue;
}
}
if (flag) {
if (options & WNOHANG)
return 0;
current->state=TASK_INTERRUPTIBLE;
fprintk(3, "%d\tW\t%d\n", current->pid, jiffies);
schedule();
if (!(current->signal &= ~(1<<(SIGCHLD-1))))
goto repeat;
else
return -EINTR;
}
return -ECHILD;
}
太难了太难了,内核太难了……