2012.2.6 - LINUX内核 - 进程运行轨迹的跟踪与统计

Posted on 2013-02-13 23:56  SnakeHunt2012  阅读(461)  评论(0)    收藏  举报

本文始作于2012年2月6日,刊登于人人网,于2013年2月13日迁移至此

看了好多个晚上,终于在今天把这个实验都做出来了,这个是最后结果的对比:

 

做完这个实验经验还是有很大长进,首先最重要的就是,实验指导书必须做为第一手知道资料,而那个《剖析》应该算作辅助,当指导书很直接要你看《剖析》上哪里哪里的时候你要好好看,如果只是提到上面哪里的内容,你应该很大概的扫视一遍,不用那么认真每行代码都看,一开始就是,指导书刚一提到fork.c程序,我就钻进去看了,每行代码都读,而且查了很多资料,还是没弄懂,最有再看指导书的时候,猛然发现跟我看的根本就没多大关系,就是有也不需要都看,所以以后还是贴着指导书看比较明智。

这个实验分为两部分,第一部分就是学会使用fork()函数进行多进程编程。这一部分需要对fork()的原理掌握得比较底层,然后就很简单了,因为sunner已经把模拟各种类型进程的函数都写出来了,你只需要学会怎么用fork()来使用他们就可以马上写完了。

第二部分是主要费时间的,大概意思是修改内核,让内核在对进程状态切换的时候输出,而且是输出到一个指定的文件/var/process.log里。创建这个文件,和打开这个文件已经告诉你了,你只需要照着做就行了。接下来的就是写一个fprintk()函数,内容也已经写好了,你只需要考虑把它放在哪,放完时候做什么,其实放在哪也已经建议你了,至于之后做什么,因为这个函数不是系统调用,只是内核里面自己用的函数,唯一要做的就是写完之后别忘了在头文件linux-0.11/include/linux/kernel.h里把这个函数的原型int fprintk(int fd, const char * fmt, ...);注册进去,以便所有内核函数在调用它的时候都能找到它。然后就是重头戏了,接下来你要把所有涉及到进程切换的函数找到,切换之处填上输出语句。这个地方做错了好多遍。

首先就是重复输出,我做好以后把文件拿出来送进stat_log.py一检查发现它报错,说我在某一行处有一个进程做了相同的事,就是之前输出过R,后来接着又输出了R,原来还不能重负阿,我想也是,状态切换就应该是不同状态之间的切换,要是相同状态之间就不存在切换了,所以又在每一句输出的时候做了些加工,就是现判断它此刻的状态是不是将要切换成的状态,如果不是才输出,这一改就得都改。

后来就进程各个状态没分清,是今天早上又看了一遍第三课的录像,然后结合《剖析》上面对那个结构体的讲解才弄明白,原来就绪跟运行用的都是TASK_RUNNING,若用state值是区分不出来的,就得想别的办法。于是我就又看了《剖析》,知道了进程队列是怎么用的。最初的想法是在全局定义一个全局变量last_state,标出现在正进行的进程的进程号,但是我无意间在代码里瞟到current这个变量,发现他就是当前整运行的进程的指针。于是就迎刃而解了。进程由就绪切换到运行用的是一个叫做switch_to()的函数,我在它上面添加这几句:

/* switch CPU */
if (current != task[next]) {
fprintk(3, "%ld\t%c\t%ld\n", task[next]->pid, 'R', jiffies);
if (current->state == 0)
fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'J', jiffies);
}

 

这样就没有问题了。另外,上面这个是唯一一个没有用state进行切换的,而其他的切换都是在state上直接改数值,所以你只要在老师说到的文件里用vi的/命令搜索state,然后挨个看是不是修改就都能找到了。下面是需要修改的文件的完整代码。

