Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
3.7 KiB

  1. /* See LICENSE file for copyright and license details. */
  2. #include <errno.h>
  3. #include <pthread.h>
  4. #include <stddef.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "connection.h"
  8. #include "queue.h"
  9. #include "server.h"
  10. #include "util.h"
  11. struct worker_data {
  12. int insock;
  13. size_t nslots;
  14. const struct server *srv;
  15. };
  16. static void *
  17. server_worker(void *data)
  18. {
  19. queue_event *event = NULL;
  20. struct connection *connection, *c, *newc;
  21. struct worker_data *d = (struct worker_data *)data;
  22. int qfd;
  23. ssize_t nready;
  24. size_t i;
  25. /* allocate connections */
  26. if (!(connection = calloc(d->nslots, sizeof(*connection)))) {
  27. die("calloc:");
  28. }
  29. /* create event queue */
  30. if ((qfd = queue_create()) < 0) {
  31. exit(1);
  32. }
  33. /* add insock to the interest list (with data=NULL) */
  34. if (queue_add_fd(qfd, d->insock, QUEUE_EVENT_IN, 1, NULL) < 0) {
  35. exit(1);
  36. }
  37. /* allocate event array */
  38. if (!(event = reallocarray(event, d->nslots, sizeof(*event)))) {
  39. die("reallocarray:");
  40. }
  41. for (;;) {
  42. /* wait for new activity */
  43. if ((nready = queue_wait(qfd, event, d->nslots)) < 0) {
  44. exit(1);
  45. }
  46. /* handle events */
  47. for (i = 0; i < (size_t)nready; i++) {
  48. c = queue_event_get_data(&event[i]);
  49. if (queue_event_is_error(&event[i])) {
  50. if (c != NULL) {
  51. queue_rem_fd(qfd, c->fd);
  52. c->res.status = 0;
  53. connection_log(c);
  54. connection_reset(c);
  55. }
  56. continue;
  57. }
  58. if (c == NULL) {
  59. /* add new connection to the interest list */
  60. if (!(newc = connection_accept(d->insock,
  61. connection,
  62. d->nslots))) {
  63. /*
  64. * the socket is either blocking
  65. * or something failed.
  66. * In both cases, we just carry on
  67. */
  68. continue;
  69. }
  70. /*
  71. * add event to the interest list
  72. * (we want IN, because we start
  73. * with receiving the header)
  74. */
  75. if (queue_add_fd(qfd, newc->fd,
  76. QUEUE_EVENT_IN,
  77. 0, newc) < 0) {
  78. /* not much we can do here */
  79. continue;
  80. }
  81. } else {
  82. /* serve existing connection */
  83. connection_serve(c, d->srv);
  84. if (c->fd == 0) {
  85. /* we are done */
  86. memset(c, 0, sizeof(struct connection));
  87. continue;
  88. }
  89. /*
  90. * rearm the event based on the state
  91. * we are "stuck" at
  92. */
  93. switch(c->state) {
  94. case C_RECV_HEADER:
  95. if (queue_mod_fd(qfd, c->fd,
  96. QUEUE_EVENT_IN,
  97. c) < 0) {
  98. connection_reset(c);
  99. break;
  100. }
  101. break;
  102. case C_SEND_HEADER:
  103. case C_SEND_BODY:
  104. if (queue_mod_fd(qfd, c->fd,
  105. QUEUE_EVENT_OUT,
  106. c) < 0) {
  107. connection_reset(c);
  108. break;
  109. }
  110. break;
  111. default:
  112. break;
  113. }
  114. }
  115. }
  116. }
  117. return NULL;
  118. }
  119. void
  120. server_init_thread_pool(int insock, size_t nthreads, size_t nslots,
  121. const struct server *srv)
  122. {
  123. pthread_t *thread = NULL;
  124. struct worker_data *d = NULL;
  125. size_t i;
  126. /* allocate worker_data structs */
  127. if (!(d = reallocarray(d, nthreads, sizeof(*d)))) {
  128. die("reallocarray:");
  129. }
  130. for (i = 0; i < nthreads; i++) {
  131. d[i].insock = insock;
  132. d[i].nslots = nslots;
  133. d[i].srv = srv;
  134. }
  135. /* allocate and initialize thread pool */
  136. if (!(thread = reallocarray(thread, nthreads, sizeof(*thread)))) {
  137. die("reallocarray:");
  138. }
  139. for (i = 0; i < nthreads; i++) {
  140. if (pthread_create(&thread[i], NULL, server_worker, &d[i]) != 0) {
  141. if (errno == EAGAIN) {
  142. die("You need to run as root or have "
  143. "CAP_SYS_RESOURCE set, or are trying "
  144. "to create more threads than the "
  145. "system can offer");
  146. } else {
  147. die("pthread_create:");
  148. }
  149. }
  150. }
  151. /* wait for threads */
  152. for (i = 0; i < nthreads; i++) {
  153. if ((errno = pthread_join(thread[i], NULL))) {
  154. warn("pthread_join:");
  155. }
  156. }
  157. }