LFYOS

目 录

  1. LFYOS
    1. 安装
    2. 数据结构
      1. 内核
      2. 内存管理器
    3. 内核实现
      1. 就绪线程
        1. 堆数据结构
        2. 就绪线程管理部件的数据结构及其实现
        3. 就绪线程管理部件提供的调用
      2. 信号量
        1. 信号量和P、V操作
        2. 内核中的信号量
        3. 信号量管理数据结构
        4. 信号量管理的实现
      3. 线程迁移
      4. 中断
      5. 处理机
        1. 处理机管理数据结构
        2. 处理机管理的实现
      6. 存储管理
        1. 存储管理数据结构
        2. 页框状态的变迁
        3. 页框散列队列
        4. 存储管理的实现
    4. 编程手册
      1. LFYOS中应用程序编程模型
        1. 单一数据存储模型
        2. 实现了数据存储、数据计算和资源管理的分离
        3. 应用程序之间的依赖关系
      2. 内核提供的系统功能调用
        1. 参数传递
        2. 系统功能调用的例子
      3. 内核中系统功能调用的格式
        1. 线程迁移和线程返回
        2. 对信号量执行P、V操作
        3. 信号量定时
        4. 创建线程
        5. 进程资源
        6. 申请和释放信号量
        7. 线程属性
        8. 查询存储体容量和地址
        9. 设置文件窗口capability校验
      4. 内存管理器提供的功能调用
        1. 文件窗口
        2. 地址映射
        3. flush
        4. 标志页框
        5. 存储域
        6. 计算存储管理区需要的存储空间
        7. 初试化和安装
        8. 操纵文件窗口
      5. 文件系统提供的功能调用


LFYOS

[目录]


安装

通过Redhat 7.1实施安装

    我们安装的开发环境是Redhat 7.1,内核版本linux-2.4.2,下面以该版本为例来讨论LINUX操作系统安装和加载问题。在Redhat 7.1Linux操作系统中,当重构内核时,首先进入目录/usr/src/ linux-2.4.2,执行make命令,该命令根据文件/usr/src/ linux-2.4.2.Makefile中的规则,执行规则指定的各个命令,其执行过程是首先生成一个内核图象,然后再把该内核图象压缩后,安装到系统之中。生成内核图象的make规则为:

vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
              $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
                     --start-group \
                     $(CORE_FILES) \
                     $(DRIVERS) \
                     $(NETWORKS) \
                     $(LIBS) \
                     --end-group \
                     -o vmlinux

    我们实现虚拟地址空间基于文件操作系统的安装和加载的方法是:修改该规则,使得做make重构内核时,不再根据生成linux内核的目标文件生成内核图象,而是根据生成虚拟地址空间基于文件操作系统的目标文件生成内核图象,为此把上诉规则修改为:

vmlinux  :      $(LFYOS)
              $(LD) $(LINKFLAGS)  $(LFYOS)  -o vmlinux

    变量$(LFYOS)中存放的是生成虚拟地址空间基于文件操作系统内核需要的目标文件,这样当我们重新做make重构内核时,就会根据变量$(LFYOS)中指定的目标文件生成一个内核图象,并把该内核图象安装到系统之中,而不再根据生成Linux的内核文件生成和安装LINUX内核图象。当重新启动系统时,就会把我们实现的内核启动起来,而不会启动一个LINUX内核。

安装和加载的详细步骤如下:

    ·i.以超级用户root注册。安装操作系统的内核当然必须是超级用户root。

    ·ii.检查系统是否安装了内核开发的软件包,是否安装了lilo,如果没有安装安装之,关于如何安装请参考安装LINUX的详细资料,此处略。

    ·iii.重构一遍linux内核,关于如何重构linux内核请参考安装LINUX的详细资料,此处略。

    ·iv. 进入目录/usr/src/linux-X.X.X(其中的X.X.X为内核版本号),复制一个Makefile,也就是执行命令:
          cp  Makefile  lfy_makefile

    ·v.编辑文件lfy_makefile,确定其中的规则:

vmlinux: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs
                            $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \
                                          --start-group \
                                          $(CORE_FILES) \
                                          $(DRIVERS) \
                                          $(NETWORKS) \
                                          $(LIBS) \
                                          --end-group \
                                   -o vmlinux

把该规则修改为:

vmlinux  :      $(LFYOS)
                            $(LD) $(LINKFLAGS)  $(LFYOS)  -o vmlinux

    ·vi.进入/etc目录,编辑lilo的配置文件/etc/lilo.conf。该文件中的内容类似于:

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=180
message=/boot/message
linear
default=dos

image=/boot/vmlinuz-2.4.2-2
       label=linux
       read-only
       root=/dev/hda7

other=/dev/hda1
       optional
       label=dos

    在该文件中开始部分是安装各个操作系统总的配置信息,后面是各个操作系统的配置信息。修改该文件为:

boot=/dev/hda
map=/boot/map
install=/boot/boot.b
prompt
timeout=180
message=/boot/message
linear
default=dos

image=/boot/vmlinuz-2.4.2-2
       label=linux
       read-only
       root=/dev/hda7

image=/boot/vmlinuz.new
label=lfyos
read-only
root=/dev/hda7

other=/dev/hda1
       optional
       label=dos

    中间部分为加入的内容,也就是虚拟地址空间基于文件操作系统的启动信息,操作系统的启动文件为/boot/vmlinux.new,名称为lfyos,只读安装,安装设备为/dev/hda7。不同的系统安装设备可能不同,只需要把安装设备设置成和linux操作系统相同安装设备即可。

    ·vii.确定安装虚拟地址空间基于文件操作系统源文件和目标文件的目录,进入该目录(在我们的实现中,源文件和目标文件安装在目录/root下的os目录中),因此利用命令cd /root进入目录/root,把虚拟地址空间基于文件操作系统源文件的压缩文件os.tar拷贝到该目录下。

    ·viii.执行命令tar –xvf os.tar ,把源文件的压缩文件解压,该命令将在/root目录下生成一个子目录os,生成虚拟地址空间基于文件操作系统的源文件将全部解压到该子目录下。

    ·ix.进入/root/os目录,编辑该目录下的makefile文件,在该文件的第一行为
           VERSION=linux-2.4.2
变量VERSION 中存放LINUX内核的版本号,如果你安装的LINUX内核的版本不是2.4.2,修改为相应的版本号。

    ·x.执行命令make。该命令执行完毕后,虚拟地址空间基于文件操作系统就已经成功的安装到你的系统。

    ·xi.重新启动系统,选择启动的操作系统,将发现可以选择的操作系统中包括lfyos,这就是安装的虚拟地址空间基于文件操作系统。选择并启动该操作系统,虚拟地址空间基于文件操作系统即开始运行。

[目录]


数据结构

[目录]


内核

1、文件kernel/arch.h
#ifndef OS_KERNEL_ARCH
#define OS_KERNEL_ARCH

#define DEFAULT_CS                (0x23)
#define DEFAULT_DS                (0x2b)
#define DEFAULT_ES                DEFAULT_DS
#define DEFAULT_FS                DEFAULT_DS
#define DEFAULT_GS                DEFAULT_DS
#define DEFAULT_SS                DEFAULT_DS
#define DEFAULT_SP                (0xc0001ffc)
#define DEFAULT_SP_0        (0xc0000ffc)

typedef struct{
                void (*ip)(void );
                int cs;
                int flag;
                char *sp;
                int ss;
                int ds,es,fs,gs;
                char *sp_0;
                int (*function)(void );
                int cr2[CR2_BUF_NUMBER];
}run_point;

#endif

2、文件kernel/capability.h
#ifndef OS_KERNEL_CAPABILITY
#define OS_KERNEL_CAPABILITY

struct capability {
        int c1,c2,c3,c4;
};

#endif

3、文件kernel/process.h
#ifndef OS_PROCESS_STRUCT
#define OS_PROCESS_STRUCT

struct thread_physical_block {
                int stack_memory_id,stack_block_id;
                int memory_id,block_id;
};


struct network_address{
                int a;
};


struct file{
                struct{
                        struct network_address network_node;
                        int server_processor,server_process,file_handler;
                }file;
                struct{
                        int processor,process;
                }proxy;
                int memory_process,open_window_id;
                int window_base_1,window_base_2,window_length,right;
                struct capability capability;
                int read_in_flag,swap_out_flag;
};

union file_system_operation_parameter{
                struct {
                        int begin_rw,end_rw;
                }read_write;
};

struct file_system_call_parameter {
                int command,sleep_semaphore;
                struct file file;
                struct thread_physical_block block;
                union file_system_operation_parameter parameter;
};

#define OPEN_FILE                0
#define CLOSE_FILE                1
#define READ_FILE                2
#define WRITE_FILE                3
#define OPERATE_FILE                4

struct process{
                run_point start_point;
                int (*driver)(struct file_system_call_parameter *par);
                int priority;
                int semaphore;
                int enter_thread_number,id;
                int max_thread_number,thread_number,thread_ring;
                int max_semaphore_number,semaphore_number,semaphore_ring;
                struct user_file_information file[USER_FILE_NUMBER];
                struct capability capability;
};

#endif
4、文件kernel/kernel_struct.h
#ifndef OS_KERNEL_STRUCT
#define OS_KERNEL_STRUCT

struct semaphore{
                int value;
                int process;
                int thread_id,thread_ring;
                int front,back;
                struct capability capability;

                int heap,v_value;
                struct kernel_time first,step;
};

struct thread ;
struct return_stack ;

struct thread_environment{
                int system_call,system_call_arg1;        /*ax,bx*/
                int system_call_arg2,system_call_arg3;        /*cx,dx*/
                int system_call_arg4,system_call_arg5;        /*si,di*/
                int system_call_arg6,system_call_arg7;        /*bp,r7*/
                run_point point;                        /*ip,cs,flag,sp,ss */
};

struct exception_item{
                int flag;
};

struct return_stack{
                struct thread_environment environment;
                int current_process,process_id,process_p_flag;
                struct exception_item exception;
                struct thread_physical_block physical_block;
};

struct thread{
                enum {SLEEP,RUN,READY} state;
                int priority;
                int set_v_operation_result_flag;
                int heap,process,pro_front,pro_back;
                int semaphore,sleep_semaphore,sem_front,sem_back;
                int cpu_id;
                struct return_stack return_stack[RETURN_BLOCK_NUMBER];
                int return_stack_top;
                struct user_file_information file[USER_FILE_NUMBER];
};

struct thread_heap{
                int thread;
};

#endif
5、文件kernel/os_struct.h

#ifndef OS_OS_STRUCT
#define OS_OS_STRUCT

struct cpu_information{
                int thread_id;
                struct{
                        int thread_id,process_id;
                        struct thread_physical_block physical_block;
                }last;
};

struct os_data{
                struct{
                        struct cpu_information used_cpu[VIRTUAL_CPU_NUMBER];
                        struct{
                                int cpu_id;
                        }free_cpu[VIRTUAL_CPU_NUMBER];
                        int free_cpu_top;
                }virtual_cpu;

                struct process process[PROCESS_NUMBER];

                struct thread thread[THREAD_NUMBER];
                struct{
                        struct thread_heap run_heap[VIRTUAL_CPU_NUMBER];
                        struct thread_heap ready_heap[THREAD_NUMBER];
                        int run_thread_number,ready_thread_number;
                }thread_heap;
                struct semaphore semaphore[SEMAPHORE_NUMBER];
                struct{
                        int semaphore_id;
                }semaphore_heap[SEMAPHORE_NUMBER];
                struct kernel_time current_time;
                struct system_file_information system_file[MEMORY_BODY_NUMBER];
                struct capability system_capability;
};

struct current_information {
                struct thread_environment *env;
                struct return_stack *rt;
                struct thread *t;
                struct cpu_information *cpu_info;
                union system_call_parameter *par;
                int thread_id,cpu_id,return_stack_top;
};
extern struct current_information current;

#endif


[目录]


内存管理器

1、文件memory/memory_struct.h

#ifndef OS_MEMORY_STRUCT
#define OS_MEMORY_STRUCT

struct file_window{
                enum{
                        FILE_OPEN,
                        FILE_CLOSE
                } state;
                struct file file;
                int block_ring;
                int file_front,file_back;
                int lock_number;
};
struct memory_sleep_semaphore{
                int processor,semaphore;
};
struct physical_block{
                enum{
                        FREE_BLOCK,
                        READING_BLOCK,
                        NOT_MODIFIED_BLOCK,
                        MODIFIED_BLOCK,
                        WRITING_BLOCK
                }state;

                int lock_number;
                int file_window,logic_block_number;
                int physical_number;
                int file_front,file_back;
                int buf_front,buf_back;
                int hash_front,hash_back;
                struct memory_sleep_semaphore sleep_semaphore;
};

struct memory_resource{
                int process_number;
                int file_number,max_file_number;
                int max_block_number,trigger_block_number;
                int block_number,read_block_number,write_block_number;
                struct capability capability;
};

struct memory_process{
                int file_number,max_file_number,file_ring;
                int max_block_number,trigger_block_number;
                int block_number,read_block_number,write_block_number;
                int block_ring,read_block_ring,write_block_ring;
                struct capability capability;
};