exit.c:

  1 /*
  2 * linux/kernel/exit.c
  3 *
  4 * (C) 1991 Linus Torvalds
  5 */
  6 
  7 #include <errno.h>
  8 #include <signal.h>
  9 #include <sys/wait.h>
 10 
 11 #include <linux/sched.h>
 12 #include <linux/kernel.h>
 13 #include <linux/tty.h>
 14 #include <asm/segment.h>
 15 
 16 int sys_pause(void);
 17 int sys_close(int fd);
 18 
 19 void release(struct task_struct * p)
 20 {
 21 int i;
 22 
 23 if (!p)
 24 return;
 25 for (i=1 ; i<NR_TASKS ; i++)
 26 if (task[i]==p) {
 27 task[i]=NULL;
 28 free_page((long)p);
 29 schedule();
 30 return;
 31 }
 32 panic("trying to release non-existent task");
 33 }
 34 
 35 static inline int send_sig(long sig,struct task_struct * p,int priv)
 36 {
 37 if (!p || sig<1 || sig>32)
 38 return -EINVAL;
 39 if (priv || (current->euid==p->euid) || suser())
 40 p->signal |= (1<<(sig-1));
 41 else
 42 return -EPERM;
 43 return 0;
 44 }
 45 
 46 static void kill_session(void)
 47 {
 48 struct task_struct **p = NR_TASKS + task;
 49 
 50 while (--p > &FIRST_TASK) {
 51 if (*p && (*p)->session == current->session)
 52 (*p)->signal |= 1<<(SIGHUP-1);
 53 }
 54 }
 55 
 56 /*
 57 * XXX need to check permissions needed to send signals to process
 58 * groups, etc. etc. kill() permissions semantics are tricky!
 59 */
 60 int sys_kill(int pid,int sig)
 61 {
 62 struct task_struct **p = NR_TASKS + task;
 63 int err, retval = 0;
 64 
 65 if (!pid) while (--p > &FIRST_TASK) {
 66 if (*p && (*p)->pgrp == current->pid) 
 67 if ((err=send_sig(sig,*p,1)))
 68 retval = err;
 69 } else if (pid>0) while (--p > &FIRST_TASK) {
 70 if (*p && (*p)->pid == pid) 
 71 if ((err=send_sig(sig,*p,0)))
 72 retval = err;
 73 } else if (pid == -1) while (--p > &FIRST_TASK) {
 74 if ((err = send_sig(sig,*p,0)))
 75 retval = err;
 76 } else while (--p > &FIRST_TASK)
 77 if (*p && (*p)->pgrp == -pid)
 78 if ((err = send_sig(sig,*p,0)))
 79 retval = err;
 80 return retval;
 81 }
 82 
 83 static void tell_father(int pid)
 84 {
 85 int i;
 86 
 87 if (pid)
 88 for (i=0;i<NR_TASKS;i++) {
 89 if (!task[i])
 90 continue;
 91 if (task[i]->pid != pid)
 92 continue;
 93 task[i]->signal |= (1<<(SIGCHLD-1));
 94 return;
 95 }
 96 /* if we don't find any fathers, we just release ourselves */
 97 /* This is not really OK. Must change it to make father 1 */
 98 printk("BAD BAD - no father found\n\r");
 99 release(current);
100 }
101 
102 int do_exit(long code)
103 {
104 int i;
105 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
106 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
107 for (i=0 ; i<NR_TASKS ; i++)
108 if (task[i] && task[i]->father == current->pid) {
109 task[i]->father = 1;
110 if (task[i]->state == TASK_ZOMBIE)
111 /* assumption task[1] is always init */
112 (void) send_sig(SIGCHLD, task[1], 1);
113 }
114 for (i=0 ; i<NR_OPEN ; i++)
115 if (current->filp[i])
116 sys_close(i);
117 iput(current->pwd);
118 current->pwd=NULL;
119 iput(current->root);
120 current->root=NULL;
121 iput(current->executable);
122 current->executable=NULL;
123 if (current->leader && current->tty >= 0)
124 tty_table[current->tty].pgrp = 0;
125 if (last_task_used_math == current)
126 last_task_used_math = NULL;
127 if (current->leader)
128 kill_session();
129 current->state = TASK_ZOMBIE;
130 /* 退出 */
131 fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'E', jiffies);
132 current->exit_code = code;
133 tell_father(current->father);
134 schedule();
135 return (-1); /* just to suppress warnings */
136 }
137 
138 int sys_exit(int error_code)
139 {
140 return do_exit((error_code&0xff)<<8);
141 }
142 
143 int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
144 {
145 int flag, code;
146 struct task_struct ** p;
147 
148 verify_area(stat_addr,4);
149 repeat:
150 flag=0;
151 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
152 if (!*p || *p == current)
153 continue;
154 if ((*p)->father != current->pid)
155 continue;
156 if (pid>0) {
157 if ((*p)->pid != pid)
158 continue;
159 } else if (!pid) {
160 if ((*p)->pgrp != current->pgrp)
161 continue;
162 } else if (pid != -1) {
163 if ((*p)->pgrp != -pid)
164 continue;
165 }
166 switch ((*p)->state) {
167 case TASK_STOPPED:
168 if (!(options & WUNTRACED))
169 continue;
170 put_fs_long(0x7f,stat_addr);
171 return (*p)->pid;
172 case TASK_ZOMBIE:
173 current->cutime += (*p)->utime;
174 current->cstime += (*p)->stime;
175 flag = (*p)->pid;
176 code = (*p)->exit_code;
177 release(*p);
178 put_fs_long(code,stat_addr);
179 return flag;
180 default:
181 flag=1;
182 continue;
183 }
184 }
185 if (flag) {
186 if (options & WNOHANG)
187 return 0;
188 current->state=TASK_INTERRUPTIBLE;
189 /* 睡眠 */
190 fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
191 schedule();
192 if (!(current->signal &= ~(1<<(SIGCHLD-1))))
193 goto repeat;
194 else
195 return -EINTR;
196 }
197 return -ECHILD;
198 }

 

