#ifndef _SCHED_H
#define _SCHED_H

#define NR_TASKS 64		// ϵͳͬʱ񣨽̣
#define HZ 100			// ϵͳʱӵδƵ(1 ٺȣÿδ10ms)

#define FIRST_TASK task[0]	// 0 Ƚ⣬һš
#define LAST_TASK task[NR_TASKS-1]	// еһ

#include <linux/head.h>		// head ͷļ˶ļ򵥽ṹͼѡ
#include <linux/fs.h>		// ļϵͳͷļļṹfile,buffer_head,m_inode ȣ
#include <linux/mm.h>		// ڴͷļҳСһЩҳͷźԭ͡
#include <signal.h>		// źͷļźŷųźŽṹԼźŲԭ͡

#if (NR_OPEN > 32)
#error "Currently the close-on-exec-flags are in one word, max 32 files/proc"
#endif

// ﶨ˽пܴ״̬
#define TASK_RUNNING 0		// л׼
#define TASK_INTERRUPTIBLE 1	// ̴ڿжϵȴ״̬
#define TASK_UNINTERRUPTIBLE 2	// ̴ڲжϵȴ״̬ҪI/O ȴ
#define TASK_ZOMBIE 3		// ̴ڽ״̬ѾֹͣУ̻ûźš
#define TASK_STOPPED 4		// ֹͣ

#ifndef NULL
#define NULL ((void *) 0)	// NULL Ϊָ롣
#endif

// ƽ̵ҳĿ¼ҳLinus Ϊںӵĺ֮һ( mm/memory.c, 105 )
extern int copy_page_tables (unsigned long from, unsigned long to, long size);
// ͷҳָڴ鼰ҳ( mm/memory.c, 150 )
extern int free_page_tables (unsigned long from, unsigned long size);

// ȳĳʼ( kernel/sched.c, 385 )
extern void sched_init (void);
// ̵Ⱥ( kernel/sched.c, 104 )
extern void schedule (void);
// 쳣()жϴʼжϵŲжźš( kernel/traps.c, 181 )
extern void trap_init (void);
// ʾں˳ϢȻѭ( kernel/panic.c, 16 )
extern void panic (const char *str);
// tty дָȵַ( kernel/chr_drv/tty_io.c, 290 )
extern int tty_write (unsigned minor, char *buf, int count);

typedef int (*fn_ptr) ();	// 庯ָ͡

// ѧЭʹõĽṹҪڱлʱi387 ִ״̬Ϣ
struct i387_struct
{
  long cwd;			// (Control word)
  long swd;			// ״̬(Status word)
  long twd;			// (Tag word)
  long fip;			// Эָ롣
  long fcs;			// ЭμĴ
  long foo;
  long fos;
  long st_space[20];		/* 8*10 bytes for each FP-reg = 80 bytes */
};

// ״̬ݽṹμбϢ
struct tss_struct
{
  long back_link;		/* 16 high bits zero */
  long esp0;
  long ss0;			/* 16 high bits zero */
  long esp1;
  long ss1;			/* 16 high bits zero */
  long esp2;
  long ss2;			/* 16 high bits zero */
  long cr3;
  long eip;
  long eflags;
  long eax, ecx, edx, ebx;
  long esp;
  long ebp;
  long esi;
  long edi;
  long es;			/* 16 high bits zero */
  long cs;			/* 16 high bits zero */
  long ss;			/* 16 high bits zero */
  long ds;			/* 16 high bits zero */
  long fs;			/* 16 high bits zero */
  long gs;			/* 16 high bits zero */
  long ldt;			/* 16 high bits zero */
  long trace_bitmap;		/* bits: trace 0, bitmap 16-31 */
  struct i387_struct i387;
};