struct memory_hash{
                int hash_ring;
};

struct memory_body_struct{
                int *free_physical_block,*free_file;
                int *block_number,*free_block_number;
                int *file_number,*process_number,*hash_number;
                struct physical_block *physical_block;
                struct file_window *file_window;
                struct memory_process *memory_process;
                struct memory_hash *hash;
                int (*hash_function)(int file,int logic_block);
                int my_processor,my_memory_body;
                struct memory_sleep_semaphore *wait_block;
};
struct install_memory_body_parameter{
                char *base;
                int (*hash_function)(int file,int logic_block);
                int my_processor,my_memory_body;
                int block_number,file_number;
                int process_number,hash_number;
                int first_block;
                struct capability capability;
};

#endif

2、文件memory/call_memory.h

#ifndef OS_MEMORY_MEMORY_CALL
#define OS_MEMORY_MEMORY_CALL

union memory_call_parameter{
                struct{
                        struct install_memory_body_parameter
                                memory_body_parameter;
                        struct capability capability;
                        int set_stack_flag;
                }setup;
                struct open_file_window{
                        int file_window_id;
                        struct file_window file_window;
                        struct capability process_capability;
                }open_file_window;
                struct close_file_window{
                        int file_window_id;
                        struct capability file_capability;
                }close_file_window;
                struct file_attribute{
                        int file_window_id;
                        struct file file;
                        struct capability capability;
                }file_attribute;
                struct memory_map_deal{
                        int file_window_id;
                        int begin_logic_address,end_logic_address;
                        struct capability file_capability;
                }memory_map_deal;
                struct flush_process_memory{
                        int give_up_flag;
                        int process_number;
                        struct capability process_capability;
                }flush_process_memory;
                struct flush_file_window{
                        int give_up_flag;
                        int file_window_id;
                        struct capability file_capability;
                }flush_file_window;
                struct mark_modify{
                        int file_window_id;
                        int begin_logic_address,end_logic_address;
                        struct capability file_capability;
                }mark_modifed;
                struct memory_resource        memory_resource;
                struct control_file_system{
                        union file_system_operation_parameter parameter;
                        struct capability capability;
                }control_file_system;
};

#endif


[目录]


内核实现

[目录]


就绪线程

内核中就绪线程管理部件的实现

    在虚拟地址空间基于文件操作系统中,采用按优先级调度方式,调度各个就绪线程占用处理机。执行线程调度时,总是选择优先数最小,也就是优先级最高的线程占用处理机。内核利用堆数据结构选择优先数最小的线程。下面首先介绍堆数据结构,然后讨论选择优先数最小线程的算法。

[目录]


堆数据结构

堆的概念

    假设r[0],r[1],… r[n-1]是一序列元素,如果对于任意r[i],同时满足条件r[i].key≤r[2* i+1].key,r[i].key≤r[2*i+2].key,则称该序列是一个堆,也称为最小化堆,如果把不等式中的小于号≤换成大于号≥,称为最大化堆。在下面的讨论中,所有的堆指的是最小化堆。
可以把序列r[0],r[1],… r[n-1]看成是按数组方式存储的一棵满二叉树,元素r[0]为树根,其它元素为树中的中间结点或叶子结点。考虑到在一棵按数组方式存储的满二叉树中,元素r[2*i+1]和元素r[2*i+2]是元素r[i]的左孩子和右孩子,因此在一个堆中,对于任一元素r[i],其键值r[i].key一定小于等于其左右两个孩子的键值r[2* i+1].key和r[2*i+2].key。
    根据堆的定义,可以得出堆的一个重要性质:如果一个按数组存放的满二叉树是堆,那么堆顶元素一定是堆中所有元素中键值最小的元素。
    该性质可以根据堆二叉树的层数利用数学归纳法证明:
    当堆二叉树的层数为1时,堆二叉树中只有一个元素r[0],因此堆顶元素是堆中所有元素中键值最小的元素。
    假设对于所有的层数小于n的堆二叉树,堆顶元素的键值是堆中所有元素中键值最小的元素。当堆二叉树的层树为n时,堆顶元素r[0]的左右子树一定是层数小于n的堆二叉树,左子树的堆顶元素是r[1],右子树的堆顶元素是r[2]。根据假设可知r[1]是左子树中键值最小的元素,r[2]是右子树中键值最小的元素;再根据堆的定义:对于任意元素r[i]满足r[i].key≤r[2* i+1].key,r[i].key≤r[2*i+2].key,可知r[0].key≤r[1].key,r[0].key≤r[2].key,因此,堆顶元素r[0]一定是堆中所有元素中键值最小的元素。
    堆的性质使得堆很适合从一组元素中选择最值元素(最大值或最小值)的场合,只要把所有可供选择的元素组织成一个堆,堆顶元素即为需要选择的最值元素。这也是我们采用堆数据结构选择优先数最小线程的原因。在LFYOS中,把所有处于就绪状态的线程根据线程的优先数组织成一个堆,堆顶元素即为优先级最高的线程,执行线程切换时,内核总是选择处于堆顶的线程占用处理机。
    元素的健值发生变化时对堆的调整
    假设在堆中存在n个元素r[0],r[1],… r[n-1],这些元素之间全部满足条件r[i].key≤r[2* i+1].key和r[i].key≤r[2*i+2].key,由于某种原因,其中某个元素r[k]的键值r[k].key改变,破坏了构成堆的条件,需要对元素序列进行相应的调整,把元素序列恢复为一个堆。
    元素r[k]的键值r[k].key改变有两种可能:键值r[k].key减小或键值r[k].key增大。在堆中,元素r[k]的键值r[k].key大于等于其双亲的键值r[INT((k-1)/2)].key,小于等于左右孩子的键值r[2* i+1].key和r[2*i+2].key,如果键值r[k].key减小,其键值仍然小于等于左右孩子的键值,但可能由于小于其双亲的键值而破坏了构成堆的条件。通过在序列中把r[k]和其双亲结点相互交换,在二叉树中把r[k]向上移动,即可把序列调整为一个堆。
    下面讨论如果某个元素r[k]其键值r[k].key增大后,如何对堆进行调整。
    假设在堆中,元素r[k]的键值r[k].key大于等于其双亲的键值r[INT((k-1)/2)].key,小于等于左右孩子的键值r[2* i+1].key和r[2*i+2].key,如果键值r[k].key增大,其键值仍然大于其双亲接点的键值,但可能由于大于其左右孩子的键值而破坏了构成堆的条件。通过在序列中把r[k]和左右孩子结点中键值较小的结点相互交换,在二叉树中把r[k]向下移动,即可把序列调整为一个堆。

堆调整算法的时间复杂度

    无论某个堆中元素的键值是增大还是减小,堆调整算法执行结点交换的次数都是很少的。假设在一个堆中存在n个元素,则堆二叉树的层数不超过1+Log 2n,当堆中某一元素的键值增大时,该元素在堆中向下移动;当堆中某一元素的键值减小时,该元素在堆中向上移动。由于堆二叉树的层数不超过1+Log2n,因此,执行堆调整算法时,结点交换的次数不超过Log2n,也就是说,堆调整算法的时间复杂度仅仅为O(Log2n)。显然,堆调整算法的时间复杂度很低,这也是我们选择堆数据结构来选择优先级最高线程的原因。

向堆中加入一个元素,从堆中删除一个元素

    向堆中加入一个元素时,把元素放在序列的最后,然后执行键值减小的上移调整;从堆中删除一个元素时,首先把被删除的元素和最后一个元素交换,把元素从序列的最后删除,再根据删除元素的键值和交换元素的键值大小执行上移或下移调整。如果删除元素的键值小于交换元素的键值,执行下移调整;如果删除元素的键值大于交换元素的键值,执行上移调整。


[目录]


就绪线程管理部件的数据结构及其实现

空闲处理机栈、处理机状态数组

    在系统中设置一空闲处理机栈,所有空闲的处理机记录在空闲处理机栈中,当某一处理机空闲时,把处理机号压入栈中,如果有线程需要运行,从栈中弹出一个处理机分配给线程使用。当就绪线程堆非空时,所有处理机都已分配给了线程,空闲处理机栈一定是空的。
在系统中设置一处理机状态数组,每个处理机对应数组中的一个元素。在数组中记录着各个处理机需要切换的线程,在大多数情况下,当前运行的线程和需要切换的线程二者相同,表示不需要执行处理机切换,如果二者不同,需要申请处理机中断,请求处理机执行处理机切换,切换另一线程占用处理机。
运行线程堆和就绪线程堆
    在虚拟地址基于文件的操作系统中,设置了两个堆数据结构:运行线程堆和就绪线程堆。所有正在处理机上运行的线程记录在运行线程堆中;所有等待到处理机上去运行的线程记录在就绪线程堆中。运行线程堆中线程的个数最多不超过系统支持的处理机数。
系统按照各个线程的优先数对两个堆实施管理。在就绪线程堆中,堆顶元素是优先数最小优先级最高的线程,如果需要选择一个就绪线程占用处理机,选择堆顶元素对应的线程;在运行线程堆中,堆顶元素是优先数最大优先级最低的线程,如果需要选择一个运行线程放弃处理机,也选择堆顶元素对应的线程。由于线程优先数越小,优先极越高,优先数越大,优先极越低,因此,运行线程堆是一个最大化堆。
    由于系统选择优先级最高的线程占用处理机运行,一般情况下,就绪线程堆堆顶元素对应线程的优先数大于运行线程堆堆顶元素对应线程的优先数。如果由于某些原因线程的优先数发生了变化(例如,线程改变了优先数、处于运行线程堆中线程睡眠、线程终止退出等),就绪线程堆堆顶元素对应线程的优先数,可能小于运行线程堆堆顶元素对应线程的优先数,表示系统中某个处于就绪态线程的优先级高于另一个处于运行态线程的优先级,需要系统执行处理机切换,使运行线程堆堆顶元素对应线程放弃处理机,就绪线程堆堆顶元素对应线程占用处理机。

向运行线程堆或就绪线程堆插入线程的算法

    如果存在空闲处理机,从空闲处理机栈弹出一个处理机号分配给线程,把分配的处理机号记录在线程的控制块中,在处理机状态数组中记录该处理机需要切换的线程,直接把线程加入到运行线程堆中,并请求处理机执行处理机切换。
如果不存在空闲处理机,比较需要插入的线程优先级和运行线程堆堆顶元素对应的线程的优先级,如果需要插入线程的优先级不高于运行线程堆堆顶元素对应线程的优先级,直接把新创建的线程加入到就绪线程堆中。
    如果需要插入线程的优先级高于运行线程堆堆顶元素对应线程的优先级,把需要插入的线程和运行线程堆堆顶元素相互交换,对运行线程堆执行下移调整,把原运行线程堆堆顶元素对应的线程加入到就绪线程堆中;同时,在处理机状态数组中对应处理机元素中,把需要切换线程域设置为新插入线程的线程标识符,请求处理机执行处理机切换。

从运行线程堆或就绪线程堆删除线程的算法

    如果线程处于就绪线程堆中,直接从就绪线程堆中删除。
    如果线程处于运行线程堆中,就绪线程堆非空,把删除的线程和就绪线程堆堆顶元素对应的线程执行交换,对运行线程堆执行下移调整,再从就绪线程堆中把线程删除;同时,在处理机状态数组对应处理机的元素中,把需要切换线程域设置为原就绪线程堆堆顶元素对应的线程,并请求处理机执行处理机切换。
    如果线程处于运行线程堆中,就绪线程堆为空,直接从运行线程堆中删除;同时,在处理机状态数组对应处理机元素中,把需要切换线程域设置为空。把处理机号压入空闲处理机栈中,并请求处理机执行处理机切换,处理机切换为空闲状态。


[目录]


就绪线程管理部件提供的调用

    管理运行线程堆和就绪线程堆的模块统称为就绪线程管理部件,就绪线程管理部件为上层共提供了四个调用:

    向运行线程堆或就绪线程堆中插入线程:线程对信号量执行V操作时,可能需要唤醒线程,调用本功能向运行线程堆或就绪线程堆插入线程。
    从运行线程堆或就绪线程堆删除线程:线程对信号量执行P操作时,可能需要使线程睡眠,调用本功能从运行线程堆或就绪线程堆删除线程。
    线程优先数调整:改变线程优先数时调用本功能,首先从运行线程堆或就绪线程堆删除线程,修改线程优先数后再插入到运行线程堆或就绪线程堆中。
    处理机切换响应:处理机管理部件仅仅选择哪些线程应该在处理机上运行,如果需要某个处理机执行处理机切换,通过中断网络向处理机申请中断,处理机响应中断,触发中断服务程序执行处理机切换的操作,并调用本功能通知处理机管理部件已完成处理机切换。

[目录]


信号量

内核中信号量管理部件的实现

    信号量(semaphore)是E. W. Dijkstra在1965年提出的一种用于实现进程之间同步和互斥的方法。一个信号量的值可以为0,表示没有积累下来的唤醒操作,也没有在信号量上睡眠的进程;或者为正值,表示有一个或多个被积累下来的唤醒操作;或者为负值,其绝对值为在信号量上睡眠的进程数。
    信号量管理部件提供四个功能调用:
    ·申请一个信号量
    ·释放一个信号量
    ·对信号量执行P操作
    ·对信号量执行V操作

