操作系统真象还原:文件描述符简介

14.3 文件描述符简介

14.3.1 文件描述符原理

inode 是操作系统为自己的文件系统准备的数据结构,它用于文件存储的管理,与用户关系不大,咱们要介绍的文件描述符才是与用户息息相关的。

文件描述符即 file descriptor,但凡叫“描述符”的数据结构都用于描述一个对象,文件描述符所描述的对象是文件的操作。

Linux 提供了称为“文件结构”的数据结构(也称为file结构),专门用于记录与文件操作相关的信息,每次打开一个文件就会产生一个文件结构,多次打开该文件就为该文件生成多个文件结构,各自文件操作的偏移量分别记录在不同的文件结构中,从而实现了“即使同一个文件被同时多次打开,各自操作的偏移量也互不影响”的灵活性
在这里插入图片描述

inode用于描述文件存储相关信息,文件结构用于描述“文件打开”后,文件读写偏移量等信息。文件与 inode一一对应,一个文件仅有一个 inode , 一个 inode 仅对应一个文件。一个文件可以被多次打开,因此一个inode 可以有多个文件结构,多个文件结构可以对应同一个 inode。
在这里插入图片描述

其实 open 操作的本质就是创建相应文件描述符的过程,剧透一下, PCB 中文件描述符数组是提前在 task_struct 中构建好的,文件表也是提前构建好的全局数据结构, inode 队列也已经构建好了,因此笼统地说,创建文件描述符的过程就是逐层在这三个数据结构中找空位,在该空位填充好数据后返回该位置的地址,比如:

  1. 在全局的 inode 队列中新建一 inode (这肯定是在空位置处新建),然后返回该 inode 地址。
  2. 在全局的文件表中的找一空位,在该位置填充文件结构,使其 inode 指向上一步中返回的 inode地址,然后返回本文件结构在文件表中的下标值 。
  3. 在 PCB 中的文件描述符数组中找一空位,使该位置的值指向上一步中返回的文件结构下标,井返回本文件描述符在文件描述符数组中的下标值。
14.3.2 文件描述符的实现

