收藏 分销(赏)

北京邮电大学操作系统实验-(2).doc

上传人:丰**** 文档编号:4306997 上传时间:2024-09-05 格式:DOC 页数:14 大小:620.19KB 下载积分:8 金币
下载 相关 举报
北京邮电大学操作系统实验-(2).doc_第1页
第1页 / 共14页
北京邮电大学操作系统实验-(2).doc_第2页
第2页 / 共14页


点击查看更多>>
资源描述
操作系统 班级:2011211302 学号:2011211168 姓名:康雅微 目录 实验5.1 进程通信观察实验 实验6.3 I/O系统编程实验 实验7.1 文件管理系统管理实验代码分析 实验5.1 观察实验 1、实验目的与内容 在Linux下,用ipcs()命令观察进程通信情况,了解Linux基本通信机制。 2、实验原理 Linux IPC继承了Unix System V及DSD等,共有6种机制: 信号(signal)、管道(pipe和命名管道(named piped)、消息队列(message queues)、共享内存(shared memory segments)、信号量(semaphore)、套接字(socket)。 本实验中用到的几种进程间通信方式: (1)共享内存段(shared memory segments)方式 – 将2个进程的虚拟地址映射到同一内存物理地址,实现内存共享 – 对共享内存的访问同步需由用户进程自身或其它IPC机制实现(如信号量) – 用户空间内实现,访问速度最快。 – Linux利用shmid_ds结构描述所有的共享内存对象。 (2)信号量(semaphore)方式 – 实现进程间的同步与互斥 – P/V操作, Signal/wait操作 – Linux利用semid_ds结构表示IPC信号量 (3)消息队列(message queues)方式 – 消息组成的链表,进程可从中读写消息。 – Linux维护消息队列向量表msgque,向量表中的每个元素都有一个指向msqid_ds结构的指针,每个msqid_ds结构完整描述一个消息队列 LINUX系统提供的IPC函数有: l msgget(关键字,方式):创建或打开一个消息队列 l msgsnd(消息队列标志符,消息体指针,消息体大小,消息类型): 向队列传递消息 l msgrcv(消息队列标志符,消息体指针,消息体大小,消息类型): 从队列中取消息 l msgctl(消息队列标志符,获取/设置/删除,maqid_ds缓冲区指针): 获取或设置某个队列信息,或删除某消息队列 Linux系统中,内核,I/O任务,服务器进程和用户进程之间采用消息队列方式,许多微内核OS中,内核和各组件间的基本通信也采用消息队列方式. 3、实验结果 实验6.3 编程实验 1、实验目的 编写一个daemon进程,该进程定时执行 ps命令,然后将该命令的输出写至文件F1尾部。通过此实验,掌握Linux I/O系统相关内容。 2、实验原理 在这个程序中,首先fork一个子程序,然后,关闭父进程,这样,新生成的子进程被交给init进程接管,并在后台执行。 新生成的子进程里,使用system系统调用,将ps的输出重定向,输入到f1.txt里面。 3、实验步骤 编写daemon.c 代码如下: #include<stdio.h> #include<stdlib.h> int main(int argc,char* argv[]) { int i,p; p = fork(); if(p > 0){ exit(0); } else if(p == 0){ for(i = 0; i < 100; i++){ sleep(100); system("ps > f1.txt"); } } else{ perror("Create new process!"); } return 1; } } 编译程序 # gcc -o daemon daemon.c 执行程序 # ./daemon 5、实验结果及分析 程序sleep(100)后会在当前目录生成一个文件f1.txt,内容如下: PID TTY TIME CMD 1258 pts/0 00:00:00 bash 2729 pts/0 00:00:00 daemon 2801 pts/0 00:00:00 sh 2802 pts/0 00:00:00 ps 再sleep(100),此文件会更新。重复执行100次。 实验7.1 代码分析 1、实验目的 了解与文件管理有关的Linux内核模块的代码结构。 2、实验内容 阅读 Linux/Minix中有关文件模块的调用主线,并写出分析报告,包括 l 文件建立模块,即系统调用create() l 文件删除模块,即系统调用rm() l 读/写模块,即 read/write 3、分析报告示例 A. 创建文件模块分析 5780 /*creat system call */ 5781 Creat() 5782 { 5783 resister *ip; 5784 extern uchar; 5785 5786 ip = namei(&uchar,1); 5787 if(ip == NULL){ 5788 if(u.u_error) 5789 return; 5790 ip = maknode(u.u_arg[1]&07777&(~ISVTX)); 5791 if (ip == NULL) 5792 return; 5793 open1(ip,FWRITE,2); 5794 }else 5795 open1(ip,FWRITE,1); 5796 } 第5 7 8 6:“namei”( 7 5 1 8 )将一路径名变换成一个“inode”指针。“uchar”是一个过程的名字,它从用户程序数据区一个字符一个字符地取得文件路径名。 5 7 8 7:一个空“inode”指针表示出了一个错,或者并没有具有给定路径名的文件存在。 5 7 8 8:对于出错的各种条件,请见U P M的C R E AT ( I I )。 5 7 9 0:“maknode”( 7 4 5 5 )调用“ialloc”创建一内存“ inode”,然后对其赋初值,并使其进入适当的目录。注意,显式地清除了“粘住”位( I S V T X )。 B. 删除文件rm模块分析 3510 unlink() 3511 { 3512 resister *ip,*pp; 3513 extern uchar; 3514 3515 pp = namei(&uchar,2); 3516 if (pp ==NULL) 3517 return; 3518 prele(pp); 3519 ip = iset(pp ->dev,u.u_dent.u_ino); 3520 if (ip == NULL) 3521 panic (*unlink – iset *); 3522 if ((ip ->i_mode%IFMT) == IFDIR && !suser()) 3523 goto out; 3524 u.u_offset[1] = - DIRSIZ+2; 3525 u.ubase = &u.u_dent; 3526 u.ucount = DIRSIZE +2; 3527 u.u_dent.u_ino = 0; 3528 writei(pp); 3529 ip ->i_nlink--; 3530 ip->i_flag =! IUPD; 3531 3532 out: 3533 iput(pp); 3534 iput(ip); 3535 } 新文件作为永久文件自动进入文件目录。关闭文件不会自动地造成文件被删除。当内存“ inode”项中的“ i _ nlink”字段值为0并且相应文件未被打开时,将删除该文件。在创建文件时,该字段由“ m a k n o d e”赋初值为1。系统调用“ link”( 5 9 4 1 )可将其值加1,系统调用“unlink”( 3 5 2 9 )则可将其值减1。创建临时“工作文件”的程序应当在其终止前执行“ unlink”系统调用将这些文件删除。 注意,“unlink”系统调用本身并没有删除文件。当引用计数( i _ count )被减为0时( 7 3 5 0、7 3 6 2 ),才删除该文件。 为了减少在程序或系统崩溃时遗留下来的临时文件所带来的问题,程序员应当遵守下列约定: (1) 在打开临时文件后立即对其执行“ unlink”操作。 (2) 应在“tmp”目录下创建临时文件。在文件名中包括进程标识数就可构成一惟一文件名 C 读/写模块,即 read/write 分析 /* * linux/fs/minix/file.c * * Copyright (C) 1991, 1992 Linus Torvalds * * minix regular file handling primitives */ #include <asm/segment.h> #include <asm/system.h> #include <linux/sched.h> #include <linux/minix_fs.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/locks.h> #define NBUF 32 #define MIN(a,b) (((a)(b))?(a):(b)) #include #include static int ext2_file_read (struct inode *, struct file *, char *, int); static int ext2_file_write (struct inode *, struct file *, char *, int); static void ext2_release_file (struct inode *, struct file *); /* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. */ static struct file_operations ext2_file_operations = { NULL, /* lseek - default */ ext2_file_read, /* read */ ext2_file_write, /* write */ NULL, /* readdir - bad */ NULL, /* select - default */ ext2_ioctl, /* ioctl */ generic_mmap, /* mmap */ NULL, /* no special open is needed */ ext2_release_file, /* release */ ext2_sync_file /* fsync */ }; struct inode_operations ext2_file_inode_operations = { &ext2_file_operations,/* default file operations */ NULL, /* create */ NULL, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ ext2_bmap, /* bmap */ ext2_truncate, /* truncate */ ext2_permission /* permission */ }; static int ext2_file_read (struct inode * inode, struct file * filp, char * buf, int count) { int read, left, chars; int block, blocks, offset; int bhrequest, uptodate; struct buffer_head ** bhb, ** bhe; struct buffer_head * bhreq[NBUF]; struct buffer_head * buflist[NBUF]; struct super_block * sb; unsigned int size; int err; if (!inode) { printk ("ext2_file_read: inode = NULL\n"); return -EINVAL; } sb = inode->i_sb; if (!S_ISREG(inode->i_mode)) { ext2_warning (sb, "ext2_file_read", "mode = %07o", inode->i_mode); return -EINVAL; } offset = filp->f_pos; size = inode->i_size; if (offset > size) left = 0; else left = size - offset; if (left > count) left = count; if (left > EXT2_BLOCK_SIZE_BITS(sb); offset &= (sb->s_blocksize - 1); size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); bhb = bhe = buflist; if (filp->f_reada) { // 37 /* This specifies how many sectors to read ahead on the disk. */ // 39 int read_ahead[MAX_BLKDEV] = {0, }; blocks += read_ahead[MAJOR(inode->i_dev)] >> (EXT2_BLOCK_SIZE_BITS(sb) - 9); if (block + blocks > size) blocks = size - block; } /* * We do this in a two stage process. We first try and request * as many blocks as we can, then we wait for the first one to * complete, and then we try and wrap up as many as are actually * done. This routine is rather generic, in that it can be used * in a filesystem by substituting the appropriate function in * for getblk * * This routine is optimized to make maximum use of the various * buffers and caches. */ do { bhrequest = 0; uptodate = 1; while (blocks) { --blocks; *bhb = ext2_getblk (inode, block++, 0, &err); if (*bhb && !(*bhb)->b_uptodate) { uptodate = 0; bhreq[bhrequest++] = *bhb; } if (++bhb == &buflist[NBUF]) bhb = buflist; /* * If the block we have on hand is uptodate, go ahead * and complete processing */ if (uptodate) break; if (bhb == bhe) break; } /* * Now request them all */ if (bhrequest) ll_rw_block (READ, bhrequest, bhreq); do { /* * Finish off all I/O that has actually completed */ if (*bhe) { wait_on_buffer (*bhe); if (!(*bhe)->b_uptodate) { /* read error? */ brelse(*bhe); if (++bhe == &buflist[NBUF]) bhe = buflist; left = 0; break; } } if (left s_blocksize - offset) chars = left; else chars = sb->s_blocksize - offset; filp->f_pos += chars; left -= chars; read += chars; if (*bhe) { memcpy_tofs (buf, offset + (*bhe)->b_data, chars); brelse (*bhe); buf += chars; } else { while (chars-- > 0) put_fs_byte (0, buf++); } offset = 0; if (++bhe == &buflist[NBUF]) bhe = buflist; } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); } while (left > 0); /* * Release the read-ahead blocks */ while (bhe != bhb) { brelse (*bhe); if (++bhe == &buflist[NBUF]) bhe = buflist; } if (!read) return -EIO; filp->f_reada = 1; if (!IS_RDONLY(inode)) { inode->i_atime = CURRENT_TIME; inode->i_dirt = 1; } return read; } static int ext2_file_write (struct inode * inode, struct file * filp, char * buf, int count) { off_t pos; int written, c; struct buffer_head * bh; char * p; struct super_block * sb; int err; if (!inode) { printk("ext2_file_write: inode = NULL\n"); return -EINVAL; } sb = inode->i_sb; if (sb->s_flags & MS_RDONLY) /* * This fs has been automatically remounted ro because of errors */ return -ENOSPC; if (!S_ISREG(inode->i_mode)) { ext2_warning (sb, "ext2_file_write", "mode = %07o\n", inode->i_mode); return -EINVAL; } /* * ok, append may not work when many processes are writing at the same time * but so what. That way leads to madness anyway. */ if (filp->f_flags & O_APPEND) pos = inode->i_size; else pos = filp->f_pos; written = 0; while (written s_blocksize, 1, &err); if (!bh) { if (!written) written = err; break; } c = sb->s_blocksize - (pos % sb->s_blocksize); if (c > count-written) c = count - written; if (c != sb->s_blocksize && !bh->b_uptodate) { ll_rw_block (READ, 1, &bh); wait_on_buffer (bh); if (!bh->b_uptodate) { brelse (bh); if (!written) written = -EIO; break; } } p = (pos % sb->s_blocksize) + bh->b_data; pos += c; if (pos > inode->i_size) { inode->i_size = pos; inode->i_dirt = 1; } written += c; memcpy_fromfs (p, buf, c); //写入到缓冲块中 buf += c; bh->b_uptodate = 1; bh->b_dirt = 1; brelse (bh); } inode->i_ctime = inode->i_mtime = CURRENT_TIME; filp->f_pos = pos; inode->i_dirt = 1; return written; } 分析: 对于整个文件的索引操作担,都使用块计算的。 整块读取时,调用底层的读取函数。只要得到了更新块就跳出去处理,否则就记录要读取的块 整块的写入时很好办的,只要整体为脏就可以了.但是对于不能整块写入的,必须写入的块原先是更新的. 源码行号 注释: 86 left = size - offset; //剩余可读数 88 left = count; //left就是最终要读取的数据 92 //下面的size和blocks是对于整个文件的索引操作担,都使用块计算的 93 size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); //整个文件的块数 94 blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); //要读取的块数 95 bhb = bhe = buflist; 97 //进行预读 98 if (filp->f_reada) { 99 100 // 37 /* This specifies how many sectors to read ahead on the disk. */ 101 // 39 int read_ahead[MAX_BLKDEV] = {0, }; 102 blocks += read_ahead[MAJOR(inode->i_dev)] >> 103 (EXT2_BLOCK_SIZE_BITS(sb) - 9); //可能都是使用512标示的,这里进行校正 104 if (block + blocks > size) 105 blocks = size - block; //校正实际能读取的块数 106 } 126 bhreq[bhrequest++] = *bhb; //同时bhrequest记录了需要重新读取的块数 128 if (++bhb == &buflist[NBUF]) //回卷到头部 134 if (uptodate) //只要得到了更新块就跳出去处理,否则就记录要读取的块 136 if (bhb == bhe) //满了,要读取NBUF块 142 if (bhrequest) //调用底层的读取函数 150 if (!(*bhe)->b_uptodate) { /* read error? */ //这里当做错误处理的,left=0,跳出大循环了 154 bhe = buflist; //不是跳出去就完了,这里的bhe将来还是有用的 184 while (bhe != bhb) { //预读的块释放掉 191 filp->f_reada = 1; //标志已经预读了 226 if (filp->f_flags & O_APPEND) //是否追加,更新文件指针 237 c = sb->s_blocksize - (pos % sb->s_blocksize); //c记录本次可以读取的字符个数 240 if (c != sb->s_blocksize && !bh->b_uptodate) { //整块的写入时很好办的,只要整体为脏就可以了.但是对于不能整块写入的,必须写入的块原先是更新的. 257 memcpy_fromfs (p, buf, c); //写入到缓冲块中
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 教育专区 > 远程教育/电大

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服