[目录]


信号量和P、V操作

    对信号量存在两种操作:对信号量的P操作和对信号量的V操作。
    对一信号量执行P操作时检查其值是否大于零。若是则将其值减1(用掉一个保存的唤醒信号)并继续执行;若值小于等于零则将其值减1后睡眠,此时P操作并未结束。检查数值、改变数值、以及可能发生的睡眠操作均作为一个单一的、不可分割的原子操作(atomic action)完成,即保证一旦一个信号量操作开始,则在操作完成或阻塞之前别的进程均不允许访问该信号量。这种原子性对于解决同步问题和避免竞争条件是非常重要的。
    V操作递增信号量的值。如果一个或多个进程在该信号量上睡眠,无法完成一个先前的P操作,则由系统选择其中的一个并允许其完成它的P操作,于是,对一个有进程在其上睡眠的信号量执行一次V操作之后,该信号量的值加1,在其上睡眠的进程少了一个。递增信号量的值和唤醒一个进程同样也是不可分割的。不会有进程因执行V而睡眠。


[目录]


内核中的信号量

    在LFYOS中,信号量是内核维护的一种资源,应用程序通过使用信号量实现线程之间的同步和互斥。
    线程可以通过内核提供的调用申请和释放信号量资源。申请信号量时,用资源ID作调用的入口参数。如果两个或多个线程使用相同的资源ID申请信号量,信号量管理部件保证它们申请到相同的信号量,以实现线程之间正确的同步和互斥。使用完信号量后应释放信号量资源,以便其它进程使用。
    LFYOS中信号量P、V操作的语义也和Dijkstra提出的信号量的语义有所不同。
    对于信号量V操作,线程可以指定递增信号量的值,不仅仅可以实现对信号量值的加一操作,而且可以增加任意一个整数;甚至可以指定唤醒所有睡眠在该信号量上的线程。信号量V操作的返回值为信号量的当前值,通过指定递增信号量的值为零,执行信号量V操作可以查询信号量的当前值。线程还可以对某个线程而不是对信号量执行V操作,由信号量管理部件对线程正在上面睡眠的信号量执行V操作把线程唤醒。
    对于信号量P操作,如果信号量的当前值小于等于0时,线程可以选择是睡眠还是直接返回;如果执行P操作的线程睡眠,等到其它线程执行了V操作后,执行P操作的线程返回。P操作的返回值为一整数类型的变量,如果其它线程执行的V操作同时唤醒了多个线程,这些线程P操作的返回值从1开始递增排序,哪一个线程可以进入临界区由应用程序确定。在LFYOS中,不仅线程自己可以执行P操作,而且可以代替其它线程对某个信号量执行P操作,从而使其它线程睡眠;再通过对信号量执行V操作将其唤醒,因此,通过P、V操作可以实现对线程的调度和控制。
    LFYOS中信号量和Dijkstra提出的信号量的另一点不同是:释放信号量时,如果存在线程睡眠在信号量上,这些线程被全部唤醒;而Dijkstra提出的信号量没有释放操作。
    如果执行对信号量的V操作时,指定唤醒所有睡眠在该信号量上的线程,P、V操作的语义类似于UNIX内核中的sleep()和wakeup()函数。

[目录]


信号量管理数据结构

    信号量管理数据结构见后面的“数据结构”部分,在系统中设置一信号量控制块数组,每个信号量对应着数组中的一个元素。
    信号量分成两类:空闲信号量和已经分配的信号量。所有空闲信号量链成一个单向链,用一个变量(空闲信号量链首)指向空闲信号量链,按先进后出的栈式管理方式实施对空闲信号量的管理。
    线程由于对某个信号量执行了P操作而睡眠,睡眠在某个信号量上的所有线程都已经从就绪线程堆或运行线程堆中删除,并链成一个双向的环链,链首指针保存在信号量控制块数组中。执行V操作时把睡眠的线程从线程环链中删除,插入就绪线程堆或运行线程堆中。

[目录]


信号量管理的实现

    信号量管理包括四个对信号量操作的实现:
    ·申请一个信号量
    ·释放一个信号量
    ·对信号量执行P操作
    ·对信号量执行V操作
    执行对信号量的P操作和V 操作以前,首先检查信号量的状态,如果是一个没有分配的信号量,不能对其执行任何操作,信号量操作直接返回,否则根据不同的操作请求,进行相应的处理:
    执行P操作时,对信号量的值执行减一操作,根据减一后信号量的值,分别处理:
    如果大于等于0,P操作直接返回,返回值为1。
    如果小于零,但是指定了P操作不睡眠,对信号量的值执行加一操作后P操作返回,返回值为0。
    如果小于零,但是指定了P操作可以睡眠,把线程从运行线程堆或就绪线程堆删除,插入到信号量的睡眠线程环链中,使线程睡眠。当线程被其它线程执行的V操作唤醒时,这些被唤醒线程的P操作返回,被V操作唤醒的各个线程的返回值从2开始顺序递增。
    执行对线程的V操作时,首先根据线程确定的信号量并设置递增信号量的值为1,然后设置一初始值为0的递增计数器,根据指定的递增信号量的值,循环重复执行以下操作:
    对信号量的值和计数器的值执行加一操作。
    如果在信号量的睡眠线程环链中存在睡眠的线程,唤醒环链上的第一个线程,把线程从信号量的睡眠线程环链中删除,插入到运行线程堆或就绪线程堆中,设置P操作的返回值为计数器的当前值;其它情况不执行线程唤醒操作。
    执行申请信号量调用时,从空闲信号量栈中取出一个信号量,执行初始化操作后把信号量ID返回给应用程序。
    执行释放信号量调用时,如果信号量上存在睡眠线程,执行V操作将其唤醒;然后把信号量插入空闲信号量栈中。

[目录]


线程迁移

内核中线程迁移部件的实现

    在LFYOS中,线程和进程的关系是一种临时性的关系,线程并非永久性地属于某一个进程,通过线程迁移调用一个线程可以从一个进程进入另一个进程,执行被调用进程相应的功能,在被调用进程中执行完毕后,通过线程返回调用线程退回到原进程中运行。通过线程迁移调用和线程返回调用,线程实现了在不同进程之间的迁移。
    通过线程迁移调用,一个线程进入另一个进程时,在新进程中,只能从进程初始执行点开始执行。通过在进程初始执行点处放置一定的检查程序,可以防止恶意的线程对进程的破坏,保证线程调用的安全性。
    同样,当一个线程从一个进程返回到原来的进程时,系统也要保证线程返回到正确的执行点,防止恶意的特洛伊木马造成的破坏,为此,在线程控制块中专门设置了线程返回控制块栈。当一个线程执行线程迁移调用,从一个进程进入另一个进程时,系统保存线程返回调用时应该恢复的返回地址、进程标识符等信息;当线程执行线程返回调用从一个进程返回到原来的进程时,根据以前保存的线程返回地址,恢复线程在原进程环境中的运行。通过保存线程返回地址,防止服务进程对调用进程恶意的破坏,保证线程返回的安全性。

线程迁移部件提供的功能调用及实现

    线程迁移部件提供了两个功能调用:线程迁移调用和线程返回调用。
    线程迁移部件分下面三步执行线程迁移调用:
    ·判断目标进程是否是一个合法的进程,如果非法直接返回出错;否则继续向下执行。
    ·如果需要把当前应该保存的信息压入线程返回控制块栈中,执行压栈操作,如果压栈操作溢出,直接返回出错信息;如果不需要执行压栈操作或需要执行压栈操作且压栈操作没有溢出,继续向下执行。
    ·最后把线程的当前所属进程设置为目标进程,根据目标进程的初始执行点,在目标进程中开始执行。

    线程迁移部件分下面步执行线程返回调用:
    从线程返回控制块栈中弹出应该恢复的信息。
    如果不能弹出应该恢复的信息,线程终止,否则根据弹出的信息恢复线程在原进程中的运行。

[目录]


中断

中断服务程序和处理机切换部件的实现

    中断服务程序是和硬件平台密切相关的,对于外部设备中断,中断服务程序根据中断对应的信号量执行对信号量的V操作;对于处理机之间的中断,中断服务程序调用处理机切换部件提供的功能,执行处理机切换操作。
    处理机切换部件首先通过处理机切换响应调用,通知就绪线程管理部件执行了处理机切换,然后调用硬件处理机切换部件执行具体的切换操作。
线程获得处理机后,首先判断是否需要执行强制返回,如果需要,执行线程返回调用返回上一级进程,否则恢复线程在当前进程中的运行。

[目录]


处理机

[目录]


处理机管理数据结构

进程管理数据结构

    在内核中设置一进程控制块数组,数据中每一个元素对应一个进程,存放着对应进程的各项信息,包括以下信息:
    ·进程的初始执行点
    ·创建线程的最高优先级
    ·进程的Capability校验
    ·操作该进程的互斥信号量
    ·允许进程申请的最大信号量数和当前进程申请的信号量数
    ·允许进程创建的线程数和当前进程创建的线程数
    ·记录进程创建线程的线程环链首指针
    ·记录进程申请信号量的信号量环链首指针
    一个进程创建的所有线程链成一个线程环链,并把链首指针存放在进程控制块中。创建线程时,向线程环链中插入一个线程;终止线程时,从线程环链中把相应的线程删除。根据线程环链可以确定一个进程创建的所有线程。
    一个进程申请的所有信号量也链成一个信号量环链,并把链首指针存放在进程控制块中。申请信号量时,向信号量环链中插入一个信号量;释放信号量时,从信号量环链中把相应的信号量删除。根据信号量环链可以确定一个进程申请的所有信号量。

线程控制块数组

    为了管理线程,系统设置一线程控制块数组,数组中每个元素对应一个线程,线程控制块中存放着以下信息:
    ·线程的状态(睡眠态、就绪态、运行态)以及线程睡眠的信号量(睡眠态)、在就绪线程堆中的位置(就绪态)或在运行线程堆中的位置(运行态)
    ·线程的优先数
    ·线程当前所在的进程、线程资源所属进程及线程环链前后指针
    ·线程返回控制块栈和栈顶指针
    ·线程的Capability校验

[目录]


处理机管理的实现

分配和查询处理机资源

    根据调用参数,重新设置创建线程的最高优先级、允许进程申请的最大信号量数、和允许进程创建的线程数,返回创建线程的最高优先级、允许进程申请的最大信号量数和当前进程申请的信号量数、允许进程创建的线程数和当前进程创建的线程数。
    只有拥有系统的Capability校验,才能够分配处理机资源,只有拥有系统的Capability校验或进程的Capability校验,才能够查询处理机资源。

线程的创建

    在内核中设置一个空闲线程信号量,并设置其初值为零,系统启动时,内核为线程控制块数组中每一个元素创建所有线程,这些线程创建后立即对系统中的空闲线程信号量执行P操作而在空闲线程信号量上睡眠。
    执行线程的创建功能调用时,对空闲线程信号量执行一次V操作,唤醒一个睡眠在空闲信号量上的线程,把唤醒的线程控制块链入到进程创建线程的线程环链中,对当前进程创建的线程数执行加一操作,最后初始化线程返回控制块栈,进入进程运行。
    线程在进程中运行完毕后,执行线程返回调用,当不能返回上一级进程时,执行线程终止操作,首先对当前进程创建的线程数执行减一操作,然后把线程控制块从到进程创建线程的线程环链中删除,最后线程对空闲线程信号量执行一次P操作重新睡眠,成为空闲线程。
    只有拥有系统的Capability校验或进程的Capability校验,才能够为进程创建线程。

设置和查询线程属性

    如果设置线程属性,首先在线程控制块中设置新的线程优先数和线程的Capability校验,然后调用就绪线程管理部件执行线程优先数调整,最后返回新的线程属性。
    只有拥有线程所属进程的Capability校验和当前所属进程的Capability校验,或者只有拥有系统的Capability校验,才能够设置和查询线程属性。

分配和释放信号量

    执行申请操作时,首先检查该进程是否还允许申请信号量,从空闲信号量环中取出一个信号量,插入到进程的信号量环链中;与此相反,执行释放信号量时,把信号量从进程的信号量环链取下信号量,插入到空闲信号量环中。
设置文件capability校验、检测线程在执行进程中是否能够访问文件
该操作的实现很简单,直接把文件的capability保存在内核相应数据结构中。

[目录]


存储管理

[目录]


存储管理数据结构

    在最初的实现中,存储管理是在内核以外由内存管理器实施的。为了提高存储管理的性能,在当前的实现中,把内存管理器放入核内,并提供专门的系统功能调用接口来操作存储管理器,和存储管理有关的数据结构包括:页框控制块表、空闲页框队列、打开文件控制块表、空闲打开文件队列、存储域控制块表、以及地址映射页表。

页框控制块表

    页框控制块表用于管理页框,每个页框对应表中的一项,根据页框的使用情况,页框控制块表中的表项链入空闲页框队列或页框文件队列中。在页框控制块中存放着页框的有关信息,其中包括:页框的状态(空闲、正在读、未修改、已修改、正在写),页框中的数据在外存文件中的偏移量,页框中对应的地址映射信息等。

