web03.lc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "unpthread.h"## 1 ##src/threads/web03.c##
  2. #include <thread.h> /* Solaris threads */## 2 ##src/threads/web03.c##
  3. #define MAXFILES 20## 3 ##src/threads/web03.c##
  4. #define SERV "80" /* port number or service name */## 4 ##src/threads/web03.c##
  5. struct file {## 5 ##src/threads/web03.c##
  6. char *f_name; /* filename */## 6 ##src/threads/web03.c##
  7. char *f_host; /* hostname or IP address */## 7 ##src/threads/web03.c##
  8. int f_fd; /* descriptor */## 8 ##src/threads/web03.c##
  9. int f_flags; /* F_xxx below */## 9 ##src/threads/web03.c##
  10. pthread_t f_tid; /* thread ID */## 10 ##src/threads/web03.c##
  11. } file[MAXFILES];## 11 ##src/threads/web03.c##
  12. #define F_CONNECTING 1 /* connect() in progress */## 12 ##src/threads/web03.c##
  13. #define F_READING 2 /* connect() complete; now reading */## 13 ##src/threads/web03.c##
  14. #define F_DONE 4 /* all done */## 14 ##src/threads/web03.c##
  15. #define F_JOINED 8 /* main has pthread_join'ed */## 15 ##src/threads/web03.c##
  16. #define GET_CMD "GET %s HTTP/1.0\r\n\r\n"## 16 ##src/threads/web03.c##
  17. int nconn, nfiles, nlefttoconn, nlefttoread;## 17 ##src/threads/web03.c##
  18. int ndone; /* number of terminated threads */## 18 ##src/threads/web03.c##
  19. pthread_mutex_t ndone_mutex = PTHREAD_MUTEX_INITIALIZER;## 19 ##src/threads/web03.c##
  20. pthread_cond_t ndone_cond = PTHREAD_COND_INITIALIZER;## 20 ##src/threads/web03.c##
  21. void *do_get_read(void *);## 21 ##src/threads/web03.c##
  22. void home_page(const char *, const char *);## 22 ##src/threads/web03.c##
  23. void write_get_cmd(struct file *);## 23 ##src/threads/web03.c##
  24. int## 24 ##src/threads/web03.c##
  25. main(int argc, char **argv)## 25 ##src/threads/web03.c##
  26. {## 26 ##src/threads/web03.c##
  27. int i, maxnconn;## 27 ##src/threads/web03.c##
  28. pthread_t tid;## 28 ##src/threads/web03.c##
  29. struct file *fptr;## 29 ##src/threads/web03.c##
  30. if (argc < 5)## 30 ##src/threads/web03.c##
  31. err_quit("usage: web <#conns> <IPaddr> <homepage> file1 ...");## 31 ##src/threads/web03.c##
  32. maxnconn = atoi(argv[1]);## 32 ##src/threads/web03.c##
  33. nfiles = min(argc - 4, MAXFILES);## 33 ##src/threads/web03.c##
  34. for (i = 0; i < nfiles; i++) {## 34 ##src/threads/web03.c##
  35. file[i].f_name = argv[i + 4];## 35 ##src/threads/web03.c##
  36. file[i].f_host = argv[2];## 36 ##src/threads/web03.c##
  37. file[i].f_flags = 0;## 37 ##src/threads/web03.c##
  38. }## 38 ##src/threads/web03.c##
  39. printf("nfiles = %d\n", nfiles);## 39 ##src/threads/web03.c##
  40. home_page(argv[2], argv[3]);## 40 ##src/threads/web03.c##
  41. nlefttoread = nlefttoconn = nfiles;## 41 ##src/threads/web03.c##
  42. nconn = 0;## 42 ##src/threads/web03.c##
  43. /* include web2 */
  44. while (nlefttoread > 0) {## 43 ##src/threads/web03.c##
  45. while (nconn < maxnconn && nlefttoconn > 0) {## 44 ##src/threads/web03.c##
  46. /* 4find a file to read */## 45 ##src/threads/web03.c##
  47. for (i = 0; i < nfiles; i++)## 46 ##src/threads/web03.c##
  48. if (file[i].f_flags == 0)## 47 ##src/threads/web03.c##
  49. break;## 48 ##src/threads/web03.c##
  50. if (i == nfiles)## 49 ##src/threads/web03.c##
  51. err_quit("nlefttoconn = %d but nothing found", nlefttoconn);## 50 ##src/threads/web03.c##
  52. file[i].f_flags = F_CONNECTING;## 51 ##src/threads/web03.c##
  53. Pthread_create(&tid, NULL, &do_get_read, &file[i]);## 52 ##src/threads/web03.c##
  54. file[i].f_tid = tid;## 53 ##src/threads/web03.c##
  55. nconn++;## 54 ##src/threads/web03.c##
  56. nlefttoconn--;## 55 ##src/threads/web03.c##
  57. }## 56 ##src/threads/web03.c##
  58. /* 4Wait for one of the threads to terminate */## 57 ##src/threads/web03.c##
  59. Pthread_mutex_lock(&ndone_mutex);## 58 ##src/threads/web03.c##
  60. while (ndone == 0)## 59 ##src/threads/web03.c##
  61. Pthread_cond_wait(&ndone_cond, &ndone_mutex);## 60 ##src/threads/web03.c##
  62. for (i = 0; i < nfiles; i++) {## 61 ##src/threads/web03.c##
  63. if (file[i].f_flags & F_DONE) {## 62 ##src/threads/web03.c##
  64. Pthread_join(file[i].f_tid, (void **) &fptr);## 63 ##src/threads/web03.c##
  65. if (&file[i] != fptr)## 64 ##src/threads/web03.c##
  66. err_quit("file[i] != fptr");## 65 ##src/threads/web03.c##
  67. fptr->f_flags = F_JOINED; /* clears F_DONE */## 66 ##src/threads/web03.c##
  68. ndone--;## 67 ##src/threads/web03.c##
  69. nconn--;## 68 ##src/threads/web03.c##
  70. nlefttoread--;## 69 ##src/threads/web03.c##
  71. printf("thread %d for %s done\n", fptr->f_tid, fptr->f_name);## 70 ##src/threads/web03.c##
  72. }## 71 ##src/threads/web03.c##
  73. }## 72 ##src/threads/web03.c##
  74. Pthread_mutex_unlock(&ndone_mutex);## 73 ##src/threads/web03.c##
  75. }## 74 ##src/threads/web03.c##
  76. exit(0);## 75 ##src/threads/web03.c##
  77. }## 76 ##src/threads/web03.c##
  78. /* end web2 */
  79. void *## 77 ##src/threads/web03.c##
  80. do_get_read(void *vptr)## 78 ##src/threads/web03.c##
  81. {## 79 ##src/threads/web03.c##
  82. int fd, n;## 80 ##src/threads/web03.c##
  83. char line[MAXLINE];## 81 ##src/threads/web03.c##
  84. struct file *fptr;## 82 ##src/threads/web03.c##
  85. fptr = (struct file *) vptr;## 83 ##src/threads/web03.c##
  86. fd = Tcp_connect(fptr->f_host, SERV);## 84 ##src/threads/web03.c##
  87. fptr->f_fd = fd;## 85 ##src/threads/web03.c##
  88. printf("do_get_read for %s, fd %d, thread %d\n",## 86 ##src/threads/web03.c##
  89. fptr->f_name, fd, fptr->f_tid);## 87 ##src/threads/web03.c##
  90. write_get_cmd(fptr); /* write() the GET command */## 88 ##src/threads/web03.c##
  91. /* 4Read server's reply */## 89 ##src/threads/web03.c##
  92. for (;;) {## 90 ##src/threads/web03.c##
  93. if ((n = Read(fd, line, MAXLINE)) == 0)## 91 ##src/threads/web03.c##
  94. break; /* server closed connection */## 92 ##src/threads/web03.c##
  95. printf("read %d bytes from %s\n", n, fptr->f_name);## 93 ##src/threads/web03.c##
  96. }## 94 ##src/threads/web03.c##
  97. printf("end-of-file on %s\n", fptr->f_name);## 95 ##src/threads/web03.c##
  98. Close(fd);## 96 ##src/threads/web03.c##
  99. fptr->f_flags = F_DONE; /* clears F_READING */## 97 ##src/threads/web03.c##
  100. Pthread_mutex_lock(&ndone_mutex);## 98 ##src/threads/web03.c##
  101. ndone++;## 99 ##src/threads/web03.c##
  102. Pthread_cond_signal(&ndone_cond);##100 ##src/threads/web03.c##
  103. Pthread_mutex_unlock(&ndone_mutex);##101 ##src/threads/web03.c##
  104. return (fptr); /* terminate thread */##102 ##src/threads/web03.c##
  105. }##103 ##src/threads/web03.c##
  106. void##104 ##src/threads/web03.c##
  107. write_get_cmd(struct file *fptr)##105 ##src/threads/web03.c##
  108. {##106 ##src/threads/web03.c##
  109. int n;##107 ##src/threads/web03.c##
  110. char line[MAXLINE];##108 ##src/threads/web03.c##
  111. n = snprintf(line, sizeof(line), GET_CMD, fptr->f_name);##109 ##src/threads/web03.c##
  112. Writen(fptr->f_fd, line, n);##110 ##src/threads/web03.c##
  113. printf("wrote %d bytes for %s\n", n, fptr->f_name);##111 ##src/threads/web03.c##
  114. fptr->f_flags = F_READING; /* clears F_CONNECTING */##112 ##src/threads/web03.c##
  115. }##113 ##src/threads/web03.c##
  116. void##114 ##src/threads/web03.c##
  117. home_page(const char *host, const char *fname)##115 ##src/threads/web03.c##
  118. {##116 ##src/threads/web03.c##
  119. int fd, n;##117 ##src/threads/web03.c##
  120. char line[MAXLINE];##118 ##src/threads/web03.c##
  121. fd = Tcp_connect(host, SERV); /* blocking connect() */##119 ##src/threads/web03.c##
  122. n = snprintf(line, sizeof(line), GET_CMD, fname);##120 ##src/threads/web03.c##
  123. Writen(fd, line, n);##121 ##src/threads/web03.c##
  124. for (;;) {##122 ##src/threads/web03.c##
  125. if ((n = Read(fd, line, MAXLINE)) == 0)##123 ##src/threads/web03.c##
  126. break; /* server closed connection */##124 ##src/threads/web03.c##
  127. printf("read %d bytes of home page\n", n);##125 ##src/threads/web03.c##
  128. /* do whatever with data */##126 ##src/threads/web03.c##
  129. }##127 ##src/threads/web03.c##
  130. printf("end-of-file on home page\n");##128 ##src/threads/web03.c##
  131. Close(fd);##129 ##src/threads/web03.c##
  132. }##130 ##src/threads/web03.c##