apue(6)

来源:互联网 发布:windows 7 toolkit 编辑:程序博客网 时间:2024/06/11 18:58
 

8.2. Process Identifiers

Process ID 0 is usually the scheduler process and is often known as the swapper. Process ID 1 is usually the init process and is invoked by the kernel at the end of the bootstrap procedure. #include <unistd.h> pid_t getpid(void); pid_t getppid(void); uid_t getuid(void); uid_t geteuid(void); gid_t getgid(void); gid_t getegid(void);

8.3. fork Function

#include <unistd.h> pid_t fork(void); Returns: 0 in child, process ID of child in parent, 1 on error (Process ID 0 is reserved for use by the kernel, so it's not possible for 0 to be the process ID of a child.) The child is a copy of the parent. For example, the child gets a copy of the parent's data space, heap, and stack. Note that this is a copy for the child; the parent and the child do not share these portions of memory. The parent and the child share the text segment. Often copy-on-write.

Variations of the fork function are provided by some platforms. All four platforms discussed in this book support thevfork(2) variant discussed in the next section.

Linux 2.4.22 also provides new process creation through theclone(2) system call. This is a generalized form of fork that allows the caller to control what is shared between parent and child.

In general, we never know whether the child starts executing before the parent or vice versa. Sizeof strlen 计算出来的字符串长度,一个包括null一个不包括null 行式缓冲在遇到一个/n后会直接清空缓冲,开启新一行。Full buffer不会。 疑问 #include <apue.h> int main(void) {  pid_t pid;  int i;  if((pid = fork()) < 0)  {  perror("fork");  exit(1);  }  else if (pid == 0)  {  for( i = 0; i !=20 ; ++i) printf("child/n");  fflush(stdout);  }  else  {  for( i = 0; i != 20; ++i) printf("parent/n");  fflush(stdout);  }  exit(0); } >temp.out  结果为 child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  arent (少个p parent  parent 或者 parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  parent  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child  child 不知到为什么?

File Sharing

Indeed, one characteristic of fork is that all file descriptors that are open in the parent are duplicated in the child. We say "duplicated" because it's as if the dup function had been called for each descriptor. The parent and the child share a file table entry for every open descriptor (recall Figure 3.8). 共享文件 The differences between the parent and child are

The child's tms_utime, tms_stime, tms_cutime, andtms_cstime values are set to 0

File locks set by the parent are not inherited by the child

Pending alarms are cleared for the child

The set of pending signals for the child is set to the empty set

There are two uses for fork:

  1. When a process wants to duplicate itself so that the parent and child can each execute different sections of code at the same time. This is common for network servers the parent waits for a service request from a client. When the request arrives, the parent calls fork and lets the child handle the request. The parent goes back to waiting for the next service request to arrive.

  2. When a process wants to execute a different program. This is common for shells. In this case, the child does anexec (which we describe in Section 8.10) right after it returns from the fork.

8.4. vfork Function

The vfork function is intended to create a new process when the purpose of the new process is to exec a new program (step 2 at the end of the previous section). The vfork function creates the new process, just like fork, without copying the address space of the parent into the child, as the child won't reference that address space. Instead, while the child is running and until it calls either exec or exit, the child runs in the address space of the parent.  Another difference between the two functions is that vfork guarantees that the child runs first, until the child calls exec or exit. When the child calls either of these functions, the parent resumes.  Child process can access father's global var.当子进程_exit(0)时,只是结束了自己。但如果用exit(0),可能关闭了父进程的fileprintf可能出错,不同系统实现不同。

8.5.exit Functions

In the case of an abnormal termination, however, the kernel, not the process, generates a termination status to indicate the reason for the abnormal termination. In any case, the parent of the process can obtain the termination status from either the wait or the waitpid function (described in the next section). 有四个宏通过wait或者waitpid的返回值判断子进程结束原因 父亲消失后,子进程以init为父进程。 子进程结束后,会留有一个僵尸进程等待父进程wait释放。

8.6. wait and waitpid Functions

When a process terminates, either normally or abnormally, the kernel notifies the parent by sending theSIGCHLD signal to the parent.

a process that calls wait or waitpid can

  • Block, if all of its children are still running

  • Return immediately with the termination status of a child, if a child has terminated and is waiting for its termination status to be fetched

  • Return immediately with an error, if it doesn't have any child processes