空闲页框队列

    在每个存储体中设置一个空闲页框队列,空闲页框队列的结构如图4-5所示,存储体中所有没有被分配的页框都被链入空闲页框队列中,并用空闲队列队首指向空闲页框队列中的第一个页框。系统按栈式队列的方式管理空闲页框队列,每次分配一个页框,系统把队列首部的页框分配给存储域,并把分配的页框从队列首部删除;每次释放一个页框时,系统把释放的页框插入队列首部。

文件窗口控制块表

    文件窗口控制块表用于实施对文件窗口的管理,每个在内存中打开的文件窗口对应表中的一项。如果文件窗口已经打开,打开文件窗口在文件窗口控制块表中对应的表项链入某个存储域控制块的打开文件窗口队列,否则链入空闲文件窗口队列。在打开文件窗口控制块中存放着文件窗口的有关信息,包括:文件服务器的标识、对应外存上文件的标识、访问文件的权限、文件窗口的大小和在外存文件中的位置、当前使用的页框、访问文件的Capability校验、文件窗口控制块所属的存储域等。

空闲文件窗口队列

    和空闲页框队列相似,在每个存储体中设置一个空闲文件窗口队列,空闲文件窗口队列的结构如图4-6所示,存储体中所有没有被分配的文件窗口控制块都被链入空闲文件窗口队列中,并用空闲队列队队首指向空闲文件窗口队列中的第一个文件窗口控制块。系统按栈式队列的方式管理空闲文件窗口队列,每次分配一个文件窗口控制块,系统把队列首部的文件窗口控制块分配给存储域,并把分配的文件控制窗口块从队列首部删除;每次释放一个文件窗口控制块时,系统把释放的文件窗口控制块插入队列首部。

存储域控制块表

    在系统中设置存储域的目的是为了实施对存储资源的管理。通过为存储域分配和回收存储资源,系统防止某些存储域占用过多的资源。存储资源包括:内存打开文件窗口和页框。
    在每个存储体中设置一个存储域控制块表,存储域控制块表的结构如图4-7所示,表中每一项对应一个存储域,其中的信息包括:允许打开的最大文件窗口数、当前打开的文件窗口数、允许使用的最大页框数、当前使用的页框数、使用了多少页框数后启动写操作把数据反写回文件、当前多少个页框在执行读操作、当前多少个页框在执行写操作、当前打开文件窗口队列的首指针、当前使用的页框队列的首指针、存储域Capability的校验信息。
    一个存储域所有的打开文件窗口控制块链成一个双向的环形队列:打开文件窗口队列,并把队首指针和存储域当前打开的文件窗口数存放在存储域控制块表的表项中,通过比较允许存储域打开的文件窗口数和当前该存储域打开的文件窗口数,系统可以判断是否还能够为该存储域打开文件窗口,防止为某一个或某几个存储域打开过多的文件窗口;通过存储域打开文件窗口队列的首指针,系统可以查找到存储域打开所有文件窗口的文件窗口控制块。
    在LFYOS中,内存的作用是缓冲文件中的数据,一个页框存放着外存上文件中的一段数据。每个文件使用的所有页框的控制块,也链成一个环形队列:文件页框队列,并把队首指针存放在文件控制块中。根据文件页框队列,系统可以找到为文件分配的所有页框。
    一个存储域使用的所有处于未修改状态和已修改状态的页框也链成一个环形队列:页框缓冲队列,并把队首指针存储在存储域控制块表中。系统根据线程对页框的访问,按LRU算法维护页框缓冲队列。每次向队列中插入一个页框,系统把该页框插入在链首;每次需要从队列中淘汰页框,系统选择淘汰队尾的页框;通过把页框从队列中删除后插入到队首,系统实现了维护页框队列的LRU算法。

[目录]


页框状态的变迁

    在LFYOS中,在任何一个时刻,每个页框处于图4-8所示的五个状态之一,并按图4-8 所示的页框状态变迁图改变其状态。
    一个被链入在空闲页框队列中的页框处于空闲态,一个页框处于空闲态意味着在该页框中没有存放文件数据,也不存在地址影射把虚拟地址影射到该页框。
    当线程访问文件中的数据时,执行地址影射,如果文件中的数据还没有读入到内存,地址影射失败,引起存储访问失效异常,执行异常处理程序,由操作系统为该文件分配一个页框,把该页框从空闲页框队列中删除,插入文件页框队列,调用文件系统执行读文件操作,把文件数据从外存读入内存,此时页框处于正在读(reading)状态。当页框处于正在读(reading)状态时,表示文件系统正在读入文件数据,有些数据已经读入了内存,有些数据还存在于外存中,该页框暂时不能访问,也就是说,当页框处于正在读(reading)状态时,页框中的数据是不确定的,需要访问该页框的线程需要暂时睡眠,等到读操作完毕后再被唤醒。
    文件系统执行读文件操作,把文件数据读入内存以后,页框退出正在读状态,进入未修改状态(Not_modified)。把页框插入到页框缓冲队列中。当页框处于未修改状态时,页框中的数据和外存文件中的数据一致,线程可以访问该页框中的数据,当系统需要淘汰该页框时,不需要把页框中的数据写入外存的文件中。
    如果页框是可写的,随着线程对页框的访问,线程将对页框中的数据执行写操作,页框退出未修改状态,进入已修改状态,表示此时页框中数据和外存文件中的数据不一致,淘汰该页框时需要把该页框中的数据反写回文件中。
    随着外存文件中的数据被大量读入内存,存储域将用尽页框,使得存储域没有足够的页框存放文件中的数据,此时系统需要淘汰一部分页框。系统按LRU算法选择需要淘汰的页框,与此相关的数据结构是页框缓冲队列。每次系统访问一个页框,系统都要把该页框从页框缓冲队列中删除,再把它插入到页框缓冲队列的队首。随着系统的运行,经常被访问的页框将位于队列的首部,而不经常被访问的页框将位于队列的尾部。系统每次选择淘汰队列尾部的页框,从而实现维护页框队列的LRU算法。
    当系统需要淘汰某一页框时,如果页框处于未修改(Not_modified)状态,把该页框从打开文件窗口队列和页框缓冲队列中删除,插入空闲页框队列,并把状态由未修改(Not_modified)状态改写为空闲(Free)状态;如果页框处于已修改(Modified)状态,把状态由已修改(Modified)状态改写为正在写(Writing)状态,把页框从页框缓冲队列中删除,调用文件系统执行写操作,读写完成后把状态由正在写(Writing)状态改写为未修改(Not_modified)状态,并把该页框插入到页框缓冲队列中。
    当页框进入正在读(Reading)状态或正在写(Writing)状态时,从页框缓冲队列中删除;当页框进入未修改(Not_modified)状态时,插入到页框缓冲队列中。


[目录]


页框散列队列

    我们提出的LFYOS面向64位处理机,64位处理机中的地址影射机制大多采用逆向页表和软件TLB。指令执行时,绝大多数的地址影射由TLB实现,当TLB影射失效时,引起TLB影射失效异常,转异常处理程序,异常处理程序查询页表,并根据查询页表的结果填充TLB中的信息(虽然INTEL处理机中的地址映射机制没有采用逆向页表和软件TLB,在我们当前的实现中,仍然把存储管理器设计成面向逆向页表和软件TLB,而把整个TEL页表看成是一个巨大的TLB)。
    我们实现的软件逆向页表组织成如图4-9 所示的链式散列结构,相同散列函数值的页框链成一个双向的环链,并把链首指针存放在散列数组中。查询页表时,首先根据虚拟地址计算出散列函数值,根据函数值确定在散列数组中对应的数据项,找到环形散列链对应的链首,从链首开始,顺序搜索直至找到对应的页框或回到链首为止。
    如果在环形散列链中找到了对应的页框,系统首先根据该页框的信息填充软件TLB中的信息,然后,在页框缓冲队列中,把该页框移到页框缓冲队列的队首(首先从队列中删除,在把它插入队首),从而实现对页框缓冲队列管理的LRU算法。
    如果在环形散列链中没有找到了对应的页框,表示虚拟地址对应的文件数据暂时存在于外存,需要把它从外存调入内存,为此系统首先根据当前文件对应的存储域,比较存储域的允许使用的最大页框数和当前使用的页框数,确定该存储域是否允许申请空闲的页框。
    如果存储域当前使用的页框数小于允许使用的最大页框数,表示系统允许该存储域申请空闲的页框,系统从空闲页框队列中取出一个空闲页框,把它插入到页框文件队列和页框散列队列中,设置该页框的状态为正在读状态(Reading),调用文件系统执行读文件操作。访问该页框的线程睡眠。
如果此时其它的线程访问该页框,系统使这些线程睡眠,等待读操作完成后唤醒。
    文件系统执行完毕文件读操作以后,通过系统功能调用通知操作系统,操作系统把页框的状态由正在读状态改写为未修改状态(Not_modified),把页框插入到页框缓冲队列,唤醒睡眠的线程。
    随着线程对文件的访问,系统修改页框在页框缓冲队列中的位置,把经常访问的页框放在队列的首部,不经常访问的页框放在队列的尾部;线程也可能对文件中的数据执行写操作,这将引起页框的状态由未修改状态(Not_modified)进入已修改状态(modified),表示如果淘汰该页框,页框中的数据需要反写回文件中。
    如果申请空闲页框时,存储域当前使用的页框数大于等于允许使用的最大页框数,表示该存储域已经使用了太多的空闲页框,需要执行淘汰算法,把一部分页框中的信息反写回文件中。
    系统按LRU算法选择被淘汰的页框,每次总是选择淘汰页框缓冲队列尾部的页框,也就是队列首部的前一个页框(因为页框缓冲队列是环形队列)。根据需要淘汰的页框的状态不同,相应的淘汰方式也不同。
    如果需要淘汰的页框的状态为未修改状态(Not_modified),表示该页框中的数据和外存文件中的数据一致,系统把该页框从页框散列队列、页框缓冲队列和页框文件队列中删除,状态修改为空闲态(Free),把该页框送入空闲页框队列,系统成功回收页框。
    如果需要淘汰的页框的状态为已修改状态(Modified),表示该页框中的数据和外存文件中的数据不一致,系统需要把该页框中的数据反写回文件中。系统把该文件的状态由已修改状态(Modified)改变为正在写状态(Writing),把该页框从页框缓冲队列中删除,启动文件系统执行写文件操作。
    文件系统执行完写操作后,页框由正在写状态(Writing)改变为未修改状态(Not_modified),表示该页框中的数据和外存文件中的数据一致,把该页框插入到页框缓冲队列中。
    处于页框缓冲队列的页框仅仅可能处于未修改状态(Not_modified)和已修改状态(Modified),不可能处于空闲态(Free)、正在读状态(Reading)或正在写(Writing)状态。


[目录]


存储管理的实现

打开和关闭文件窗口

    执行打开文件窗口调用时,首先比较允许该存储域打开的最大文件窗口数和当前该存储域打开的文件窗口数,如果存储域已经打开了允许打开的所有文件窗口,直接返回出错;否则从空闲文件窗口队列中移出一个文件窗口控制块,插入到存储域的文件窗口队列中,对存储域当前打开的文件窗口数执行加一操作,设置文件窗口控制块中的各个域(文件服务器的标识,对应的外存上文件的标识,访问文件的权限,文件窗口的大小和在外存文件中的位置,访问文件的Capability校验和访问文件窗口的Capability校验,文件窗口控制块所属的存储域)。文件页框队列首指针设置为空。
执行关闭文件窗口调用时,首先判断当前使用的页框数是否为零,如果为零把文件窗口控制块从存储域的文件窗口队列中删除,插入到空闲文件窗口队列中,对存储域当前打开的文件窗口数执行减一操作。
    如果大于零,首先对文件窗口执行Flush操作,把内存中已经修改的数据写回到文件中,然后执行从文件页框队列的链首开始,重复执行以下操作:
    ·如果页框的状态为正在读或如果页框的状态为正在写,睡眠等待读写完成。唤醒后返回重新执行关闭文件操作。
    ·如果页框的状态为未修改,把页框从地址映射部件中删除,把页框从文件页框队列和页框缓冲队列中删除,插入到空闲页框队列中,对存储域的当前使用的页框数执行减一操作。
    ·如果页框的状态为已修改,重新对文件窗口执行Flush操作,返回重新执行文件关闭操作。
    在LFYOS中,执行打开文件窗口操作,需要拥有存储域Capability的校验或者拥有系统Capability的校验信息;执行关闭文件窗口操作,需要拥有访问文件窗口的Capability校验或者拥有系统Capability的校验信息。
    把文件数据反写回文件Flush和访问文件测试Touch
    执行Flush调用时,首先从文件窗口控制块取出文件页框队列的首指针,然后按从队列首部到队列尾部顺序,检查每个页框的状态,对于处于已修改状态的页框,把页框控制块从页框缓冲队列删除,设置其状态为正在写状态,调用文件服务器执行写文件操作。
    执行访问文件测试Touch调用时,首先查询页表(和计算机系统的体系结构相关的,不同的地址映射机制采用不同的查询方法),如果对应的页表项在页表中存在,说明该页已经从文件服务器中读入内存,根据页表项中的信息中的信息,可以确定对应的页框控制块,把页框控制块移到页框缓冲队列的队首,返回访问文件测试Touch调用的各项信息。
    如果对应的页表项在页表中不存在,那么需要从文件服务器中读入文件数据。首先,比较存储域中的两个域:允许使用的最大页框数和当前使用的页框数,判断是否允许该存储域继续使用空闲页框,如果没有足够的空闲页框,执行页框淘汰算法,把内存中的文件数据反写回文件中,释放占用的页框。页框淘汰算法执行完毕后存储域也就拥有了足够的空闲页框。
    如果存在足够的空闲页框,那么从空闲页框队列的队首删除一个页框控制块,把它插入到文件页框队列,但并不插入页框缓冲队列,初始化页框控制块,状态设置为正在读,通过线程迁移调用启动文件服务器执行读文件操作。读文件操作完成后,返回访问文件测试Touch调用的各项信息。

