summaryrefslogtreecommitdiff
path: root/ot_tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_tcp.c')
-rw-r--r--ot_tcp.c66
1 files changed, 5 insertions, 61 deletions
diff --git a/ot_tcp.c b/ot_tcp.c
index 47697ca..4a5008b 100644
--- a/ot_tcp.c
+++ b/ot_tcp.c
@@ -20,6 +20,7 @@
20#include "ot_http.h" 20#include "ot_http.h"
21#include "ot_mutex.h" 21#include "ot_mutex.h"
22#include "ot_socket.h" 22#include "ot_socket.h"
23#include "ot_worker.h"
23#include "ot_stats.h" 24#include "ot_stats.h"
24#include "ot_tcp.h" 25#include "ot_tcp.h"
25#include "trackerlogic.h" 26#include "trackerlogic.h"
@@ -164,75 +165,18 @@ void tcp_accept(const int64_t serversocket, struct ot_workstruct *ws) {
164 } 165 }
165} 166}
166 167
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. */
169struct tcp_worker {
170 pthread_t thread;
171 int64_t sock;
172 _Atomic int left;
173};
174
175static struct tcp_worker **g_workers;
176static size_t g_worker_count;
177
178/* A worker blocks in accept and nowhere else: the connection it is handed is 168/* 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 169 non blocking, so a client that stops talking is given to the event loop
180 rather than keeping this thread. */ 170 rather than keeping this thread. */
181static void *tcp_worker(void *args) { 171static void tcp_run(struct ot_worker *me) {
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) 172 while (g_opentracker_running)
192 tcp_accept(me->sock, &ws); 173 tcp_accept(me->sock, &me->ws);
193
194 workstruct_deinit(&ws);
195 atomic_store(&me->left, 1);
196 return NULL;
197} 174}
198 175
199void tcp_worker_install(int64_t sock) { 176void 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); 177 socket_set_blocking((int)sock, 1);
212 socket_defer_accept((int)sock); 178 socket_defer_accept((int)sock);
213 179
214 if (pthread_create(&worker->thread, NULL, tcp_worker, worker)) 180 if (worker_start(tcp_run, sock) == -1)
215 free(worker); 181 fprintf(stderr, "Warning: could not install a tcp worker, this socket stays with the workers already running.\n");
216 else
217 g_workers[g_worker_count++] = worker;
218}
219
220void 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} 182}