// 񣨽̣ݽṹΪ
// ==========================
// long state ״̬-1 У0 ()>0 ֹͣ
// long counter ʱ(ݼ)δʱƬ
// long priority ʼʱcounter = priorityԽԽ
// long signal źšλͼÿλһźţźֵ=λƫֵ+1
// struct sigaction sigaction[32] źִԽṹӦźŽҪִеĲͱ־Ϣ
// long blocked ź루Ӧźλͼ
// --------------------------
// int exit_code ִֹͣ˳룬丸̻ȡ
// unsigned long start_code εַ
// unsigned long end_code 볤ȣֽ
// unsigned long end_data 볤 + ݳȣֽ
// unsigned long brk ܳȣֽ
// unsigned long start_stack ջεַ
// long pid ̱ʶ(̺)
// long father ̺š
// long pgrp š
// long session Ựš
// long leader Ự졣
// unsigned short uid ûʶţûid
// unsigned short euid Чûid
// unsigned short suid ûid
// unsigned short gid ʶţid
// unsigned short egid Чid
// unsigned short sgid id
// long alarm ʱֵδ
// long utime û̬ʱ䣨δ
// long stime ϵͳ̬ʱ䣨δ
// long cutime ӽû̬ʱ䡣
// long cstime ӽϵͳ̬ʱ䡣
// long start_time ̿ʼʱ̡
// unsigned short used_math ־ǷʹЭ
// --------------------------
// int tty ʹtty 豸š-1 ʾûʹá
// unsigned short umask ļλ
// struct m_inode * pwd ǰĿ¼i ڵṹ
// struct m_inode * root Ŀ¼i ڵṹ
// struct m_inode * executable ִļi ڵṹ
// unsigned long close_on_exec ִʱرļλͼ־μinclude/fcntl.h
// struct file * filp[NR_OPEN] ʹõļṹ
// --------------------------
// struct desc_struct ldt[3] ľֲ0-գ1-cs2-ݺͶջds&ss
// --------------------------
// struct tss_struct tss ̵״̬Ϣṹ
// ==========================
struct task_struct
{
/* these are hardcoded - don't touch */
  long state;			/* -1 unrunnable, 0 runnable, >0 stopped */
  long counter;
  long priority;
  long signal;
  struct sigaction sigaction[32];
  long blocked;			/* bitmap of masked signals */
/* various fields */
  int exit_code;
  unsigned long start_code, end_code, end_data, brk, start_stack;
  long pid, father, pgrp, session, leader;
  unsigned short uid, euid, suid;
  unsigned short gid, egid, sgid;
  long alarm;
  long utime, stime, cutime, cstime, start_time;
  unsigned short used_math;
/* file system info */
  int tty;			/* -1 if no tty, so it must be signed */
  unsigned short umask;
  struct m_inode *pwd;
  struct m_inode *root;
  struct m_inode *executable;
  unsigned long close_on_exec;
  struct file *filp[NR_OPEN];
/* ldt for this task 0 - zero 1 - cs 2 - ds&ss */
  struct desc_struct ldt[3];
/* tss for this task */
  struct tss_struct tss;
};

/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x9ffff (=640kB)
*/
/*
* INIT_TASK õ1 ޸ģԸ?
* ַBase = 0γlimit = 0x9ffff=640kB
*/
// Ӧṹĵ1 Ϣ
#define INIT_TASK \
/* state etc */ { 0,15,15, \	// state, counter, priority
/* signals */ 0,
{
  {
  }
,}

, 0, \				// signal, sigaction[32], blocked
					/* ec,brk... */ 0, 0, 0, 0, 0, 0, \
					// exit_code,start_code,end_code,end_data,brk,start_stack
					/* pid etc.. */ 0, -1, 0, 0, 0, \
					// pid, father, pgrp, session, leader
					/* uid etc */ 0, 0, 0, 0, 0, 0, \
					// uid, euid, suid, gid, egid, sgid
					/* alarm */ 0, 0, 0, 0, 0, 0, \
					// alarm, utime, stime, cutime, cstime, start_time
				/* math */ 0, \
				// used_math
							/* fs info */ -1, 0022, NULL, NULL, NULL, 0, \
							// tty,umask,pwd,root,executable,close_on_exec
/* filp */
{
NULL,}

, \				// filp[20]
{
  \				// ldt[3]
  {
  0, 0}
  ,
/* ldt */
  {
  0x9f, 0xc0fa00}
  , \				// 볤640Kַ0x0G=1D=1DPL=3P=1 TYPE=0x0a
  {
  0x9f, 0xc0f200}
  , \				// ݳ640Kַ0x0G=1D=1DPL=3P=1 TYPE=0x02
}

,
/*tss*/
{
  0, PAGE_SIZE + (long) &init_task, 0x10, 0, 0, 0, 0, (long) &pg_dir, \	// tss
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, _LDT (0), 0x80000000,
  {
  }
}
,}