页框淘汰算法重复执行以下操作:

    根据页框缓冲队列尾部的页框控制块的状态,选择执行:
    ·如果为未修改状态:把该页框控制块从文件页框队列和页框缓冲队列删除,插入到空闲页框队列中,同时修改页表中该页框控制块对应的信息,对存储域控制块中当前使用的页框数执行减一操作。
    ·如果为已修改状态:把页框控制块页框缓冲队列删除,设置其状态为正在写状态,调用文件服务器执行写文件操作。
    ·其它状态出错。
    页框淘汰算法重复执行,直到以下条件中成立为止:存储域控制块中的当前多少个页框在执行写操作大于等于最多同时写多少个页框,或者当前使用的页框数小于使用了多少页框数后,启动写操作把数据反写回文件。
    执行把文件数据反写回文件Flush调用和访问文件测试Touch调用,需要拥有访问文件窗口的Capability校验或者拥有系统Capability的校验信息。
    设置文件数据已经被修改
    在LFYOS中,文件数据读入页框以后页框处于未修改状态,表示淘汰该页框时不需要写回该页框中的数据,如果线程修改了页框中的数据,操作系统的内核将使线程迁移至内存管理器,调用内存管理器中的设置文件数据已经被修改功能,该功能把页框的状态修改为已修改状态,因此当执行页框淘汰时,将把该页的内存写回文件中。
    存储管理器执行该功能时,首先检查参数,根据调用参数调用search_physical_block()函数确定需要设置修改的页框,把该页框的状态改为已修改状态。

分配和查询存储资源

    在LFYOS中,存储资源包括文件窗口和页框。执行分配存储资源调用时,设置存储域控制块中的允许该存储域打开的最大文件窗口数和允许该存储域使用的最大页框数;执行查询存储资源调用时,返回允许该存储域打开的最大文件窗口数、当前该存储域打开的文件窗口数、允许该存储域使用的最大页框数、当前该存储域使用的页框数。
    在LFYOS中,只有拥有系统Capability的校验,才能为存储域分配资源;只要拥有存储域Capability的校验或者拥有系统Capability的校验信息,即可查询存储域的存储资源。

存储体的初始化

    调用该功能实现存储体的初始化,初始化内存管理器中的各个数据结构。


[目录]


编程手册

[目录]


LFYOS中应用程序编程模型

    和传统操作系统相比,LFYOS具有不同的体系结构,因此也就具有不同的编程模型,其和传统操作系统最大的不同就是:LFYOS实现了单一数据存储模型,实现了数据存储、数据计算和资源管理的分离。

[目录]


单一数据存储模型

    在LFYOS中,所有的数据都存在于文件中,线程就通过虚拟地址空间直接访问文件数据,内存的作用仅仅实现对文件数据的缓冲。当应用程序访问文件数据时,如果文件数据在内存中不存在,线程将产生一个异常(存储访问失效异常),异常处理程序调用内存管理器,内存管理器分配页框,再迁移至文件系统进程或者调用驱动程序执行文件数据的读写,当线程从文件系统或者驱动程序返回内存管理器后,内存管理器建立地址映射,因此当从内存管理器返回后,线程就可以通过虚拟地址空间直接访问文件数据了。

1.虚拟地址空间和文件窗口的对应关系
    在我们当前的实现中,在4G的虚拟地址空间(线性地址空间)中,0-3G分别对应线程的六个已经打开的文件窗口,高端的一个G由操作系统使用。如果线程运行于核心态(0态),线程也可以访问高端的数据;如果线程运行于用户态(3态),线程仅仅可以访问高端的操作系统代码(读取或执行),不能访问操作系统数据。
    LDT没有使用,在GDT中,仅仅包含20项内容。描述符0未用,描述符0x08指向任务的tss,描述符0x10、0x18直接映射到4G的线性地址空间,只能在核心态下使用,描述符0x10用于读取和执行,描述符0x18用于读取和修改。
    描述符0x23、0x2b及其以下的描述符由运行于用户态的应用程序使用,描述符0x23映射区域从线性地址0至操作系统代码的终止,因此通过描述符0x23,应用程序可以读取和执行操作系统内核代码,但是不能修改操作系统内核代码,也不能访问操作系统数据。描述符0x2b映射区域从线性地址0开始,长度为3G+8K,低端的3G对应六个文件窗口,每个文件最大长度窗口为512M,3G-3G+4K的页面用于向操作系统内核传递参数。当线程调用内核提供的系统功能调用时,如果需要传递的参数很多,无法全部放在寄存器,则把其它的参数放在3G-3G+4K的页面中。3G+4K-3G+8K的页面由文件系统使用,当内存管理器通过线程迁移调用请求文件系统执行文件读写时,文件系统不需要知道数据的具体存放位置,只需从区间3G+4K-3G+8K读或向区间3G+4K-3G+8K写即可。
    描述符0x033、0x03b,描述符0x043、0x04b,描述符0x053、0x05b,描述符0x063、0x06b,描述符0x073、0x07b,描述符0x083、0x08b分别对应六个文件窗口,描述符0x0X3用于读取和执行,描述符0x0Xb用于读取和修改。
描述符0x093、描述符0x09b分别映射至线性地址3G-3G+8K的两个页面。

2.和文件有关的几个概念
    @存储体:在虚地址空间基于文件操作系统中,把物理地址空间划分为几个存储体,每个存储体由一个内存管理器负责管理和维护(内存管理器是一个在核心态下运行的程序),应用程序打开文件窗口时需要确定在哪个存储体中打开文件窗口,当发生存储访问失效异常时,操作系统系统内核利用存储体信息确定线程迁移到哪个进程。
    @系统文件窗口:内存管理器管理和维护的文件窗口。当打开文件时,内存管理器建立系统文件窗口。
    @线程文件窗口:当线程运行时,对线程而言,GDT中各个段描述符对应的文件窗口
    @进程文件窗口:当线程运行时,对进程而言,GDT中各个段描述符对应的文件窗口。当线程访问地址空间中的数据时,如果当前进程设定了进程文件窗口,访问进程文件窗口中的数据,否则访问线程文件窗口中的数据。

3.和文件窗口有关的几个系统功能调用
    @设置进程文件窗口的capability校验(21号功能):该系统功能调用用来建立进程文件窗口和系统文件窗口的对应关系,同时设置进程文件窗口的capability校验。
    @设置线程文件窗口的capability校验(22号功能):该系统功能调用用来建立线程文件窗口和系统文件窗口的对应关系,同时设置线程文件窗口的capability校验。
    @检查线程是否可以访问某个文件窗口:只有进程文件窗口的capability校验和系统文件窗口的capability校验相同,或者线程文件窗口的capability校验和系统文件窗口的capability校验相同,应用程序才能访问相应的系统文件窗口。

4.进程文件窗口和系统文件窗口的对应关系,线程文件窗口和系统文件窗口的对应关系:当应用程序在系统中运行时,如果访问虚拟地址空间对应的文件窗口,系统首先判断相应的进程文件窗口和系统文件窗口的对应关系,判断二者的capability是否相同,如果相同则认为应用程序访问进程文件窗口对应的系统文件窗口,否则判断相应的线程文件窗口和系统文件窗口的对应关系,判断二者的capability是否相同,如果相同则认为应用程序访问线程文件窗口对应的系统文件窗口,否则说明应用程序不能访问虚拟地址空间对应的文件窗口。

[目录]


实现了数据存储、数据计算和资源管理的分离

    在LFYOS中,数据存储由文件抽象实现,数据计算由线程抽象实现,资源管理由进程抽象实现,三者在系统中是分离的,表现在以下三个方面:

1.线程和文件之间不存在任何确定的对应关系:数据存储在文件中,只要不影响安全性,任何文件可以被任何线程访问,任何线程也都可以计算任何文件中的数据。

2.线程和进程之间也不存在确定的对应关系:线程可以在不同的进程之间迁移,在不同时刻线程以不同进程的身份申请和使用资源。由于所有应用程序在同一个文件空间中运行,线程迁移时,仅仅需要执行CPU现场的迁移,不需要执行程序代码、数据和堆栈等的迁移。

3.文件和进程之间也不存在确定的对应关系:文件属于文件服务器,是文件服务器维护的一个对象,进程是系统进行资源管理的对象,是操作系统内核实施资源管理的抽象,是系统资源的持有者。

[目录]


应用程序之间的依赖关系

    在LFYOS中,当应用程序运行时,如果文件数据在物理内存中不存在,线程请求文件服务器执行读写文件操作,执行完毕后线程继续运行。一个应用程序的运行,需要其它的应用程序(文件服务器)在后台的支持,而该文件服务器又可能需要其它的文件服务器在后台的支持。如果文件服务器无法运行,线程在当前应用程序中就无法运行,因此所谓虚拟地址空间基于文件,也可以说就是一个应用程序执行的程序和访问的数据,是由另一个应用程序为其维护的,一个应用程序的运行,需要依赖于其它应用程序的运行,因此在各个应用程序之间必然存在一个相互之间的依赖关系,并最终所有应用程序依赖于传统意义下的文件系统。
    在LFYOS中,应用程序之间存在相互依赖关系,那么所有应用程序最终依赖的是哪个应用程序?该应用程序是如何运行的?它是否也依赖于某个应用程序呢?
    就象在UNIX中必须存在0#进程一样,在LFYOS中,必须至少存在一个文件服务器直接在物理内存上运行而不依赖其它任何服务器。常驻内存的文件服务器可以是一个具体的文件服务器,也可以是虚拟文件服务器。
    如果常驻内存的文件服务器是一个具体的文件服务器,例如管理硬盘、软盘或者光盘等的文件服务器,那么所有的应用程序最终都将依赖于这个常驻内存的文件服务器,如果常驻内存的文件服务器消亡,就象传统操作系统中对换设备损坏一样,整个系统也将不能运行,因此要求系统至少存在一个具体的外部存储设备,同时常驻这个设备的文件服务器。
    如果常驻内存的服务器是一个虚拟文件服务器,例如通信服务器,那么系统可能不需要任何外部存储设备,而是利用通信服务器在远程的文件服务器上存取数据,在这种情况下,要求通信服务器直接常驻内存而不依赖于任何其它的应用程序。

    总之,在系统内存中至少需要常驻以下三个部件,其它的内容可以在系统运行时动态地安装和卸载,可以在系统运行时动态地换入换出:
1.内核
2.内存管理器
3.至少一个具体的文件服务器或者一个通信服务器

[目录]


内核提供的系统功能调用

[目录]


参数传递

    线程请求内核执行系统功能调用时,通过寄存器传递参数,如果需要传递的参数很多,无法全部放在寄存器中,其它参数存放线性地址空间的3G-3G+4K的页面。在以后的实现中,可能把参数区分配在其它地址,为了实现兼容,可以通过以下三个宏取得参数区地址:
    get_kernel_parameter() 定义为指向联合union system_call_parameter的指针,用于向内核传递参数。其值为3G。
    get_memory_parameter()定义为指向联合union memory_call_parameter的指针,用于向内存管理器传递参数。其值为3G。
    get_file_system_parameter()定义为指向结构struct file_system_call_parameter的指针,用于向文件系统进程传递参数。其值为3G。
    get_thread_physical_block()定义为指向字符指针,当内存管理器请求文件系统读写文件时,文件系统从此处读取数据,或向此处存放数据。其值为3G+4K。
    为了在C语言中调用内核提供系统功能调用,我们编制了一段用内嵌汇编实现的C函数,该程序接收C语言传送的一个结构指针(struct thread_environment *),把该指针指向的数据装入寄存器中,然后调用内核,并把返回后各个寄存器中的值保存到指针指向的数据结构中。该函数是一个静态的inline函数,其原型为:

void call_kernel(struct thread_environment *env);

    其中,数据结构struct thread_environment 的定义为:

struct thread_environment{
        int system_call,system_call_arg1;                    /*ax,bx*/
        int system_call_arg2,system_call_arg3;                /*cx,dx*/
        int system_call_arg4,system_call_arg5;                /*si,di*/
        int system_call_arg6,system_call_arg7;                /*bp,r7*/
        run_point point;                                                /*ip,cs,flag,sp,ss */
        int (*function)(int thread_id,struct thread *t,
                struct return_stack *rt,struct thread_environment *env,
                union kernel_call_parameter *parameter);
        union kernel_call_parameter parameter;
};
#define         ax        system_call
#define         bx        system_call_arg1
#define         cx        system_call_arg2
#define         dx        system_call_arg3
#define         si        system_call_arg4
#define         di        system_call_arg5
#define         bp        system_call_arg6
#define         r7        system_call_arg7
typedef struct thread_environment REG;

    函数void call_kernel(struct thread_environment *env)的定义为(完全用内嵌汇编实现):

extern void call_kernel(struct thread_environment *env);


[目录]


系统功能调用的例子

1.        仅仅通过寄存器传递参数:
#include”../include/os.h”
{
        REG r;
r.ax=0;
r.bx=2;
call_kernel(&r);
/*调用内核的0号功能,执行线程迁移,线程迁移至2号进程) */
}


2.        通过寄存器传递参数,也通过内核参数区传递参数的例子
#include”../include/os.h”
{
REG r;
union system_call_parameter *par;
par=get_kernel_parameter();
r.ax=22;
r.bx=0;
r.cx=0;
r.dx=0;
r.si=512;
r.di=READ_WRITE;
RESET_CAPABILITY(par->capability.capability_1); /*设置参数区中的参数*/
call_kernel(&r);


[目录]


内核中系统功能调用的格式

[目录]


线程迁移和线程返回

0号功能

    1.功能:实现线程从一个进程迁移到另一个进程,线程在目标进程中从进程的初始执行点开始运行。通过线程返回系统功能调用,线程可以返回原来的进程中。
    2.格式:ax.寄存器的值为零,bx寄存器的绝对值为进程ID。
如果当前的进程为管程,bx>0表示线程离开当前进程进入目标进程后,允许其它线程进入当前进程;bx <0表示即使线程迁移离开当前进程进入目标进程,也不允许其它线程进入当前进程,因此当线程从目标进程返回后,可以保证数据的一致性;bx=0为非法。
    3.返回值:如果ax.寄存器的值小于零,表示失败;否则,ax.寄存器的值为同时返回了几次,因此如果大于零也表示失败;bx.寄存器的值为TRUE表示正常返回,为FALSE表示异常返回(例如,线程在目标进程中运行时发生了不可恢复的异常而返回)。
    4.例:

#include”../include/os.h”
{
    REG r;
    r.ax=0;
    r.bx=2;
        /*迁移至2号进程,从其初始执行点开始运行线程离开当前进程进入目标进程后,允许其它线程进入当前进程。*/
    call_kernel(&r);
}

1号功能
    1.功能:实现线程从一个进程迁移到另一个进程,线程在目标进程中从进程的初始执行点开始运行,和0号功能不同的是:线程不能再次返回到原来的进程中。
    2.格式:ax.寄存器的值为1,bx寄存器的绝对值为进程ID。
如果当前的进程为管程,bx>0表示线程离开当前进程进入目标进程后,允许其它线程进入当前进程;bx <0表示即使线程迁移离开当前进程进入目标进程,也不允许其它线程进入当前进程。只有对当前进程的管程信号量执行V操作,才能允许其它线程进入当前进程;bx=0为非法。
    3.返回值:如果执行成功,线程不可能返回,返回则表示失败。
    4.例:

#include”../include/os.h”
{
    REG r;
    r.ax=1;
    r.bx=(-2);
        /*迁移至2号进程,从其初始执行点开始运行线程离开当前进程进入目标进程后,不允许其它线程进入当前进程。*/
    call_kernel(&r);
}

2号功能
    1.功能:线程迁移(修改线程可以访问的物理页框)。
    2.格式:ax.寄存器的值为2
        cx寄存器存放存储体ID,dx寄存器存放参数页框ID,si寄存器存放线程可以直接访问的物理页框ID,其它参数和格式同0号功能。
    3.返回值:同0号功能

3号功能
    1.功能:实现线程从当前的进程返回到原来的进程,如果线程已经没有进程可以返回,则线程终止退出。
    2.格式:ax.寄存器的值为3,bx寄存器的值为TRUE表示正常返回,否则为异常返回。如果线程由于异常进入当前的进程,异常返回表示引起线程运行异常的原因没有解决,因此内核将使线程再次返回,直至线程可以正常运行为止。这就是为什么执行一次线程返回调用会引起多次线程返回的原因,而0号功能的返回值当其大于等于零时即为线程返回的次数。
    3.返回值:不可能返回
    4.例:

#include”../include/os.h”
{
    REG r;
    r.ax=3;
    r.bx=TRUE;
    call_kernel(&r);
}

    在传统操作系统中,线程进入内核时,将从一个固定的地址开始执行,与此类似,在虚地址空间基于文件操作系统中,当线程从一个进程进入另一个进程时,线程从目标进程的初始执行点开始执行。通过设置进程的初始执行点,可以指定线程在进程中开始执行的地址。
当线程在目标进程中开始执行时,ax寄存器存放当前线程返回栈的栈顶指针,通过该参数,线程可以判断是否可以再次执行线程迁移,迁移到其它的进程。
    bx寄存器的绝对值存放着当前线程的ID,也就是当前线程的标志信号量ID,该信号量和当前的进程具有相同的capability校验。如果bx>0,表示线程通过调用线程迁移系统功能调用进入当前进程,如果bx<0,表示线程并没有调用线程迁移系统功能调用,但是线程执行时产生了异常,内核中的异常处理程序使线程迁移到当前的进程,请求进程执行异常处理。
    如果当前的进程成功解决了异常(例如,内存管理器成功把页面调入内存从而解决了存储访问失效异常),执行线程返回时,bx中的值为TRUE,线程返回到原来的进程中继续运行;如果当前的进程无法成功解决了异常,表示线程在原来的进程中已无法运行,执行线程返回时,bx中的值为FALSE,內核将执行多次线程返回,直到线程能够正确执行为止。
    通过线程迁移和线程返回处理异常,即使线程运行时出现不能解决的异常,仅仅使线程返回到原来的进程中,不会使线程或进程完全退出,解决了UNIX系统中的core dump问题。

[目录]


对信号量执行P、V操作

    在虚地址空间基于文件操作系统中,利用线程迁移实现了线程和进程的分离,通过线程迁移实现异常处理。线程在进程中可以使用线程的标志信号量,通过对其执行P、V操作,实现线程之间的同步互斥。

4号功能
    1.功能:对信号量执行P、V操作,实现线程之间的同步互斥。
    2.格式:ax.寄存器的值为4
        bx中为执行V操作的信号量ID的绝对值,如果bx=0,不执行V操作;如果bx<0,则执行V操作以前对该信号量复位。cx中为执行V操作时信号量的增加值,如果cx中的值大于等于零,把信号增加相应的数值,如果必要唤醒在信号量睡眠的线程;如果cx中的值小于零,则把在信号量睡眠的线程全部唤醒。
        dx中为执行P操作的信号量ID的绝对值,如果dx=0,不执行P操作;如果dx<0,则执行P操作以前对该信号量复位。si寄存器中的值指定当信号量的值小于0时线程是否睡眠,si寄存器中的值为TRUE,则睡眠,如果为FALSE,不睡眠,di寄存器中的值指定当线程睡眠时,是否允许其它线程进入进程,如果di寄存器中的值为TRUE,允许其它线程进入进程;如果di寄存器中的值为FALSE,不允许其它线程进入进程。
        在参数区中,get_kernel_parameter()->capability.capability_1存放V操作信号量的capability校验,get_kernel_parameter()->capability.capability_2放P作信号量的capability校验。
    3.返回值:bx中存放V操作的执行结果,dx中存放P操作的执行结果,大于等于表示成功,小于零表示失败。
    4.例1:对信号量执行V操作

#include”../include/os.h”
{
    REG r;
    union system_call_parameter *par;
    par= get_kernel_parameter();                /*取参数区地址*/
    COPY_CAPABILITY((*(memory_body->capability)),(par->capability.capability_1));        /*设置信号量的capability校验*/
    r.system_call=4;
    r.system_call_arg1=semaphore;                /*信号量ID*/
    r.system_call_arg2=1;                        /*增加值为1*/
    r.system_call_arg3=0;                        /*不执行P操作*/
    call_kernel(&r);
}

    5.例2:对信号量执行P操作

#include”../include/os.h”
{
    REG r;
    union system_call_parameter *par;
    par= get_kernel_parameter();                /*取参数区地址*/
    COPY_CAPABILITY((*(memory_body->capability)),(par->capability.capability_2));        /*设置信号量的capability校验*/
    r.system_call=4;
    r.system_call_arg1=0;                        /*不执行V操作*/
    r.system_call_arg3= semaphore;;                /*信号量ID*/
    r.system_call_arg4=TRUE;                        /*如果需要,线程睡眠*/
    r.system_call_arg5=TRUE;                        /*允许其它线程进入进程*/
    call_kernel(&r);
}

6.例3:对信号量执行V操作和P操作
#include”../include/os.h”
{
    REG r;
    union system_call_parameter *par;

    par= get_kernel_parameter();                /*取参数区地址*/
    COPY_CAPABILITY((*(memory_body->capability)),(par->capability.capability_1));        /*设置V操作信号量的capability校验*/
    COPY_CAPABILITY((*(memory_body->capability)),(par->capability.capability_2));        /*设置P操作信号量的capability校验*/
    r.system_call=4;
    r.system_call_arg1=v_semaphore;                /*V操作信号量ID*/
    r.system_call_arg2=1;                        /*增加值为1*/
    r.system_call_arg3= p_semaphore;                /*P操作信号量ID*/
    r.system_call_arg4=TRUE;                        /*如果需要,线程睡眠*/
    r.system_call_arg5=TRUE;                        /*允许其它线程进入进程*/
    call_kernel(&r);
}


[目录]


信号量定时

5号功能
    在虚地址空间基于文件操作系统中,定时功能是通过信号量实现。应用程序可以指定一个信号量的定时时刻以及定时间隔。当信号量的定时时刻到来时,操作系统内核把定时时刻向后调整一个定时间隔,同时对信号量执行V操作,因此如果有线程在信号量上睡眠,则将其唤醒,从而实现定时。
    1.功能:设定信号量的定时时刻,并对信号量执行P操作。
    2.格式:ax.寄存器的值为5
        bx.寄存器的值为信号量ID
        cx.寄存器的值指定对信号量执行P操作时,是否睡眠。TRUE则睡眠,FALSE不睡眠。
        dx.寄存器的值指定线程睡眠时,是否允许其它的线程进入进程。TRUE则允许,FALSE不允许。
        si.寄存器的值指定定时时间到时,执行V操作的增加值。如果小于零,把所有睡眠在信号量上的线程唤醒。
        参数区get_kernel_parameter()->set_semaphore_time.first_time中存放定时时刻。
        参数区get_kernel_parameter()->set_semaphore_time. step_time中存放定时间隔。
        参数区get_kernel_parameter()->set_semaphore_time.semaphore_capability存放信号量的capability校验。
    3.返回值:ax.寄存器的值大于等于零表示成功,小于零表示失败。
    4.例1:信号量定时

#include”../include/os.h”
{
        union system_call_parameter *par=get_kernel_parameter();
        REG r;
        r.system_call=5;
        r.system_call_arg1=sem_id;
        r.system_call_arg2=TRUE;
        r.system_call_arg3=TRUE;
        r.system_call_arg4=(-1);
        get_current_time(&(par->set_semaphore_time.first_time));
        TIME_INC(1,(par->set_semaphore_time.first_time));
        SET_MINIMAL_STEP(par->set_semaphore_time.step_time);
        RESET_CAPABILITY(par->set_semaphore_time.semaphore_capability);
        call_kernel(&r);
}


[目录]


创建线程

6号功能
    1.功能:创建线程。
    2.格式:ax.寄存器的值为6
        bx.寄存器的值为被创建的线程所属的进程
        cx.寄存器的值指定被创建的线程从何处开始执行
        dx.寄存器的值指定被创建的线程的堆栈指针设在何处
        在参数区中,get_kernel_parameter()->capability.capability_1存放被创建线程所属的进程的capability校验
    3.返回值:
        父线程:ax.寄存器的值大于等于零表示创建成功,其值为子线程的ID,同时bx.寄存器的值为0;如果ax.寄存器的值小于零,表示创建失败。
        子线程:ax.寄存器的值子线程的ID,bx.寄存器的值为1,并把堆栈指针设置到dx.寄存器指定的地址后,从cx.寄存器的值指定地址开始执行。
    4.例 创建线程

#include”../include/os.h”
{
    union system_call_parameter *par;
    REG r;

    par=get_kernel_parameter();
    RESET_CAPABILITY(par->capability.capability_1);
    r.ax=6;
    r.bx=1;
    r.cx=(int)test;                /* this is the entry point        where the new thread will execute */
    r.dx=DEFAULT_SP;        /*this is stack pointer for the new thread */
    call_kernel(&r);
}


[目录]


进程资源

10号功能
    1.功能:为进程分配资源。
    2.格式:ax.寄存器的值为10
        bx寄存器存放进程ID
        在参数区中,get_kernel_parameter()-> process_attribute.process存放进程的各项参数
        在参数区中,get_kernel_parameter()->process_attribute.capability存放系统的capability校验。只有拥有系统的capability校验,才能为进程分配资源。
    3.返回值:如果分配成功,ax.寄存器的值大于等于零,同时在参数区get_kernel_parameter()->process_attribute.process中存放分配以后进程的各项参数;如果分配失败,ax.寄存器的值小于零。
    进程的各项参数保存在一个数据结构

struct process{
    run_point start_point;                /*进程的初始执行点*/
    int (*driver)(struct file_system_call_parameter *par);/*进程对应的驱动程序*/
    int priority;                                /*进程的优先级*/
    int semaphore;                                /*进程的管程信号量*/
    int enter_thread_number,id;
                /*进入进程的线程数,进程的ID*/
    int max_thread_number,thread_number,thread_ring;
                /*允许进程创建的最多线程数,当前创建的线程数*/
                /* thread_ring;为内核使用的数据结构*/
    int max_semaphore_number,semaphore_number,semaphore_ring;
                /*允许进程申请的最多信号量数,当前申请的信号量数*/
                /* semaphore_ring;为内核使用的数据结构*/
    struct user_file_information file[USER_FILE_NUMBER];
                /*进程的文件信息*/
    struct capability capability;
                /*进程的capability校验信息*/
}

11号功能
    1.功能:查询进程的资源。
    2.格式:ax.寄存器的值为11
        bx寄存器存放进程ID
        在参数区中,get_kernel_parameter()->process_attribute.capability存放capability校验。只有拥有系统的capability校验,或者进程的capability校验,才能查询进程的资源。
    3.返回值:如果查询进程的资源成功,ax.寄存器的值大于等于零,同时在参数区get_kernel_parameter()-> process_attribute.process中存放进程的各项参数;如果分配失败,ax.寄存器的值小于零。
    4.例:查询进程的资源和分配进程的资源

#include”../include/os.h”
{
    REG r;
    union system_call_parameter *par;

    par=get_kernel_parameter();
    RESET_CAPABILITY(par->process_attribute.capability);
    RESET_CAPABILITY(par->process_attribute.process.capability);
    r.ax=11;
    r.bx=1;
    call_kernel(&r);
    par->process_attribute.process.max_thread_number=THREAD_NUMBER;
    par->process_attribute.process.max_semaphore_number=SEMAPHORE_NUMBER;
    RESET_CAPABILITY(par->process_attribute.capability);
    RESET_CAPABILITY(par->process_attribute.process.capability);
    par->process_attribute.process.start_point.ip=enter_file_system;
    par->process_attribute.process.start_point.cs=0x23;
    par->process_attribute.process.start_point.ds=0x2b;
    par->process_attribute.process.start_point.ss=0x2b;

    r.ax=10;
    r.bx=1;
    call_kernel(&r);
}


[目录]


申请和释放信号量

12号功能
    1.功能:申请信号量
    2.格式:ax.寄存器的值为12
        bx寄存器存放进程ID
        cx寄存器存放信号量初值
    在参数区中,get_kernel_parameter()->capability.capability_1存放进程的capability校验。只有拥有进程的capability校验,才能申请进程的信号量;get_kernel_parameter()->capability.capability_2存放信号量的capability校验。
    3.返回值:如果申请信号量成功,ax.寄存器的值为信号量ID,同时把信号量的capability校验设置为get_kernel_parameter()->capability.capability_2;如果申请信号量失败,ax.寄存器的值小于零。
    4.例:申请信号量

#include”../include/os.h”
{
    REG r;
    union system_call_parameter *par;
    par=get_kernel_parameter();
    RESET_CAPABILITY(par->capability.capability_1); /*进程capability校验*/
    RESET_CAPABILITY(par->capability.capability_2); /*信号量的capability校验*/
    r.ax=12;
    r.bx=2;        /*进程ID*/
    r.cx=1;        /*寄存器存放信号量初值*/
    call_kernel(&r);
}

13号功能
    1.功能:释放信号量
    2.格式:ax.寄存器的值为13
        bx寄存器存放信号量ID
        在参数区中,get_kernel_parameter()->capability.capability_1存放信号量的capability校验。
    3.返回值:如果释放信号量成功,ax.寄存器的值大于等于零;如果释放信号量失败,ax.寄存器的值小于零。

[目录]


线程属性

14号功能
    1.功能:设置线程属性
    2.格式:ax.寄存器的值为14
        bx寄存器存放线程ID,也就是线程对应的信号量的ID。
        cx寄存器存放强制线程返回的次数,如果该参数大于零,同时具有相应的capability校验,可以实现线程的强制返回。
        dx寄存器存放线程的优先级
        在参数区中,get_kernel_parameter()->thread_attribute.current_process_capability存放线程当前所属进程的capability校验。只有拥有线程当前所属进程的capability校验,才能设置线程属性。
    3.返回值:
    如果设置线程属性失败,ax.寄存器的值小于零
    如果设置线程属性成功,ax.寄存器的值大于等于零,表示执行了多少次强制线程返回,bx.寄存器的值返回设置线程属性后查询线程属性的结果,如果bx.寄存器的值小于零,表示查询线程属性失败;如果bx.寄存器的值大于等于零,表示查询线程属性成功,查询结果保存在参数区的下面几个域中:
a)get_kernel_parameter()->thread_attribute.priority:线程优先级
b)get_kernel_parameter()->thread_attribute.return_stack_top:线程返回栈栈顶指针
c)get_kernel_parameter()->thread_attribute.process:线程所属进程
d)get_kernel_parameter()->thread_attribute.current_process:线程当前所属进程
get_kernel_parameter()->thread_attribute. exception_item.flag:存放线程是正常迁移到当前进程还是异常迁移到当前进程。

