?? sched.h
字號:
#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-代碼段cs,2-數據和堆棧段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,基址0x0,G=1,D=1,DPL=3,P=1 TYPE=0x0a{0x9f,0xc0f200}, \ // 數據長640K,基址0x0,G=1,D=1,DPL=3,P=1 TYPE=0x02}, \/*tss*/ {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\ // tss0,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-沒有用nul,1-代碼段cs,2-數據段ds,3-系統段syscall* 4-任務狀態段TSS0,5-局部表LTD0,6-任務狀態段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)將切換當前任務到任務nr,即n。首先檢測任務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 偏移7;edx - 基地址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
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -