• CSAPP 之 cache 与 virtual memory

  • book · csapp · 2016-08-27 · yuex
  • Cache

    cache 结构中有 set/line/block 的概念。一般是一个 cache 中有多个 set,每个 set 中有多条 line,每条 line 由多个字节 block 组成。而地址会被切分成三个部分来在这个三层结构中进 行缓存访问定位

    +---------------+------------+--------------+
    |      Tag      |  Set Index | Block Offset |
    +---------------+------------+--------------+
    

    其中有几条 line 就叫几路关联(n-way associative),因为 line 的访问是顺序查找的,相 同 set 内的缓存块可以缓存在任何一条 line 中。特别地,如果只有一个 set,叫全关联缓存 (full-associative)。如果每个 set 只有一条 line,叫直接映射缓存(direct-mapped)。 tag 用于在同一个 set 中定位访问的 line。

    Virtual Memory

    在虚拟地址中 …

  • CSAPP 之 file descriptor

  • book · csapp · 2016-08-27 · yuex
  • 当文件与进程结合时,有以下几个地方需要注意

    fd table -> open file table -> v-node table
    1. fd table 是每进程独立的数据
    2. open file table 是所有进程共享的系统全局数据。这里维护了每个打开文件的反
       向映射数目和当前光标位置。当映射数目为 0 时,文件会被关闭。每个 open() 都会
       导致一个新的 open file table entry,即使打开的是同一文件。
    3. v-node table 是所有进程共享的系统全局数据。这里维护了每个文件的信息,如访
       问权限、文件类型、文件大小、三个时间等
    

    基于以上事实,如果文件打开之后进行 fork,那么 fork 后的子母进程其实是共享了打开文 件的读写位置的,虽然 fd 是独立的。

    当然 fd table 中的前三号是默认帮你打开到 stdin/stdout/stderr …

  • CSAPP 之 thread 与 signal

  • book · csapp · 2016-08-27 · yuex
  • Thread

    函数与 thread 结合起来有几个概念,还比较绕,这里总结一下。一个函数被称为

    thread-safe:总是给出正确运行结果即使是从多个同步线程中反复调用
    reentrant:不使用任何共享数据
    

    需要注意的是,reentrant function 一定是 thread-safe 的,因为完全没有共享数据。而反 之则不然,例如一个 thread-safe 的函数可以使用同步机制来同步对于共享数据的访问。

    另外,调用 thread-unsafe 函数的函数不一定就是 thread-unsafe 的。例如,如果只是被调 用的函数有一些共享数据,则完全可以通过同步来使其安全。

    这里再给出 race 的定义

    race:程序的执行结果的正确性取决于线程是如何调度的
    

    thread 相关的函数

    pthread_create(tid, attr, func, arg): 创建线程。tid 用于返回线程号,func 是要
        运行的线程逻辑函数,arg 是一个指针,指向要传递的函数参数。成功返回 0
    pthread_exit(rc): 结束当前线程
    pthread_cancel …
  • CSAPP 之 asm 函数调用

  • book · csapp · 2016-08-24 · yuex
  • 可能你已经比较熟悉 asm 函数调用的参数传递和地址跳转了,不过这里还是做一个简单的概 述。毕竟这是最基本的程序单元。

    地址跳转

    asm 中的地址跳转是通过 callret 进行的,但经常容易忽略的一个事实是

    call 会将下一条指令的地址 (pc) 压栈
    ret 会从栈上弹出一个地址到 pc
    

    也就是说这两条指令都会导致栈指针的变化。在 32 位系统中,由于参数传递是通过压栈进 行的,要注意的是 call 一般都是在参数传递压栈之后(也必须这样),所以函数调用的返 回地址总是紧临被调用函数的 stack frame。

    在 32 位系统中,在每次调用后,被调用函数一般还要维护 esp 和 ebp。一般都是将 ebp 压到栈 上,紧临返回地址。leave 是一个复合指令,用于弹栈以恢复 ebp。

    参数传递

    32 位系统中是依靠压栈进行参数传递的。而在 64 位系统中,小于等于六个的参数是通过寄 存器传递的 …

  • CSAPP 之 struct 填充

  • book · csapp · 2016-08-24 · yuex
  • 在 C 语言中计算定义的 struct 类型的大小应该是每个 C 语言初学者绕不过的门槛。毕竟这是 一门系统编程语言,如果连自己定义的数据类型的内存大小都算不对,那么哪里还谈得上 压榨系统性能呢?struct 填充初看其实非常简单

     所有数据类型要对齐到其类型大小的内存地址上
    

    但其实这其中还有几个点很容易被忽略。而一旦忽略了这几个点,在某些情况下就会计算 不对 struct 类型的大小

    1. struct 类型的尾部要进行填充,以保证下一个连续的同类型的 struct 可以正常对齐
    

    简言之就是,尾部要填充以保证后续地址对齐到其内含的最大的数据类型大小

    2. 32 位系统以的对齐以指针大小 4 为上限
    

    这在 64 位系统中可能感觉不深,因为最大的基本数据长度就是 8 个字节嘛。但在 32 位系统中 ,地址大小是 4 个字节,如果内含了 double 类型,需要注意这个变量是对齐到 4 而不是 8。因 为 double 大小已经超出了指针大小,会被视为复合类型而非基本类型。而在 64 …