您的位置:首页 > 编程语言

进程编程2 – Unix环境高级编程8章读书笔记

2008-06-08 20:47 393 查看
Process Control

1 Process Identifiers

1.     PID=0一般是调度进程,又称为swapper2.     PID=1一般是init进程,在引导过程之后启动,负责启动整个UNIX系统,所有Orphaned子进程都会自动成为init的子进程3.     PID=2一般是页面守护进程,负责将虚拟内存的换页4.     下面函数被用来获得pid:
#include   pid_t getpid(void);   返回进程pid   pid_t getppid(void);   返回父进程的pid   uid_t getuid(void);   返回进程的user id       uid_t geteuid(void);   返回进程的effective user id   gid_t getgid(void);   返回进程的group id   gid_t getegid(void);   返回进程的effective group id
 

2 fork

fork函数原型如下:
#include   pid_t fork(void);   在子进程中返回0,父进程中返回实际的子进程pid,-1则出错
1.     这个函数创建出一个和父进程相同的子进程,比较特别的是子进程也会从这个函数调用,和父进程只是返回值不同。2.     子进程起初和父进程共享同样的物理内存,当某个页面被修改的时候,系统会给子进程分配新的空间给这个页面。这个行为被称为COW (Copy On Write)3.     父进程还是子进程先继续执行无法预测4.     父进程的所有文件描述符在子进程中都被调用dup函数复制,并且文件offset是在子进程和父进程之中共享的5.     子进程继承了父进程的下列特性:a.     File Descriptorsb.     Real user ID, real group ID, effective user ID, effective group IDc.     Supplementary group IDsd.     Process group IDe.     Session IDf.      Controlling terminalg.     Set-user-ID & set-group-ID flagsh.     Working directoryi.      Root directoryj.      File mode creation maskk.     Signal mask & dispositionsl.      The close-on-exec flag for any open file descriptionsm.    Environmentn.     Attached shared memory segmentso.     Memory mappingp.     Resource limits6.     子进程和父进程不同的地方有:a.     fork函数的返回值b.     Process IDc.     Parent process IDd.     tms_utime, tms_stime, tms_cutime, tms_cstime = 0e.     File lock不被子进程继承f.      Pending alarm被清除g.     Pending signal被清除7.     fork失败的可能性有:a.     系统中的进程过多b.     超过系统设置的limit

3 vfork

vfork的原型和返回值和fork相同,区别在于:1.     创建的子进程和父进程共享同一个地址空间2.     创建的子进程一般的作用是再调用exec创建一个新的进程,在某些系统上可能会有一些优化

4 exit

1.     当父进程先于子进程退出的时候,子进程会变成orphaned并被init进程“收养”,init成为这些子进程的新的父进程。2.     当子进程先于父进程退出的时候,而且父进程也没有用wait, waitpid函数等待子进程结束,则子进程的部分信息会被保存起来,如PID,退出状态,CPU时间等,直到子进程被wait。处于这样状态的子进程被称为zombie3.     被init进程inherit的子进程如果中止不会变成zombie,因为init会自动当进程结束的时候调用wait

5 wait & waitpid

1.     当子进程结束的时候,父进程会收到SIGCHLD通知2.     进程可以调用wait / waitpid等待此Signal:a.     当所有子进程都在执行的时候,会blockb.     当某个子进程中止,成为zombie的时候,立刻返回c.     如果没有任何子进程,则返回错误3.     wait和waitpid函数原型如下:
#include   pid_t wait(void);   pid_t waitpid(pid_t pid, int *statloc, int options);   正常情况下返回pid,或者0(waitpid在非block模式下才有可能返回),-1代表错误
 4.     这两个函数区别如下:a.     Wait函数会因为等待子进程结束而block,而waitpid有一个option可以允许waitpid函数不blockb.     waitpid等待某个特定进程5.     waitpid函数的statloc参数保存了退出进程的状态,当然也可以传NULL。这个状态通常和实现相关,不过可以用wait.h中定义的macro来检测。a.     WIFEXITED(status):返回值b.     WIFSIGNALED(status):返回造成退出的signal的numberc.     WIFSTOPPED(status):是否被stop,可以用WSTOPSIG(status)来获得具体的signald.     WIFCONTINUED(status):返回是否被continue6.     waitpid的pid参数:a.     pid == -1:等待任意子进程,等价于waitb.     pid > 0,等待pid指定的子进程c.     pid == 0,等待和调用进程相同group id的任意子进程d.     pid < -1,等待任意group id = pid的绝对值的子进程7.     waitpid的options参数可以是下面的组合:a.     WCONTINUED:等待任何指定的子进程在stop之后被continueb.     WNOHANG:如果还没有退出,不block,返回0c.     WUNTRACED:被stopped的进程 

6 waitid

