#ifndef _SCHED_H
#define _SCHED_H
#define NR_TASKS 64
#define HZ 100
#define FIRST_TASK task[0]
#define LAST_TASK task[NR_TASKS-1]
#include <linux/head.h>
#include <linux/fs.h>
#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
#define TASK_ZOMBIE 3
#define TASK_STOPPED 4
#ifndef NULL
#define NULL ((void *) 0)
#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
{
};
// 任务状态段数据结构(参见列表后的信息)。
struct tss_struct
{
};
// 这里是任务(进程)数据结构,或称为进程描述符。
// ==========================
// 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
{
};
// 对应上面任务结构的第1 个任务的信息。
#define INIT_TASK \
{ 0,15,15, \
0,
{
,}
, 0, \
{
NULL,}
, \
{
}
,
{
}
,}
extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
extern long volatile jiffies;
extern long startup_time;
#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);
// 全局表中第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" \
"subl %2,%%eax\n\t" \
: "=a" (n):"a" (0), "i" (FIRST_TSS_ENTRY << 3))
// 输入:%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" \
// 在任务切换回来后才会继续执行下面的语句。
}
// 页面地址对准。(在内核代码中没有任何地方引用!!)
#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" \
"rorl $16,%%edx\n\t" \
::"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" \
::"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" \
:"=d" (__base) \
:"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