第三十章 客户/服务器程序设计范式:
示例:
#include "err_exit.h"
#include <sys/mman.h>
/*
* Allocate an array of "nchildren" longs in shared memory that can
* be used as a counter by each child of how many clients it services.
* See pp. 467-470 of "Advanced Programming in the Unix Environment."
*/
long *
meter(int nchildren)
{
int fd;
long * ptr;
#ifdef MAP_ANON
if ((ptr = mmap(0, nchildren*sizeof(long), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) {
err_exit("mmap error");
}
#else
if ((fd = open("/dev/zero", O_RDWR, 0)) == -1) {
err_exit("open /dev/zero error");
}
if ((ptr = mmap(0, nchildren*sizeof(long), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0)) == MAP_FAILED) {
err_exit("mmap error");
}
Close(fd);
#endif
return(ptr);
}
#include "myio.h"
#include "warp.h"
#include "tcp_connect.h"
#define MAXN 16384 /* max # bytes to request from server */
int
main(int argc, char ** argv)
{
int i;
int j;
int fd;
int nchildren;
int nloops;
int nbytes;
pid_t pid;
ssize_t n;
char request[MAXLINE];
char reply[MAXN];
if (argc != 6) {
printf("usage: client <hostname or IPaddr> <port> <#children> "
"<#loops/child> <#bytes/request>\n");
exit(1);
}
nchildren = atoi(argv[3]);
nloops = atoi(argv[4]);
nbytes = atoi(argv[5]);
snprintf(request, sizeof(request), "%d\n", nbytes); /* newline at end */
for (i = 0; i < nchildren; i++) {
if ((pid = Fork()) == 0) { /* child */
for (j = 0; j < nloops; j++) {
fd = tcp_connect(argv[1], argv[2]);
n = strlen(request);
if (write(fd, request, n) != n) {
err_msg("write error", errno);
}
if ((n = readn(fd, reply, nbytes)) != nbytes) {
err_msg("readn error", errno);
}
Close(fd); /* TIME_WAIT on client, not server */
}
printf("child %d done\n", i);
exit(0);
}
/* parent loops around to fork() again */
}
while (wait(NULL) > 0) { /* now parent waits for all children */
}
if (errno != ECHILD) {
err_msg("wait error", errno);
}
exit(0);
}
#ifndef __READLINE_R_H__
#define __READLINE_R_H__
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifndef MAXLINE
#define MAXLINE 4096
#endif
typedef struct {
int read_fd; /* caller's descriptor to read from */
char * read_ptr; /* caller's buffer to read into */
size_t read_maxlen; /* max #bytes to read */
int rl_cnt; /* initialize to 0 */
char * rl_bufptr; /* initialize to rl_buf */
char rl_buf[MAXLINE];
} Rline;
ssize_t
my_read_r(Rline * rptr, char * ptr)
{
if (rptr->rl_cnt <= 0) {
again:
rptr->rl_cnt = read(rptr->read_fd, rptr->rl_buf, sizeof(rptr->rl_buf));
if (rptr->rl_cnt < 0) {
if (errno == EINTR) {
goto again;
}
else {
return(-1);
}
}
else if (rptr->rl_cnt == 0) {
return(0);
}
rptr->rl_bufptr = rptr->rl_buf;
}
rptr->rl_cnt--;
*ptr = *rptr->rl_bufptr++ & 255;
return(1);
}
void
readline_rinit(int fd, void * ptr, size_t maxlen, Rline * rptr)
{
rptr->read_fd = fd; /* save caller's arguments */
rptr->read_ptr = ptr;
rptr->read_maxlen = maxlen;
rptr->rl_cnt = 0; /* and init our counter & pointer */
rptr->rl_bufptr = rptr->rl_buf;
}
ssize_t
readline_r(Rline * rptr)
{
int n;
int rc;
char c;
char * ptr;
ptr = rptr->read_ptr;
for (n = 1; n < rptr->read_maxlen; n++) {
if ((rc = my_read_r(rptr, &c)) == 1) {
*ptr++ = c;
if (c == '\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 */
}
}
*ptr = 0;
return(n);
}
ssize_t
Readline_r(Rline * rptr)
{
ssize_t n = readline_r(rptr);
if (n == -1) {
printf("readline_r error : %s\n", strerror(errno));
}
return(n);
}
#endif
#include "readline_r.h"
#define MAXN 16384 /* max #bytes that a client can request */
void
web_child(int sockfd)
{
int ntowrite;
ssize_t nread;
char line[MAXLINE];
char result[MAXN];
Rline rline;
readline_rinit(sockfd, line, MAXLINE, &rline);
for ( ; ; ) {
if ((nread = Readline_r(&rline)) == 0) {
return; /* connection closed by other end */
}
/* line from client specifies #bytes to write back */
ntowrite = atol(line);
if ((ntowrite <= 0) || (ntowrite > MAXN)) {
printf("client request for %d bytes\n", ntowrite);
exit(1);
}
if (writen(sockfd, result, ntowrite) != ntowrite) {
printf("writen error : %s\n", strerror(errno));
exit(1);
}
}
}
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/resource.h>
void
pr_cpu_time(void)
{
double user;
double sys;
struct rusage myusage;
struct rusage childusage;
if (getrusage(RUSAGE_SELF, &myusage) < 0) {
printf("getrusage error : %s\n", strerror(errno));
exit(1);
}
if (getrusage(RUSAGE_CHILDREN, &childusage) < 0) {
printf("getrusage error : %s\n", strerror(errno));
exit(1);
}
user = (double)myusage.ru_utime.tv_sec +
myusage.ru_utime.tv_usec/1000000.0;
user += (double)childusage.ru_utime.tv_sec +
childusage.ru_utime.tv_usec/1000000.0;
sys = (double)myusage.ru_stime.tv_sec +
myusage.ru_stime.tv_usec/1000000.0;
sys += (double)childusage.ru_stime.tv_sec +
childusage.ru_stime.tv_usec/1000000.0;
printf("\nuser time = %g, sys time = %g\n", user, sys);
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
void
sig_int(int signo)
{
pr_cpu_time();
exit(0);
}
int
main(int argc, char ** argv)
{
int listenfd;
int connfd;
socklen_t clilen;
socklen_t addrlen;
struct sockaddr * cliaddr;
if (argc == 2) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 3) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#>\n", argv[0]);
exit(1);
}
cliaddr = Malloc(addrlen);
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
web_child(connfd); /* process the request */
Close(connfd); /* parent closes connected socket */
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
void
sig_int(int signo)
{
pr_cpu_time();
exit(0);
}
void
sig_chld(int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
/* printf("child %d terminated\n", pid); */
}
return;
}
int
main(int argc, char ** argv)
{
int listenfd;
int connfd;
pid_t childpid;
socklen_t clilen;
socklen_t addrlen;
struct sockaddr * cliaddr;
if (argc == 2) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 3) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#>\n", argv[0]);
exit(1);
}
cliaddr = Malloc(addrlen);
if (my_signal(SIGCHLD, sig_chld) == SIG_ERR) {
err_msg("my_signal error", errno);
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
clilen = addrlen;
if ((connfd = accept(listenfd, cliaddr, &clilen)) < 0) {
if (errno == EINTR) {
continue; /* back to for() */
}
else {
err_msg("accept error", errno);
exit(1);
}
}
if ((childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
web_child(connfd); /* process request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
int nchildren;
pid_t * pids;
void
sig_int(int signo)
{
int i;
/* terminate all children */
for (i = 0; i < nchildren; i++) {
kill(pids[i], SIGTERM);
}
while (wait(NULL) > 0) { /* wait for all children */
}
if (errno != ECHILD) {
err_msg("wait error", errno);
}
pr_cpu_time();
exit(0);
}
void
child_main(int i, int listenfd, int addrlen)
{
int connfd;
socklen_t clilen;
struct sockaddr * cliaddr;
cliaddr = Malloc(addrlen);
printf("child %ld starting\n", (long)getpid());
for ( ; ; ) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
web_child(connfd); /* process the request */
Close(connfd);
}
}
pid_t
child_make(int i, int listenfd, int addrlen)
{
pid_t pid;
if ((pid = Fork()) > 0) {
return(pid); /* parent */
}
child_main(i, listenfd, addrlen); /* never returns */
}
int
main(int argc, char ** argv)
{
int listenfd;
int i;
socklen_t addrlen;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
exit(1);
}
nchildren = atoi(argv[argc-1]);
pids = Calloc(nchildren, sizeof(pid_t));
for (i = 0; i < nchildren; i++) {
pids[i] = child_make(i, listenfd, addrlen); /* parent returns */
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
pause(); /* everything done by children */
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
int nchildren;
pid_t * pids;
struct flock lock_it;
struct flock unlock_it;
int lock_fd = -1; /* fcntl() will fail if my_lock_init() not called */
void
my_lock_init(char * pathname)
{
char lock_file[1024];
/* must copy caller's string, in case it's a constant */
strncpy(lock_file, pathname, sizeof(lock_file));
if ((lock_fd = mkstemp(lock_file)) == -1) {
printf("mkstemp error : %s\n", strerror(errno));
exit(1);
}
if (unlink(lock_file) == -1) { /* but lock_fd remains open */
printf("unlink error : %s\n", strerror(errno));
exit(1);
}
lock_it.l_type = F_WRLCK;
lock_it.l_whence = SEEK_SET;
lock_it.l_start = 0;
lock_it.l_len = 0;
unlock_it.l_type = F_UNLCK;
unlock_it.l_whence = SEEK_SET;
unlock_it.l_start = 0;
unlock_it.l_len = 0;
}
void
my_lock_wait()
{
while (fcntl(lock_fd, F_SETLKW, &lock_it) == -1) {
if (errno == EINTR) {
continue;
}
else {
printf("fcntl error for my_lock_wait\n");
exit(1);
}
}
}
void
my_lock_release()
{
if (fcntl(lock_fd, F_SETLKW, &unlock_it) == -1) {
printf("fcntl error for my_lock_release\n");
exit(1);
}
}
void
child_main(int i, int listenfd, int addrlen)
{
int connfd;
socklen_t clilen;
struct sockaddr * cliaddr;
cliaddr = Malloc(addrlen);
printf("child %ld starting\n", (long)getpid());
for ( ; ; ) {
clilen = addrlen;
my_lock_wait();
connfd = Accept(listenfd, cliaddr, &clilen);
my_lock_release();
web_child(connfd); /* process the request */
Close(connfd);
}
}
pid_t
child_make(int i, int listenfd, int addrlen)
{
pid_t pid;
if ((pid = Fork()) > 0) {
return(pid); /* parent */
}
child_main(i, listenfd, addrlen); /* never returns */
}
void
sig_int(int signo)
{
int i;
/* terminate all children */
for (i = 0; i < nchildren; i++) {
kill(pids[i], SIGTERM);
}
while (wait(NULL) > 0) { /* wait for all children */
}
if (errno != ECHILD) {
err_msg("wait error", errno);
}
pr_cpu_time();
exit(0);
}
int
main(int argc, char ** argv)
{
int listenfd;
int i;
socklen_t addrlen;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
exit(1);
}
nchildren = atoi(argv[argc-1]);
pids = Calloc(nchildren, sizeof(pid_t));
my_lock_init("/tmp/lock.XXXXXX"); /* one lock file for all children */
for (i = 0; i < nchildren; i++) {
pids[i] = child_make(i, listenfd, addrlen); /* parent returns */
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
pause(); /* everything done by children */
}
}
#include <fcntl.h>
#include <sys/mman.h>
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
int nchildren;
pid_t * pids;
pthread_mutex_t * mptr; /* actual mutex will be in shared memory */
void
my_lock_init(char * pathname)
{
int fd;
int error;
pthread_mutexattr_t mattr;
if ((fd = open("/dev/zero", O_RDWR, 0)) == -1) {
err_msg("open /dev/zero error", errno);
}
if ((mptr = mmap(0, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0)) == MAP_FAILED) {
err_msg("mmap error", errno);
}
Close(fd);
if ((error = pthread_mutexattr_init(&mattr)) != 0) {
err_msg("pthread_mutexattr_init error", error);
}
if ((error = pthread_mutexattr_setpshared(&mattr,
PTHREAD_PROCESS_SHARED)) != 0) { /* process lock */
err_msg("pthread_mutexattr_setpshared error", error);
}
if ((error = pthread_mutex_init(mptr, &mattr)) != 0) {
err_msg("pthread_mutex_init error", error);
}
}
void
my_lock_wait()
{
Pthread_mutex_lock(mptr);
}
void
my_lock_release()
{
Pthread_mutex_unlock(mptr);
}
void
child_main(int i, int listenfd, int addrlen)
{
int connfd;
socklen_t clilen;
struct sockaddr * cliaddr;
cliaddr = Malloc(addrlen);
printf("child %ld starting\n", (long)getpid());
for ( ; ; ) {
clilen = addrlen;
my_lock_wait();
connfd = Accept(listenfd, cliaddr, &clilen);
my_lock_release();
web_child(connfd); /* process the request */
Close(connfd);
}
}
pid_t
child_make(int i, int listenfd, int addrlen)
{
pid_t pid;
if ((pid = Fork()) > 0) {
return(pid); /* parent */
}
child_main(i, listenfd, addrlen); /* never returns */
}
void
sig_int(int signo)
{
int i;
/* terminate all children */
for (i = 0; i < nchildren; i++) {
kill(pids[i], SIGTERM);
}
while (wait(NULL) > 0) { /* wait for all children */
}
if (errno != ECHILD) {
err_msg("wait error", errno);
}
pr_cpu_time();
exit(0);
}
int
main(int argc, char ** argv)
{
int listenfd;
int i;
socklen_t addrlen;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
exit(1);
}
nchildren = atoi(argv[argc-1]);
pids = Calloc(nchildren, sizeof(pid_t));
my_lock_init(NULL);
for (i = 0; i < nchildren; i++) {
pids[i] = child_make(i, listenfd, addrlen); /* parent returns */
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
pause(); /* everything done by children */
}
}
#include <unistd.h>
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "read_fd.h"
#include "write_fd.h"
#include "web_child.h"
#include "pr_cpu_time.h"
#define max(a, b) ((a) > (b) ? (a) : (b))
typedef struct {
pid_t child_pid; /* process ID */
int child_pipefd; /* parent's stream pipe to/from child */
int child_status; /* 0 = ready */
long child_count; /* # connections handled */
} Child;
Child * cptr; /* array of Child structures; calloc'ed */
int nchildren;
void
child_main(int i, int listenfd, int addrlen)
{
char c;
int connfd;
ssize_t n;
printf("child %ld starting\n", (long)getpid());
for ( ; ; ) {
if ((n = read_fd(STDERR_FILENO, &c, 1, &connfd)) < 0) {
err_msg("read_fd error", errno);
}
else if (n == 0) {
printf("read_fd returned 0\n");
exit(1);
}
if (connfd < 0) {
printf("no descriptor from read_fd\n");
exit(1);
}
web_child(connfd); /* process request */
Close(connfd);
/* tell parent we're ready again */
if (write(STDERR_FILENO, "", 1) != 1) {
err_msg("write error", errno);
}
}
}
pid_t
child_make(int i, int listenfd, int addrlen)
{
int sockfd[2];
pid_t pid;
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd) == -1) {
err_msg("socketpair error", errno);
}
if ((pid = Fork()) > 0) {
Close(sockfd[1]);
cptr[i].child_pid = pid;
cptr[i].child_pipefd = sockfd[0];
cptr[i].child_status = 0;
return(pid); /* parent */
}
/* child's stream pipe to parent */
if (dup2(sockfd[1], STDERR_FILENO) == -1) {
err_msg("dup2 error", errno);
}
Close(sockfd[0]);
Close(sockfd[1]);
Close(listenfd); /* child does not need this open */
child_main(i, listenfd, addrlen); /* never returns */
}
void
sig_int(int signo)
{
int i;
/* terminate all children */
for (i = 0; i < nchildren; i++) {
kill(cptr[i].child_pid, SIGTERM);
}
while (wait(NULL) > 0) { /* wait for all children */
}
if (errno != ECHILD) {
err_msg("wait error", errno);
}
pr_cpu_time();
for (i = 0; i < nchildren; i++) {
printf("child %d, %ld connections\n", i, cptr[i].child_count);
}
exit(0);
}
int
main(int argc, char ** argv)
{
int listenfd;
int i;
int navail;
int maxfd;
int nsel;
int connfd;
int rc;
ssize_t n;
fd_set rset;
fd_set masterset;
socklen_t addrlen;
socklen_t clilen;
struct sockaddr * cliaddr;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#children>\n", argv[0]);
exit(1);
}
FD_ZERO(&masterset);
FD_SET(listenfd, &masterset);
maxfd = listenfd;
cliaddr = Malloc(addrlen);
nchildren = atoi(argv[argc-1]);
navail = nchildren;
cptr = Calloc(nchildren, sizeof(Child));
/* prefork all the children */
for (i = 0; i < nchildren; i++) {
child_make(i, listenfd, addrlen); /* parent returns */
FD_SET(cptr[i].child_pipefd, &masterset);
maxfd = max(maxfd, cptr[i].child_pipefd);
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
rset = masterset;
if (navail <= 0) {
FD_CLR(listenfd, &rset); /* turn off if no available children */
}
if ((nsel = select(maxfd + 1, &rset, NULL, NULL, NULL)) == -1) {
err_msg("select error", errno);
}
/* check for new connections */
if (FD_ISSET(listenfd, &rset)) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
for (i = 0; i < nchildren; i++) {
if (cptr[i].child_status == 0) {
break; /* available */
}
}
if (i == nchildren) {
printf("no available children\n");
exit(1);
}
cptr[i].child_status = 1; /* mark child as busy */
cptr[i].child_count++;
navail--;
if ((n = write_fd(cptr[i].child_pipefd, "", 1, connfd)) < 0) {
err_msg("write_fd error", errno);
}
Close(connfd);
if (--nsel == 0) {
continue; /* all done with select() results */
}
}
/* find any newly-available children */
for (i = 0; i < nchildren; i++) {
if (FD_ISSET(cptr[i].child_pipefd, &rset)) {
if ((n = read(cptr[i].child_pipefd, &rc, 1)) < 0) {
err_msg("read error", errno);
}
else if (n == 0) {
printf("child %d terminated unexpectedly\n", i);
exit(1);
}
cptr[i].child_status = 0;
navail++;
if (--nsel == 0) {
break; /* all done with select() results */
}
}
}
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
void *
doit(void * arg)
{
Pthread_detach(pthread_self());
web_child((int)arg);
Close((int)arg);
return(NULL);
}
void
sig_int(int signo)
{
pr_cpu_time();
exit(0);
}
int
main(int argc, char ** argv)
{
int listenfd;
int connfd;
pthread_t tid;
socklen_t clilen;
socklen_t addrlen;
struct sockaddr * cliaddr;
if (argc == 2) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 3) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#>\n", argv[0]);
exit(1);
}
cliaddr = (struct sockaddr *)Malloc(addrlen);
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
Pthread_create(&tid, NULL, &doit, (void *)connfd);
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
typedef struct {
pthread_t thread_tid; /* thread ID */
long thread_count; /* # connections handled */
} Thread;
Thread * tptr; /* array of Thread structures; calloc'ed */
int listenfd;
int nthreads;
socklen_t addrlen;
pthread_mutex_t mlock = PTHREAD_MUTEX_INITIALIZER;
void *
thread_main(void * arg)
{
int connfd;
socklen_t clilen;
struct sockaddr * cliaddr;
cliaddr = Malloc(addrlen);
printf("thread %d starting\n", (int) arg);
for ( ; ; ) {
clilen = addrlen;
Pthread_mutex_lock(&mlock);
connfd = Accept(listenfd, cliaddr, &clilen);
Pthread_mutex_unlock(&mlock);
tptr[(int)arg].thread_count++;
web_child(connfd); /* process request */
Close(connfd);
}
}
void
thread_make(int i)
{
Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)i);
return; /* main thread returns */
}
void
sig_int(int signo)
{
int i;
pr_cpu_time();
for (i = 0; i < nthreads; i++) {
printf("thread %d, %ld connections\n", i, tptr[i].thread_count);
}
exit(0);
}
int
main(int argc, char ** argv)
{
int i;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#threads>\n", argv[0]);
exit(1);
}
nthreads = atoi(argv[argc-1]);
tptr = Calloc(nthreads, sizeof(Thread));
for (i = 0; i < nthreads; i++) {
thread_make(i); /* only main thread returns */
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
pause(); /* everything done by threads */
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
typedef struct {
pthread_t thread_tid; /* thread ID */
long thread_count; /* # connections handled */
} Thread;
Thread * tptr; /* array of Thread structures; calloc'ed */
#define MAXNCLI 32
int clifd[MAXNCLI];
int iget;
int iput;
pthread_mutex_t clifd_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t clifd_cond = PTHREAD_COND_INITIALIZER;
int nthreads;
void *
thread_main(void * arg)
{
int connfd;
printf("thread %d starting\n", (int)arg);
for ( ; ; ) {
Pthread_mutex_lock(&clifd_mutex);
while (iget == iput) {
Pthread_cond_wait(&clifd_cond, &clifd_mutex);
}
connfd = clifd[iget]; /* connected socket to service */
if (++iget == MAXNCLI) {
iget = 0;
}
Pthread_mutex_unlock(&clifd_mutex);
tptr[(int)arg].thread_count++;
web_child(connfd); /* process request */
Close(connfd);
}
}
void
thread_make(int i)
{
Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)i);
return; /* main thread returns */
}
void
sig_int(int signo)
{
int i;
pr_cpu_time();
for (i = 0; i < nthreads; i++) {
printf("thread %d, %ld connections\n", i, tptr[i].thread_count);
}
exit(0);
}
int
main(int argc, char ** argv)
{
int i;
int listenfd;
int connfd;
socklen_t addrlen;
socklen_t clilen;
struct sockaddr * cliaddr;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#threads>\n", argv[0]);
}
cliaddr = Malloc(addrlen);
nthreads = atoi(argv[argc-1]);
tptr = Calloc(nthreads, sizeof(Thread));
iget = iput = 0;
/* create all the threads */
for (i = 0; i < nthreads; i++) {
thread_make(i); /* only main thread returns */
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
Pthread_mutex_lock(&clifd_mutex);
clifd[iput] = connfd;
if (++iput == MAXNCLI) {
iput = 0;
}
if (iput == iget) {
printf("iput = iget = %d\n", iput); /* children too less to hold */
exit(1);
}
Pthread_cond_signal(&clifd_cond);
Pthread_mutex_unlock(&clifd_mutex);
}
}
#include "myio.h"
#include "warp.h"
#include "my_signal.h"
#include "tcp_listen.h"
#include "web_child.h"
#include "pr_cpu_time.h"
typedef struct {
pthread_t thread_tid; /* thread ID */
long thread_count; /* #connections handled */
} Thread;
Thread * tptr; /* array of Thread structures; calloc'ed */
int listenfd;
int nthreads;
socklen_t addrlen;
void *
thread_main(void * arg)
{
int connfd;
socklen_t clilen;
struct sockaddr * cliaddr;
cliaddr = Malloc(addrlen);
printf("thread %d starting\n", (int)arg);
for ( ; ; ) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);
tptr[(int)arg].thread_count++;
web_child(connfd); /* process the request */
Close(connfd);
}
}
void
thread_make(int i)
{
Pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void *)i);
return; /* main thread returns */
}
void
sig_int(int signo)
{
int i;
pr_cpu_time();
for (i = 0; i < nthreads; i++) {
printf("thread %d, %ld connections\n", i, tptr[i].thread_count);
}
exit(0);
}
int
main(int argc, char ** argv)
{
int i;
if (argc == 3) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 4) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: %s [ <host> ] <port#> <#threads>\n", argv[0]);
exit(1);
}
nthreads = atoi(argv[argc-1]);
tptr = Calloc(nthreads, sizeof(Thread));
for (i = 0; i < nthreads; i++) {
thread_make(i); /* only main thread returns */
}
if (my_signal(SIGINT, sig_int) == SIG_ERR) {
err_msg("my_signal error", errno);
}
for ( ; ; ) {
pause(); /* everything done by threads */
}
}