fork.c:

  1 /*
  2 * linux/kernel/fork.c
  3 *
  4 * (C) 1991 Linus Torvalds
  5 */
  6 
  7 /*
  8 * 'fork.c' contains the help-routines for the 'fork' system call
  9 * (see also system_call.s), and some misc functions ('verify_area').
 10 * Fork is rather simple, once you get the hang of it, but the memory
 11 * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
 12 */
 13 #include <errno.h>
 14 
 15 #include <linux/sched.h>
 16 #include <linux/kernel.h>
 17 #include <asm/segment.h>
 18 #include <asm/system.h>
 19 
 20 extern void write_verify(unsigned long address);
 21 
 22 long last_pid=0;
 23 
 24 void verify_area(void * addr,int size)
 25 {
 26 unsigned long start;
 27 
 28 start = (unsigned long) addr;
 29 size += start & 0xfff;
 30 start &= 0xfffff000;
 31 start += get_base(current->ldt[2]);
 32 while (size>0) {
 33 size -= 4096;
 34 write_verify(start);
 35 start += 4096;
 36 }
 37 }
 38 
 39 int copy_mem(int nr,struct task_struct * p)
 40 {
 41 unsigned long old_data_base,new_data_base,data_limit;
 42 unsigned long old_code_base,new_code_base,code_limit;
 43 
 44 code_limit=get_limit(0x0f);
 45 data_limit=get_limit(0x17);
 46 old_code_base = get_base(current->ldt[1]);
 47 old_data_base = get_base(current->ldt[2]);
 48 if (old_data_base != old_code_base)
 49 panic("We don't support separate I&D");
 50 if (data_limit < code_limit)
 51 panic("Bad data_limit");
 52 new_data_base = new_code_base = nr * 0x4000000;
 53 p->start_code = new_code_base;
 54 set_base(p->ldt[1],new_code_base);
 55 set_base(p->ldt[2],new_data_base);
 56 if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
 57 printk("free_page_tables: from copy_mem\n");
 58 free_page_tables(new_data_base,data_limit);
 59 return -ENOMEM;
 60 }
 61 return 0;
 62 }
 63 
 64 /*
 65 * Ok, this is the main fork-routine. It copies the system process
 66 * information (task[nr]) and sets up the necessary registers. It
 67 * also copies the data segment in it's entirety.
 68 */
 69 int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
 70 long ebx,long ecx,long edx,
 71 long fs,long es,long ds,
 72 long eip,long cs,long eflags,long esp,long ss)
 73 {
 74 struct task_struct *p;
 75 int i;
 76 struct file *f;
 77 
 78 p = (struct task_struct *) get_free_page();
 79 if (!p)
 80 return -EAGAIN;
 81 task[nr] = p;
 82 *p = *current; /* NOTE! this doesn't copy the supervisor stack */
 83 p->state = TASK_UNINTERRUPTIBLE;
 84 /* new */
 85 fprintk(3, "%ld\t%c\t%ld\n", last_pid, 'N', jiffies);
 86 p->pid = last_pid;
 87 p->father = current->pid;
 88 p->counter = p->priority;
 89 p->signal = 0;
 90 p->alarm = 0;
 91 p->leader = 0; /* process leadership doesn't inherit */
 92 p->utime = p->stime = 0;
 93 p->cutime = p->cstime = 0;
 94 p->start_time = jiffies;
 95 p->tss.back_link = 0;
 96 p->tss.esp0 = PAGE_SIZE + (long) p;
 97 p->tss.ss0 = 0x10;
 98 p->tss.eip = eip;
 99 p->tss.eflags = eflags;
100 p->tss.eax = 0;
101 p->tss.ecx = ecx;
102 p->tss.edx = edx;
103 p->tss.ebx = ebx;
104 p->tss.esp = esp;
105 p->tss.ebp = ebp;
106 p->tss.esi = esi;
107 p->tss.edi = edi;
108 p->tss.es = es & 0xffff;
109 p->tss.cs = cs & 0xffff;
110 p->tss.ss = ss & 0xffff;
111 p->tss.ds = ds & 0xffff;
112 p->tss.fs = fs & 0xffff;
113 p->tss.gs = gs & 0xffff;
114 p->tss.ldt = _LDT(nr);
115 p->tss.trace_bitmap = 0x80000000;
116 if (last_task_used_math == current)
117 __asm__("clts ; fnsave %0"::"m" (p->tss.i387));
118 if (copy_mem(nr,p)) {
119 task[nr] = NULL;
120 free_page((long) p);
121 return -EAGAIN;
122 }
123 for (i=0; i<NR_OPEN;i++)
124 if ((f=p->filp[i]))
125 f->f_count++;
126 if (current->pwd)
127 current->pwd->i_count++;
128 if (current->root)
129 current->root->i_count++;
130 if (current->executable)
131 current->executable->i_count++;
132 set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
133 set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
134 p->state = TASK_RUNNING; /* do this last, just in case */
135 /* ready */
136 fprintk(3, "%ld\t%c\t%ld\n", p->pid, 'J', jiffies);
137 return last_pid;
138 }
139 
140 int find_empty_process(void)
141 {
142 int i;
143 
144 repeat:
145 if ((++last_pid)<0) last_pid=1;
146 for(i=0 ; i<NR_TASKS ; i++)
147 if (task[i] && task[i]->pid == last_pid) goto repeat;
148 for(i=1 ; i<NR_TASKS ; i++)
149 if (!task[i])
150 return i;
151 return -EAGAIN;
152 }

 