extern struct task_struct *task[NR_TASKS];	// 顣
extern struct task_struct *last_task_used_math;	// һʹùЭĽ̡
extern struct task_struct *current;	// ǰ̽ṹָ
extern long volatile jiffies;	// ӿʼĵδ10ms/δ𣩡
extern long startup_time;	// ʱ䡣1970:0:0:0 ʼʱ

#define CURRENT_TIME (startup_time+jiffies/HZ)	// ǰʱ䣨

// Ӷʱʱʱjiffies δʱʱú*fn()( kernel/sched.c,272)
extern void add_timer (long jiffies, void (*fn) (void));
// жϵĵȴ˯ߡ( kernel/sched.c, 151 )
extern void sleep_on (struct task_struct **p);
// жϵĵȴ˯ߡ( kernel/sched.c, 167 )
extern void interruptible_sleep_on (struct task_struct **p);
// ȷ˯ߵĽ̡( kernel/sched.c, 188 )
extern void wake_up (struct task_struct **p);

/*
* Entry into gdt where to find first TSS. 0-nul, 1-cs, 2-ds, 3-syscall
* 4-TSS0, 5-LDT0, 6-TSS1 etc ...
*/
/*
* Ѱҵ1 TSS ȫֱеڡ0-ûnul1-cs2-ݶds3-ϵͳsyscall
* 4-״̬TSS05-ֲLTD06-״̬TSS1ȡ
*/
// ȫֱе1 ״̬(TSS)ѡš
#define FIRST_TSS_ENTRY 4
// ȫֱе1 ֲ(LDT)ѡš
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
// 궨壬ȫֱеn TSS ţѡ
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
// 궨壬ȫֱеn LDT š
#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
// 궨壬صn Ĵtr
#define ltr(n) __asm__( "ltr %%ax":: "a" (_TSS(n)))
// 궨壬صn ľֲĴldtr
#define lldt(n) __asm__( "lldt %%ax":: "a" (_LDT(n)))
// ȡǰţеֵ̺pid ͬ
// أn - ǰš( kernel/traps.c, 79)
#define str(n) \
__asm__( "str %%ax\n\t" \	// ĴTSS εЧַ??ax
"subl %2,%%eax\n\t" \		// (eax - FIRST_TSS_ENTRY*8)??eax
  "shrl $4,%%eax" \		// (eax/16)??eax = ǰš
: "=a" (n):"a" (0), "i" (FIRST_TSS_ENTRY << 3))
/*
* switch_to(n) should switch tasks to task nr n, first
* checking that n isn't the current task, in which case it does nothing.
* This also clears the TS-flag if the task we switched to has used
* tha math co-processor latest.
*/
/*
* switch_to(n)лǰnrnȼn ǵǰ
* ʲôҲ˳лϴУʹùѧ
* ЭĻ踴λƼĴcr0 еTS ־
*/
// 룺%0 - TSS ƫƵַ(*&__tmp.a) %1 - TSS ѡֵ(*&__tmp.b)
// dx - n ѡecx - ָtask[n]
// ʱݽṹ__tmp Уa ֵ32 λƫֵb ΪTSS ѡлʱa ֵ
// ûãԣжϴִǷʹùЭʱͨ״̬εĵַ
// last_task_used_math еʹùЭ״̬εĵַбȽ϶ġ
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__( "cmpl %%ecx,_current\n\t" \	// n ǵǰ?(current ==task[n]?)
  "je 1f\n\t" \			// ǣʲô˳
  "movw %%dx,%1\n\t" \		// ѡ??*&__tmp.b
  "xchgl %%ecx,_current\n\t" \	// current = task[n]ecx = л
  "ljmp %0\n\t" \		// ִгת*&__tmpл
// лŻִ䡣
  "cmpl %%ecx,_last_task_used_math\n\t" \	// ϴʹùЭ
  "jne 1f\n\t" \		// ûת˳
  "clts\n" \			// ϴʹùЭcr0 TS ־
  "1:"::"m" (*&__tmp.a), "m" (*&__tmp.b),
  "d" (_TSS (n)), "c" ((long) task[n]));
}

// ҳַ׼ں˴ûκεط!!
#define PAGE_ALIGN(n) (((n)+0xfff)&0xfffff000)

// λڵַaddr еĸֶַ(ַbase)μб˵
// %0 - ַaddr ƫ2%1 - ַaddr ƫ4%2 - ַaddr ƫ7edx - ַbase
#define _set_base(addr,base) \
__asm__( "movw %%dx,%0\n\t" \	// ַbase 16 λ(λ15-0)??[addr+2]
"rorl $16,%%edx\n\t" \		// edx лַ16 λ(λ31-16)??dx
  "movb %%dl,%1\n\t" \		// ַ16 λеĵ8 λ(λ23-16)??[addr+4]
  "movb %%dh,%2" \		// ַ16 λеĸ8 λ(λ31-24)??[addr+7]
::"m" (*((addr) + 2)), "m" (*((addr) + 4)), "m" (*((addr) + 7)), "d" (base):"dx")
// λڵַaddr еĶ޳ֶ(γlimit)
// %0 - ַaddr%1 - ַaddr ƫ6 edx - γֵlimit
#define _set_limit(addr,limit) \
__asm__( "movw %%dx,%0\n\t" \	// γlimit 16 λ(λ15-0)??[addr]
  "rorl $16,%%edx\n\t" \	// edx еĶγ4 λ(λ19-16)??dl
  "movb %1,%%dh\n\t" \		// ȡԭ[addr+6]ֽ??dhи4 λЩ־
  "andb $0xf0,%%dh\n\t" \	// dh ĵ4 λ(Ŷγλ19-16)
  "orb %%dh,%%dl\n\t" \		// ԭ4 λ־Ͷγĸ4 λ(λ19-16)ϳ1 ֽڣ
  "movb %%dl,%1" \		// Ż[addr+6]
::"m" (*(addr)), "m" (*((addr) + 6)), "d" (limit):"dx")
// þֲldt ĻֶַΡ
#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base )
// þֲldt ĶγֶΡ
#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 )
// ӵַaddr ȡλַ_set_base()෴
// edx - Żַ(__base)%1 - ַaddr ƫ2%2 - ַaddr ƫ4%3 - addr ƫ7
#define _get_base(addr) ({\
unsigned long __base; \
__asm__( "movb %3,%%dh\n\t" \	// ȡ[addr+7]ַ16 λĸ8 λ(λ31-24)??dh
  "movb %2,%%dl\n\t" \		// ȡ[addr+4]ַ16 λĵ8 λ(λ23-16)??dl
  "shll $16,%%edx\n\t" \	// ַ16 λƵedx и16 λ
  "movw %1,%%dx" \		// ȡ[addr+2]ַ16 λ(λ15-0)??dx
:"=d" (__base) \		// Ӷedx к32 λĶλַ
:"m" (*((addr) + 2)), "m" (*((addr) + 4)), "m" (*((addr) + 7)));
__base;
}

)
// ȡֲldt ָеĻַ
#define get_base(ldt) _get_base( ((char *)&(ldt)) )
// ȡѡsegment Ķγֵ
// %0 - Ŷγֵ(ֽ)%1 - ѡsegment
#define get_limit(segment) ({ \
unsigned long __limit; \
__asm__( "lsll %1,%0\n\tincl %0": "=r" (__limit): "r" (segment)); \
__limit;})
#endif
