10.8
由于stat函数和fstat函数在功能上很相似,都是检索文件的信息,只是stat函数以文件名作为输入,而fstat函数是以文件描述符作为输入,所以只需把Stat(argv[1],&stat)改为fstat(atoi(argv[1]),&stat)即可实现功能
include “csapp.h”
Int main(int argc,char **argv)
{
struct stat stat;
char type,readok;
fstat(atoi(argv[1]),&stat);
if(S_ISREG(stat.st_mode))
type=”regular”;
else if(S_ISDIR(stat.st_mode))
type=”directory”;
else
type=”other”;
if((stat.st_mode & S_IRUSR))
readok=”yes”;
else
readok=”no”;
printf(“type: %s,read:%s
”,type,readok);
exit(0);
}
10.9
输入重定向到了foo.txt,然而3这个描述符是不存在的。
说明foo.txt并没有单独的描述符3。
所以Shell执行的代码应该是这样的:
if (Fork() == 0) {/* Child */
int fd = open("foo.txt", O_RDONLY, 0);
dup2(fd, 1);
close(fd);
Execve("fstatcheck", argv, envp);
}
9.11
A.虚拟地址:0x027c
13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 1 0 0 1 1 1 1 1 0 0
B.地址翻译
参数 值
VPN 0x09
TLB索引 0x01
TLB标记 0x02
TLB命中 No
缺页 No
PPN 0x17
C.物理地址格式
11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 1 1 1 1 1 1 1 0 0
D.物理地址引用
参数 值
字节偏移 0x0
缓存索引 0xF
缓存标记 0x17
缓存命中 No
返回缓存字节 -
9.12
A.虚拟地址:0x03a9
13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 1 1 1 0 1 0 1 0 0 1
B.地址翻译
参数 值
VPN 0x0E
TLB索引 0x02
TLB标记 0x03
TLB命中 No
缺页 No
PPN 0x11
C.物理地址格式
11 10 9 8 7 6 5 4 3 2 1 0
0 1 0 0 0 1 1 0 1 0 0 1
D.物理地址引用
参数 值
字节偏移 0x1
缓存索引 0xA
缓存标记 0x11
缓存命中 No
返回缓存字节 -
9.13
A.虚拟地址:0x0040
13 12 11 10 9 8 7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 1 0 0 0 0 0 0
B.地址翻译
参数 值
VPN 0x01
TLB索引 0x01
TLB标记 0x00
TLB命中 No
缺页 Yes
PPN -
9.15
请求 块大小 块头部
malloc(3) 8 0x9
malloc(11) 16 0x11
malloc(20) 24 0x19
malloc(21) 32 0x21
9.19
1) a; 对于伙伴系统,如果要申请大小为33的空间,那么需要分配64个空间。如果申请大小为65的空间,那么块大小就需要128,所以最多可能有约50%的空间被浪费。b中,最佳适配要搜索所有空间,所以肯定比首次适配要慢一些。c,边界标记主要功能是释放一个块时,能立即和前后空闲块合并。如果空闲块不按顺序排列的话,其实也能够和前一个或者后一个空闲块进行合并,但如果要和前后一起合并,可能会有些困难,那需要搜索前后块在空闲链表中的位置,并且删除一个再进行合并。可以参考P576,LIFO方法。d,其实任何分配器都可能有外部碎片,只要剩余的空闲块大小和足够但是单个都不够,就会产生外部碎片。
2) d; 块大小递增,那么最佳适配法找到的块和首次适配找到的块是同一个,因为最佳适配总是想找一个刚好大于请求块大小的空闲块。a,块大小递减,首次适配很容易找到,所以分配性能会很高。b,最佳适配方法无论怎样,都要搜索所有的链表(除非维护成块大小递增的链表)。c,是匹配的最小的。
3) c; 保守的意思就是所有可能被引用的堆都会被标记,int像指针,所以可能认为它表示的地址是正在被引用的(实际上它只是个int)。
11.9
serve_static中的存储器映射语句改为:
srcfd = open(filename, O_RDONLY, 0);
srcp = (char*)malloc(sizeof(char)*filesize);
rio_readn(srcfd, srcp, filesize);
close(srcfd);
rio_writen(fd, srcp, filesize);
free(srcp);
12.24
可重入函数:当它们被多个线程调用时,不会引用任何共享数据。
满足下面条件之一的多数是不可重入函数:
1.使用了静态数据结构
2.调用了malloc或free
3.调用了标准I/O函数;标准I/O库很多实现都一不可重入的方式使用全局数据结构
4.进行了浮点运算。许多的处理器/编译器中,浮点一般都是不可重入的(浮点运算大多使用协处理器或者软件模拟来实现)
rio_readn(int fd,void *usrbuf,size_t n)是不可重入函数,因为每次调用都共享read(fd,bufp,nleft),使用全局数据结构
rio_writen(int fd,void *usrbuf,size_t n)是不可重入函数, 使用全局数据结构
rio_read(int fd,void *usrbuf,size_t n)是不可重入函数,使用全局数据结构
rio_readlineb(int fd,void *usrbuf,size_t maxlen)是不可重入函数,使用全局数据结构
rio_readnb(int ,void *usrbuf,size_t n)是不可重入函数,使用全局数据结构