worker.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // SPDX-License-Identifier: GPL-2.0 or GPL-3.0
  2. // Copyright © 2018-2019 Ariadne Devos
  3. /* shttpd - functions for workers */
  4. /* # High-level architecture
  5. There are multiple processes.
  6. In a process, there are multiple workers.
  7. Each worker has its own file descriptor table.
  8. This table can have the following format:
  9. 0: unix socket (control lifecycle)
  10. 1: /dev/null (for now)
  11. 2: /dev/null (for now)
  12. 3: epollfd
  13. ???: asynchronous IO?
  14. ...: accept sockets, read/write sockets, open files,
  15. connections to external services ...
  16. The unix socket is for controlling when the worker should stop.
  17. The worker polls for changes in file descriptor readyness and reacts
  18. to those and asynchronous IO events.
  19. Everything is mutually distrusting.
  20. # Seperation of knowledge
  21. Use case: a HTTPS server. A HTTPS server conceptually is TLS encryption
  22. after a HTTP server encrypted connections. The HTTP code and TLS code
  23. (or even HTTPS code and encryption and signing) can live in different
  24. workers or processes.
  25. TODO: an intra-shttpd communication system (passing around and transcribing
  26. paper).
  27. # Paper
  28. A character buffer that can be passed around.
  29. # The control thread
  30. - Control thread creates worker.
  31. - Control thread -> asks worker to perform apoptosis
  32. - Control thread -> sends tasks to worker
  33. - Control thread -> asks tasks from worker -> sends tasks to control thread
  34. - Worker thread -> reports hard errors to control thread
  35. - Kernel -> notifies worker -> asks kernel to do stuff
  36. */
  37. #include <stddef.h>
  38. #include <stdint.h>
  39. #include <sys/epoll.h>
  40. /* Don't change this group! control.c relies upon these values. */
  41. #define sHT_FD_CONTROL 0
  42. #define sHT_FD_STDOUT 1
  43. #define sHT_FD_STDERR 2
  44. /* Only for sHT_start_worker. Points to a worker executable. */
  45. #define sHT_FD_WORKEREXE 4
  46. #include <sHT/paper.h>
  47. #include <sHT/task.h>
  48. #include <sHT/taskset.h>
  49. #include <sHT/scheduling.h>
  50. typedef unsigned int sHT_worker_flags;
  51. #define sHT_WORKER_OOM 1
  52. #define sHT_WORKER_LIMIT_TASKS 2
  53. #define sHT_WORKER_LIMIT_PAPER 4
  54. #define sHT_WORKER_LIMIT_WATCHES 8
  55. /* file descriptor */
  56. #define sHT_WORKER_LIMIT_FDS 16
  57. /* file descriptor */
  58. #define sHT_WORKER_SYSTEM_FDS 32
  59. struct sHT_objcache;
  60. struct sHT_worker
  61. {
  62. struct sHT_objcache *papers;
  63. /* Use sHT_deschedule_rr, sHT_schedule_rr */
  64. struct sHT_taskset todo;
  65. struct sHT_objcache *free_streams;
  66. /* length: todo->n */
  67. struct epoll_event *epoll_events;
  68. /* indexed by fd, length: todo->capacity */
  69. struct sHT_task *tasks;
  70. /* The control thread is notified if any is set. */
  71. sHT_worker_flags flags;
  72. sHT_watch_set watches;
  73. };
  74. /* epoll_wait(2) returned n events. Schedule corresponding tasks, setting
  75. task->epollflags.
  76. @var{n} must be less than SSIZE_MAX. */
  77. __attribute__((nonnull (1)))
  78. void
  79. sHT_schedule_events(struct sHT_worker *worker, size_t n);
  80. /* _logic$ is defined by worker-specific code */
  81. __attribute__((nonnull (1, 2)))
  82. void
  83. sHT_diy_logic(struct sHT_worker *worker, struct sHT_task *task);
  84. __attribute__((nonnull (1, 2)))
  85. void
  86. sHT_aio_logic(struct sHT_worker *worker, struct sHT_task *task);
  87. /* Send information about resource utilisation to the control thread.
  88. More specifically,
  89. send and clear task->flags.
  90. Doesn't allocate any resources.
  91. (May be extended) */
  92. __attribute__((nonnull (1, 2)))
  93. void
  94. sHT_sendstatus_task(struct sHT_worker *worker, struct sHT_task *task);
  95. /* Perform the IO actions of worker->io_type.
  96. Then, call sHT_diy_logic, sHT_socket_logic, sHT_aio_logic or
  97. sHT_accept_logic, depending on the io type.
  98. task must reschedule itself if it:
  99. - it has some things to do, even if no IO is possible
  100. */
  101. __attribute__((nonnull (1, 2)))
  102. void
  103. sHT_perform_task(struct sHT_worker *worker, struct sHT_task *task);
  104. __attribute__((nonnull (1)))
  105. _Noreturn void
  106. sHT_worker(struct sHT_worker *worker);