可将操作系统定义为一种软件,控制硬件资源,提供程序运行环境。通常称之为内核
UNIX操作系统体系结构:
内核的接口被称为系统调用。公用函数库构建在系统调用接口之上,应用程序既可使用公用函数库,也可使用系统调用。shell是一个特殊的应用程序,为运行其他应用程序提供了一个接口。
UNIX中一切皆文件,文件在Unix环境中是非常重要的东西,Unix文件系统就是一个虚拟层次结构,所有目录都挂载于/根目录,文件夹也可以被认为是一种文件,设备也是一种文件。
斜线(/)和空字符不能出现在文件名中,斜线用来分隔构成路径名的各文件名,空字符则用来终止一个路径名。文件系统根的名字(/)是一个特殊的绝对路径名,它不包含文件名。
1、文件描述符
通常是一个小的非负整数,内核用以标识一个特定进程正在访问的文件。当内核打开一个现有文件或创建一个新文件时,它都返回一个稳健描述符。在读写文件时,可以使用这个描述符。
两个常量STDIN_FILENO和STDOUT_FILENO定义在
程序是一个存储在磁盘上某个目录中的可执行文件,程序的执行实例被称为进程。
一个进程内的所有线程共享同一地址空间、文件描述符、栈以及与进程相关的属性。因为它们能访问同一储存区,各线程在访问共享数据时需要采取同步措施以避免不一致性。
线程ID只在它所属的 进程中起作用
当UNIX系统出错时,通常会返回一个负值,设置在整形变量errno
文件
E2BIG Argument list too long (POSIX.1)
EACCES Permission denied (POSIX.1)
EADDRINUSE Address already in use (POSIX.1)
EADDRNOTAVAIL Address not available (POSIX.1)
EAFNOSUPPORT Address family not supported (POSIX.1)
EAGAIN Resource temporarily unavailable (may be the same value as EWOULDBLOCK) (POSIX.1)
EALREADY Connection already in progress (POSIX.1)
EBADE Invalid exchange
EBADF Bad file descriptor (POSIX.1)
EBADFD File descriptor in bad state
EBADMSG Bad message (POSIX.1)
EBADR Invalid request descriptor
EBADRQC Invalid request code
EBADSLT Invalid slot
EBUSY Device or resource busy (POSIX.1)
ECANCELED Operation canceled (POSIX.1)
ECHILD No child processes (POSIX.1)
ECHRNG Channel number out of range
ECOMM Communication error on send
ECONNABORTED Connection aborted (POSIX.1)
ECONNREFUSED Connection refused (POSIX.1)
ECONNRESET Connection reset (POSIX.1)
EDEADLK Resource deadlock avoided (POSIX.1)
EDEADLOCK Synonym for EDEADLK
EDESTADDRREQ Destination address required (POSIX.1)
EDOM Mathematics argument out of domain of function (POSIX.1, C99)
EDQUOT Disk quota exceeded (POSIX.1)
EEXIST File exists (POSIX.1)
EFAULT Bad address (POSIX.1)
EFBIG File too large (POSIX.1)
EHOSTDOWN Host is down
EHOSTUNREACH Host is unreachable (POSIX.1)
EIDRM Identifier removed (POSIX.1)
EILSEQ Illegal byte sequence (POSIX.1, C99)
EINPROGRESS Operation in progress (POSIX.1)
EINTR Interrupted function call (POSIX.1); see signal(7).
EINVAL Invalid argument (POSIX.1)
EIO Input/output error (POSIX.1)
EISCONN Socket is connected (POSIX.1)
EISDIR Is a directory (POSIX.1)
EISNAM Is a named type file
EKEYEXPIRED Key has expired
EKEYREJECTED Key was rejected by service
EKEYREVOKED Key has been revoked
EL2HLT Level 2 halted
EL2NSYNC Level 2 not synchronized
EL3HLT Level 3 halted
EL3RST Level 3 halted
ELIBACC Cannot access a needed shared library
ELIBBAD Accessing a corrupted shared library
ELIBMAX Attempting to link in too many shared libraries
ELIBSCN lib section in a.out corrupted
ELIBEXEC Cannot exec a shared library directly
ELOOP Too many levels of symbolic links (POSIX.1)
EMEDIUMTYPE Wrong medium type
EMFILE Too many open files (POSIX.1); commonly caused by exceeding the RLIMIT_NOFILE resource limit described in getr‐
limit(2)
EMLINK Too many links (POSIX.1)
EMSGSIZE Message too long (POSIX.1)
EMULTIHOP Multihop attempted (POSIX.1)
ENAMETOOLONG Filename too long (POSIX.1)
ENETDOWN Network is down (POSIX.1)
ENETRESET Connection aborted by network (POSIX.1)
ENETUNREACH Network unreachable (POSIX.1)
ENFILE Too many open files in system (POSIX.1); on Linux, this is probably a result of encountering the /proc/sys/fs/file-
max limit (see proc(5)).
ENOBUFS No buffer space available (POSIX.1 (XSI STREAMS option))
ENODATA No message is available on the STREAM head read queue (POSIX.1)
ENODEV No such device (POSIX.1)
ENOENT No such file or directory (POSIX.1)
ENOEXEC Exec format error (POSIX.1)
ENOKEY Required key not available
ENOLCK No locks available (POSIX.1)
ENOLINK Link has been severed (POSIX.1)
ENOMEDIUM No medium found
ENOMEM Not enough space (POSIX.1)
ENOMSG No message of the desired type (POSIX.1)
ENONET Machine is not on the network
ENOPKG Package not installed
ENOPROTOOPT Protocol not available (POSIX.1)
ENOSPC No space left on device (POSIX.1)
ENOSR No STREAM resources (POSIX.1 (XSI STREAMS option))
ENOSTR Not a STREAM (POSIX.1 (XSI STREAMS option))
ENOSYS Function not implemented (POSIX.1)
ENOTBLK Block device required
ENOTCONN The socket is not connected (POSIX.1)
ENOTDIR Not a directory (POSIX.1)
ENOTEMPTY Directory not empty (POSIX.1)
ENOTSOCK Not a socket (POSIX.1)
ENOTSUP Operation not supported (POSIX.1)
ENOTTY Inappropriate I/O control operation (POSIX.1)
ENOTUNIQ Name not unique on network
ENXIO No such device or address (POSIX.1)
EOPNOTSUPP Operation not supported on socket (POSIX.1)
(ENOTSUP and EOPNOTSUPP have the same value on Linux, but according to POSIX.1 these error values should be dis‐
tinct.)
EOVERFLOW Value too large to be stored in data type (POSIX.1)
EPERM Operation not permitted (POSIX.1)
EPFNOSUPPORT Protocol family not supported
EPIPE Broken pipe (POSIX.1)
EPROTO Protocol error (POSIX.1)
EPROTONOSUPPORT Protocol not supported (POSIX.1)
EPROTOTYPE Protocol wrong type for socket (POSIX.1)
ERANGE Result too large (POSIX.1, C99)
EREMCHG Remote address changed
EREMOTE Object is remote
EREMOTEIO Remote I/O error
ERESTART Interrupted system call should be restarted
EROFS Read-only filesystem (POSIX.1)
ESHUTDOWN Cannot send after transport endpoint shutdown
ESPIPE Invalid seek (POSIX.1)
ESOCKTNOSUPPORT Socket type not supported
ESRCH No such process (POSIX.1)
ESTALE Stale file handle (POSIX.1)
This error can occur for NFS and for other filesystems
ESTRPIPE Streams pipe error
ETIME Timer expired (POSIX.1 (XSI STREAMS option))
(POSIX.1 says "STREAM ioctl(2) timeout")
ETIMEDOUT Connection timed out (POSIX.1)
ETXTBSY Text file busy (POSIX.1)
EUCLEAN Structure needs cleaning
EUNATCH Protocol driver not attached
EUSERS Too many users
EWOULDBLOCK Operation would block (may be same value as EAGAIN) (POSIX.1)
EXDEV Improper link (POSIX.1)
EXFULL Exchange full
linux支持多线程存取errno,定义为:
extern int *__errno_location(void);
#define errno (*__errno_location())
errno两条规则:
如果没有出错,其值不会被例程清除,仅当函数的返回值指明出错时,才检验其值。
任何函数都不会将errno设置为0。
C标准定义了两个函数,用于打印出错信息。
#include
char *strerror(int errnum);
strerror函数将errnum(通常就是errno值)映射为一个出错消息字符串,并且返回此字符串的指针。
perror函数基于errno的当前值,在错误标准上产生一条出错信息,然后返回
#include
void perror(const char *msg);
#include "apue.h"
#include
int
main(int argc, char *argv[])
{
fprintf(stderr, "EACCES: %s\n", strerror(EACCES));
errno = ENOENT;
perror(argv[0]);
exit(0);
}
编译执行:
./testerror
EACCES: Permission denied
./testerror: No such file or directory
我们将argv[0]作为perror参数,让程序名作为错误信息一部分来输出,是一种Unix编程惯例,我们经常可以看到,当程序运行失败的时候,会出现失败程序的名称,这样就能很方便的分清出错程序是哪一个。
用户id(uid)是一个数值,它向系统标识不同的用户,uid为0的用户即为root用户,它能对系统为所欲为,在查看很多GNU软件的源代码的时候,我们经常可以看到这样的代码
if (getuid() == 0)
也就是说一个进程拥有root权限,那么大部分文件权限检查都不再执行。
组id(gid)是一个数值,用于确定用户所属用户组。这种机制能够让同组内的不同成员共享资源,系统维护了一个uid、gid与用户名、组名映射对应的机制,一般情况下就是/etc/passwd和/etc/group文件,目前大部分的Unix系统使用32位整形表示uid和gid,我们可以通过检查uid_t和gid_t来确定。
#include "apue.h"
int
main(void)
{
printf("uid = %d, gid = %d\n", getuid(), getgid());
exit(0);
}
每个用户除了在/etc/passwd中指定了一个gid以外,大多数Unix版本还允许一个用户属于其他一些组,POSIX标准要求系统应该最少支持8个附属组,但是实际上大多数系统都支持至少16个附属组。
注:Mac OS X系统并非依靠/etc/passwd来维护用户列表,这个文件只有系统以单用户模式启动的时候才会使用
信号用于通知进程发生了某些情况。例如一个进程执行了除以0的操作,CPU引发中断,内核截获中断,然后发出SIGFPE(浮点异常)信号给进程,进程有三种方式处理信号:
1.忽略信号。由于很多信号表示硬件异常,例如,除以0或者访问进程地址空间以外的存储单元,因为这些异常引起的后果不明确,所以不推荐使用这种方式。
2.系统默认方式处理。对于很多信号,系统默认方式就是终止进程,这点非常类似现代编程语言中异常的抛出,例如Node.js对于异常不捕获的操作,就是终止进程
3.提供一个函数,信号发生时调用该函数这被称为捕捉该信号。通过提供自编的函数,我们就能知道什么时候产生了信号,并按期望的方式处理它。
很多情况都会产生信号,终端键盘CTRL+C和CTRL+\通常能产生信号终止当前进程,也可以使用kill命令或者kill函数,从当前终端或者进程向另外一个进程发送一个信号,当然,想要发送一个信号,我们必须是接受信号的进程的所有者或者root用户。
历史上,UNIX系统使用过两种不同的时间值。
(1)日历时间。该值是自协调世界时(UTC) 1970年1月1日00:00:00这个特定时间以来所经过的秒数累计值。这个时间值可用于记录文件最近一次的修改时间等。
系统基本数据类型time_t用于保存这种时间值。
(2)进程时间。也被称为CPU时间,用以度量进程使用的中央资源处理器资源。进程时间以时钟滴答计算。每秒钟曾经取为50、60或100个时钟滴答。
系统基本数据类型clock_t保存这种时间值
Unix系统为一个进程维护了三个进程时间值
时钟时间
用户CPU时间
系统CPU时间
时钟时间也称为真实事件,是进程运行的时间总量,用户CPU时间是执行用户指令所用的时间量,系统CPU时间是指执行内核指令所用的时间量,用户CPU时间与系统CPU时间之和就是CPU时间。
cd /usr/include/
time -p grep _POSIX_SOURCE */*.h > /dev/null
real 1.65
user 0.01
sys 0.02
某些shell并不运行/usr/bin/time程序,而是使用内置函数测量
系统调用与库函数之间有根本的区别,我们可以替换库函数,但是系统调用通常是不能被替换的。
例如内存管理malloc函数族,它是一种通用存储器管理器,它自己的描述是这样的
The malloc(), calloc(), valloc(), realloc(), and reallocf() functions allocate memory. The allocated memory is aligned such that it can
be used for any data type, including AltiVec- and SSE-related types. The free() function frees allocations that were created via the
preceding allocation functions.
而Unix系统内部的分配内存的系统调用是sbrk和’brk’,它们并不分配变量内存,它们只是根据字节数改变segment size,正如系统手册上写的
The brk and sbrk functions are historical curiosities left over from earlier days before the advent of virtual memory management. The
brk() function sets the break or lowest address of a process's data segment (uninitialized data) to addr (immediately above bss). Data
addressing is restricted between addr and the lowest stack pointer to the stack segment. Memory is allocated by brk in page size pieces;
if addr is not evenly divisible by the system page size, it is increased to the next page boundary.
malloc只是实现了类型内存分配,但是分配内存用的还是sbrk系统调用,如果有兴趣,我们完全可以自行实现内存的分配,但是我们不可能越过系统调用。换言之,系统调用分配了空间,而malloc只是在用户层次管理分配的内存空间。