本文分析基于Linux 0.11内核,转载请标明出处
http://blog.csdn.net/yming0221/archive/2011/06/09/6533865.aspx。
main.c中在move_to_user_mode()之后,切换到用户模式下运行,task0然后执行fork()创建进程task1来执行init()函数。init()函数如下:
[cpp] view plain copy print ?
- void init (void)
- {
- int pid, i;
-
-
- setup ((void *) &drive_info);
- (void) open ("/dev/tty0", O_RDWR, 0);
-
-
- (void) dup (0);
- (void) dup (0);
- printf ("%d buffers = %d bytes buffer space/n/r", NR_BUFFERS, NR_BUFFERS * BLOCK_SIZE);
- printf ("Free mem: %d bytes/n/r", memory_end - main_memory_start);
-
-
-
-
- if (!(pid = fork ()))
- {
- close (0);
- if (open ("/etc/rc", O_RDONLY, 0))
- _exit (1);
- execve ("/bin/sh", argv_rc, envp_rc);
- _exit (2);
- }
-
-
-
- if (pid > 0)
- while (pid != wait (&i))
- ;
-
-
-
-
-
-
-
- while (1)
- {
- if ((pid = fork ()) < 0)
- {
- printf ("Fork failed in init/r/n");
- continue;
- }
- if (!pid)
- {
- close (0);
- close (1);
- close (2);
- setsid ();
- (void) open ("/dev/tty0", O_RDWR, 0);
- (void) dup (0);
- (void) dup (0);
- _exit (execve ("/bin/sh", argv, envp));
- }
- while (1)
- if (pid == wait (&i))
- break;
- printf ("/n/rchild %d died with code %04x/n/r", pid, i);
- sync ();
- }
- _exit (0);
- }
init进程通过fork()产生子进程,产生的子进程开始读取硬盘参数包括分区表信息并建立虚拟盘和安装根文件系统设备,打开设备,并运行sh程序
,当该进程异常结束,就会循环重试上述过程。然而进程0这时会运行到代码
for(;;) pause()
处,pause()函数是系统调用,它也被声明为内联函数,通过int 0x80调用系统调用sys_pause()。
[cpp] view plain copy print ?
- int
- sys_pause (void)
- {
- current->state = TASK_INTERRUPTIBLE;
- schedule ();
- return 0;
- }
该系统调用所做的任务就是将当前任务的运行状态改为可中断运行状态,然后执行调度函数schedule()。
[cpp] view plain copy print ?
- void
- schedule (void)
- {
- int i, next, c;
- struct task_struct **p;
-
-
-
- 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;
- }
-
-
- 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;
- }
- switch_to (next);
- }
该段代码有很多精巧之处,如果让我自己来实现同样的功能,代码可能会很繁琐。
精巧之处:
1、i起初赋值64,循环的时候先进行变量的--,然后再判断,这样正好执行63次,task0没有必要循环判断。
2、c起初赋值为-1,next赋值0,这样可以解决当循环63次后,task[1]--task[63]没有相应的任务在执行,这时,执行下一句break后,跳
出死循环,执行swtich_to(next)语句,正好切换到task[0],task0这时继续循环执行pause()语句,调用调度函数。所以说task0是个闲置的
任务,只有task数组没有其他任务的时候才执行task0,让task0继续执行调度函数。重新调度进程运行。