本文共 34150 字,大约阅读时间需要 113 分钟。
process pair | cocurrent? |
---|---|
AB | No |
AC | Yes |
AD | Yes |
BC | Yes |
BD | Yes |
CD | Yes |
A. call once, return twice
fork B. call once, never return longjmp, execve C. call once, return 1 or more times setjmp4行
c +-------+ | "hello" | c | p +-------+-------+ | fork "hello" | | c | +-------+ | | "hello" | | | p | p +------+-------+-------+ main fork fork "hello"
8行
c +-------+---------+ | "hello" "hello" | c | p +-------+-------+---------+ | fork "hello" "hello" | | c | +-------+---------+ | | "hello" "hello" | | | p | p +------+-------+-------+---------+ main fork fork "hello" "hello"
a = 4 a=4 a=4
a = 3 a=3 a=3 a = 2 a=2 a=23行
c +-------+ | "hello" | c | p +-------+-------+ | fork "hello" | | p +------+-------+-------+ main fork return "hello"
5行
c +-------+---------+ | "hello" "hello" | c | p +-------+-------+---------+ | fork "hello" "hello" | | | p +------+-------+-------+ main fork return "hello"
c o u n t e r = 2 counter = 2 counter=2
注意子进程有自己的计数器。hello 0 1 Bye 2 Byehello 1 0 Bye 2 Byehello 1 Bye 0 2 Bye
c +-------+---------+ | "0" exit "2" | c | p +-------+-------+---------+ | fork "1" exit "2" | (atexit) | c | +-------+---------+ | | "0" exit | | | p | p +------+-------+-------+---------+ main fork fork "1" exit
2一定在0/1后面,所以是B、D
2 n = 2 6 = 64 2^n=2^6=64 2n=26=64
#include#include "csapp.h"int main(int argc, char* argv[], char* env[]) { if (execve("/bin/ls", argv, env) == -1) { fprintf(stderr, "execve error: %s\n", strerror(errno)); exit(1); }}
abc或bac
#include#include "csapp.h"int mysystem(char* command) { pid_t pid; int status; if ((pid = Fork()) == 0) { char* argv[4] = { "", "-c", command, NULL }; execve("/bin/sh", argv, environ); } printf("child pid: %d\n", pid); if (Waitpid(pid, &status, 0) > 0) { if (WIFEXITED(status)) return WEXITSTATUS(status); if (WIFSIGNALED(status)) return WTERMSIG(status); }}int main(int argc, char* argv[]) { int code; code = mysystem("./exit-code"); printf("normally exit, code: %d\n", code); fflush(stdout); code = mysystem("./wait-sig"); printf("exit caused by signal, code: %d\n", code); fflush(stdout); return 0;}
csapp.h
#ifndef __CSAPP_H__#define __CSAPP_H__#include#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Default file permissions are DEF_MODE & ~DEF_UMASK *//* $begin createmasks */#define DEF_MODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH#define DEF_UMASK S_IWGRP|S_IWOTH/* $end createmasks *//* Simplifies calls to bind(), connect(), and accept() *//* $begin sockaddrdef */typedef struct sockaddr SA;/* $end sockaddrdef *//* Persistent state for the robust I/O (Rio) package *//* $begin rio_t */#define RIO_BUFSIZE 8192typedef struct { int rio_fd; /* Descriptor for this internal buf */ int rio_cnt; /* Unread bytes in internal buf */ char *rio_bufptr; /* Next unread byte in internal buf */ char rio_buf[RIO_BUFSIZE]; /* Internal buffer */} rio_t;/* $end rio_t *//* External variables */extern int h_errno; /* Defined by BIND for DNS errors */ extern char **environ; /* Defined by libc *//* Misc constants */#define MAXLINE 8192 /* Max text line length */#define MAXBUF 8192 /* Max I/O buffer size */#define LISTENQ 1024 /* Second argument to listen() *//* Our own error-handling functions */void unix_error(char *msg);void posix_error(int code, char *msg);void dns_error(char *msg);void gai_error(int code, char *msg);void app_error(char *msg);/* Process control wrappers */pid_t Fork(void);void Execve(const char *filename, char *const argv[], char *const envp[]);pid_t Wait(int *status);pid_t Waitpid(pid_t pid, int *iptr, int options);void Kill(pid_t pid, int signum);unsigned int Sleep(unsigned int secs);void Pause(void);unsigned int Alarm(unsigned int seconds);void Setpgid(pid_t pid, pid_t pgid);pid_t Getpgrp();/* Signal wrappers */typedef void handler_t(int);handler_t *Signal(int signum, handler_t *handler);void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);void Sigemptyset(sigset_t *set);void Sigfillset(sigset_t *set);void Sigaddset(sigset_t *set, int signum);void Sigdelset(sigset_t *set, int signum);int Sigismember(const sigset_t *set, int signum);int Sigsuspend(const sigset_t *set);/* Sio (Signal-safe I/O) routines */ssize_t sio_puts(char s[]);ssize_t sio_putl(long v);void sio_error(char s[]);/* Sio wrappers */ssize_t Sio_puts(char s[]);ssize_t Sio_putl(long v);void Sio_error(char s[]);/* Unix I/O wrappers */int Open(const char *pathname, int flags, mode_t mode);ssize_t Read(int fd, void *buf, size_t count);ssize_t Write(int fd, const void *buf, size_t count);off_t Lseek(int fildes, off_t offset, int whence);void Close(int fd);int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);int Dup2(int fd1, int fd2);void Stat(const char *filename, struct stat *buf);void Fstat(int fd, struct stat *buf) ;/* Directory wrappers */DIR *Opendir(const char *name);struct dirent *Readdir(DIR *dirp);int Closedir(DIR *dirp);/* Memory mapping wrappers */void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);void Munmap(void *start, size_t length);/* Standard I/O wrappers */void Fclose(FILE *fp);FILE *Fdopen(int fd, const char *type);char *Fgets(char *ptr, int n, FILE *stream);FILE *Fopen(const char *filename, const char *mode);void Fputs(const char *ptr, FILE *stream);size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream);void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);/* Dynamic storage allocation wrappers */void *Malloc(size_t size);void *Realloc(void *ptr, size_t size);void *Calloc(size_t nmemb, size_t size);void Free(void *ptr);/* Sockets interface wrappers */int Socket(int domain, int type, int protocol);void Setsockopt(int s, int level, int optname, const void *optval, int optlen);void Bind(int sockfd, struct sockaddr *my_addr, int addrlen);void Listen(int s, int backlog);int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);/* Protocol independent wrappers */void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);void Freeaddrinfo(struct addrinfo *res);void Inet_ntop(int af, const void *src, char *dst, socklen_t size);void Inet_pton(int af, const char *src, void *dst); /* DNS wrappers */struct hostent *Gethostbyname(const char *name);struct hostent *Gethostbyaddr(const char *addr, int len, int type);/* Pthreads thread control wrappers */void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp, void * (*routine)(void *), void *argp);void Pthread_join(pthread_t tid, void **thread_return);void Pthread_cancel(pthread_t tid);void Pthread_detach(pthread_t tid);void Pthread_exit(void *retval);pthread_t Pthread_self(void);void Pthread_once(pthread_once_t *once_control, void (*init_function)());/* POSIX semaphore wrappers */void Sem_init(sem_t *sem, int pshared, unsigned int value);void P(sem_t *sem);void V(sem_t *sem);/* Rio (Robust I/O) package */ssize_t rio_readn(int fd, void *usrbuf, size_t n);ssize_t rio_writen(int fd, void *usrbuf, size_t n);void rio_readinitb(rio_t *rp, int fd); ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);/* Wrappers for Rio package */ssize_t Rio_readn(int fd, void *usrbuf, size_t n);void Rio_writen(int fd, void *usrbuf, size_t n);void Rio_readinitb(rio_t *rp, int fd); ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);/* Reentrant protocol-independent client/server helpers */int open_clientfd(char *hostname, char *port);int open_listenfd(char *port);/* Wrappers for reentrant protocol-independent client/server helpers */int Open_clientfd(char *hostname, char *port);int Open_listenfd(char *port);#endif /* __CSAPP_H__ *//* $end csapp.h */
csapp.c
#include "csapp.h"/************************** * Error-handling functions **************************//* $begin errorfuns *//* $begin unixerror */void unix_error(char *msg) /* Unix-style error */{ fprintf(stderr, "%s: %s\n", msg, strerror(errno)); exit(0);}/* $end unixerror */void posix_error(int code, char *msg) /* Posix-style error */{ fprintf(stderr, "%s: %s\n", msg, strerror(code)); exit(0);}void gai_error(int code, char *msg) /* Getaddrinfo-style error */{ fprintf(stderr, "%s: %s\n", msg, gai_strerror(code)); exit(0);}void app_error(char *msg) /* Application error */{ fprintf(stderr, "%s\n", msg); exit(0);}/* $end errorfuns */void dns_error(char *msg) /* Obsolete gethostbyname error */{ fprintf(stderr, "%s\n", msg); exit(0);}/********************************************* * Wrappers for Unix process control functions ********************************************//* $begin forkwrapper */pid_t Fork(void) { pid_t pid; if ((pid = fork()) < 0) unix_error("Fork error"); return pid;}/* $end forkwrapper */void Execve(const char *filename, char *const argv[], char *const envp[]) { if (execve(filename, argv, envp) < 0) unix_error("Execve error");}/* $begin wait */pid_t Wait(int *status) { pid_t pid; if ((pid = wait(status)) < 0) unix_error("Wait error"); return pid;}/* $end wait */pid_t Waitpid(pid_t pid, int *iptr, int options) { pid_t retpid; if ((retpid = waitpid(pid, iptr, options)) < 0) unix_error("Waitpid error"); return(retpid);}/* $begin kill */void Kill(pid_t pid, int signum) { int rc; if ((rc = kill(pid, signum)) < 0) unix_error("Kill error");}/* $end kill */void Pause() { (void)pause(); return;}unsigned int Sleep(unsigned int secs) { unsigned int rc; if ((rc = sleep(secs)) < 0) unix_error("Sleep error"); return rc;}unsigned int Alarm(unsigned int seconds) { return alarm(seconds);}void Setpgid(pid_t pid, pid_t pgid) { int rc; if ((rc = setpgid(pid, pgid)) < 0) unix_error("Setpgid error"); return;}pid_t Getpgrp(void) { return getpgrp();}/************************************ * Wrappers for Unix signal functions ***********************************//* $begin sigaction */handler_t *Signal(int signum, handler_t *handler) { struct sigaction action, old_action; action.sa_handler = handler; sigemptyset(&action.sa_mask); /* Block sigs of type being handled */ action.sa_flags = SA_RESTART; /* Restart syscalls if possible */ if (sigaction(signum, &action, &old_action) < 0) unix_error("Signal error"); return (old_action.sa_handler);}/* $end sigaction */void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset){ if (sigprocmask(how, set, oldset) < 0) unix_error("Sigprocmask error"); return;}void Sigemptyset(sigset_t *set){ if (sigemptyset(set) < 0) unix_error("Sigemptyset error"); return;}void Sigfillset(sigset_t *set){ if (sigfillset(set) < 0) unix_error("Sigfillset error"); return;}void Sigaddset(sigset_t *set, int signum){ if (sigaddset(set, signum) < 0) unix_error("Sigaddset error"); return;}void Sigdelset(sigset_t *set, int signum){ if (sigdelset(set, signum) < 0) unix_error("Sigdelset error"); return;}int Sigismember(const sigset_t *set, int signum){ int rc; if ((rc = sigismember(set, signum)) < 0) unix_error("Sigismember error"); return rc;}int Sigsuspend(const sigset_t *set){ int rc = sigsuspend(set); /* always returns -1 */ if (errno != EINTR) unix_error("Sigsuspend error"); return rc;}/************************************************************* * The Sio (Signal-safe I/O) package - simple reentrant output * functions that are safe for signal handlers. *************************************************************//* Private sio functions *//* $begin sioprivate *//* sio_reverse - Reverse a string (from K&R) */static void sio_reverse(char s[]){ int c, i, j; for (i = 0, j = strlen(s)-1; i < j; i++, j--) { c = s[i]; s[i] = s[j]; s[j] = c; }}/* sio_ltoa - Convert long to base b string (from K&R) */static void sio_ltoa(long v, char s[], int b) { int c, i = 0; int neg = v < 0; if (neg) v = -v; do { s[i++] = ((c = (v % b)) < 10) ? c + '0' : c - 10 + 'a'; } while ((v /= b) > 0); if (neg) s[i++] = '-'; s[i] = '\0'; sio_reverse(s);}/* sio_strlen - Return length of string (from K&R) */static size_t sio_strlen(char s[]){ int i = 0; while (s[i] != '\0') ++i; return i;}/* $end sioprivate *//* Public Sio functions *//* $begin siopublic */ssize_t sio_puts(char s[]) /* Put string */{ return write(STDOUT_FILENO, s, sio_strlen(s)); //line:csapp:siostrlen}ssize_t sio_putl(long v) /* Put long */{ char s[128]; sio_ltoa(v, s, 10); /* Based on K&R itoa() */ //line:csapp:sioltoa return sio_puts(s);}void sio_error(char s[]) /* Put error message and exit */{ sio_puts(s); _exit(1); //line:csapp:sioexit}/* $end siopublic *//******************************* * Wrappers for the SIO routines ******************************/ssize_t Sio_putl(long v){ ssize_t n; if ((n = sio_putl(v)) < 0) sio_error("Sio_putl error"); return n;}ssize_t Sio_puts(char s[]){ ssize_t n; if ((n = sio_puts(s)) < 0) sio_error("Sio_puts error"); return n;}void Sio_error(char s[]){ sio_error(s);}/******************************** * Wrappers for Unix I/O routines ********************************/int Open(const char *pathname, int flags, mode_t mode) { int rc; if ((rc = open(pathname, flags, mode)) < 0) unix_error("Open error"); return rc;}ssize_t Read(int fd, void *buf, size_t count) { ssize_t rc; if ((rc = read(fd, buf, count)) < 0) unix_error("Read error"); return rc;}ssize_t Write(int fd, const void *buf, size_t count) { ssize_t rc; if ((rc = write(fd, buf, count)) < 0) unix_error("Write error"); return rc;}off_t Lseek(int fildes, off_t offset, int whence) { off_t rc; if ((rc = lseek(fildes, offset, whence)) < 0) unix_error("Lseek error"); return rc;}void Close(int fd) { int rc; if ((rc = close(fd)) < 0) unix_error("Close error");}int Select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { int rc; if ((rc = select(n, readfds, writefds, exceptfds, timeout)) < 0) unix_error("Select error"); return rc;}int Dup2(int fd1, int fd2) { int rc; if ((rc = dup2(fd1, fd2)) < 0) unix_error("Dup2 error"); return rc;}void Stat(const char *filename, struct stat *buf) { if (stat(filename, buf) < 0) unix_error("Stat error");}void Fstat(int fd, struct stat *buf) { if (fstat(fd, buf) < 0) unix_error("Fstat error");}/********************************* * Wrappers for directory function *********************************/DIR *Opendir(const char *name) { DIR *dirp = opendir(name); if (!dirp) unix_error("opendir error"); return dirp;}struct dirent *Readdir(DIR *dirp){ struct dirent *dep; errno = 0; dep = readdir(dirp); if ((dep == NULL) && (errno != 0)) unix_error("readdir error"); return dep;}int Closedir(DIR *dirp) { int rc; if ((rc = closedir(dirp)) < 0) unix_error("closedir error"); return rc;}/*************************************** * Wrappers for memory mapping functions ***************************************/void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { void *ptr; if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1)) unix_error("mmap error"); return(ptr);}void Munmap(void *start, size_t length) { if (munmap(start, length) < 0) unix_error("munmap error");}/*************************************************** * Wrappers for dynamic storage allocation functions ***************************************************/void *Malloc(size_t size) { void *p; if ((p = malloc(size)) == NULL) unix_error("Malloc error"); return p;}void *Realloc(void *ptr, size_t size) { void *p; if ((p = realloc(ptr, size)) == NULL) unix_error("Realloc error"); return p;}void *Calloc(size_t nmemb, size_t size) { void *p; if ((p = calloc(nmemb, size)) == NULL) unix_error("Calloc error"); return p;}void Free(void *ptr) { free(ptr);}/****************************************** * Wrappers for the Standard I/O functions. ******************************************/void Fclose(FILE *fp) { if (fclose(fp) != 0) unix_error("Fclose error");}FILE *Fdopen(int fd, const char *type) { FILE *fp; if ((fp = fdopen(fd, type)) == NULL) unix_error("Fdopen error"); return fp;}char *Fgets(char *ptr, int n, FILE *stream) { char *rptr; if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream)) app_error("Fgets error"); return rptr;}FILE *Fopen(const char *filename, const char *mode) { FILE *fp; if ((fp = fopen(filename, mode)) == NULL) unix_error("Fopen error"); return fp;}void Fputs(const char *ptr, FILE *stream) { if (fputs(ptr, stream) == EOF) unix_error("Fputs error");}size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { size_t n; if (((n = fread(ptr, size, nmemb, stream)) < nmemb) && ferror(stream)) unix_error("Fread error"); return n;}void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { if (fwrite(ptr, size, nmemb, stream) < nmemb) unix_error("Fwrite error");}/**************************** * Sockets interface wrappers ****************************/int Socket(int domain, int type, int protocol) { int rc; if ((rc = socket(domain, type, protocol)) < 0) unix_error("Socket error"); return rc;}void Setsockopt(int s, int level, int optname, const void *optval, int optlen) { int rc; if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0) unix_error("Setsockopt error");}void Bind(int sockfd, struct sockaddr *my_addr, int addrlen) { int rc; if ((rc = bind(sockfd, my_addr, addrlen)) < 0) unix_error("Bind error");}void Listen(int s, int backlog) { int rc; if ((rc = listen(s, backlog)) < 0) unix_error("Listen error");}int Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { int rc; if ((rc = accept(s, addr, addrlen)) < 0) unix_error("Accept error"); return rc;}void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen) { int rc; if ((rc = connect(sockfd, serv_addr, addrlen)) < 0) unix_error("Connect error");}/******************************* * Protocol-independent wrappers *******************************//* $begin getaddrinfo */void Getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){ int rc; if ((rc = getaddrinfo(node, service, hints, res)) != 0) gai_error(rc, "Getaddrinfo error");}/* $end getaddrinfo */void Getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags){ int rc; if ((rc = getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)) != 0) gai_error(rc, "Getnameinfo error");}void Freeaddrinfo(struct addrinfo *res){ freeaddrinfo(res);}void Inet_ntop(int af, const void *src, char *dst, socklen_t size){ if (!inet_ntop(af, src, dst, size)) unix_error("Inet_ntop error");}void Inet_pton(int af, const char *src, void *dst) { int rc; rc = inet_pton(af, src, dst); if (rc == 0) app_error("inet_pton error: invalid dotted-decimal address"); else if (rc < 0) unix_error("Inet_pton error");}/******************************************* * DNS interface wrappers. * * NOTE: These are obsolete because they are not thread safe. Use * getaddrinfo and getnameinfo instead ***********************************//* $begin gethostbyname */struct hostent *Gethostbyname(const char *name) { struct hostent *p; if ((p = gethostbyname(name)) == NULL) dns_error("Gethostbyname error"); return p;}/* $end gethostbyname */struct hostent *Gethostbyaddr(const char *addr, int len, int type) { struct hostent *p; if ((p = gethostbyaddr(addr, len, type)) == NULL) dns_error("Gethostbyaddr error"); return p;}/************************************************ * Wrappers for Pthreads thread control functions ************************************************/void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp, void * (*routine)(void *), void *argp) { int rc; if ((rc = pthread_create(tidp, attrp, routine, argp)) != 0) posix_error(rc, "Pthread_create error");}void Pthread_cancel(pthread_t tid) { int rc; if ((rc = pthread_cancel(tid)) != 0) posix_error(rc, "Pthread_cancel error");}void Pthread_join(pthread_t tid, void **thread_return) { int rc; if ((rc = pthread_join(tid, thread_return)) != 0) posix_error(rc, "Pthread_join error");}/* $begin detach */void Pthread_detach(pthread_t tid) { int rc; if ((rc = pthread_detach(tid)) != 0) posix_error(rc, "Pthread_detach error");}/* $end detach */void Pthread_exit(void *retval) { pthread_exit(retval);}pthread_t Pthread_self(void) { return pthread_self();}void Pthread_once(pthread_once_t *once_control, void (*init_function)()) { pthread_once(once_control, init_function);}/******************************* * Wrappers for Posix semaphores *******************************/void Sem_init(sem_t *sem, int pshared, unsigned int value) { if (sem_init(sem, pshared, value) < 0) unix_error("Sem_init error");}void P(sem_t *sem) { if (sem_wait(sem) < 0) unix_error("P error");}void V(sem_t *sem) { if (sem_post(sem) < 0) unix_error("V error");}/**************************************** * The Rio package - Robust I/O functions ****************************************//* * rio_readn - Robustly read n bytes (unbuffered) *//* $begin rio_readn */ssize_t rio_readn(int fd, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nread; char *bufp = usrbuf; while (nleft > 0) { if ((nread = read(fd, bufp, nleft)) < 0) { if (errno == EINTR) /* Interrupted by sig handler return */ nread = 0; /* and call read() again */ else return -1; /* errno set by read() */ } else if (nread == 0) break; /* EOF */ nleft -= nread; bufp += nread; } return (n - nleft); /* Return >= 0 */}/* $end rio_readn *//* * rio_writen - Robustly write n bytes (unbuffered) */ /* $begin rio_writen */ssize_t rio_writen(int fd, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nwritten; char *bufp = usrbuf; while (nleft > 0) { if ((nwritten = write(fd, bufp, nleft)) <= 0) { if (errno == EINTR) /* Interrupted by sig handler return */ nwritten = 0; /* and call write() again */ else return -1; /* errno set by write() */ } nleft -= nwritten; bufp += nwritten; } return n;}/* $end rio_writen *//* * rio_read - This is a wrapper for the Unix read() function that * transfers min(n, rio_cnt) bytes from an internal buffer to a user * buffer, where n is the number of bytes requested by the user and * rio_cnt is the number of unread bytes in the internal buffer. On * entry, rio_read() refills the internal buffer via a call to * read() if the internal buffer is empty. *//* $begin rio_read */static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n){ int cnt; while (rp->rio_cnt <= 0) { /* Refill if buf is empty */ rp->rio_cnt = read(rp->rio_fd, rp->rio_buf, sizeof(rp->rio_buf)); if (rp->rio_cnt < 0) { if (errno != EINTR) /* Interrupted by sig handler return */ return -1; } else if (rp->rio_cnt == 0) /* EOF */ return 0; else rp->rio_bufptr = rp->rio_buf; /* Reset buffer ptr */ } /* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */ cnt = n; if (rp->rio_cnt < n) cnt = rp->rio_cnt; memcpy(usrbuf, rp->rio_bufptr, cnt); rp->rio_bufptr += cnt; rp->rio_cnt -= cnt; return cnt;}/* $end rio_read *//* * rio_readinitb - Associate a descriptor with a read buffer and reset buffer *//* $begin rio_readinitb */void rio_readinitb(rio_t *rp, int fd) { rp->rio_fd = fd; rp->rio_cnt = 0; rp->rio_bufptr = rp->rio_buf;}/* $end rio_readinitb *//* * rio_readnb - Robustly read n bytes (buffered) *//* $begin rio_readnb */ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n) { size_t nleft = n; ssize_t nread; char *bufp = usrbuf; while (nleft > 0) { if ((nread = rio_read(rp, bufp, nleft)) < 0) return -1; /* errno set by read() */ else if (nread == 0) break; /* EOF */ nleft -= nread; bufp += nread; } return (n - nleft); /* return >= 0 */}/* $end rio_readnb *//* * rio_readlineb - Robustly read a text line (buffered) *//* $begin rio_readlineb */ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) { int n, rc; char c, *bufp = usrbuf; for (n = 1; n < maxlen; n++) { if ((rc = rio_read(rp, &c, 1)) == 1) { *bufp++ = c; if (c == '\n') { n++; break; } } else if (rc == 0) { if (n == 1) return 0; /* EOF, no data read */ else break; /* EOF, some data was read */ } else return -1; /* Error */ } *bufp = 0; return n-1;}/* $end rio_readlineb *//********************************** * Wrappers for robust I/O routines **********************************/ssize_t Rio_readn(int fd, void *ptr, size_t nbytes) { ssize_t n; if ((n = rio_readn(fd, ptr, nbytes)) < 0) unix_error("Rio_readn error"); return n;}void Rio_writen(int fd, void *usrbuf, size_t n) { if (rio_writen(fd, usrbuf, n) != n) unix_error("Rio_writen error");}void Rio_readinitb(rio_t *rp, int fd){ rio_readinitb(rp, fd);} ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n) { ssize_t rc; if ((rc = rio_readnb(rp, usrbuf, n)) < 0) unix_error("Rio_readnb error"); return rc;}ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen) { ssize_t rc; if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0) unix_error("Rio_readlineb error"); return rc;} /******************************** * Client/server helper functions ********************************//* * open_clientfd - Open connection to server atand * return a socket descriptor ready for reading and writing. This * function is reentrant and protocol-independent. * * On error, returns: * -2 for getaddrinfo error * -1 with errno set for other errors. *//* $begin open_clientfd */int open_clientfd(char *hostname, char *port) { int clientfd, rc; struct addrinfo hints, *listp, *p; /* Get a list of potential server addresses */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; /* Open a connection */ hints.ai_flags = AI_NUMERICSERV; /* ... using a numeric port arg. */ hints.ai_flags |= AI_ADDRCONFIG; /* Recommended for connections */ if ((rc = getaddrinfo(hostname, port, &hints, &listp)) != 0) { fprintf(stderr, "getaddrinfo failed (%s:%s): %s\n", hostname, port, gai_strerror(rc)); return -2; } /* Walk the list for one that we can successfully connect to */ for (p = listp; p; p = p->ai_next) { /* Create a socket descriptor */ if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; /* Socket failed, try the next */ /* Connect to the server */ if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1) break; /* Success */ if (close(clientfd) < 0) { /* Connect failed, try another */ //line:netp:openclientfd:closefd fprintf(stderr, "open_clientfd: close failed: %s\n", strerror(errno)); return -1; } } /* Clean up */ freeaddrinfo(listp); if (!p) /* All connects failed */ return -1; else /* The last connect succeeded */ return clientfd;}/* $end open_clientfd *//* * open_listenfd - Open and return a listening socket on port. This * function is reentrant and protocol-independent. * * On error, returns: * -2 for getaddrinfo error * -1 with errno set for other errors. *//* $begin open_listenfd */int open_listenfd(char *port) { struct addrinfo hints, *listp, *p; int listenfd, rc, optval=1; /* Get a list of potential server addresses */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; /* Accept connections */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */ hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */ if ((rc = getaddrinfo(NULL, port, &hints, &listp)) != 0) { fprintf(stderr, "getaddrinfo failed (port %s): %s\n", port, gai_strerror(rc)); return -2; } /* Walk the list for one that we can bind to */ for (p = listp; p; p = p->ai_next) { /* Create a socket descriptor */ if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) continue; /* Socket failed, try the next */ /* Eliminates "Address already in use" error from bind */ setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, //line:netp:csapp:setsockopt (const void *)&optval , sizeof(int)); /* Bind the descriptor to the address */ if (bind(listenfd, p->ai_addr, p->ai_addrlen) == 0) break; /* Success */ if (close(listenfd) < 0) { /* Bind failed, try the next */ fprintf(stderr, "open_listenfd close failed: %s\n", strerror(errno)); return -1; } } /* Clean up */ freeaddrinfo(listp); if (!p) /* No address worked */ return -1; /* Make it a listening socket ready to accept connection requests */ if (listen(listenfd, LISTENQ) < 0) { close(listenfd); return -1; } return listenfd;}/* $end open_listenfd *//**************************************************** * Wrappers for reentrant protocol-independent helpers ****************************************************/int Open_clientfd(char *hostname, char *port) { int rc; if ((rc = open_clientfd(hostname, port)) < 0) unix_error("Open_clientfd error"); return rc;}int Open_listenfd(char *port) { int rc; if ((rc = open_listenfd(port)) < 0) unix_error("Open_listenfd error"); return rc;}/* $end csapp.c */
SIGUSR2 SIGUSR2 SIGUSR2 SIGUSR2 SIGUSR2 | | | | | being handled Pending Canceld Canceld Canceld need 1 sec
在任何时刻只有一个信号处于等待状态,其他的都会被取消。
#include "csapp.h"#define N 2#define LEN 100int main() { int status, i; pid_t pid; /* Parent creates N children */ for (i = 0; i < N; i++) if ((pid = Fork()) == 0) { /* access address 0, cause fault */ char* cptr = NULL; *cptr = 'd'; } /* Parent reaps N children in no particular order */ while ((pid = waitpid(-1, &status, 0)) > 0) { if (WIFEXITED(status)) printf("child %d terminated normally with exit status=%d\n", pid, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) { /* print signal that cause process exit */ char buf[LEN]; sprintf(buf, "child %d terminated by signal %d", pid, WTERMSIG(status)); psignal(WTERMSIG(status), buf); } else printf("child %d terminated abnormally\n", pid); } /* The only normal termination is if there are no more children */ if (errno != ECHILD) unix_error("waitpid error"); exit(0);}/* $end waitpid1 */
#include#include "csapp.h"sigjmp_buf buf;void handler(int sig) { /* jump */ siglongjmp(buf, 1);}char* tfgets(char* s, int size, FILE* stream) { char* result; if (!sigsetjmp(buf, 1)) { alarm(5); if (signal(SIGALRM, handler) == SIG_ERR) unix_error("set alarm handler error"); return fgets(s, size, stream); } else { /* run out of time */ return NULL; }}#define LEN 100int main(int argc, char* argv[]) { char buf[LEN]; char* input = tfgets(buf, LEN, stdin); if (input == NULL) { printf("nothing input: NULL\n"); } else { printf("%s", input); } return 0;}
转载地址:http://eywai.baihongyu.com/