waitid函数在waitpid函数上提供了额外的灵活性:
#include   int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);   成功返回0,错误返回-1
1.     idtype_t可以是下面的值之一:a.     P_PID:等待某指定的子进程b.     P_PGID:等待任意指定group id的子进程c.     P_ALL:任意子进程,id会被忽略2.     Options可以是下面的值:a.     WCONTINUED:等待被stop并且被continue的进程b.     WEXITED:等待退出的进程c.     WNOHANG:如果没有子进程需要等待则立刻返回d.     WNOWAIT:不会将zombie子进程的退出状态撤销,下次调用wait系列函数的时候还可以继续获得这个退出状态e.     WSTOPPED:等待被stop的进程3.     Infop指向一个siginfo_t结构,表示使得进程退出的signal的产生原因: 
struct siginfo_t {       int   si_signo;   /* signal */       int   si_errno;   /* errrno */       int   si_code;    /* 额外信息,和具体signal相关 */       pid_t si_pid;     /* 发送signal进程的pid */       uid_t si_uid;     /* 发送signal的进程的uid */       void  *si_addr;   /* 产生fault(SIG_SEGV)的地址 */       int   si_status;  /* 退出值或者signal数值 */       long  si_band;    /* SIGPOLL的band数值 */ };
 

7 wait3 & wait4

这两个函数的用处是返回额外的关于进程资源使用状况的信息,以struct rusage *rusage的形式返回

8 exec functions

之前提到了vfork可以创建一个并非是父进程copy的子进程,专门用来调用exec函数。exec系列函数的作用是调用一个新的程序在该进程中运行,PID不改变,也没有创建新进程,只是replace当前的进程,该函数成功情况下不会返回。原型如下:
#include   int execl(const char *pathname, const char *arg0, … /* (char *) 0 */ );   int execv(const char *pathname, char *const argv[]);   int execle(const char *pathname, const char *arg0, … /* (char *)0, char *const envp[] */);   int execve(const char *pathname, char *const argv[], char *const envp[]);   int execlp(const char *filename, const char *arg0, … /* (char *)0 */ );   int execvp(const char *filename, char *const argv[]);   错误返回-1,成功不会返回
 1.     前面4个是pathname,后面两个则是filename。Filename如果有’/’字符,则被认为是pathname,否则认为是filename并会在PATH路径指定的位置查找2.     execlp和execvp对于非可ELF执行文件会认为是Shell脚本来处理3.     execl, execlp, execle需要每个参数单独传递,NULL作为结束。而execv, execvp, execve则是传入argv4.     execle, execve可以传入环境,其他四个函数则会使用environ变量中的内容总结一下,各个字符代表的意义是:1.     v:用argv传入参数2.     l:用每个参数作为argument传入3.     e:传入环境,没有的话则使用environ变量的值4.     p:传入的是filename,并会处理PATH的内容,否则是pathname需要注意的是,exec调用之后进程的real user ID和real group ID不变,如果被执行的程序的set-user-ID位被设置,effective user ID被设置成owner ID。也就是说,如果一个normal user用exec执行了一个owner为superuser的程序,并且该程序的set-user-id被设置,那么一旦该程序被运行,该程序的effective user id=super user,这可能是潜在的安全问题。

9 Change User IDs and Group IDs

1.     User ID & Group ID的意义如下:
ID Description
real user ID real group ID 真正的user ID和group ID
effective user ID effective group ID supplementary group ID 用于文件访问权限检查
saved set-user-ID saved set-group-ID 由exec保存起来。如果没有提供这个feature(通过_POSIX_SAVED_IDS)可以判断,则这些ID不存在
 2.     setuid 和setgid函数用来设置User ID / Group ID,原型如下:
#include   int setuid(uid_t uid);   int setgid(gid_t gid);   成功返回0,错误返回-1
 3.     setuid的规则如下:a.     有超级用户的权限的进程,setuid会修改real user id, effective user ID, & saved set-user-ID为uidb.     当进程没有超级用户权限,并且uid = real user ID / saved set-user-ID的话,setuid会修改effective user ID为uidc.     否则,errno被设置为EPERM,返回-1d.     上面这些规则也适用于setgid4.     对于uid下面规则成立:a.     只有超级用户的进程才可以改变real user ID。一般情况下不会改变real user IDb.     当程序的set-user-ID位被设置,exec才会设置effective user ID为程序的user ID,否则则不改变c.     Saved set-user-ID从exec所设置的effective user ID拷贝而来5.     POSIX.1还提供了两个函数seteuid和setegid,用来修改effective user ID / effective group IDa.     对于一般用户,只能设置effective user ID为real user ID或者saved set-user-ID,不能为其他值b.     对于超级用户,可以设置effective user ID为任意值 

10 system

1.     System函数用于执行参数中给出的string,调用程序2.     System函数的基本实现是调用fork,在子进程中调用exec执行/bin/sh或者其他shell,执行命令,父进程调用waitpid等待子进程的结束3.     之前在讨论exec的时候提到过, exec调用之后进程的real user ID和real group ID不变,如果被执行的程序的set-user-ID位被设置,effective user ID被设置成owner ID。也就是说,如果一个normal user用exec执行了一个owner为superuser的程序,并且该程序的set-user-id被设置,那么一旦该程序被运行,该程序的effective user id=super user (real user ID不变),这可能是潜在的安全问题。这个问题同样适用于system

11 User Identification

getlogin函数可以获得用户名:
#include   char *getlogin(void);   成功返回具体name,错误返回NULL
 

12 Process Times

times函数可以获得和进程相关的时间:
#include   clock_t times(struct tms *buf);   成功返回wall clock time,错误返回-1
tms结构如下:
struct tms {       clock_t     tms_utime;        /* user CPU time */       clock_t     tms_stime;        /* system CPU time */       clock_t     tms_cutime;       /* user CPU time, terminated children */       clock_t     tms_cstime;       /* system CPU time, terminated children */ };
 作者:      ATField
Blog:      http://blog.csdn.net/atfield
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: