Files
OS/lab6/report/report.tex
2025-04-24 23:50:26 +08:00

128 lines
7.0 KiB
TeX
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
\documentclass[12pt, a4paper]{article}
\usepackage[UTF8]{ctex}
\usepackage{geometry}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{amssymb}
\usepackage{enumitem}
\usepackage{float}
\usepackage{graphicx}
\usepackage{extarrows}
\usepackage{booktabs}
\usepackage{diagbox}
\usepackage{siunitx}
\usepackage{subcaption}
\usepackage{fontspec}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{siunitx}
\usepackage[ruled,vlined]{algorithm2e}
\sisetup{
group-separator={,},
}
\definecolor{vscodeBlue}{RGB}{0,0,255} % 关键字/语句
\definecolor{vscodeRed}{RGB}{163,21,21} % 字符串
\definecolor{vscodeGreen}{RGB}{0,128,0} % 注释
\newfontfamily\codefont{Fira Code}
\lstset{
basicstyle = \footnotesize\codefont,
% ---
tabsize = 4,
showstringspaces = false,
numbers = left,
numberstyle = \codefont,
% ---
breaklines = true,
captionpos = t,
% ---
frame = l,
flexiblecolumns,
commentstyle=\color{vscodeGreen}, % 注释样式
keywordstyle=\color{vscodeBlue}, % 关键字样式
stringstyle=\color{vscodeRed}, % 字符串样式
rangebeginprefix = //\ BEGIN_LST_,
rangeendprefix = //\ END_LST_
}
\renewcommand{\qedsymbol}{}
\lstMakeShortInline|
\geometry{a4paper,scale=0.8}
\allowdisplaybreaks[4] %允许公式跨页
\setenumerate[1]{label=\arabic{*}. }
\setenumerate[2]{label=(\arabic{*})}
\title{\Huge{{\bf 操作系统大作业实验6报告}}}
\author{高艺轩 2022010639}
\date{}
\begin{document}
\maketitle
\section{实验题目}
选择的题目为“管道驱动程序开发”。
\section{问题描述}
管道是现代操作系统中重要的进程间通信IPC机制之一Linux和Windows操作系统都支持管道。
管道在本质上就是在进程之间以字节流方式传送信息的通信通道,每个管道具有两个端,一端用于输入,一端用于输出,如下图所示。在相互通信的两个进程中,一个进程将信息送入管道的输入端,另一个进程就可以从管道的输出端读取该信息。显然,管道独立于用户进程,所以只能在内核态下实现。
在本实验中请通过编写设备驱动程序mypipe实现自己的管道并通过该管道实现进程间通信。
你需要编写一个设备驱动程序mypipe实现管道该驱动程序创建两个设备实例一个针对管道的输入端另一个针对管道的输出端。另外你还需要编写两个测试程序一个程序向管道的输入端写入数据另一个程序从管道的输出端读出数据从而实现两个进程间通过你自己实现的管道进行数据通信。
\section{思路与程序结构}
实现Linux管道驱动的核心是编写一个character device驱动我们将它通过模块的形式挂载到内核中。实验内核版本为|6.14.3-arch1-1|。作为一个管道程序我们需要向系统注册两个设备一个作为输出一个作为输入同时需要开辟一片缓冲区用于暂时接收从管道入口发来的信息在这里我选择使用了环形缓存ring buffer
首先,定义一些变量用于存储状态:
\lstinputlisting[language=c, linerange=DEF]{../wendy_mod/wendy.c}
作为一个设备驱动模块,我们要做的最主要的事情就是提供|module_init|和|module_exit|两个回调函数。我们的驱动程序将在这两个|module_init|中初始化自身,向操作系统注册我们创建的设备以及注册另一个重要的回调函数结构体|mypipe_fops|,同时在|module_exit|中做相反的操作。模块初始化与销毁的代码如下:
\lstinputlisting[language=c, linerange=INIT]{../wendy_mod/wendy.c}
在|module_init|中我们注册了回调函数结构体|cdev_init(&pdata.cdev, &mypipe_fops);|这其中的|mypipe_fops|定义为:
\lstinputlisting[language=c, linerange=FOP]{../wendy_mod/wendy.c}
|open||release||read||write|可以粗略地看作对应了用户态下的|fopen||fclose||fread||fwrite|四个操作。我们需要实现这四个回调函数才能正确地完成目标。对于|open|与|release|,由于我们实现的是一个虚拟设备,无需与物理硬件交互,所以不需要进行特别的操作;为了保证只有一个程序可以向管道写入,同时保证在写入程序关闭管道时向读取端提示已经写入端已经关闭,需要处理|pdata.is_active|量来标识当前是否有程序正在占用管道的写入端。
\lstinputlisting[language=c, linerange=OPEN_RELEASE]{../wendy_mod/wendy.c}
对于|read|与|write|函数,首先需要判断|minor|号是否匹配:我们不允许在入口调用|read|,也不允许在出口调用|write|。之后的操作是类似的,以|read|为例。首先尝试获取缓冲区的锁如果当前的数据长度为0那么要么是对面端已经关闭了管道而且我们已经读取了所有的数据要么是管道对面还有等着写入的数据暂时没有写入。对于前者我们可以直接返回|0|代表已经读取完毕,对于后者,我们可以将自己放入等待区,等待|pdata.data_len > 0|的事件发生时重启此系统调用。如果当前的数据长度不为0那么我们就可以从环形缓存中依次读取数据放入用户提供的缓冲区中并且提醒可能的正在等待的写入端我们已经腾出了空间。|write|的操作是完全类似的。
\lstinputlisting[language=c, linerange=READ_WRITE]{../wendy_mod/wendy.c}
\section{程序运行情况}
首先编写简单的写入Listings \ref{code:pwrite}与读出程序Listings \ref{code:pread})进行测试:
\begin{figure}[H]
\centering
\includegraphics[width=\linewidth]{../exps/read_write.png}
\caption{简单读入读出测试}
\end{figure}
之后尝试利用管道传输超出缓冲区容量的数据Listings \ref{code:tester}),读取大约\SI{620}{KB}
\begin{figure}[H]
\centering
\includegraphics[width=\linewidth]{../exps/longread_start.png}
\caption{程序输出的开头}
\end{figure}
\begin{figure}[H]
\centering
\includegraphics[width=\linewidth]{../exps/longread_end.png}
\caption{程序输出的结尾}
\end{figure}
\section{实验总结}
在本次实验中我第一次实现了一个简单的Linux驱动。在阅读了一些教程后对代码结构有了基本的认识实际写起来也并不觉得过于困难这次时间很大地提升了我的编程水平。
\appendix
\section{完整源代码}
\lstinputlisting[language=c, title=管道驱动程序代码, caption={内核驱动模块代码}]{../wendy_mod/wendy.c}
\lstinputlisting[language=c, title=pipe\_write.c, caption={简单写入程序代码}, label={code:pwrite}]{../pipe_write.c}
\lstinputlisting[language=c, title=pipe\_read.c, caption={简单读出程序代码}, label={code:pread}]{../pipe_read.c}
\lstinputlisting[language=c++, title=pipe\_tester.cpp, caption={测试程序代码}, label={code:tester}]{../pipe_tester.cpp}
\end{document}