#include <sys/wait.h> pid_t wait(int *statloc); pid_t waitpid(pid_t pid, int *statloc, int options); Both return: process ID if OK, 0 (see later), or 1 on error

The differences between these two functions are as follows.

  • The wait function can block the caller until a child process terminates, whereaswaitpid has an option that prevents it from blocking.

  • The waitpid function doesn't wait for the child that terminates first; it has a number of options that control which process it waits for.

If a child has already terminated and is a zombie,wait returns immediately with that child's status. If the caller blocks and has multiple children,wait returns when one terminates. We can always tell which child terminated, because the process ID is returned by the function.

Statloc 用于保存终止信息,如果不需要可以使用NULL。用四个宏来判断。

The interpretation of the pid argument forwaitpid depends on its value:

pid == -1

Waits for any child process. In this respect,waitpid is equivalent to wait.

pid > 0

Waits for the child whose process ID equals pid.

pid == 0

Waits for any child whose process group ID equals that of the calling process. (We discuss process groups inSection 9.4.)

pid < -1

Waits for any child whose process group ID equals the absolute value of pid.


options

WCONTINUED

If the implementation supports job control, the status of any child specified by pid that has been continued after being stopped, but whose status has not yet been reported, is returned (XSI extension to POSIX.1).

WNOHANG(主要的)

The waitpid function will not block if a child specified by pid is not immediately available. In this case, the return value is 0.

WUNTRACED

If the implementation supports job control, the status of any child specified by pid that has stopped, and whose status has not been reported since it has stopped, is returned. TheWIFSTOPPED macro determines whether the return value corresponds to a stopped child process.

main(void) { pid_t pid; if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* first child */ if ((pid = fork()) < 0) err_sys("fork error"); else if (pid > 0) exit(0); /* parent from second fork == first child */ /* * We're the second child; our parent becomes init as soon * as our real parent calls exit() in the statement above. * Here's where we'd continue executing, knowing that when * we're done, init will reap our status. */ sleep(2); printf("second child, parent pid = %d/n", getppid()); exit(0); } if (waitpid(pid, NULL, 0) != pid) /* wait for first child */ err_sys("waitpid error"); /* * We're the parent (the original process); we continue executing, * knowing that we're not the parent of the second child. */ exit(0); }

8.7. waitid Function

#include <sys/wait.h> int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); 

The id parameter is interpreted based on the value of idtype.

Constant

Description

P_PID

Wait for a particular process: id contains the process ID of the child to wait for.

P_PGID

Wait for any child process in a particular process group: id contains the process group ID of the children to wait for.

P_ALL

Wait for any child process: id is ignored.

Options

Constant

Description

WCONTINUED

Wait for a process that has previously stopped and has been continued, and whose status has not yet been reported.

WEXITED

Wait for processes that have exited.

WNOHANG

Return immediately instead of blocking if there is no child exit status available.

WNOWAIT

Don't destroy the child exit status. The child's exit status can be retrieved by a subsequent call towait, waitid,or waitpid.

WSTOPPED

Wait for a process that has stopped and whose status has not yet been reported.

The infop argument is a pointer to asiginfo structure.

8.8. wait3 and wait4 Functions

#include <sys/types.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/resource.h> pid_t wait3(int *statloc, int options, struct rusage *rusage); pid_t wait4(pid_t pid, int *statloc, int options, struct rusage *rusage); 

The only feature provided by these two functions that isn't provided by thewait, waitid, and waitpid functions is an additional argument that allows the kernel to return a summary of the resources used by the terminated process and all its child processes.

The resource information includes such statistics as the amount of user CPU time, the amount of system CPU time, number of page faults, number of signals received, and the like.

Struct rusage 参见 getruage函数手册。

8.9. Race Conditions

Polling

To avoid race conditions and to avoid polling, some form of signaling is required between multiple processes. Signals can be used, and we describe one way to do this inSection 10.16. Various forms of interprocess communication (IPC) can also be used. We'll discuss some of these inChapters 15 and 17.

8.10. exec Functions

The process ID does not change across anexec, because a new process is not created; exec merely replaces the current processits text, data, heap, and stack segmentswith a brand new program from disk.

#include <unistd.h> 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 []); (char *)0 is needed. PATH=/bin:/usr/bin:/usr/local/bin/:. If either execlp or execvp finds an executable file using one of the path prefixes, but the file isn't a machine executable that was generated by the link editor, the function assumes that the file is a shell script and tries to invoke /bin/sh with the filename as input to the shell. After exec, the handling of open files depends on the value of the close-on-exec flag for each descriptor. The default is to leave the descriptor open across the exec unless we specifically set the close-on-exec flag using fcntl.

Note that the real user ID and the real group ID remain the same across theexec, but the effective IDs can change, depending on the status of the set-user-ID and the set- group-ID bits for the program file that is executed. If the set-user-ID bit is set for the new program, the effective user ID becomes the owner ID of the program file. Otherwise, the effective user ID is not changed (it's not set to the real user ID). The group ID is handled in the same way.

Only one of these six functions,execve, is a system call within the kernel.

8.11. Changing User IDs and Group IDs

#include <unistd.h> int setuid(uid_t uid); int setgid(gid_t gid);

If the process has superuser privileges, thesetuid function sets the real user ID, effective user ID, and saved set-user-ID to uid.

If the process does not have superuser privileges, but uid equals either the real user ID or the saved set-user-ID,setuid sets only the effective user ID to uid. The real user ID and the saved set-user-ID are not changed.

If neither of these two conditions is true,errno is set to EPERM, and 1 is returned.

Figure 8.18. Ways to change the three user IDs

ID

exec

setuid(uid)

set-user-ID bit off

set-user-ID bit on

superuser

unprivileged user

real user ID

unchanged

unchanged

set to uid

unchanged

effective user ID

unchanged

set from user ID of program file

set to uid

set to uid

saved set-user ID

copied from effective user ID

copied from effective user ID

set to uid

unchanged

seteuid andsetegid Functions

#include <unistd.h> int seteuid(uid_t uid); int setegid(gid_t gid);

An unprivileged user can set its effective user ID to either its real user ID or its saved set-user-ID. For a privileged user, only the effective user ID is set to uid. (This differs from thesetuid function, which changes all three user IDs.)

8.12. Interpreter Files

All contemporary UNIX systems support interpreter files. These files are text files that begin with a line of the form

 #! pathname [ optional-argument ]

执行这些文件时,execarg数组附在pathname [ optional-argument ]之后

8.13.system Function

#include <stdlib.h> int system(const char *cmdstring);

Because system is implemented by callingfork, exec, and waitpid, there are three types of return values.

  1. If either the fork fails orwaitpid returns an error other thanEINTR, system returns-1 with errno set to indicate the error.

  2. If the exec fails, implying that the shell can't be executed, the return value is as if the shell had executedexit(127).

  3. Otherwise, all three functionsfork,exec, and waitpidsucceed, and the return value fromsystem is the termination status of the shell, in the format specified forwaitpid.

int system(const char *cmdstring) /* version without signal handling */ { pid_t pid; int status; if (cmdstring == NULL) return(1); /* always a command processor with UNIX */ if ((pid = fork()) < 0) { status = -1; /* probably out of processes */ } else if (pid == 0) { /* child */ execl("/bin/sh", "sh", "-c", cmdstring, (char *)0); _exit(127); /* execl error *///Note that we call _exit instead of exit. We do this to prevent any standard I/O buffers, which would have been copied from the parent to the child across the fork, from being flushed in the child. } else { /* parent */ while (waitpid(pid, &status, 0) < 0) { if (errno != EINTR) { status = -1; /* error other than EINTR from waitpid() */ break; } } } return(status); }


Sh -c commands

The shell's -c option tells it to take the next command-line argumentcmdstring, in this caseas its command input instead of reading from standard input or from a given file.  The advantage in using system, instead of using fork and exec directly, is that system does all the required error handling and (in our next version of this function in Section 10.18) all the required signal handling. The system function should never be used from a set-user-ID or a set-group-ID program.

8.14. Process Accounting(?)

When enabled, the kernel writes an accounting record each time a process terminates. These accounting records are typically a small amount of binary data with the name of the command, the amount of CPU time used, the user ID and group ID, the starting time, and so on. ?

8.15. User Identification

#include <unistd.h> char *getlogin(void);

8.16. Process Times

wall clock time, user CPU time, and system CPU time. #include <sys/times.h> clock_t times(struct tms *buf);


Returns: 返回值是wall time, -1 on error

 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 */ }; 一般开头记录,最后减去开头,除以(double)sysconf(_SC_CLK_TLK)