Process Control
Process Identifiers ---- PID(嘿嘿,和自控里面的不同哇。。。)
<span style="font-size:14px;">#include <unistd.h> pid_t getpid(void); Returns: process ID of calling process pid_t getppid(void); Returns: parent process ID of calling process uid_t getuid(void); Returns: real user ID of calling process uid_t geteuid(void); Returns: effective user ID of calling process gid_t getgid(void); Returns: real group ID of calling process gid_t getegid(void); Returns: effective group ID of calling process</span>
include <fcntl.h> #include <stdio.h> int main() { printf("current process ID:%d\n",getpid()); printf("parent process ID:%d\n",getppid()); printf("real user ID:%d\n",getuid()); printf("effective user ID:%d\n",geteuid()); printf("real group ID:%d\n",getgid()); printf("effective user ID:%d\n",getegid()); return 0; }
current process ID:15278
parent process ID:12931
real user ID:1000
effective user ID:1000
real group ID:1000
effective user ID:1000
fork Function
An existing process can create a new one by calling thefork function.#include <unistd.h> pid_t fork(void); Returns: 0 in child, process ID of child in parent,−1 on error
The new process created by fork is called the child process.This function is called once but returns twice.
modify these regions, the kernel then makes a copy of that piece of memory only, typically a ‘‘page’’ in a virtual memory system.
<span style="font-size:14px;">#include"apue.h" int glob = 6; char buf[] = "a write to stdout\n"; int main(int argc ,char* argv[]) { int var; pid_t pid; var = 88; if(write(STDOUT_FILENO,buf,sizeof(buf)-1) != sizeof(buf)-1) { printf("write error"); } printf("before fork\n"); if((pid = fork()) < 0) { printf("fork error"); } else if(pid == 0) { glob++; var++; } else { sleep(2); } printf("pid = %d glob = %d var = %d\n",getpid(),glob,var); return 0; }</span><span style="font-size:18px;"> </span>
liuzjian@ubuntu:/Ad_Pro_in_Unix/chapter_8$ ./a.out
a write to stdout
before fork
pid = 15338 glob = 7 var = 89
pid = 15337 glob = 6 var = 88
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_8$ cat ./temp.txt
a write to stdout
before fork
pid = 15383 glob = 7 var = 89
before fork
pid = 15382 glob = 6 var = 88
File Sharing
•Real user ID, real group ID, effective user ID, and effective group ID•Supplementary group IDs•Process group ID•Session ID•Controlling terminal•The set-user-ID and set-group-ID flags•Current working directory•Root directory•File mode creation mask•Signal mask and dispositions•The close-on-exec flag for any open file descriptors•Environment•Attached shared memory segments•Memory mappings•Resource limits
•The return values from fork are different.•The process IDs are different.•The two processes have different parent process IDs: the parent process ID of the child is the parent; the parent process ID of the parent doesn’t change.•The child’s tms_utime, tms_stime, tms_cutime, and tms_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.
1. When a process wants to duplicate itself so that the parent and the child can each execute different sections of code at the same time.2. When a process wants to execute a different program.
vfork Function
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; the child simply calls exec (or exit)right after the vfork. Instead, the child runs in the address space of the parent until it calls either exec or exit
#include"apue.h" #include"myerr.h" int glob = 6; int main() { int var; pid_t pid; var = 88; printf("before fork!\n"); if((pid = vfork()) < 0) { err_sys("vfork error\n"); } else if(pid == 0) { glob++; var++; _exit(0); } printf("pid = %d,glob = %d,var = %d\n",getpid(),glob,var); exit(0); }
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_8$ ./a.out
before fork!
pid = 15758,glob = 7,var = 89
exit Functions
1. Executing a return from the main function. This is equivalent to calling exit.
2. Calling the exit function. This function is defined by ISO C and includes the calling of all exit handlers that have been registered by calling at exit and closing all standard I/O streams.
3. Calling the _exit or _Exit function. _Exit to provide a way for a process to terminate without running exit handlers or signal handlers. Whether standard I/O streams are flushed depends on the implementation.
4. Executing a return from the start routine of the last thread in the process.
5. Calling the pthread_exit function from the last thread in the process.
1. Calling abort
2. When the process receives certain signals.
3. The last thread responds to a cancellation request.
executed. This kernel code closes all the open descriptors for the process, releases the
memory that it was using, and so on
status to indicate the reason for the abnormal termination.
wait functions to fetch the termination status.
wait and waitpid Functions
•Block, if all of its children ar estill 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
<span style="font-size:14px;">#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</span>下面是linux里面对于waitpid的解释
/* Wait for a child matching PID to die.
If PID is (pid_t) -1, match any process.
If PID is (pid_t) 0, match any process with the
same process group as the current process.
If PID is less than -1, match any process whose
process group is the absolute value of PID.
If the WNOHANG bit is set in OPTIONS, and that child
is not already dead, return (pid_t) 0. If successful,
return PID and store the dead child's status in STAT_LOC.
Return (pid_t) -1 for errors. If the WUNTRACED bit is
set in OPTIONS, return status for stopped children; otherwise don't.
This function is a cancellation point and therefore not marked with
__THROW. */
and return its process ID. For errors, return (pid_t) -1.
This function is a cancellation point and therefore not marked with
__THROW. */
extern __pid_t wait (__WAIT_STATUS __stat_loc);
<span style="font-size:14px;">#include"apue.h" #include"pr_exit.h" #include"myerr.h" #include<sys/wait.h> int main () { pid_t pid; int status; if((pid = fork()) < 0) { err_sys("fork error\n"); } else if(pid == 0) { exit(7); } if(wait(&status) != pid) { err_sys("wait pid\n"); } pr_exit(status); if((pid = fork()) < 0) { err_sys("wait error\n"); } else if(pid == 0) { abort(); } if(wait(&status) != pid) { err_sys("wait pid\n"); } pr_exit(status); if((pid = fork()) < 0) { err_sys("fork error\n"); } else if(pid == 0) { status /= 0; } if(wait(&status) != pid) { err_sys("wait error\n"); } pr_exit(status); exit(0); }</span>pr_exit.h 文件的实现:
#ifndef _PR_EXIT_H #define _PR_EXIT_H #include"apue.h" #include<sys/wait.h> void pr_exit(int status) { if(WIFEXITED(status)) { printf("normal termination,exit status = %d\n",WEXITSTATUS(status)); } else if(WIFSIGNALED(status)) { printf("abnormal termination,signal number =%d%s\n",WTERMSIG(status), #ifdef WCOREDUMP WCOREDUMP(status) ? "(core file generated)" : " "); } #else " "); } #endif else if(WIFSTOPPED(status)) { printf("child stopped,signal number = %d\n",WSTOPSIG(status)); } } #endif
normal termination,exit status = 7
abnormal termination,signal number =6
abnormal termination,signal number =8
<span style="font-size:14px;">#include"apue.h" #include"myerr.h" #include"stdio.h" #include<sys/wait.h> int main() { pid_t pid; if((pid = fork()) < 0) { err_sys("forkerror!\n"); } else if(pid == 0) { if((pid = fork()) < 0) { err_sys("forkerror\n"); } else if(pid > 0) { /* if(waitpid(pid,NULL,0) != pid) { printf("waitpid error\n"); } printf("firstchild pid = %d\n",getpid()); */ exit(0); } sleep(2); printf("\nsecond child, parentgetppid =%d second child pid = %d\n",getppid(),getpid()); exit(0); } if(waitpid(pid,NULL,0) != pid) { err_sys("waitpiderror\n"); } printf("parent pid = %d\n",getppid()); exit(0); }</span>
The wait()system call suspends execution of the calling process until one of its childrenterminates. The call wait(&status) is equivalent to: waitpid(-1, &status, 0);
waitid Function
#include <sys/wait.h> int waitid(idtype_t idtype ,id_t id ,siginfo_t *infop,int options ); Returns: 0 ifOK,−1 on error
Instead of encoding this information in a single argument combined with the process ID or process group ID, two separate arguments are used.
<span style="font-size:14px;">/************************************************************* code writer :EOF code date :2014.03.28 e-mail:jasonleaster@gmail.com code purpose : I just share my demo with who isinteresting in APUE. Open source makethe world more beautiful. I would like to recept yourfeedback, if there is something wrong with my code. Please touch meby e-mail. Thank you *************************************************************/ #include<stdio.h> #include<apue.h> #include<sys/wait.h> #include<stdlib.h> #include<signal.h> int main() { int pid = 0; int status = 0; siginfo_t* p_siginfo = NULL; p_siginfo =(siginfo_t*)malloc(sizeof(siginfo_t)); if(p_siginfo == NULL) { printf("malloc error\n"); return 0; } if((pid = fork()) < 0) { printf("forkerror\n"); } else if(pid == 0) { printf("hello! I am thechild %d\n",getpid()); exit(0); } /* if(waitpid(pid,&status,0) < 0 ) { printf("waitpiderror\n"); } */ int temp = 0; if((temp =waitid(P_PID,pid,p_siginfo,0)) < 0)// why there would return -1 { printf("waitiderror\n"); } if(WIFEXITED(status)) { printf("normallytermination,exit status = %d\n",status); } printf("parent exit\n"); free(p_siginfo); return 0; }</span>
写了个demo,但是不知道waitid的哪个地方错了。老是提示waitid错误
Race Conditions
For our purposes, a race condition occurs when multiple processes aretrying to do something with shared data and the final outcome depends on the order in which the processes run.
</pre><pre name="code" class="cpp">#include <apue.h> #include<stdio.h> #include<myerr.h> static void charatatime(char*); int main() { pid_t pid; if((pid = fork()) < 0) { err_sys("forerror\n"); } else if(pid == 0) { charatatime("output fromchild\n"); } else { charatatime("output fromparent\n"); } return 0; } static void charatatime(char*str) { char * ptr; int c ; setbuf(stdout,NULL); for(ptr = str;(c = *ptr++) != 0;) { putc(c,stdout); } }
Test result
liuzjian@ubuntu:/Ad_Pro_in_Unix/chapter_8$./a.out
ououttppuutt ffrom child
rom parent
exec Functions
#include <unistd.h> int execl(const char *pathname ,const char *arg0 ,... /* (char *)0 */ ); int execv(const char *pathname ,char *constargv []); int execle(const char * pathname ,const char *arg0 ,... /* (char *)0, char *constenvp [] */ ); int execve(const char * pathname ,char *constargv [], char *constenvp []); int execlp(const char * filename,const char *arg0 ,... /* (char *)0 */ ); int execvp(const char * filename,char *constargv []); int fexecve(intfd ,char *constargv [], char *constenvp []); All seven return:−1 on error, no return on success
•If filename contains a slash, it is taken as a pathname.
•Otherwise, the executable file is searched for in the directories specified by the PATH environment variable.
•Process ID and parent process ID•Real user ID and real group ID•Supplementary group IDs•Process group ID•Session ID•Controlling terminal•Time left until alarm clock•Current working directory•Root directory•File mode creation mask•File locks•Pro cess signal mask•Pending signals•Resource limits•Nice value (on XSI-conformant systems; see Section 8.16)•Values for tms_utime, tms_stime, tms_cutime,andtms_cstime
<span style="font-size:14px;">/**************************************************************** code writer : EOF code date : 2014.03.27 e-mail: jaosonleaster@gmail.com attention: The ./a.out ./b.out problem is just simple "hello world" program.If you want to use another program to repleace the program it is OK. ****************************************************************/ #include"apue.h" #include"myerr.h" #include"sys/wait.h" char* env_init[] = {"USER=unknown" ,"PATH=/tmp",NULL}; int main() { pid_t pid; if((pid = fork()) < 0) { err_sys("fork error\n"); } else if( pid == 0) { if(execle("./a.out","a.out",(char*)0,env_init) < 0) { err_sys("execle error\n"); } } else { if(waitpid(pid,NULL,0) < 0) { err_sys("wait error\n"); } printf("parent\n"); } if((pid = fork()) < 0) { err_sys("fork error\n"); } else if(pid == 0) { if(execlp("./b.out","b.out",(char*) 0) < 0) { err_sys("execlp error\n"); } } else { if(waitpid(pid,NULL,0) < 0) { err_sys("wait error\n"); } printf("parent\n"); } exit(0); }</span>
The first hello world!
parent
The second hello world!
parent
Changing User IDs and Group IDs
<span style="font-size:14px;">#include <unistd.h> int setuid(uid_t uid); int setgid(gid_t gid); Both return: 0 if OK, −1 on error</span>
1. If the process has superuser privileges, the setuid function sets the real user ID, effective user ID, and saved set-user-ID to uid.
2. 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.
3. If neither of these two conditions is true, errno is set to EPERM and −1 is returned.
#! pathname [ optional-argument ]
The recognition of these files is done within the kernel as part of processing the exec system call. The actual file that gets executed by the kernel is not the interpreter file, but rather the file specified by the pathname on the first line of the interpreter file.
<span style="font-size:14px;">#! /usr/bin/awk -f BEGIN { for(i = 0;i< ARGC;i++) { printf("ARGV[%d] = %s\n",i,ARGV[i]); } exit(0); }</span><span style="font-size:18px;"> </span>
<span style="font-size:14px;">#include"apue.h" #include"sys/wait.h" #include"myerr.h" int main() { pid_t pid; if((pid = fork()) < 0) { err_sys("fork error!\n"); } else if(pid == 0) { //if(execl("/Ad_Pro_in_Unix/chapter_8/awkexample","awkexample",NULL) < 0)//this is for figure-21 if(execl("./testinterp","testinterp",NULL) < 0)//this is fir figure-20 { err_sys("execl error!\n"); } } if(waitpid(pid,NULL,0) < 0) { err_sys("waitpid error!\n"); } exit(0); }</span><span style="font-size:18px;"> </span>testinterp:
#! ./a.out
就这么简单,理解interpreter file概念就好
script, however, we can simply write
#!/bin/csh
system Function
#include <stdlib.h> int system(const char * cmdstring); Returns: (see below)
1. If either the fork fails or waitpid returns an error other than EINTR, system are turns −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 executed exit(127).
3. Otherwise, all three functions—fork, exec,and waitpid—succeed, and the return value from system is the termination status of the shell, in the format specified for waitpid.
<span style="font-size:14px;">#include<sys/wait.h> #include<errno.h> #include<unistd.h> int system(const char* cmdstring) { pid_t pid; int status; if(cmdstring == NULL) { return (1); } if((pid = fork()) < 0) { status = -1; } else if(pid == 0) { execl("/bin/sh","sh","-c",cmdstring,NULL); _exit(127); } else { while(waitpid(pid,&status,0) < 0) { if(errno != EINTR) { status = -1; break; } } } return (status); }</span><span style="font-size:18px;"> </span>
The shell’s -c option tells it to take the next command -line argument—cmdstring,in this case —as its command input instead of reading from standard input or from a given file.
<span style="font-size:14px;">#include<sys/wait.h> #include<errno.h> #include<unistd.h> int system(const char* cmdstring) { pid_t pid; int status; if(cmdstring == NULL) { return (1); } if((pid = fork()) < 0) { status = -1; } else if(pid == 0) { execl("/bin/sh","sh","-c",cmdstring,NULL); _exit(127); } else { while(waitpid(pid,&status,0) < 0) { if(errno != EINTR) { status = -1; break; } } } return (status); }</span>
test result:
2014年 03月 28日 星期五 20:39:53 CST
normal termination,exit status = 0
sh: 1: nosuchcommand: not found
normal termination,exit status = 127
liuzjian tty7 2014-03-19 18:55 (:0)
liuzjian pts/2 2014-03-28 14:00 (:0.0)
normal termination,exit status = 44
<span style="font-size:14px;">#include"apue.h" #include"myerr.h" #include"pr_exit.h" int main(int argc,char* argv[]) { int status; if(argc < 2) { err_quit("command-line argument required"); } if((status = system(argv[1])) < 0) { err_sys("system() error\n"); } pr_exit(status); exit(0); }</span>
<span style="font-size:14px;">#include"apue.h" #include"stdio.h" int main() { printf("real uid = %d,effective uid = %d\n",getuid(),geteuid()); exit(0); }</span>
real uid = 1000,effective uid = 1000
normal termination,exit status = 0
Process Accounting
#include <unistd.h> int acct(const char *filename); On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
DESCRIPTION
The acct() system call enables or disables process accounting. If called with the name of an existing file as its argument, accounting is turned on, and records for each terminating process are appended to filename as it terminates. An argument of NULL causes accounting to be turned off.
acct.h 里面翻出来的acct 结构体的定义
<span style="font-size:14px;">struct acct { char ac_flag; /* Flags. */ u_int16_t ac_uid; /* Real user ID. */ u_int16_t ac_gid; /* Real group ID. */ u_int16_t ac_tty; /* Controlling terminal. */ u_int32_t ac_btime; /* Beginning time. */ comp_t ac_utime; /* User time. */ comp_t ac_stime; /* System time. */ comp_t ac_etime; /* Elapsed time. */ comp_t ac_mem; /* Average memory usage. */ comp_t ac_io; /* Chars transferred. */ comp_t ac_rw; /* Blocks read or written. */ comp_t ac_minflt; /* Minor pagefaults. */ comp_t ac_majflt; /* Major pagefaults. */ comp_t ac_swaps; /* Number of swaps. */ u_int32_t ac_exitcode; /* Process exitcode. */ char ac_comm[ACCT_COMM+1]; /* Command name. */ char ac_pad[10]; /* Padding bytes. */ };</span>
linux 2.4的不支持SCOMPAT 和AEXPND。。。。现在3.0 还是不支持
<span style="font-size:14px;">enum { AFORK = 0x01, /* Has executed fork, but no exec. */ ASU = 0x02, /* Used super-user privileges. */ ACORE = 0x08, /* Dumped core. */ AXSIG = 0x10 /* Killed by a signal. */ };</span>
笔记一下有问题的代码:
#include <apue.h> #include <sys/wait.h> #include <sys/acct.h> #include <myerr.h> #ifdef HAS_SA_STAT #define FMT "%-*.*s e = %6ld,chars = %7ld,stat = %3u: %c %c %c %c\n" #else #define FMT "%-*.*s e = %6ld,chars = %7ld,%c %c %c %c\n" #endif #ifndef HAS_ACORE #define ACORE 0 #endif #ifndef HAS_AXSIG #define AXSIG 0 #endif static unsigned long compt2ulong(comp_t comptime) { unsigned long val; int exp; val = comptime & 0x1fff; exp = (comptime >> 13) & 7; while(exp-- >0) { val *= 8; } return (val); } int main(int argc,char* argv[]) { struct acct acdata; FILE *fp; if(argc != 2) { err_quit("usage: pracct filename"); } if((fp = fopen(argv[1],"r")) == NULL) { err_sys("can't open %s",argv[1]); } while(fread(&acdata,sizeof(acdata),1,fp) ==1) { printf(FMT,(int)sizeof(acdata.ac_comm),(int)sizeof(acdata.ac_comm),acdata.ac_comm,compt2ulong(acdata.ac_etime),compt2ulong(acdata.ac_io), #ifdef HAS_STAT (unsigned char) acdata.ac_stat, #endif acdata.ac_flag & ACORE ? 'D' :' ', acdata.ac_flag & AXSIG ? 'X' :' ', acdata.ac_flag & AFORK ? 'F' :' ', acdata.ac_flag & ASU ? 'S' :' '); } if(ferror(fp)) { err_sys("read error\n"); } exit(0); }
我始终不明白上面这段代码什么APUE给出的是fread一个argv[1] 这个我猜测就是regular file但是空文本有什么用呢。抑或说读的是特殊的文件?APUE没有给出操作过程,只有最后一个结果显示。。。让我非常头疼
执行./a.out ./test.c 这里test.c 就是个简单的hello world 程序的source code输出很奇怪。。。
User Identification:
#include <unistd.h> char *getlogin(void); Returns: pointer to string giving login name if OK,NULL on error
还有一种方式返回user name。。。
The getpwuid() function returns a pointer to a structure containing the broken-out fields of the record in the password database that matches the user ID uid.
The passwd structure is defined in <pwd.h> as follows:
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
<span style="font-size:14px;">#include <stdio.h> #include <unistd.h> int main() { printf("the user login: %s\n",getlogin()); return 0; }</span><span style="font-size:18px;"> </span>
test result:
the user login: jasonleaster
Process Times
感觉times这个函数遇到很多次了。。。。。
#include <sys/times.h> clock_t times(struct tms *buf ); Returns: elapsed wall clock time in clock ticks if OK,−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 childr };
#include"apue.h" #include"myerr.h" #include"pr_exit.h" #include <sys/times.h> static void pr_times(clock_t,struct tms*, struct tms*); static void do_cmd(char*); int main (int argc ,char* argv[]) { int i; setbuf(stdout,NULL); for(i =1;i< argc ;i++) { do_cmd(argv[i]); } exit(0); } static void do_cmd(char* cmd) { struct tms tmsstart,tmsend; clock_t start,end; int status; printf("\ncommand:%s\n",cmd); if((start = times(&tmsstart)) == -1) { err_sys("times error\n"); } if((status = system(cmd)) < 0) { err_sys("system() error\n"); } if((end = times(&tmsend)) == -1) { err_sys("times error\n"); } pr_times(end-start,&tmsstart,&tmsend); pr_exit(status); } static void pr_times(clock_t real,struct tms* tmsstart,struct tms* tmsend) { static long clktck = 0; if(clktck == 0) { if((clktck = sysconf(_SC_CLK_TCK)) < 0) { err_sys("sysconf error\n"); } printf(" real: %7.2f\n",real / (double) clktck); printf(" user: %7.2f\n", (tmsend->tms_utime - tmsstart->tms_utime) / (double) clktck); printf(" sys: %7.2f\n", (tmsend->tms_stime - tmsstart->tms_stime) / (double) clktck); printf(" child user: %7.2f\n", (tmsend->tms_cutime - tmsstart->tms_cutime) / (double) clktck); printf(" child sys: %7.2f\n", (tmsend->tms_cstime - tmsstart->tms_cstime) / (double) clktck); } }
test result :
command:date
2014年 03月 28日 星期五 23:35:50 CST
real: 0.01
user: 0.00
sys: 0.00
child user: 0.00
child sys: 0.00
normal termination,exit status = 0
command:pwd
/Ad_Pro_in_Unix/chapter_8
normal termination,exit status = 0
也不知道是进程控制这章比较重要话的时间长,还是自己拖拉。。。拖拖搞搞,两天才弄完。。。T_T