Posted in FreeBSD, 学习 on September 6th, 2008 No Comments »
出自:
http://www.mydigitallife.info/2006/04/23/freebsd-apache-http-accept-filter-error/
When Apache web server is starting up in FreeBSD system, Apache loads succcessfully and web server functioning properly, but the following warning error occurs:
[warn] (2)No such file or directory:
Failed to enable the ‘httpready’ Accept Filter
The resolution to the above problem is to a accf_http module, which function is to buffer incoming connections until a certain [...]
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 28th, 2006 No Comments »
FreeBSD系统启动后内核首先建立13个系统进程,这些进程叫做内核进程。内核还会为设备创建相应的内核进程,来处理设备的中断。在内核建立了所有的内核进程之后,开始建立用户态的进程,init为1号进程,其他所有的用户进程都从这个进程派生而来。
用户进程通过系统调用来使用内核提供的服务。当然,进入内核的方式不仅仅限于系统调用,如下三种方式,均可以进入内核(包括系统调用),它们是:硬件中断,硬件陷阱,软件产生的陷阱。
内核在运行的时候分为上下两个部分,上半部分主要是和用户进程的系统调用还有一些陷阱作出反应,上半部分是在特权模式下运行的,既可以访问内核的数据结构也可以访问用户进程的context,下半部分也是在特权模式下运行的,主要负责处理硬件中断,包括了处理硬件中断的例程。中断操作和中断源是同步的,但是跟上半部分的运行是异步的。
所以说,在上半部分运行的时候,有可能被下半部分运行的中断所打断。如果上半部分进程不想被某个设备的中断打断,需要将一个新的工作项链接到该设备的工作链表。
通过陷阱或者中断进入内核的时候,在开始提供系统服务之前,内核必须保存当前的许多状态,例如程序计数器,用户堆栈,寄存器,处理器状态字等信息。保存这些信息的目的是为了在从内核中返回到用户态的时候可以恢复进入内核服务之前的状态。
发生系统调用的时候,无论系统调用是否成功,最终都会返回到用户进程。如果系统调用失败,那么在全局变量errno中的值为错误代码,返回寄存器中的值设置为-1,用户进程看到返回寄存器为-1就可以断定系统调用失败,那么去查找errno的值,确定具体的错误。
系统调用发生错误有两种可能性:1系统内核检测到有错误发生。2在系统调用过程中收到中断信号,如果当时中断处理程序指定被中断的系统调用直接返回一个错误,那么系统调用失败。
如果系统调用过程中收到了信号,那么系统调用退出之前先要执行相应的信号处理程序,执行完毕后系统调用检查是否有更高级的进程需要优先运行,如果有,系统调用的退出代码就会调用上下文切换例程,返回,然后继续执行用户的进程(如果在此之前还需要内核剖析数据,那么系统退出代码还会执行剖析数据的相关操作)。
中断方式有如下的优先级:硬中断>软中断>用户进程。一般硬件中断都是由硬件设备发起的,软件中断用于类似于网络处理,进程调度等。
时钟中断,每秒100个节拍,每个节拍都产生中断,会调用hardclock()例程,hardclock()例程需要很快执行完毕。hardclock()优先级很高,如果需要处理稍低一些的优先级,则需要softclock()系统调用。
softclock调用通常是安排周期性事件:
进程的实时定时器。
网络丢包重传。
外设上需要监视的watchdog定时器。
系统进程重新调度的事件。
还有另外两个时钟,statclock每秒128拍,用于收集系统统计信息,profclock每秒1024拍,用于收集剖析信息。
FreeBSD内核的内存管理,每个进程开始执行的时候有代码段,数据段,堆栈段。数据段还分为初始化数据段和非初始化数据段。
在FreeBSD中,每一个可执行文件都有一个exec头,包含了幻数,这个幻数指定了可执行文件的类型,在FreeBSD可执行文件类型有脚本,AOUT,ELF,和采用gzip压缩过的ELF格式。 文件头还指出了代码,初始化数据,为初始化数据,调试信息的大小。在FreeBSD5.2中,非初始化数据中的数据段全被置为0。
FreeBSD5.2中采用demand paging技术来将程序载入内存。当载入静态连接的二进制文件的时候,所有的库例程和系统调用都会加到二进制文件中,而对于动态连接的二进制程序,内核会把一套共享库映射到二进制自己的地址空间中,在第一次调用共享库的例程的时候,会在共享库中找到那个例程,并且创建到该例程的动态连接。
FreeBSD中的内核向进程提供了几种不同的时间服务,包括实时运行的定时器,还有进程执行时才运行的定时器。
刚刚提到了profclock()时钟中断,在这个时钟中断中,除了收集剖析信息外,还要检查当前进程是否申请了剖析定时器,如果申请了,那么就对这个定时器减1(1个时间单位)。如果这个定时器的值为0,就向进程发送一个SIGPROF的信号。
profclock()中除了检查剖析定时器,还会检测虚拟定时器的,当虚拟定时器的值为0的时候,就会进程发送SIGVTALRM信号。
setuid和setgid, 当设置了一个setuid位的程序运行的时候,该进程拥有的权限为此程序对应uid的权限,这是进程的uid成为有效uid(effective UID),原来的uid成为real UID。对于setgid同理。
FreeBSD中还增加了saved UID作用于保存setuid程序的uid,setuid的执行会影响effective UID和saved UID,而seteuid则只影响effective UID 。内核中是通过effective UID来验证进程权限。
当然,还有类似saved UID同样的机制用于saved GID。
内核对于进程管理中还有进程组和会话的概念,FreeBSD中,一个进程组中有多个进程,一个会话中有多个进程组。每个进程都可以将自己所属于的进程组的ID设置为自己的PID(进程ID),这相当于新建立了一个进程组,任何一个进程,如果它不是一个进程组的先导进程,就可以建立新的会话。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
这几篇是对FreeBSD以及Unix历史,内核功能的一个概要性的学习,通过学习我对FreeBSD以及Unix操作系统有了一个宏观上的认识,今后的学习过程中,将深入学习研究这十二篇学习笔记中提及到的一些概念,功能的具体实现。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
在学习Linux的时候,曾经提到过系统启动流程,现在简述一下FreeBSD的启动流程。首先FreeBSD的启动内核被加载到内存中,然后进行初始化,将硬件设置为已知状态。接下来内核进行初始化工作,随后系统进入single user mode,接下来就是检测硬盘,启动配额检查,一切正常后,系统进入多用户模式。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
FreeBSD中的进程间通信是在通信域中进行的,有如下几种通信域:
PF_UNIX, PF_LOCAL Local communication unix(7)
PF_INET IPv4 Internet protocols ip(7)
PF_INET6 IPv6 Internet protocols
PF_IPX IPX - Novell protocols
PF_NETLINK Kernel user interface device netlink(7)
PF_X25 ITU-T X.25 / ISO-8208 protocol [...]
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
最早,可以通过RS232的终端来与计算机进行交互,这对后来FreeBSD的伪终端的出现起到了重要的影响。伪终端涉及到主设备和从设备,从设备连接到伪终端的主设备,任何写入从设备的内容作为主设备的输入,写入主设备的内容也作为从设备的输入。
一般情况下,终端使用默认的行规程,输入是一行一行提供给进程的。 非规范模式是只输入是一次一个字符的传给进程,不对输入的字符作处理。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
对于Unix的文件系统,用户看来只有一个,实际上这是一个虚拟的文件系统,它是由很多物理的文件系统构成的。一个物理设备上可以拥有多个文件系统,反过来是不行的。这些文件系统位于在物理设备上划分出来的逻辑设备上,每个逻辑设备上只能有一个文件系统。
另外,Unix中的系统调用link曾经用来实现mkdir,rmdir操作。4.2BSD中已经专门加入了这些系统调用主要出于下面的目的:原子性,网络文件系统中的原子性,不同文件系统的操作。
FreeBSD中除了使用3级控制机制来控制文件的访问权限(777,775等),还可以通过ACL这样的访问控制列表对每个用户或者每个组指定读、写和执行权限。
另外,文件的内容在物理设备上的具体存储方式是通过filestore来负责的。FreeBSD使用的文件系统是伯克利的快速文件系统。FreeBSD采用了soft update机制来确保故障后的恢复能力同时不失良好的性能。
另外关于网络文件系统NFS,用户可以在本地装载位于网络中其他机器上的文件系统,对于用户来说,和操作本地的文件系统没有区别。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
为了简化大多数程序进行I/O操作,UNIX系统中的I/O被简化为一个字节序列,可以顺序访问也可以随机访问。在用户进程中既没有访问方法也没有控制块。
UNIX进程中,使用描述符来表是一个I/O流,通过open或者socket这样的系统调用返回描述符。然后通过write,read系统调用进行I/O操作。
FreeBSD中,描述符可以表示4中类型的对象:文件,管道,fifo,套接口。
在4.2BSD之前的系统,管道通过文件系统实现的,通过标准输入和标准输出实现。当4.2BSD中引入了套接口,管道便通过套接口来实现,但是在FreeBSD中,并没有使用套接口来实现管道和fifo。
内核中会为每个进程维护描述符表,这个描述符表记录了进程中的描述符的外部表示对应的内部表示形式。一个进程的描述服可以从父进程处继承下来,也可以创建或者打开一个新的对象来获得描述符。
在Unix系统中,系统内核将设备视为文件,用户可以像访问普通文件一样访问设备,而访问的具体细节,硬件相关性代码则封装在驱动程序中。
4.2BSD中还有一个叫做分散/聚集I/O,可以同时在一个进程地址空间的不同部分的缓冲区中I/O数据 ,保证原子性,以及提高了I/O效率。
FreeBSD中(其他Unix也是如此),通过在内核中加入了虚拟节点来实现多文件系统的支持,通过可动态加载的内核模块实现的。
FreeBSD中的设备管理也针对于现在的许多设备可以热插拔的特点进行了扩展,使用一种newbus的设备驱动程序来管理plug&play设备。另外在GEOM层实现操作系统的磁盘管理。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
FreeBSD的虚拟内存系统是对4.4BSD的虚拟内存的实现做了调整之后的版本。具有如下特点:共享机制的效率高,彻底分离了硬件无关与硬件相关功能,并且支持多处理器。
虚拟内存的作用是可以将用户进程中的数据传入到系统内核的数据缓冲区中。一般情况下,会通过从进程的地址空间复制到内核的缓冲区中的方法。但是如果需要复制的数据非常大,那么复制操作会十分的费时,引此使用虚拟内存的内存空间映射技术可以代替复制数据的办法,提高效率。内存映射通过mmap()系统调用实现。
内核中的内存分配很多情况都需要动态分配内存,FreeBSD内核中加入了一种通用的内存分配机制。除了这种方式还有一种区域分配方式,可以在一个区域内分配内存。
Posted in FreeBSD, Unix,Linux,BSD, 学习 on December 25th, 2006 No Comments »
FreeBSD支持多进程,每一个任务或者过程就被称作一个进程。进程的上下文context分为两个状态,用户态和系统态。
内核通过fork来创建一个新的进程, 子进程中的context完全复制于父进程,当然我们可以通过execve来覆盖掉子进程中原父进程的context。根据fork调用的返回值可以判断当前程序流程中的代码段是父进程的还是子进程的,如果返回值不为0,那么当前的代码段为子进程,否则则应该为父进程。
系统调用exit可以结束一个进程,并且向该进程的父进程发送8bit的退出状态码。 如果要发送超过1个字节的信息,则需要通过进程间通信的一些方式,例如管道,套接口,或者共享文件的方式。
如果一个子进程由于父进程先于其退出,而变为orphan进程,那么系统会自动将init进程设置为该orphan进程的父进程,负责orphan进程的内存回收等工作。
进程中可以接收系统发来的信号,可以采用系统默认方式处理,也可以采用由用户指定处理方式的方式进行处理。整个处理过程如同中断处理机制,首先保存进程上下文,然后创建新的上下文,接下来执行信号处理程序,处理完毕后可以结束进程,也可以返回进程原来的执行处。整个信号处理的过程要阻塞该信号,以免产生新的信号。
进程组表示一组相关的进程,创建进程组的时候,进程组的编号和创建它的进程的进程标识一样。例如管道的应用就会将管道中的所有进程放在同一个进程组中。
用户可以对整个进程组中的进程进行控制。每个控制终端也有一个进程组标识符,只有进程的进程组标识符和控制终端相同的时候才可以读取终端的描述符信息。