15号功能
    1.功能:查询线程属性
    2.格式:ax.寄存器的值为15
        bx寄存器存放线程ID
        在参数区中,get_kernel_parameter()->thread_attribute.current_process_capability存放线程当前所属进程的capability校验。只有拥有线程当前所属进程的capability校验,才能查询线程属性。
    3.返回值:
    如果bx寄存器存放线程ID大于零,表示查询指定线程的属性成功;如果查询线程属性失败,ax.寄存器的值小于零;如果查询线程属性成功,ax.寄存器的值大于等于零,同时各项属性参数保存在:
a)get_kernel_parameter()->thread_attribute.priority:线程优先级
b)get_kernel_parameter()->thread_attribute.return_stack_top:线程返回栈栈顶指针
c)get_kernel_parameter()->thread_attribute.process:线程所属进程
d)get_kernel_parameter()->thread_attribute.current_process:线程当前所属进程
e)get_kernel_parameter()->thread_attribute. exception_item.flag:存放线程是正常迁移到当前进程还是异常迁移到当前进程。
        如果bx寄存器存放线程ID小于零,表示查询当前运行线程的属性,
a)ax.寄存器的值返回线程ID,也就是说线程对应的信号量。
b)bx.寄存器的值返回线程优先级
c)cx.寄存器的值返回线程返回栈栈顶指针
d)dx.寄存器的值返回线程所属进程
e)si.寄存器的值返回线程当前所属进程
di.寄存器的值返回存放线程是正常迁移到当前进程还是异常迁移到当前进程

[目录]


查询存储体容量和地址

20号功能
    1.功能:查询存储体的容量和在物理内存的位置
    2.格式:ax.寄存器的值为20
        bx寄存器存放存储体ID
    3.返回值:
        如果bx寄存器指定的存储体ID存储体存在,则ax.寄存器的值为存储体的容量,而bx.寄存器的值为存储体在物理内存的地址。
        如果bx寄存器指定的存储体ID存储体不存在,则ax寄存器中的值小于零
    4. 例:申请信号量

#include”../include/os.h”
{
    REG r;
    r.ax=20;
    r.bx=0;                /*零号存储体*/
    call_kernel(&r);
    block_number=r.ax;
    block_base=r.bx;
}


[目录]


设置文件窗口capability校验

21号功能
    1.功能:设置进程文件窗口的capability校验
    2.格式:ax.寄存器的值为21
        bx寄存器存放进程的文件窗口ID
        cx寄存器存放进程的文件窗口map_length,也就是当发生地址映射失效异常时,同时建立地址映射的虚空间区域长度。
        dx寄存器存放文件窗口访问权限
        在参数区中,get_kernel_parameter()->capability.capability_1存放进程文件窗口的capability校验。
        si寄存器存放该进程文件窗口对应的系统文件在哪个存储体
        di寄存器存放该进程文件窗口对应的系统文件是存储体中的哪个系统文件窗口
    3.返回值:
        如果设置成功,则ax的返回值大于等于零
        如果设置失败,则ax的返回值小于零
    4.例:设置文件的进程capability校验

#include”../include/os.h”
{
    REG r;
    RESET_CAPABILITY(get_kernel_parameter()->capability.capability_1);
        /*设置文件校验信息*/
    r.ax=21;
    r.bx=2;        /*进程的文件窗口ID*/
    r.cx=512;        /*当发生地址映射失效异常时,同时建立地址映射的虚空间区域长度*/
    r.dx=READ_ONLY;/* dx寄存器存放文件窗口访问权限*/
    r.si=0;/*si寄存器存放该进程文件窗口对应的系统文件在哪个存储体*/
    r.di=0;/*di寄存器存放该进程文件窗口对应的系统文件是存储体中的哪个文件窗口*/
    call_kernel(&r);
}

22号功能
    1.功能:设置线程文件的capability校验
    2.格式:ax.寄存器的值为22
        bx寄存器存放线程文件窗口ID
        cx寄存器存放线程文件窗口map_length,也就是当发生地址映射失效异常时,同时建立地址映射的虚空间区域长度。
        dx寄存器存放线程文件窗口访问权限
        在参数区中,get_kernel_parameter()->capability.capability_1存放线程文件窗口的capability校验。
        si寄存器存放该进程文件对应的系统文件窗口在哪个存储体
        di寄存器存放该进程文件对应的系统文件窗口是存储体中的哪个系统文件窗口
    3.返回值:
        如果设置成功,则ax的返回值大于等于零
        如果设置失败,则ax的返回值小于零
    4.例:设置文件的进程capability校验

#include”../include/os.h”
{
    REG r;
    RESET_CAPABILITY(get_kernel_parameter()->capability.capability_1);
                ./*设置文件校验信息*/
    r.ax=22;
    r.bx=2;                /*线程文件ID*/
    r.cx=512;        /*当发生地址映射失效异常时,同时建立地址映射的虚空间区域长度。*/
    r.dx=READ_ONLY;        /* dx寄存器存放文件访问权限*/
    r.si=0;                 /*si寄存器存放该线程文件对应的系统文件在哪个存储体*/
    r.di=0;        /* di寄存器存放该线程文件对应的系统文件是存储体中的哪个文件*/
    call_kernel(&r);
}

23号功能
    1.功能:检查线程是否可以访问某个文件
    2.格式:ax.寄存器的值为23
        bx寄存器存放文件ID
    3.返回值:
        如果可以访问文件,则ax的返回值大于等于零,其值为该文件对应的系统文件是存储体中的哪个系统文件。
a)cx寄存器返回该文件对应的系统文件位于哪个存储体
b)dx寄存器返回该文件对应的系统文件是存储体中的哪个系统文件窗口
c)si寄存器返回当发生地址映射失效异常时,同时为多少个页面建立地址映射。
d)di寄存器返回文件访问权限
如果不可以访问文件,则ax的返回值小于零


[目录]


内存管理器提供的功能调用

    在虚地址空间基于文件操作系统中,由内存管理器负责内存的管理和分配,当应用程序运行时,如果线程访问的数据在内存不存在,操作系统内核中的异常处理程序将调用内存管理器,内存管理器分配页框,再从内存管理器迁移到文件系统执行文件数据的读写,当线程从文件系统返回时,数据已经存储在内存的页框中,内存管理器建立地址映射然后返回,当线程从内存管理器返回后,线程访问的数据已经在内存中,线程也就可以继续执行了。
    内存管理器通过存储域的概念实施存储资源的管理,每次应用程序打开文件窗口,都需要声明以哪个存储域的身份打开,每次应用程序请求分配页框读写数据,都需要声明以哪个存储域的身份请求分配。内存管理器通过存储域抽象实施对资源的控制,防止某些应用程序使用过多的存储资源。
[目录]


文件窗口

0号功能
    1.功能:打开文件窗口
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为0,也就是打开文件窗口的功能号。
    在参数区中,get_memory_parameter()->open_file_window.file_window_id存放文件窗口的ID,如果>=0,表示指定打开的文件窗口ID;如果<0,表示由内存管理器分配一个文件窗口ID。
    get_memory_parameter()->open_file_window.file_window.file存放文件窗口的各项参数,其数据结构为:
    struct file{
        struct{
            struct network_address network_node;
                                        /*文件系统的网络地址*/
            int server_processor,server_process,file_handler;
                                        /*文件系统所存在的处理机ID,文件系统的进程ID*/
                                        /*文件在文件系统中的文件ID */
        }file;
        struct{
            int processor,process;        /*文件在本地代理的处理机ID和进程ID*/
        }proxy;
        int memory_process,open_window_id;
                        /*文件窗口所属的存储域, 文件窗口在内核中的标识数*/
        int window_base_1,window_base_2,window_length,right;
                /*文件窗口在文件中的基地址, 长度和权限*/
        struct capability capability;
                        /*文件窗口的capability 校验*/
        int read_in_flag,swap_out_flag;
                        /*是否从外存读文件数据标志,是否换出标志*/
    };
    get_memory_parameter()->open_file_window. process_capability存放文件窗口所属存储域的capability校验。
    3.返回值:
        如果打开成功,则ax的返回值大于等于零,为文件窗口的ID。
        如果打开失败,则ax的返回值小于零。