schde.c:

  1 /*
  2 * linux/kernel/sched.c
  3 *
  4 * (C) 1991 Linus Torvalds
  5 */
  6 
  7 /*
  8 * 'sched.c' is the main kernel file. It contains scheduling primitives
  9 * (sleep_on, wakeup, schedule etc) as well as a number of simple system
 10 * call functions (type getpid(), which just extracts a field from
 11 * current-task
 12 */
 13 #include <linux/sched.h>
 14 #include <linux/kernel.h>
 15 #include <linux/sys.h>
 16 #include <linux/fdreg.h>
 17 #include <asm/system.h>
 18 #include <asm/io.h>
 19 #include <asm/segment.h>
 20 
 21 #include <signal.h>
 22 
 23 #define _S(nr) (1<<((nr)-1))
 24 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
 25 
 26 void show_task(int nr,struct task_struct * p)
 27 {
 28 int i,j = 4096-sizeof(struct task_struct);
 29 
 30 printk("%d: pid=%d, state=%d, ",nr,p->pid,p->state);
 31 i=0;
 32 while (i<j && !((char *)(p+1))[i])
 33 i++;
 34 printk("%d (of %d) chars free in kernel stack\n\r",i,j);
 35 }
 36 
 37 void show_stat(void)
 38 {
 39 int i;
 40 
 41 for (i=0;i<NR_TASKS;i++)
 42 if (task[i])
 43 show_task(i,task[i]);
 44 }
 45 
 46 #define LATCH (1193180/HZ)
 47 
 48 extern void mem_use(void);
 49 
 50 extern int timer_interrupt(void);
 51 extern int system_call(void);
 52 
 53 union task_union {
 54 struct task_struct task;
 55 char stack[PAGE_SIZE];
 56 };
 57 
 58 static union task_union init_task = {INIT_TASK,};
 59 
 60 long volatile jiffies=0;
 61 long startup_time=0;
 62 struct task_struct *current = &(init_task.task);
 63 struct task_struct *last_task_used_math = NULL;
 64 
 65 struct task_struct * task[NR_TASKS] = {&(init_task.task), };
 66 
 67 long user_stack [ PAGE_SIZE>>2 ] ;
 68 
 69 struct {
 70 long * a;
 71 short b;
 72 } stack_start = { & user_stack [PAGE_SIZE>>2] , 0x10 };
 73 /*
 74 * 'math_state_restore()' saves the current math information in the
 75 * old math state array, and gets the new ones from the current task
 76 */
 77 void math_state_restore()
 78 {
 79 if (last_task_used_math == current)
 80 return;
 81 __asm__("fwait");
 82 if (last_task_used_math) {
 83 __asm__("fnsave %0"::"m" (last_task_used_math->tss.i387));
 84 }
 85 last_task_used_math=current;
 86 if (current->used_math) {
 87 __asm__("frstor %0"::"m" (current->tss.i387));
 88 } else {
 89 __asm__("fninit"::);
 90 current->used_math=1;
 91 }
 92 }
 93 
 94 /*
 95 * 'schedule()' is the scheduler function. This is GOOD CODE! There
 96 * probably won't be any reason to change this, as it should work well
 97 * in all circumstances (ie gives IO-bound processes good response etc).
 98 * The one thing you might take a look at is the signal-handler code here.
 99 *
100 * NOTE!! Task 0 is the 'idle' task, which gets called when no other
101 * tasks can run. It can not be killed, and it cannot sleep. The 'state'
102 * information in task[0] is never used.
103 */
104 void schedule(void)
105 {
106 int i,next,c;
107 struct task_struct ** p;
108 
109 /* check alarm, wake up any interruptible tasks that have got a signal */
110 
111 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
112 if (*p) {
113 if ((*p)->alarm && (*p)->alarm < jiffies) {
114 (*p)->signal |= (1<<(SIGALRM-1));
115 (*p)->alarm = 0;
116 }
117 if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&
118 (*p)->state==TASK_INTERRUPTIBLE) {
119 /* running */
120 if ((*p)->state != TASK_RUNNING)
121 fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);
122 (*p)->state=TASK_RUNNING;
123 }
124 }
125 
126 /* this is the scheduler proper: */
127 
128 while (1) {
129 c = -1;
130 next = 0;
131 i = NR_TASKS;
132 p = &task[NR_TASKS];
133 while (--i) {
134 if (!*--p)
135 continue;
136 if ((*p)->state == TASK_RUNNING && (*p)->counter > c)
137 c = (*p)->counter, next = i;
138 }
139 if (c) break;
140 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
141 if (*p)
142 (*p)->counter = ((*p)->counter >> 1) +
143 (*p)->priority;
144 }
145 /* switch CPU */
146 if (current != task[next]) {
147 fprintk(3, "%ld\t%c\t%ld\n", task[next]->pid, 'R', jiffies);
148 if (current->state == 0)
149 fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'J', jiffies);
150 }
151 switch_to(next);
152 }
153 
154 int sys_pause(void)
155 {
156 /* wait */
157 if (current->state != TASK_INTERRUPTIBLE)
158 fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
159 current->state = TASK_INTERRUPTIBLE;
160 schedule();
161 return 0;
162 }
163 
164 void sleep_on(struct task_struct **p)
165 {
166 struct task_struct *tmp;
167 
168 if (!p)
169 return;
170 if (current == &(init_task.task))
171 panic("task[0] trying to sleep");
172 tmp = *p;
173 *p = current;
174 /* wait */
175 if (current->state != TASK_UNINTERRUPTIBLE)
176 fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
177 current->state = TASK_UNINTERRUPTIBLE;
178 schedule();
179 if (tmp) {
180 /* running */
181 if (tmp->state != 0)
182 fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);
183 tmp->state=0;
184 }
185 }
186 
187 void interruptible_sleep_on(struct task_struct **p)
188 {
189 struct task_struct *tmp;
190 
191 if (!p)
192 return;
193 if (current == &(init_task.task))
194 panic("task[0] trying to sleep");
195 tmp=*p;
196 *p=current;
197 repeat: 
198 /* wait */
199 if (current->state != TASK_INTERRUPTIBLE)
200 fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
201 current->state = TASK_INTERRUPTIBLE;
202 schedule();
203 if (*p && *p != current) {
204 /* running */
205 if ((**p).state != 0)
206 fprintk(3, "%ld\t%c\t%ld\n", (**p).pid, 'J', jiffies);
207 (**p).state=0;
208 goto repeat;
209 }
210 *p=NULL;
211 if (tmp) {
212 /* running */
213 if (tmp->state != 0)
214 fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);
215 tmp->state=0;
216 }
217 }
218 
219 void wake_up(struct task_struct **p)
220 {
221 if (p && *p) {
222 /* running */
223 if ((**p).state != 0)
224 fprintk(3, "%ld\t%c\t%ld\n", (**p).pid, 'J', jiffies);
225 (**p).state=0;
226 *p=NULL;
227 }
228 }
229 
230 /*
231 * OK, here are some floppy things that shouldn't be in the kernel
232 * proper. They are here because the floppy needs a timer, and this
233 * was the easiest way of doing it.
234 */
235 static struct task_struct * wait_motor[4] = {NULL,NULL,NULL,NULL};
236 static int mon_timer[4]={0,0,0,0};
237 static int moff_timer[4]={0,0,0,0};
238 unsigned char current_DOR = 0x0C;
239 
240 int ticks_to_floppy_on(unsigned int nr)
241 {
242 extern unsigned char selected;
243 unsigned char mask = 0x10 << nr;
244 
245 if (nr>3)
246 panic("floppy_on: nr>3");
247 moff_timer[nr]=10000; /* 100 s = very big :-) */
248 cli(); /* use floppy_off to turn it off */
249 mask |= current_DOR;
250 if (!selected) {
251 mask &= 0xFC;
252 mask |= nr;
253 }
254 if (mask != current_DOR) {
255 outb(mask,FD_DOR);
256 if ((mask ^ current_DOR) & 0xf0)
257 mon_timer[nr] = HZ/2;
258 else if (mon_timer[nr] < 2)
259 mon_timer[nr] = 2;
260 current_DOR = mask;
261 }
262 sti();
263 return mon_timer[nr];
264 }
265 
266 void floppy_on(unsigned int nr)
267 {
268 cli();
269 while (ticks_to_floppy_on(nr))
270 sleep_on(nr+wait_motor);
271 sti();
272 }
273 
274 void floppy_off(unsigned int nr)
275 {
276 moff_timer[nr]=3*HZ;
277 }
278 
279 void do_floppy_timer(void)
280 {
281 int i;
282 unsigned char mask = 0x10;
283 
284 for (i=0 ; i<4 ; i++,mask <<= 1) {
285 if (!(mask & current_DOR))
286 continue;
287 if (mon_timer[i]) {
288 if (!--mon_timer[i])
289 wake_up(i+wait_motor);
290 } else if (!moff_timer[i]) {
291 current_DOR &= ~mask;
292 outb(current_DOR,FD_DOR);
293 } else
294 moff_timer[i]--;
295 }
296 }
297 
298 #define TIME_REQUESTS 64
299 
300 static struct timer_list {
301 long jiffies;
302 void (*fn)();
303 struct timer_list * next;
304 } timer_list[TIME_REQUESTS], * next_timer = NULL;
305 
306 void add_timer(long jiffies, void (*fn)(void))
307 {
308 struct timer_list * p;
309 
310 if (!fn)
311 return;
312 cli();
313 if (jiffies <= 0)
314 (fn)();
315 else {
316 for (p = timer_list ; p < timer_list + TIME_REQUESTS ; p++)
317 if (!p->fn)
318 break;
319 if (p >= timer_list + TIME_REQUESTS)
320 panic("No more time requests free");
321 p->fn = fn;
322 p->jiffies = jiffies;
323 p->next = next_timer;
324 next_timer = p;
325 while (p->next && p->next->jiffies < p->jiffies) {
326 p->jiffies -= p->next->jiffies;
327 fn = p->fn;
328 p->fn = p->next->fn;
329 p->next->fn = fn;
330 jiffies = p->jiffies;
331 p->jiffies = p->next->jiffies;
332 p->next->jiffies = jiffies;
333 p = p->next;
334 }
335 }
336 sti();
337 }
338 
339 void do_timer(long cpl)
340 {
341 extern int beepcount;
342 extern void sysbeepstop(void);
343 
344 if (beepcount)
345 if (!--beepcount)
346 sysbeepstop();
347 
348 if (cpl)
349 current->utime++;
350 else
351 current->stime++;
352 
353 if (next_timer) {
354 next_timer->jiffies--;
355 while (next_timer && next_timer->jiffies <= 0) {
356 void (*fn)(void);
357 
358 fn = next_timer->fn;
359 next_timer->fn = NULL;
360 next_timer = next_timer->next;
361 (fn)();
362 }
363 }
364 if (current_DOR & 0xf0)
365 do_floppy_timer();
366 if ((--current->counter)>0) return;
367 current->counter=0;
368 if (!cpl) return;
369 schedule();
370 }
371 
372 int sys_alarm(long seconds)
373 {
374 int old = current->alarm;
375 
376 if (old)
377 old = (old - jiffies) / HZ;
378 current->alarm = (seconds>0)?(jiffies+HZ*seconds):0;
379 return (old);
380 }
381 
382 int sys_getpid(void)
383 {
384 return current->pid;
385 }
386 
387 int sys_getppid(void)
388 {
389 return current->father;
390 }
391 
392 int sys_getuid(void)
393 {
394 return current->uid;
395 }
396 
397 int sys_geteuid(void)
398 {
399 return current->euid;
400 }
401 
402 int sys_getgid(void)
403 {
404 return current->gid;
405 }
406 
407 int sys_getegid(void)
408 {
409 return current->egid;
410 }
411 
412 int sys_nice(long increment)
413 {
414 if (current->priority-increment>0)
415 current->priority -= increment;
416 return 0;
417 }
418 
419 void sched_init(void)
420 {
421 int i;
422 struct desc_struct * p;
423 
424 if (sizeof(struct sigaction) != 16)
425 panic("Struct sigaction MUST be 16 bytes");
426 set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
427 set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
428 p = gdt+2+FIRST_TSS_ENTRY;
429 for(i=1;i<NR_TASKS;i++) {
430 task[i] = NULL;
431 p->a=p->b=0;
432 p++;
433 p->a=p->b=0;
434 p++;
435 }
436 /* Clear NT, so that we won't have troubles with that later on */
437 __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
438 ltr(0);
439 lldt(0);
440 outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
441 outb_p(LATCH & 0xff , 0x40); /* LSB */
442 outb(LATCH >> 8 , 0x40); /* MSB */
443 set_intr_gate(0x20,&timer_interrupt);
444 outb(inb_p(0x21)&~0x01,0x21);
445 set_system_gate(0x80,&system_call);
446 }