diff options
Diffstat (limited to 'ot_tcp.c')
| -rw-r--r-- | ot_tcp.c | 83 |
1 files changed, 82 insertions, 1 deletions
| @@ -5,6 +5,10 @@ | |||
| 5 | 5 | ||
| 6 | /* System */ | 6 | /* System */ |
| 7 | #include <errno.h> | 7 | #include <errno.h> |
| 8 | #include <pthread.h> | ||
| 9 | #include <stdatomic.h> | ||
| 10 | #include <stdio.h> | ||
| 11 | #include <stdlib.h> | ||
| 8 | #include <string.h> | 12 | #include <string.h> |
| 9 | #include <unistd.h> | 13 | #include <unistd.h> |
| 10 | 14 | ||
| @@ -149,9 +153,86 @@ void tcp_accept(const int64_t serversocket, struct ot_workstruct *ws) { | |||
| 149 | if (fdstate_generation((int)sock) != generation) | 153 | if (fdstate_generation((int)sock) != generation) |
| 150 | continue; | 154 | continue; |
| 151 | 155 | ||
| 152 | if (http_adopt(sock, &cookie) == -1) | 156 | /* Handling it may already have given it a heap home and handed it to |
| 157 | another thread, and then it is no longer this frame's to touch */ | ||
| 158 | if (fdstate_cookie((int)sock) != &cookie) | ||
| 159 | fdstate_release((int)sock); | ||
| 160 | else if (!http_adopt(sock)) | ||
| 153 | http_close(sock); | 161 | http_close(sock); |
| 154 | else | 162 | else |
| 155 | fdstate_release((int)sock); | 163 | fdstate_release((int)sock); |
| 156 | } | 164 | } |
| 157 | } | 165 | } |
| 166 | |||
| 167 | /* One of these per worker, each allocated on its own so that growing the | ||
| 168 | array below never moves the one a running worker holds. */ | ||
| 169 | struct tcp_worker { | ||
| 170 | pthread_t thread; | ||
| 171 | int64_t sock; | ||
| 172 | _Atomic int left; | ||
| 173 | }; | ||
| 174 | |||
| 175 | static struct tcp_worker **g_workers; | ||
| 176 | static size_t g_worker_count; | ||
| 177 | |||
| 178 | /* A worker blocks in accept and nowhere else: the connection it is handed is | ||
| 179 | non blocking, so a client that stops talking is given to the event loop | ||
| 180 | rather than keeping this thread. */ | ||
| 181 | static void *tcp_worker(void *args) { | ||
| 182 | struct tcp_worker *me = args; | ||
| 183 | struct ot_workstruct ws; | ||
| 184 | |||
| 185 | if (workstruct_init(&ws) == -1) { | ||
| 186 | fprintf(stderr, "Warning: a tcp worker could not get its buffers and will not run.\n"); | ||
| 187 | atomic_store(&me->left, 1); | ||
| 188 | return NULL; | ||
| 189 | } | ||
| 190 | |||
| 191 | while (g_opentracker_running) | ||
| 192 | tcp_accept(me->sock, &ws); | ||
| 193 | |||
| 194 | workstruct_deinit(&ws); | ||
| 195 | atomic_store(&me->left, 1); | ||
| 196 | return NULL; | ||
| 197 | } | ||
| 198 | |||
| 199 | void tcp_worker_install(int64_t sock) { | ||
| 200 | struct tcp_worker **grown = realloc(g_workers, (g_worker_count + 1) * sizeof(*g_workers)); | ||
| 201 | struct tcp_worker *worker; | ||
| 202 | |||
| 203 | if (!grown || !(worker = calloc(1, sizeof(*worker)))) { | ||
| 204 | fprintf(stderr, "Warning: out of memory installing a tcp worker, this socket stays with the workers already running.\n"); | ||
| 205 | g_workers = grown ? grown : g_workers; | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | g_workers = grown; | ||
| 209 | worker->sock = sock; | ||
| 210 | |||
| 211 | socket_set_blocking((int)sock, 1); | ||
| 212 | socket_defer_accept((int)sock); | ||
| 213 | |||
| 214 | if (pthread_create(&worker->thread, NULL, tcp_worker, worker)) | ||
| 215 | free(worker); | ||
| 216 | else | ||
| 217 | g_workers[g_worker_count++] = worker; | ||
| 218 | } | ||
| 219 | |||
| 220 | void tcp_workers_deinit(void) { | ||
| 221 | size_t i; | ||
| 222 | |||
| 223 | for (i = 0; i < g_worker_count; ++i) { | ||
| 224 | struct tcp_worker *worker = g_workers[i]; | ||
| 225 | |||
| 226 | /* Repeated because a signal only interrupts a call already under way */ | ||
| 227 | while (!atomic_load(&worker->left)) { | ||
| 228 | pthread_kill(worker->thread, OT_SIGNAL_WAKE); | ||
| 229 | usleep(1000); | ||
| 230 | } | ||
| 231 | pthread_join(worker->thread, NULL); | ||
| 232 | free(worker); | ||
| 233 | } | ||
| 234 | |||
| 235 | free(g_workers); | ||
| 236 | g_workers = NULL; | ||
| 237 | g_worker_count = 0; | ||
| 238 | } | ||