4.例:打开文件窗口

#include"../include/os.h"
{
    REG r;
    union memory_call_parameter *par)
    struct file *f;
    par->open_file_window.file_window_id=fd;
        f=&(par->open_file_window.file_window);

        f->file.file.server_processor=0;
        f->file.file.server_process=2;
        f->file.file.file_handler=0;

        f->file.proxy.processor=0;
        f->file.proxy.process=((fd&0x01)==0)?2:2;

        f->file.open_window_id=fd;
        f->file.window_base_1=0;
        f->file.window_base_2=0;
        f->file.window_length=512*1024*1024;

        f->file.memory_process=0;
        f->file.right=READ_WRITE;

        RESET_CAPABILITY(f->file.capability);
        RESET_CAPABILITY(par->open_file_window.process_capability);

        f->file.read_in_flag=TRUE;
        f->file.swap_out_flag=TRUE;

    r.ax=0;
    r.bx=0;
    call_memory(&r);
}

1号功能
    1.功能:关闭文件窗口
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为1,也就是关闭文件窗口的功能号。
        在参数区中,get_memory_parameter()->close_file_window.file_window_id存放请求关闭的文件窗口ID。
        在参数区中,get_memory_parameter()->par->close_file_window.file_capability存放文件窗口capability校验。
    3.返回值:
        如果关闭成功,则ax的返回值大于等于零。
        如果关闭失败,则ax的返回值小于零。

[目录]


地址映射

2号功能
    1.功能:建立地址映射
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为2,也就是建立地址映射的功能号。
        在参数区中,get_memory_parameter()->memory_map_deal.file_window_id存放请求建立地址映射的文件窗口。
        在参数区中,get_memory_parameter()->memory_map_deal.begin_logic_address存放请求建立地址映射的文件窗口起始地址。
        在参数区中,get_memory_parameter()->memory_map_deal.end_logic_address,存放请求建立地址映射的文件窗口终止地址。
        在参数区中,get_memory_parameter()->memory_map_deal.file_capability,存放请求建立地址映射的文件窗口的capability校验。
    3.返回值:
        如果建立地址映射成功,则ax的返回值大于等于零。
        如果建立地址映射失败,则ax的返回值小于零。

[目录]


flush

3号功能
    1.功能:把某个存储域的所有已经修改的物理页框中的数据写回文件中。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为3,也就是flush存储域的功能号。
        在参数区中,get_memory_parameter()->flush_memory_process.give_up_flag存放是否放弃标志,如果该标志为TRUE,则仅仅标志各个已经修改的物理页框中的数据已经写回文件中,但是不执行写文件操作。
        在参数区中,get_memory_parameter()->flush_memory_process.process_number存放存储域的ID。
        在参数区中,get_memory_parameter()->flush_memory_process. process_capability存放存储域的capability校验。
    3.返回值:
        如果flush存储域成功,则ax的返回值大于等于零。
        如果flush存储域失败,则ax的返回值小于零。

4号功能
    1.功能:把某个文件窗口的所有已经修改的物理页框中的数据写回文件中。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为4,也就是flush文件窗口的功能号。
        在参数区中,get_memory_parameter()->flush_file_window.give_up_flag存放是否放弃标志,如果该标志为TRUE,则仅仅标志各个已经修改的物理页框中的数据已经写回文件中,但是不执行写文件操作。
        在参数区中,get_memory_parameter()->flush_file_window.file_window_id存放文件窗口的ID。
        在参数区中,get_memory_parameter()->flush_file_window.file_capability存放文件窗口的capability校验。
    3.返回值:
        如果flush文件窗口成功,则ax的返回值大于等于零。
        如果flush文件窗口失败,则ax的返回值小于零。

[目录]


标志页框

5号功能
    1.功能:标志某个页框中的数据已经被已修改,也就是执行了写操作,当执行flush操作时,将把其中的数据写回文件中。在虚地址空间基于文件操作系统中,当执行2号功能建立地址映射时,内存管理器仅仅建立具有只读权限的地址映射,这样当应用程序对页面执行写操作时,将再次引起存储访问失效异常,异常处理程序使线程迁移到内存管理器,执行内存管理器中的5号功能,把页框标志为已修改,同时建立具有读写权限的地址映射,当线程从内存管理期中返回时,应用程序就可以直接访问文件中的数据了。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为5,也就是flush文件窗口的功能号。
        在参数区中,get_memory_parameter()->mark_modifed.file_window_id,存放文件窗口的ID。
        在参数区中,get_memory_parameter()->mark_modifed.begin_logic_address存放应用程序访问文件文件窗口的起始地址。
        在参数区中,get_memory_parameter()->mark_modifed.end_logic_address存放应用程序访问文件文件窗口的终止地址。
        在参数区中,get_memory_parameter()->mark_modifed.file_capability存放文件窗口的capability校验。
    3.返回值:
        如果flush文件窗口成功,则ax的返回值大于等于零。
        如果flush文件窗口失败,则ax的返回值小于零。

[目录]


存储域

6号功能
    1.功能:查询存储域的资源。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为6,也就是查询存储域资源的功能号。
        在参数区中,get_memory_parameter()->memory_resource,存放资源管理的数据结构struct memory_resource,其定义为:
struct memory_resource{
        int process_number;        /*存储域的ID*/
        int file_number,max_file_number;
/*存储域当前打开的文件窗口数,存储域允许打开的最大文件窗口数*/
        int max_block_number,trigger_block_number;
/*存储域最大允许使用的页框数,使用了多少页框后开始执行页框淘汰操作*/
        int block_number,read_block_number,write_block_number;
/*存储域当前使用的页框数,读页框数,写页框数*/
        struct capability capability;
/*存储域的capability校验*/
};
    3.返回值:
        如果查询存储域的资源成功,则cx的返回值大于等于零,同时在参数区get_memory_parameter()->memory_resource返回资源的使用情况。
如果查询存储域的资源失败,则cx的返回值小于零。

7号功能
    1.功能:设置允许存储域使用的资源。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为7,也就是设置允许存储域使用资源的功能号。
        在参数区中,get_memory_parameter()->memory_resource,存放资源管理的数据结构struct memory_resource。
    3.返回值:
        如果设置允许存储域使用的资源成功,则ax的返回值大于等于零,同时在参数区get_memory_parameter()->memory_resource返回设置后资源的使用情况。
        如果查询存储域的资源失败,则ax的返回值小于零。

[目录]


计算存储管理区需要的存储空间

8号功能
    1.功能:计算存储管理区需要的存储空间。内存管理器不可能把全部的页框用于存放数据,需要其中一部分用于内存管理,8号功能计算存储管理区需要的存储空间大小。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为8,也就是计算存储管理区需要的存储空间的功能号。
        在参数区中,get_memory_parameter()->setup.memory_body_parameter,存放存储体的各项参数,其数据结构为:
struct install_memory_body_parameter{
        char *base;                                                /*存储体在物理空间的基地址*/
        int (*hash_function)(int file,int logic_block); /*用于查询的hash函数指针*/
        int my_processor,my_memory_body;        /*处理机ID,在本处理机的存储体ID*/
        int my_processor_process;                        /*内存管理器的进程ID*/
        int block_number,file_number;                 /*页框数,文件窗口数*/
        int process_number,hash_number;                /*存储域数,hash表大小*/
        int first_block;                                                /*用于存放文件数据的第一个页框*/
        struct capability capability;                        /*capability校验*/
};
    3.返回值:
        如果计算存储管理区需要的存储空间成功,则ax的返回值大于等于零,其值为存储管理区需要的存储空间大小。
        如果计算存储管理区需要的存储空间失败,则ax的返回值小于零。

[目录]


初试化和安装

9号功能
    1.功能:初试化存储体
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为9,也就是初试化存储体的功能号。
        在参数区中,get_memory_parameter()->setup.memory_body_parameter,存放存储体的各项参数。
    3.返回值:
        如果初试化存储体成功,则cx的返回值大于等于零。
如果初试化存储体失败,则cx的返回值小于零。

10号功能
    1.功能:初试化存储体
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为10,也就是安装存储体的功能号。
        在参数区中,get_memory_parameter()->setup.memory_body_parameter,存放存储体的各项参数。
    3.返回值:
        如果安装存储体成功,则ax的返回值大于等于零。
        如果安装存储体失败,则ax的返回值小于零。

[目录]


操纵文件窗口

11号功能
    1.功能:控制文件窗口。文件操作不仅包括文件的打开、关闭、读文件和写文件,还包括文件控制,11号功能实现该功能。
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为11,也就是控制文件窗口的功能号。
        在参数区中,get_memory_parameter()->control_file_system.parameter,存放控制文件窗口的各项参数。
        在参数区中,get_memory_parameter()->->control_file_system.capability,存放文件窗口的capability校验。
    3.返回值:
        如果控制文件窗口成功,则ax的返回值大于等于零。
如果控制文件窗口失败,则ax的返回值小于零。

12号功能
    1.功能:检查文件窗口的属性
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为12,也就是检查文件窗口属性的功能号。
        在参数区中,get_memory_parameter()存放文件窗口的各项参数。
    3.返回值:
        如果检查文件窗口的属性成功,则ax的返回值大于等于零。
如果检查文件窗口的属性失败,则ax的返回值小于零。

13号功能
    1.功能:设置文件窗口的属性
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为12,也就是设置文件窗口属性的功能号。
        在参数区中,get_memory_parameter()存放文件窗口的各项参数。
3返回值:
        如果设置文件窗口的属性成功,则ax的返回值大于等于零。
        如果设置文件窗口的属性失败,则ax的返回值小于零。

14号功能
    1.功能:检查页框使用情况
    2.格式:
        ax寄存器存放存储体ID。
        bx.寄存器的值为14,也就是检查页框使用情况的功能号。
        cx寄存器存放重复循环的次数。
        dx寄存器存放每次检查多少个页表项。
    3.返回值:没有返回值。

[目录]


文件系统提供的功能调用

    在虚地址空间基于文件操作系统中,文件系统是作为一个进程存在和运行的,当应用程序访问文件数据时,如果需要读写文件,内存管理器将执行线程迁移,线程迁移到文件系统执行文件读写操作,如果应用程序调用了内存管理器中的文件控制功能,内存管理器也将执行线程迁移,使线程迁移到文件系统执行文件控制操作。
    应用程序不仅可以通过内存管理器调用文件系统,也可以直接调用文件系统执行文件操作。
    当调用文件系统时,在参数区中存放一个结构为struct file_system_call_parameter的数据,在其中存放文件系统需要的各种调用参数,
struct file_system_call_parameter的定义为:

struct file_system_call_parameter {
                int command,sleep_semaphore;
                struct file file;
                struct thread_physical_block block;
/*线程当前可以访问的两个物理页框*/
                union file_system_operation_parameter parameter;
};
其中command的取值为:
#define OPEN_FILE                0                /*打开文件*/
#define CLOSE_FILE                1                /*关闭文件*/
#define READ_FILE                2                /*读文件*/
#define WRITE_FILE                3                /*写文件*/
#define CONTROL_FILE        4                /*控制文件*/

    sleep_semaphore是用于实现同步和互斥的信号量,和当前进程的capability具有相同的capability。文件系统可以使用。
结构        struct file的定义为:

struct file{
                struct{
                        struct network_address network_node; /*文件系统的网络地址*/
                        int server_processor,server_process,file_handler;
                                                /*文件系统所存在的处理机ID,文件系统的进程ID*/
                                                /*文件在文件系统中的文件ID,访问权限*/
                        }file;
                        struct{
                                int processor,process;
/*文件系统的本地代理所存在的处理机ID,进程ID*/
                        }proxy;
                        int memory_process,open_window_id;
                                                        /*文件窗口所属的存储域,文件窗口在内核中的标识数*/
                        int window_base_1,window_base_2,window_length,right;
                                                        /*文件窗口在文件中的基地址和长度*/
                        struct capability capability;
                                                        /*文件窗口的capability 校验*/
                        int read_in_flag,swap_out_flag;
                                                        /*是否从文件中读入数据的标志,是否对换到外存标志*/
};

    联合union file_system_operation_parameter的定义为:

union file_system_operation_parameter{
                struct {
                        int begin_rw,end_rw; /*数据在文件中的起始地址和终止地址*/
                }read_write;
};

    根据参数区中存放的结构为struct file_system_call_parameter操作文件请求,文件系统进程执行相应的功能。如果需要读写数据,则从get_thread_physical_block()处写数据或把数据读到get_thread_physical_block()处。

[目录]


[ 本文件由良友·收藏家自动生成 ]