web02.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /* Doesn't work right. Main thread sucks up all the CPU time polling unless
  2. we call thr_yield(). */
  3. #include "unpthread.h"
  4. #include <thread.h> /* Solaris threads */
  5. #define MAXFILES 20
  6. #define SERV "80" /* port number or service name */
  7. struct file {
  8. char *f_name; /* filename */
  9. char *f_host; /* hostname or IP address */
  10. int f_fd; /* descriptor */
  11. int f_flags; /* F_xxx below */
  12. pthread_t f_tid; /* thread ID */
  13. } file[MAXFILES];
  14. #define F_CONNECTING 1 /* connect() in progress */
  15. #define F_READING 2 /* connect() complete; now reading */
  16. #define F_DONE 4 /* all done */
  17. #define F_JOINED 8 /* main has pthread_join'ed */
  18. int nconn, nfiles, nlefttoconn, nlefttoread;
  19. char get[] = "GET / HTTP/1.0\r\n\r\n"; /* for home page */
  20. int ndone; /* number of terminated threads & mutex */
  21. pthread_mutex_t ndone_mutex = PTHREAD_MUTEX_INITIALIZER;
  22. void *do_get_read(void *);
  23. void home_page(const char *, const char *);
  24. void write_get_cmd(struct file *);
  25. int
  26. main(int argc, char **argv)
  27. {
  28. int i, n, maxnconn;
  29. pthread_t tid;
  30. struct file *fptr;
  31. if (argc < 5)
  32. err_quit("usage: web <#conns> <IPaddr> <homepage> file1 ...");
  33. maxnconn = atoi(argv[1]);
  34. nfiles = min(argc - 4, MAXFILES);
  35. for (i = 0; i < nfiles; i++) {
  36. file[i].f_name = argv[i + 4];
  37. file[i].f_host = argv[2];
  38. file[i].f_flags = 0;
  39. }
  40. printf("nfiles = %d\n", nfiles);
  41. home_page(argv[2], argv[3]);
  42. nlefttoread = nlefttoconn = nfiles;
  43. nconn = 0;
  44. while (nlefttoread > 0) {
  45. /* printf("nconn = %d, nlefttoconn = %d\n", nconn, nlefttoconn); */
  46. while (nconn < maxnconn && nlefttoconn > 0) {
  47. /* find a file to read */
  48. for (i = 0 ; i < nfiles; i++)
  49. if (file[i].f_flags == 0)
  50. break;
  51. if (i == nfiles)
  52. err_quit("nlefttoconn = %d but nothing found", nlefttoconn);
  53. if ( (n = pthread_create(&tid, NULL, &do_get_read, &file[i])) != 0)
  54. errno = n, err_sys("pthread_create error");
  55. printf("created thread %d\n", tid);
  56. file[i].f_tid = tid;
  57. file[i].f_flags = F_CONNECTING;
  58. nconn++;
  59. nlefttoconn--;
  60. }
  61. thr_yield();
  62. /* See if one of the threads is done */
  63. if ( (n = pthread_mutex_lock(&ndone_mutex)) != 0)
  64. errno = n, err_sys("pthread_mutex_lock error");
  65. if (ndone > 0) {
  66. for (i = 0; i < nfiles; i++) {
  67. if (file[i].f_flags & F_DONE) {
  68. if ( (n = pthread_join(file[i].f_tid, (void **) &fptr)) != 0)
  69. errno = n, err_sys("pthread_join error");
  70. if (&file[i] != fptr)
  71. err_quit("file[i] != fptr");
  72. fptr->f_flags = F_JOINED; /* clears F_DONE */
  73. ndone--;
  74. nconn--;
  75. nlefttoread--;
  76. printf("thread id %d for %s done\n",
  77. file[i].f_tid, fptr->f_name);
  78. }
  79. }
  80. }
  81. if ( (n = pthread_mutex_unlock(&ndone_mutex)) != 0)
  82. errno = n, err_sys("pthread_mutex_unlock error");
  83. }
  84. exit(0);
  85. }
  86. void *
  87. do_get_read(void *vptr)
  88. {
  89. int fd, n;
  90. char line[MAXLINE];
  91. struct file *fptr;
  92. fptr = (struct file *) vptr;
  93. fd = Tcp_connect(fptr->f_host, SERV);
  94. fptr->f_fd = fd;
  95. printf("do_get_read for %s, fd %d, thread %d\n",
  96. fptr->f_name, fd, fptr->f_tid);
  97. write_get_cmd(fptr); /* write() the GET command */
  98. /* Read server's reply */
  99. for ( ; ; ) {
  100. if ( (n = read(fd, line, MAXLINE)) <= 0) {
  101. if (n == 0)
  102. break; /* server closed connection */
  103. else
  104. err_sys("read error");
  105. }
  106. printf("read %d bytes from %s\n", n, fptr->f_name);
  107. }
  108. printf("end-of-file on %s\n", fptr->f_name);
  109. close(fd);
  110. fptr->f_flags = F_DONE; /* clears F_READING */
  111. if ( (n = pthread_mutex_lock(&ndone_mutex)) != 0)
  112. errno = n, err_sys("pthread_mutex_lock error");
  113. ndone++;
  114. if ( (n = pthread_mutex_unlock(&ndone_mutex)) != 0)
  115. errno = n, err_sys("pthread_mutex_unlock error");
  116. return(fptr); /* terminate thread */
  117. }
  118. void
  119. write_get_cmd(struct file *fptr)
  120. {
  121. int n;
  122. char line[MAXLINE];
  123. strcpy(line, "GET ");
  124. strcat(line, fptr->f_name);
  125. strcat(line, " HTTP/1.0\r\n\r\n");
  126. n = strlen(line);
  127. if (writen(fptr->f_fd, line, n) != n)
  128. err_sys("writen error");
  129. printf("wrote %d bytes for %s\n", n, fptr->f_name);
  130. fptr->f_flags = F_READING; /* clears F_CONNECTING */
  131. }
  132. void
  133. home_page(const char *host, const char *fname)
  134. {
  135. int fd, n;
  136. char line[MAXLINE];
  137. fd = Tcp_connect(host, SERV);
  138. strcpy(line, "GET ");
  139. strcat(line, fname);
  140. strcat(line, " HTTP/1.0\r\n\r\n");
  141. n = strlen(line);
  142. if (writen(fd, line, n) != n)
  143. err_sys("writen error");
  144. for ( ; ; ) {
  145. if ( (n = read(fd, line, MAXLINE)) <= 0) {
  146. if (n == 0)
  147. break; /* server closed connection */
  148. else
  149. err_sys("read error");
  150. }
  151. printf("read %d bytes of home page\n", n);
  152. /* do whatever with data */
  153. }
  154. printf("end-of-file on home page\n");
  155. close(fd);
  156. }