为了支持文件描述符,我们要取修改task_struct结构体的定义。(还新增了parent_idcwd_inode_nr

#define MAX_FILES_OPEN_PER_PROC 8

/*进程或线程的pcb,程序控制块*/
struct task_struct{
    uint32_t* self_kstack;  //各内核线程都用自己的内核栈
    pid_t pid;
    enum task_status status;
    char name[16];
    uint8_t priority;     //线程优先级
    uint8_t ticks;  //每次在处理器上执行的时间滴答数
    /*任务自上 cpu 运行后至今占用了多少 cpu 嘀嗒数,也就是此任务执行了多久**/
    uint32_t elapsed_ticks;
    int32_t fd_table[MAX_FILES_OPEN_PER_PROC];  //文件描述符数组
    uint32_t cwd_inode_nr;                        // 进程所在的工作目录的inode编号
    int16_t parent_pid;                           // 父进程pid
    /* general_tag的作用是用于线程在一般的队列中的结点*/
    struct list_elem general_tag;
    
    /*all_list_tag的作用是用于线程队列 thread_all_list 中的结点*/
    struct list_elem all_list_tag;

    uint32_t* pgdir;    //进程自己的页表的虚拟地址
    struct virtual_addr userprog_vaddr; //用户进程的虚拟地址
    struct mem_block_desc u_block_desc[DESC_CNT];    //用户进程内存块描述符
    uint32_t stack_magic;   ///栈的边界标记,用于检测栈的溢出
};

初始化:

/* 初始化线程基本信息 , pcb中存储的是线程的管理信息,此函数用于根据传入的pcb的地址,线程的名字等来初始化线程的管理信息*/
void init_thread(struct task_struct *pthread, char *name, int prio)
{
    memset(pthread, 0, sizeof(*pthread)); // 把pcb初始化为0
    pthread->pid = allocate_pid();
    strcpy(pthread->name, name); // 将传入的线程的名字填入线程的pcb中

    if (pthread == main_thread)
    {
        pthread->status = TASK_RUNNING; // 由于把main函数也封装成一个线程,并且它一直是运行的,故将其直接设为TASK_RUNNING */
    }
    else
    {
        pthread->status = TASK_READY;
    }
    pthread->priority = prio;
    /* self_kstack是线程自己在内核态下使用的栈顶地址 */
    pthread->ticks = prio;
    pthread->elapsed_ticks = 0;
    pthread->pgdir = NULL;                                            // 线程没有自己的地址空间,进程的pcb这一项才有用,指向自己的页表虚拟地址
    pthread->self_kstack = (uint32_t *)((uint32_t)pthread + PG_SIZE); // 本操作系统比较简单,线程不会太大,就将线程栈顶定义为pcb地址
                                                                      //+4096的地方,这样就留了一页给线程的信息(包含管理信息与运行信息)空间
    /* 标准输入输出先空出来 */
    pthread->fd_table[0] = 0;
    pthread->fd_table[1] = 1;
    pthread->fd_table[2] = 2;
    /* 其余的全置为-1 */
    uint8_t fd_idx = 3;
    while (fd_idx < MAX_FILES_OPEN_PER_PROC)
    {
        pthread->fd_table[fd_idx] = -1;
        fd_idx++;
    }
    pthread->cwd_inode_nr = 0;         // 以根目录做为默认工作路径
    pthread->parent_pid = -1;          // -1表示没有父进程
    pthread->stack_magic = 0x19870916; // 定义的边界数字,随便选的数字来判断线程的栈是否已经生长到覆盖pcb信息了
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/798550.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【周末闲谈】Stable Diffusion会魔法的绘画师

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️Python】 文章目录 前言Stable Diffusion介绍 使用ComfyUI 和 WebUIComfyUIWebUI 配置需求 Stable Diffusion资源分享吐司AiAUTOMATIC1111Civitai绘世整合包Nenly同学stability.ai 前言 在很早之前&…

【前端项目笔记】10 项目优化上线

项目优化上线 目标&#xff1a;优化Vue项目部署Vue项目&#xff08;上线提供使用&#xff09; 项目优化 项目优化策略&#xff1a; 生成打包报告&#xff1a;根据生成的报告发现问题并解决第三方库启用CDN&#xff1a;提高首屏页面的加载效率Element-UI组件按需加载路由懒加…

Django 删除所有数据

1&#xff0c;添加模型 Test/app11/models.py from django.db import modelsclass Post(models.Model):title models.CharField(max_length200)content models.TextField()pub_date models.DateTimeField(date published)class Book(models.Model):title models.CharFiel…

优势洗牌(田忌赛马

Nums2的位置不能改变&#xff0c;所以用优先队列&#xff0c;存储索引的同时弄出最大值&#xff0c;nums1用双指针排序&#xff0c;因为它位置可以比变化。 对nums2进行最大堆排序&#xff0c;存储索引位置和值 Nums1 sort排序即可。 class Solution {public int[] advantag…

Go:基本变量与数据类型

目录 前言 前期准备 Hello World! 一、基本变量 1.1 声明变量 1.2 初始化变量 1.3 变量声明到初始化的过程 1.4 变量值交换 1.5 匿名变量 1.6 变量的作用域 二、数据类型 1.1 整型 1.2 浮点型 1.3 字符串 1.4 布尔类型 1.5 数据类型判断 1.6 数据类型转换 1.…

Linux系列--用户、文件管理

一、概述 Linux系统中超级用户是root&#xff0c;通过超级用户root可以创建其它的普通用户&#xff0c;Linux是一个支持多用户的操作系统。在实际使用中&#xff0c;一般会分配给开发人员专属的账户&#xff0c;这个账户只拥有部分权限&#xff0c;如果权限太高&#xff0c;操作…

golang程序性能提升改进篇之文件的读写---第一篇

背景&#xff1a;接手的项目是golang开发的&#xff08;本人初次接触golang&#xff09;经常出现oom。这个程序是计算和io密集型&#xff0c;调用流量属于明显有波峰波谷&#xff0c;但是因为各种原因&#xff0c;当前无法快速通过serverless或者动态在高峰时段调整资源&#x…

持续学习的综述: 理论、方法与应用(三:泛化分析)

前文连接&#xff1a;持续学习的综述: 理论、方法与应用&#xff08;一&#xff09; 前文连接&#xff1a;持续学习的综述: 理论、方法与应用&#xff08;二&#xff1a;理论基础&#xff09; 泛化分析 目前持续学习的理论研究主要是在增量任务的训练集上进行的&#xff0c;假…

QT VTK 简单测试工程

目录 1 目录结构 2 文件源码 3 运行结果 4 报错及处理 使用编译好的VTK库进行测试 1 目录结构 2 文件源码 Pro文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c17# You can make your code fail to compile if it uses deprecated APIs. #…

STM32-寄存器点灯案例详解

本文以PA1引脚点亮LED灯为案例&#xff0c;解析了STM32寄存器操作的配置过程&#xff0c;以及从手册查询方法和寄存器配置步骤。 一、概念 1.十六进制和二进制之间相互转换关系 首先&#xff0c;需要了解十六进制和二进制之间的基本转换方法。十六进制是一种基数为16的数制&…

《战甲神兵》开发者报告:游戏崩溃问题80%发生在Intel可超频酷睿i9处理器上——酷睿i7 K系列CPU也表现出高崩溃率

在Intel持续面临第13代和第14代CPU崩溃问题的背景下&#xff0c;近日&#xff0c;《战甲神兵》(Warframe)的开发者们于7月9日披露了游戏崩溃的统计数据&#xff0c;并描述了诊断该问题的过程。根据开发团队的说法&#xff0c;一名未进行超频且使用全新PC的员工&#xff0c;即便…

FOC(笔记二)

接上篇文章&#xff1a;FOC算法(笔记一)_马鞍波和三角波调制合成-CSDN博客 前面已经对FOC的开环控制进行了介绍&#xff0c;下面对FOC的闭环控制进行介绍。 本次使用的电机参数如下图所示&#xff1a; 一、HALL传感器 1.1、霍尔传感器的角度、速度计算 因为本次使用的是120安…

2024安全行业大模型技术应用态势发展报告

以上是资料简介和目录&#xff0c;如需下载&#xff0c;请前往星球获取&#xff1a;https://t.zsxq.com/dH9bu

蒙特卡洛抽样方法

目录 认识该方法 认识该方法 不断抽样逐渐逼近 计算Π 打点&#xff0c;落在圆&#xff08;1/4&#xff09;的概率 抽样点越多&#xff0c;Π的值越准确 蒙特卡洛不在于精确&#xff0c;也不在于找到最准确的数值。如下图所示&#xff0c;Π就等于红

Git代码管理工具 — 3 Git基本操作指令详解

目录 1 获取本地仓库 2 基础操作指令 2.1 基础操作指令框架 2.2 git status查看修改的状态 2.3 git add添加工作区到暂存区 2.4 提交暂存区到本地仓库 2.5 git log查看提交日志 2.6 git reflog查看已经删除的记录 2.7 git reset版本回退 2.8 添加文件至忽略列表 1 获…

006-三台交换机堆叠

三台交换机堆叠 链形连接和环形连接 链形配置IRF与环形配置IRF的区别 三个交换机链形配置IRF与三个交换机环形配置IRF的主要区别体现在以下几个方面&#xff1a; 物理位置要求&#xff1a; 链形连接&#xff1a;对成员设备的物理位置要求相对较低&#xff0c;主要适用于成员…

鸿蒙语言基础类库:【@system.app (应用上下文)】

应用上下文 说明&#xff1a; 从API Version 7 开始&#xff0c;该接口不再维护&#xff0c;推荐使用新接口。本模块首批接口从API version 3开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 import app from system.app;app.getInfo …

Scrapy框架实现数据采集的详细步骤

需求描述&#xff1a; 本项目目标是使用Scrapy框架从宁波大学经济学院网站&#xff08;nbufe.edu.cn&#xff09;爬取新闻或公告详情页的内容。具体需求如下&#xff1a; 1、通过遍历多个页面&#xff08;共55页&#xff09;构建翻页URL。 2、使用scrapy自带的xpath从每页的…

C++基础(二十):常见C++11的新特性

1979年&#xff0c;贝尔实验室的本贾尼等人试图分析unix内核的时候&#xff0c;试图将内核模块化&#xff0c;于是在C 语言的基础上进行扩展&#xff0c;增加了类的机制&#xff0c;完成了一个可以运行的预处理程序&#xff0c;称之为C with classes。语言的发展就像是练功打怪…

项目三层架构详情

三层架构 三层架构就是为了符合“高内聚&#xff0c;低耦合”思想&#xff0c;把各个功能模块划分为表示层&#xff08;UI&#xff09;、业务逻辑层&#xff08;BLL&#xff09;和数据访问层&#xff08;DAL&#xff09;三层架构&#xff0c;各层之间采用接口相互访问&#xf…