Bug Summary

File:lwan-thread.c
Warning:line 662, column 25
Assigned value is garbage or undefined

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name lwan-thread.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=all -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -fno-plt -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/clang/10.0.0 -include /home/buildbot/lwan-worker/clang-analyze/build/lwan-build-config.h -D _FILE_OFFSET_BITS=64 -D _TIME_BITS=64 -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib/missing -I /usr/include/luajit-2.0 -I /usr/include/valgrind -I /home/buildbot/lwan-worker/clang-analyze/build/src/lib -I /home/buildbot/lwan-worker/clang-analyze/build -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/10.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -Wno-free-nonheap-object -std=gnu99 -fdebug-compilation-dir /home/buildbot/lwan-worker/clang-analyze/build/src/lib -ferror-limit 19 -fmessage-length 0 -stack-protector 2 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -faddrsig -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2020-07-11-180817-1285247-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c
1/*
2 * lwan - simple web server
3 * Copyright (c) 2012, 2013 Leandro A. F. Pereira <leandro@hardinfo.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 * USA.
19 */
20
21#define _GNU_SOURCE
22#include <assert.h>
23#include <errno(*__errno_location ()).h>
24#include <fcntl.h>
25#include <pthread.h>
26#include <sched.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/epoll.h>
30#include <sys/ioctl.h>
31#include <sys/socket.h>
32#include <unistd.h>
33
34#if defined(HAVE_EVENTFD)
35#include <sys/eventfd.h>
36#endif
37
38#include "lwan-private.h"
39#include "lwan-tq.h"
40#include "list.h"
41
42static void lwan_strbuf_free_defer(void *data)
43{
44 lwan_strbuf_free((struct lwan_strbuf *)data);
45}
46
47static void graceful_close(struct lwan *l,
48 struct lwan_connection *conn,
49 char buffer[static DEFAULT_BUFFER_SIZE4096])
50{
51 int fd = lwan_connection_get_fd(l, conn);
52
53 while (TIOCOUTQ0x5411) {
54 /* This ioctl isn't probably doing what it says on the tin; the details
55 * are subtle, but it seems to do the trick to allow gracefully closing
56 * the connection in some cases with minimal system calls. */
57 int bytes_waiting;
58 int r = ioctl(fd, TIOCOUTQ0x5411, &bytes_waiting);
59
60 if (!r && !bytes_waiting) /* See note about close(2) below. */
61 return;
62 if (r < 0 && errno(*__errno_location ()) == EINTR4)
63 continue;
64
65 break;
66 }
67
68 if (UNLIKELY(shutdown(fd, SHUT_WR) < 0)__builtin_expect(((shutdown(fd, SHUT_WR) < 0)), (0))) {
69 if (UNLIKELY(errno == ENOTCONN)__builtin_expect((((*__errno_location ()) == 107)), (0)))
70 return;
71 }
72
73 for (int tries = 0; tries < 20; tries++) {
74 ssize_t r = read(fd, buffer, DEFAULT_BUFFER_SIZE4096);
75
76 if (!r)
77 break;
78
79 if (r < 0) {
80 switch (errno(*__errno_location ())) {
81 case EAGAIN11:
82 coro_yield(conn->coro, CONN_CORO_WANT_READ);
83 /* Fallthrough */
84 case EINTR4:
85 continue;
86 default:
87 return;
88 }
89 }
90
91 coro_yield(conn->coro, CONN_CORO_YIELD);
92 }
93
94 /* close(2) will be called when the coroutine yields with CONN_CORO_ABORT */
95}
96
97__attribute__((noreturn)) static int process_request_coro(struct coro *coro,
98 void *data)
99{
100 /* NOTE: This function should not return; coro_yield should be used
101 * instead. This ensures the storage for `strbuf` is alive when the
102 * coroutine ends and lwan_strbuf_free() is called. */
103 struct lwan_connection *conn = data;
104 struct lwan *lwan = conn->thread->lwan;
105 int fd = lwan_connection_get_fd(lwan, conn);
106 enum lwan_request_flags flags = lwan->config.request_flags;
107 struct lwan_strbuf strbuf = LWAN_STRBUF_STATIC_INIT(struct lwan_strbuf) { .buffer = "" };
108 char request_buffer[DEFAULT_BUFFER_SIZE4096];
109 struct lwan_value buffer = {.value = request_buffer, .len = 0};
110 char *next_request = NULL((void*)0);
111 char *header_start[N_HEADER_START64];
112 struct lwan_proxy proxy;
113 const int error_when_n_packets = lwan_calculate_n_packets(DEFAULT_BUFFER_SIZE4096);
114
115 coro_defer(coro, lwan_strbuf_free_defer, &strbuf);
116
117 const size_t init_gen = 1; /* 1 call to coro_defer() */
118 assert(init_gen == coro_deferred_get_generation(coro))((void) sizeof ((init_gen == coro_deferred_get_generation(coro
)) ? 1 : 0), __extension__ ({ if (init_gen == coro_deferred_get_generation
(coro)) ; else __assert_fail ("init_gen == coro_deferred_get_generation(coro)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 118, __extension__ __PRETTY_FUNCTION__); }))
;
119
120 while (true1) {
121 struct lwan_request_parser_helper helper = {
122 .buffer = &buffer,
123 .next_request = next_request,
124 .error_when_n_packets = error_when_n_packets,
125 .header_start = header_start,
126 };
127 struct lwan_request request = {
128 .conn = conn,
129 .global_response_headers = &lwan->headers,
130 .fd = fd,
131 .response = {.buffer = &strbuf},
132 .flags = flags,
133 .proxy = &proxy,
134 .helper = &helper,
135 };
136
137 lwan_process_request(lwan, &request, next_request);
138
139
140 if (LIKELY(conn->flags & CONN_IS_KEEP_ALIVE)__builtin_expect((!!(conn->flags & CONN_IS_KEEP_ALIVE)
), (1))
) {
141 if (next_request && *next_request) {
142 conn->flags |= CONN_CORK;
143 coro_yield(coro, CONN_CORO_WANT_WRITE);
144 } else {
145 conn->flags &= ~CONN_CORK;
146 coro_yield(coro, CONN_CORO_WANT_READ);
147 }
148 } else {
149 graceful_close(lwan, conn, request_buffer);
150 break;
151 }
152
153 lwan_strbuf_reset(&strbuf);
154 coro_deferred_run(coro, init_gen);
155
156 /* Only allow flags from config. */
157 flags = request.flags & (REQUEST_PROXIED | REQUEST_ALLOW_CORS);
158 next_request = helper.next_request;
159 }
160
161 coro_yield(coro, CONN_CORO_ABORT);
162 __builtin_unreachable();
163}
164
165static ALWAYS_INLINEinline __attribute__((always_inline)) uint32_t
166conn_flags_to_epoll_events(enum lwan_connection_flags flags)
167{
168 static const uint32_t map[CONN_EVENTS_MASK + 1] = {
169 [0 /* Suspended (timer or await) */] = EPOLLRDHUPEPOLLRDHUP,
170 [CONN_EVENTS_WRITE] = EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP,
171 [CONN_EVENTS_READ] = EPOLLINEPOLLIN | EPOLLRDHUPEPOLLRDHUP,
172 [CONN_EVENTS_READ_WRITE] = EPOLLINEPOLLIN | EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP,
173 };
174
175 return map[flags & CONN_EVENTS_MASK];
176}
177
178static void update_epoll_flags(int fd,
179 struct lwan_connection *conn,
180 int epoll_fd,
181 enum lwan_connection_coro_yield yield_result)
182{
183 static const enum lwan_connection_flags or_mask[CONN_CORO_MAX] = {
184 [CONN_CORO_YIELD] = 0,
185
186 [CONN_CORO_WANT_READ_WRITE] = CONN_EVENTS_READ_WRITE,
187 [CONN_CORO_WANT_READ] = CONN_EVENTS_READ,
188 [CONN_CORO_WANT_WRITE] = CONN_EVENTS_WRITE,
189
190 /* While the coro is suspended, we're not interested in either EPOLLIN
191 * or EPOLLOUT events. We still want to track this fd in epoll, though,
192 * so unset both so that only EPOLLRDHUP (plus the implicitly-set ones)
193 * are set. */
194 [CONN_CORO_SUSPEND_TIMER] = CONN_SUSPENDED_TIMER,
195 [CONN_CORO_SUSPEND_ASYNC_AWAIT] = CONN_SUSPENDED_ASYNC_AWAIT,
196
197 /* Ideally, when suspending a coroutine, the current flags&CONN_EVENTS_MASK
198 * would have to be stored and restored -- however, resuming as if the
199 * client coroutine is interested in a write event always guarantees that
200 * they'll be resumed as they're TCP sockets. There's a good chance that
201 * trying to read from a socket after resuming a coroutine will succeed,
202 * but if it doesn't because read() returns -EAGAIN, the I/O wrappers will
203 * yield with CONN_CORO_WANT_READ anyway. */
204 [CONN_CORO_RESUME] = CONN_EVENTS_WRITE,
205 };
206 static const enum lwan_connection_flags and_mask[CONN_CORO_MAX] = {
207 [CONN_CORO_YIELD] = ~0,
208
209 [CONN_CORO_WANT_READ_WRITE] = ~0,
210 [CONN_CORO_WANT_READ] = ~CONN_EVENTS_WRITE,
211 [CONN_CORO_WANT_WRITE] = ~CONN_EVENTS_READ,
212
213 [CONN_CORO_SUSPEND_TIMER] = ~(CONN_EVENTS_READ_WRITE | CONN_SUSPENDED_ASYNC_AWAIT),
214 [CONN_CORO_SUSPEND_ASYNC_AWAIT] = ~(CONN_EVENTS_READ_WRITE | CONN_SUSPENDED_TIMER),
215 [CONN_CORO_RESUME] = ~CONN_SUSPENDED,
216 };
217 enum lwan_connection_flags prev_flags = conn->flags;
218
219 conn->flags |= or_mask[yield_result];
220 conn->flags &= and_mask[yield_result];
221
222 if (conn->flags == prev_flags)
223 return;
224
225 struct epoll_event event = {
226 .events = conn_flags_to_epoll_events(conn->flags),
227 .data.ptr = conn,
228 };
229
230 if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event) < 0)__builtin_expect(((epoll_ctl(epoll_fd, 3, fd, &event) <
0)), (0))
)
231 lwan_status_perror("epoll_ctl")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 231, __FUNCTION__, "epoll_ctl")
;
232}
233
234static void clear_async_await_flag(void *data)
235{
236 struct lwan_connection *async_fd_conn = data;
237
238 async_fd_conn->flags &= ~CONN_ASYNC_AWAIT;
239}
240
241static enum lwan_connection_coro_yield
242resume_async(struct timeout_queue *tq,
243 enum lwan_connection_coro_yield yield_result,
244 int64_t from_coro,
245 struct lwan_connection *conn,
246 int epoll_fd)
247{
248 static const enum lwan_connection_flags to_connection_flags[] = {
249 [CONN_CORO_ASYNC_AWAIT_READ] = CONN_EVENTS_READ,
250 [CONN_CORO_ASYNC_AWAIT_WRITE] = CONN_EVENTS_WRITE,
251 [CONN_CORO_ASYNC_AWAIT_READ_WRITE] = CONN_EVENTS_READ_WRITE,
252 };
253 int await_fd = (int)((uint64_t)from_coro >> 32);
254 enum lwan_connection_flags flags;
255 int op;
256
257 assert(await_fd >= 0)((void) sizeof ((await_fd >= 0) ? 1 : 0), __extension__ ({
if (await_fd >= 0) ; else __assert_fail ("await_fd >= 0"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 257, __extension__ __PRETTY_FUNCTION__); }))
;
258 assert(yield_result >= CONN_CORO_ASYNC_AWAIT_READ &&((void) sizeof ((yield_result >= CONN_CORO_ASYNC_AWAIT_READ
&& yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE
) ? 1 : 0), __extension__ ({ if (yield_result >= CONN_CORO_ASYNC_AWAIT_READ
&& yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE
) ; else __assert_fail ("yield_result >= CONN_CORO_ASYNC_AWAIT_READ && yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 259, __extension__ __PRETTY_FUNCTION__); }))
259 yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE)((void) sizeof ((yield_result >= CONN_CORO_ASYNC_AWAIT_READ
&& yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE
) ? 1 : 0), __extension__ ({ if (yield_result >= CONN_CORO_ASYNC_AWAIT_READ
&& yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE
) ; else __assert_fail ("yield_result >= CONN_CORO_ASYNC_AWAIT_READ && yield_result <= CONN_CORO_ASYNC_AWAIT_READ_WRITE"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 259, __extension__ __PRETTY_FUNCTION__); }))
;
260
261 flags = to_connection_flags[yield_result];
262
263 struct lwan_connection *await_fd_conn = &tq->lwan->conns[await_fd];
264 if (LIKELY(await_fd_conn->flags & CONN_ASYNC_AWAIT)__builtin_expect((!!(await_fd_conn->flags & CONN_ASYNC_AWAIT
)), (1))
) {
265 if (LIKELY((await_fd_conn->flags & CONN_EVENTS_MASK) == flags)__builtin_expect((!!((await_fd_conn->flags & CONN_EVENTS_MASK
) == flags)), (1))
)
266 return CONN_CORO_SUSPEND_ASYNC_AWAIT;
267
268 op = EPOLL_CTL_MOD3;
269 } else {
270 op = EPOLL_CTL_ADD1;
271 flags |= CONN_ASYNC_AWAIT;
272 coro_defer(conn->coro, clear_async_await_flag, await_fd_conn);
273 }
274
275 struct epoll_event event = {.events = conn_flags_to_epoll_events(flags),
276 .data.ptr = conn};
277 if (LIKELY(!epoll_ctl(epoll_fd, op, await_fd, &event))__builtin_expect((!!(!epoll_ctl(epoll_fd, op, await_fd, &
event))), (1))
) {
278 await_fd_conn->flags &= ~CONN_EVENTS_MASK;
279 await_fd_conn->flags |= flags;
280 return CONN_CORO_SUSPEND_ASYNC_AWAIT;
281 }
282
283 return CONN_CORO_ABORT;
284}
285
286static ALWAYS_INLINEinline __attribute__((always_inline)) void resume_coro(struct timeout_queue *tq,
287 struct lwan_connection *conn,
288 int epoll_fd)
289{
290 assert(conn->coro)((void) sizeof ((conn->coro) ? 1 : 0), __extension__ ({ if
(conn->coro) ; else __assert_fail ("conn->coro", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 290, __extension__ __PRETTY_FUNCTION__); }))
;
291
292 int64_t from_coro = coro_resume(conn->coro);
293 enum lwan_connection_coro_yield yield_result = from_coro & 0xffffffff;
294
295 if (UNLIKELY(yield_result >= CONN_CORO_ASYNC)__builtin_expect(((yield_result >= CONN_CORO_ASYNC)), (0)))
296 yield_result = resume_async(tq, yield_result, from_coro, conn, epoll_fd);
297
298 if (UNLIKELY(yield_result == CONN_CORO_ABORT)__builtin_expect(((yield_result == CONN_CORO_ABORT)), (0)))
299 return timeout_queue_expire(tq, conn);
300
301 return update_epoll_flags(lwan_connection_get_fd(tq->lwan, conn), conn,
302 epoll_fd, yield_result);
303}
304
305static void update_date_cache(struct lwan_thread *thread)
306{
307 time_t now = time(NULL((void*)0));
308
309 lwan_format_rfc_time(now, thread->date.date);
310 lwan_format_rfc_time(now + (time_t)thread->lwan->config.expires,
311 thread->date.expires);
312}
313
314static ALWAYS_INLINEinline __attribute__((always_inline)) void spawn_coro(struct lwan_connection *conn,
315 struct coro_switcher *switcher,
316 struct timeout_queue *tq)
317{
318 struct lwan_thread *t = conn->thread;
319
320 assert(!conn->coro)((void) sizeof ((!conn->coro) ? 1 : 0), __extension__ ({ if
(!conn->coro) ; else __assert_fail ("!conn->coro", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 320, __extension__ __PRETTY_FUNCTION__); }))
;
321 assert(t)((void) sizeof ((t) ? 1 : 0), __extension__ ({ if (t) ; else __assert_fail
("t", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 321, __extension__ __PRETTY_FUNCTION__); }))
;
322 assert((uintptr_t)t >= (uintptr_t)tq->lwan->thread.threads)((void) sizeof (((uintptr_t)t >= (uintptr_t)tq->lwan->
thread.threads) ? 1 : 0), __extension__ ({ if ((uintptr_t)t >=
(uintptr_t)tq->lwan->thread.threads) ; else __assert_fail
("(uintptr_t)t >= (uintptr_t)tq->lwan->thread.threads"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 322, __extension__ __PRETTY_FUNCTION__); }))
;
323 assert((uintptr_t)t <((void) sizeof (((uintptr_t)t < (uintptr_t)(tq->lwan->
thread.threads + tq->lwan->thread.count)) ? 1 : 0), __extension__
({ if ((uintptr_t)t < (uintptr_t)(tq->lwan->thread.
threads + tq->lwan->thread.count)) ; else __assert_fail
("(uintptr_t)t < (uintptr_t)(tq->lwan->thread.threads + tq->lwan->thread.count)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 324, __extension__ __PRETTY_FUNCTION__); }))
324 (uintptr_t)(tq->lwan->thread.threads + tq->lwan->thread.count))((void) sizeof (((uintptr_t)t < (uintptr_t)(tq->lwan->
thread.threads + tq->lwan->thread.count)) ? 1 : 0), __extension__
({ if ((uintptr_t)t < (uintptr_t)(tq->lwan->thread.
threads + tq->lwan->thread.count)) ; else __assert_fail
("(uintptr_t)t < (uintptr_t)(tq->lwan->thread.threads + tq->lwan->thread.count)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 324, __extension__ __PRETTY_FUNCTION__); }))
;
325
326 *conn = (struct lwan_connection) {
327 .coro = coro_new(switcher, process_request_coro, conn),
328 .flags = CONN_EVENTS_READ,
329 .time_to_expire = tq->current_time + tq->move_to_last_bump,
330 .thread = t,
331 };
332 if (UNLIKELY(!conn->coro)__builtin_expect(((!conn->coro)), (0))) {
333 conn->flags = 0;
334 lwan_status_error("Could not create coroutine")lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 334, __FUNCTION__, "Could not create coroutine")
;
335 return;
336 }
337
338 timeout_queue_insert(tq, conn);
339}
340
341static void accept_nudge(int pipe_fd,
342 struct lwan_thread *t,
343 struct lwan_connection *conns,
344 struct timeout_queue *tq,
345 struct coro_switcher *switcher,
346 int epoll_fd)
347{
348 uint64_t event;
349 int new_fd;
350
351 /* Errors are ignored here as pipe_fd serves just as a way to wake the
352 * thread from epoll_wait(). It's fine to consume the queue at this
353 * point, regardless of the error type. */
354 (void)read(pipe_fd, &event, sizeof(event));
355
356 while (spsc_queue_pop(&t->pending_fds, &new_fd)) {
357 struct lwan_connection *conn = &conns[new_fd];
358 struct epoll_event ev = {
359 .data.ptr = conn,
360 .events = conn_flags_to_epoll_events(CONN_EVENTS_READ),
361 };
362
363 if (LIKELY(!epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd, &ev))__builtin_expect((!!(!epoll_ctl(epoll_fd, 1, new_fd, &ev)
)), (1))
)
364 spawn_coro(conn, switcher, tq);
365 }
366
367 timeouts_add(t->wheel, &tq->timeout, 1000);
368}
369
370static bool_Bool process_pending_timers(struct timeout_queue *tq,
371 struct lwan_thread *t,
372 int epoll_fd)
373{
374 struct timeout *timeout;
375 bool_Bool should_expire_timers = false0;
376
377 while ((timeout = timeouts_get(t->wheel))) {
378 struct lwan_request *request;
379
380 if (timeout == &tq->timeout) {
381 should_expire_timers = true1;
382 continue;
383 }
384
385 request = container_of(timeout, struct lwan_request, timeout)((struct lwan_request *) ((char *)(timeout) - __builtin_offsetof
(struct lwan_request, timeout)) + ((typeof(*(timeout)) *)0 !=
(typeof(((struct lwan_request *)0)->timeout) *)0))
;
386
387 update_epoll_flags(request->fd, request->conn, epoll_fd,
388 CONN_CORO_RESUME);
389 }
390
391 if (should_expire_timers) {
392 timeout_queue_expire_waiting(tq);
393
394 /* tq timeout expires every 1000ms if there are connections, so
395 * update the date cache at this point as well. */
396 update_date_cache(t);
397
398 if (!timeout_queue_empty(tq)) {
399 timeouts_add(t->wheel, &tq->timeout, 1000);
400 return true1;
401 }
402
403 timeouts_del(t->wheel, &tq->timeout);
404 }
405
406 return false0;
407}
408
409static int
410turn_timer_wheel(struct timeout_queue *tq, struct lwan_thread *t, int epoll_fd)
411{
412 timeout_t wheel_timeout;
413 struct timespec now;
414
415 if (UNLIKELY(clock_gettime(monotonic_clock_id, &now) < 0)__builtin_expect(((clock_gettime(monotonic_clock_id, &now
) < 0)), (0))
)
416 lwan_status_critical("Could not get monotonic time")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 416, __FUNCTION__, "Could not get monotonic time")
;
417
418 timeouts_update(t->wheel,
419 (timeout_t)(now.tv_sec * 1000 + now.tv_nsec / 1000000));
420
421 wheel_timeout = timeouts_timeout(t->wheel);
422 if (UNLIKELY((int64_t)wheel_timeout < 0)__builtin_expect((((int64_t)wheel_timeout < 0)), (0)))
423 goto infinite_timeout;
424
425 if (wheel_timeout == 0) {
426 if (!process_pending_timers(tq, t, epoll_fd))
427 goto infinite_timeout;
428
429 wheel_timeout = timeouts_timeout(t->wheel);
430 if (wheel_timeout == 0)
431 goto infinite_timeout;
432 }
433
434 return (int)wheel_timeout;
435
436infinite_timeout:
437 return -1;
438}
439
440static void *thread_io_loop(void *data)
441{
442 struct lwan_thread *t = data;
443 int epoll_fd = t->epoll_fd;
444 const int read_pipe_fd = t->pipe_fd[0];
445 const int max_events = LWAN_MIN((int)t->lwan->thread.max_fd, 1024)({ const __typeof__(((int)t->lwan->thread.max_fd) + 0) lwan_tmp_id6
= ((int)t->lwan->thread.max_fd); const __typeof__((1024
) + 0) lwan_tmp_id7 = (1024); lwan_tmp_id6 > lwan_tmp_id7 ?
lwan_tmp_id7 : lwan_tmp_id6; })
;
446 struct lwan *lwan = t->lwan;
447 struct epoll_event *events;
448 struct coro_switcher switcher;
449 struct timeout_queue tq;
450
451 lwan_status_debug("Worker thread #%zd starting",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 452, __FUNCTION__, "Worker thread #%zd starting", t - t->
lwan->thread.threads + 1)
452 t - t->lwan->thread.threads + 1)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 452, __FUNCTION__, "Worker thread #%zd starting", t - t->
lwan->thread.threads + 1)
;
453 lwan_set_thread_name("worker");
454
455 events = calloc((size_t)max_events, sizeof(*events));
456 if (UNLIKELY(!events)__builtin_expect(((!events)), (0)))
457 lwan_status_critical("Could not allocate memory for events")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 457, __FUNCTION__, "Could not allocate memory for events")
;
458
459 update_date_cache(t);
460
461 timeout_queue_init(&tq, lwan);
462
463 pthread_barrier_wait(&lwan->thread.barrier);
464
465 for (;;) {
466 int timeout = turn_timer_wheel(&tq, t, epoll_fd);
467 int n_fds = epoll_wait(epoll_fd, events, max_events, timeout);
468
469 if (UNLIKELY(n_fds < 0)__builtin_expect(((n_fds < 0)), (0))) {
470 if (errno(*__errno_location ()) == EBADF9 || errno(*__errno_location ()) == EINVAL22)
471 break;
472 continue;
473 }
474
475 for (struct epoll_event *event = events; n_fds--; event++) {
476 struct lwan_connection *conn;
477
478 if (UNLIKELY(!event->data.ptr)__builtin_expect(((!event->data.ptr)), (0))) {
479 accept_nudge(read_pipe_fd, t, lwan->conns, &tq, &switcher,
480 epoll_fd);
481 continue;
482 }
483
484 conn = event->data.ptr;
485
486 if (UNLIKELY(event->events & (EPOLLRDHUP | EPOLLHUP))__builtin_expect(((event->events & (EPOLLRDHUP | EPOLLHUP
))), (0))
) {
487 timeout_queue_expire(&tq, conn);
488 continue;
489 }
490
491 resume_coro(&tq, conn, epoll_fd);
492 timeout_queue_move_to_last(&tq, conn);
493 }
494 }
495
496 pthread_barrier_wait(&lwan->thread.barrier);
497
498 timeout_queue_expire_all(&tq);
499 free(events);
500
501 return NULL((void*)0);
502}
503
504static void create_thread(struct lwan *l, struct lwan_thread *thread,
505 const size_t n_queue_fds)
506{
507 int ignore;
508 pthread_attr_t attr;
509
510 memset(thread, 0, sizeof(*thread));
511 thread->lwan = l;
512
513 thread->wheel = timeouts_open(&ignore);
514 if (!thread->wheel)
515 lwan_status_critical("Could not create timer wheel")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 515, __FUNCTION__, "Could not create timer wheel")
;
516
517 if ((thread->epoll_fd = epoll_create1(EPOLL_CLOEXECEPOLL_CLOEXEC)) < 0)
518 lwan_status_critical_perror("epoll_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 518, __FUNCTION__, "epoll_create")
;
519
520 if (pthread_attr_init(&attr))
521 lwan_status_critical_perror("pthread_attr_init")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 521, __FUNCTION__, "pthread_attr_init")
;
522
523 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEMPTHREAD_SCOPE_SYSTEM))
524 lwan_status_critical_perror("pthread_attr_setscope")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 524, __FUNCTION__, "pthread_attr_setscope")
;
525
526 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLEPTHREAD_CREATE_JOINABLE))
527 lwan_status_critical_perror("pthread_attr_setdetachstate")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 527, __FUNCTION__, "pthread_attr_setdetachstate")
;
528
529#if defined(HAVE_EVENTFD)
530 int efd = eventfd(0, EFD_NONBLOCKEFD_NONBLOCK | EFD_SEMAPHOREEFD_SEMAPHORE | EFD_CLOEXECEFD_CLOEXEC);
531 if (efd < 0)
532 lwan_status_critical_perror("eventfd")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 532, __FUNCTION__, "eventfd")
;
533
534 thread->pipe_fd[0] = thread->pipe_fd[1] = efd;
535#else
536 if (pipe2(thread->pipe_fd, O_NONBLOCK04000 | O_CLOEXEC02000000) < 0)
537 lwan_status_critical_perror("pipe")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 537, __FUNCTION__, "pipe")
;
538#endif
539
540 struct epoll_event event = { .events = EPOLLINEPOLLIN, .data.ptr = NULL((void*)0) };
541 if (epoll_ctl(thread->epoll_fd, EPOLL_CTL_ADD1, thread->pipe_fd[0], &event) < 0)
542 lwan_status_critical_perror("epoll_ctl")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 542, __FUNCTION__, "epoll_ctl")
;
543
544 if (pthread_create(&thread->self, &attr, thread_io_loop, thread))
545 lwan_status_critical_perror("pthread_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 545, __FUNCTION__, "pthread_create")
;
546
547 if (pthread_attr_destroy(&attr))
548 lwan_status_critical_perror("pthread_attr_destroy")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 548, __FUNCTION__, "pthread_attr_destroy")
;
549
550 if (spsc_queue_init(&thread->pending_fds, n_queue_fds) < 0) {
551 lwan_status_critical("Could not initialize pending fd "lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 552, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
552 "queue width %zu elements", n_queue_fds)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 552, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
;
553 }
554}
555
556void lwan_thread_nudge(struct lwan_thread *t)
557{
558 uint64_t event = 1;
559
560 if (UNLIKELY(write(t->pipe_fd[1], &event, sizeof(event)) < 0)__builtin_expect(((write(t->pipe_fd[1], &event, sizeof
(event)) < 0)), (0))
)
561 lwan_status_perror("write")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 561, __FUNCTION__, "write")
;
562}
563
564void lwan_thread_add_client(struct lwan_thread *t, int fd)
565{
566 for (int i = 0; i < 10; i++) {
567 bool_Bool pushed = spsc_queue_push(&t->pending_fds, fd);
568
569 if (LIKELY(pushed)__builtin_expect((!!(pushed)), (1)))
570 return;
571
572 /* Queue is full; nudge the thread to consume it. */
573 lwan_thread_nudge(t);
574 }
575
576 lwan_status_error("Dropping connection %d", fd)lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 576, __FUNCTION__, "Dropping connection %d", fd)
;
577 /* FIXME: send "busy" response now, even without receiving request? */
578 close(fd);
579}
580
581#if defined(__linux__1) && defined(__x86_64__1)
582static bool_Bool read_cpu_topology(struct lwan *l, uint32_t siblings[])
583{
584 char path[PATH_MAX4096];
585
586 for (unsigned int i = 0; i < l->n_cpus; i++) {
587 FILE *sib;
588 uint32_t id, sibling;
589 char separator;
590
591 snprintf(path, sizeof(path),
592 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
593 i);
594
595 sib = fopen(path, "re");
596 if (!sib) {
597 lwan_status_warning("Could not open `%s` to determine CPU topology",lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 598, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
598 path)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 598, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
;
599 return false0;
600 }
601
602 switch (fscanf(sib, "%u%c%u", &id, &separator, &sibling)) {
603 case 2: /* No SMT */
604 siblings[i] = id;
605 break;
606 case 3: /* SMT */
607 if (!(separator == ',' || separator == '-')) {
608 lwan_status_critical("Expecting either ',' or '-' for sibling separator")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 608, __FUNCTION__, "Expecting either ',' or '-' for sibling separator"
)
;
609 __builtin_unreachable();
610 }
611
612 siblings[i] = sibling;
613 break;
614 default:
615 lwan_status_critical("%s has invalid format", path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 615, __FUNCTION__, "%s has invalid format", path)
;
616 __builtin_unreachable();
617 }
618
619
620 fclose(sib);
621 }
622
623 return true1;
624}
625
626static void
627siblings_to_schedtbl(struct lwan *l, uint32_t siblings[], uint32_t schedtbl[])
628{
629 int *seen = alloca(l->n_cpus * sizeof(int))__builtin_alloca (l->n_cpus * sizeof(int));
630 int n_schedtbl = 0;
631
632 for (uint32_t i = 0; i < l->n_cpus; i++)
14
Assuming 'i' is < field 'n_cpus'
15
Loop condition is true. Entering loop body
16
Assuming 'i' is < field 'n_cpus'
17
Loop condition is true. Entering loop body
18
Assuming 'i' is < field 'n_cpus'
19
Loop condition is true. Entering loop body
20
Assuming 'i' is >= field 'n_cpus'
21
Loop condition is false. Execution continues on line 635
633 seen[i] = -1;
634
635 for (uint32_t i = 0; i < l->n_cpus; i++) {
22
Loop condition is true. Entering loop body
25
Loop condition is true. Entering loop body
28
Loop condition is true. Entering loop body
31
Loop condition is false. Execution continues on line 644
636 if (seen[siblings[i]] < 0) {
23
Assuming the condition is false
24
Taking false branch
26
Assuming the condition is true
27
Taking true branch
29
Assuming the condition is true
30
Taking true branch
637 seen[siblings[i]] = (int)i;
638 } else {
639 schedtbl[n_schedtbl++] = (uint32_t)seen[siblings[i]];
640 schedtbl[n_schedtbl++] = i;
641 }
642 }
643
644 if (!n_schedtbl
31.1
'n_schedtbl' is 2
)
32
Taking false branch
645 memcpy(schedtbl, seen, l->n_cpus * sizeof(int));
646}
647
648static void
649topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
650{
651 uint32_t *siblings = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
652
653 if (!read_cpu_topology(l, siblings)) {
11
Assuming the condition is false
12
Taking false branch
654 for (uint32_t i = 0; i < n_threads; i++)
655 schedtbl[i] = (i / 2) % l->thread.count;
656 } else {
657 uint32_t *affinity = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
658
659 siblings_to_schedtbl(l, siblings, affinity);
13
Calling 'siblings_to_schedtbl'
33
Returning from 'siblings_to_schedtbl'
660
661 for (uint32_t i = 0; i < n_threads; i++)
34
Assuming 'i' is < 'n_threads'
35
Loop condition is true. Entering loop body
36
Assuming 'i' is < 'n_threads'
37
Loop condition is true. Entering loop body
38
Assuming 'i' is < 'n_threads'
39
Loop condition is true. Entering loop body
662 schedtbl[i] = affinity[i % l->n_cpus];
40
Assigned value is garbage or undefined
663 }
664}
665
666static void
667adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t mask)
668{
669 for (uint32_t i = 0; i < l->thread.count; i++) {
670 cpu_set_t set;
671
672 CPU_ZERO(&set)do __builtin_memset (&set, '\0', sizeof (cpu_set_t)); while
(0)
;
673 CPU_SET(schedtbl[i & mask], &set)(__extension__ ({ size_t __cpu = (schedtbl[i & mask]); __cpu
/ 8 < (sizeof (cpu_set_t)) ? (((__cpu_mask *) ((&set)
->__bits))[((__cpu) / (8 * sizeof (__cpu_mask)))] |= ((__cpu_mask
) 1 << ((__cpu) % (8 * sizeof (__cpu_mask))))) : 0; }))
;
674
675 if (pthread_setaffinity_np(l->thread.threads[i].self, sizeof(set),
676 &set))
677 lwan_status_warning("Could not set affinity for thread %d", i)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 677, __FUNCTION__, "Could not set affinity for thread %d", i
)
;
678 }
679}
680#elif defined(__x86_64__1)
681static void
682topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
683{
684 for (uint32_t i = 0; i < n_threads; i++)
685 schedtbl[i] = (i / 2) % l->thread.count;
686}
687
688static void
689adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t n)
690{
691}
692#endif
693
694void lwan_thread_init(struct lwan *l)
695{
696 if (pthread_barrier_init(&l->thread.barrier, NULL((void*)0),
1
Assuming the condition is false
2
Taking false branch
697 (unsigned)l->thread.count + 1))
698 lwan_status_critical("Could not create barrier")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 698, __FUNCTION__, "Could not create barrier")
;
699
700 lwan_status_debug("Initializing threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 700, __FUNCTION__, "Initializing threads")
;
701
702 l->thread.threads =
703 calloc((size_t)l->thread.count, sizeof(struct lwan_thread));
704 if (!l->thread.threads)
3
Assuming field 'threads' is non-null
4
Taking false branch
705 lwan_status_critical("Could not allocate memory for threads")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 705, __FUNCTION__, "Could not allocate memory for threads")
;
706
707 const size_t n_queue_fds = LWAN_MIN(l->thread.max_fd / l->thread.count,({ const __typeof__((l->thread.max_fd / l->thread.count
) + 0) lwan_tmp_id8 = (l->thread.max_fd / l->thread.count
); const __typeof__(((size_t)(2 * lwan_socket_get_backlog_size
())) + 0) lwan_tmp_id9 = ((size_t)(2 * lwan_socket_get_backlog_size
())); lwan_tmp_id8 > lwan_tmp_id9 ? lwan_tmp_id9 : lwan_tmp_id8
; })
5
Assuming 'lwan_tmp_id4' is <= 'lwan_tmp_id5'
6
'?' condition is false
708 (size_t)(2 * lwan_socket_get_backlog_size()))({ const __typeof__((l->thread.max_fd / l->thread.count
) + 0) lwan_tmp_id8 = (l->thread.max_fd / l->thread.count
); const __typeof__(((size_t)(2 * lwan_socket_get_backlog_size
())) + 0) lwan_tmp_id9 = ((size_t)(2 * lwan_socket_get_backlog_size
())); lwan_tmp_id8 > lwan_tmp_id9 ? lwan_tmp_id9 : lwan_tmp_id8
; })
;
709 lwan_status_debug("Pending client file descriptor queue has %zu items", n_queue_fds)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 709, __FUNCTION__, "Pending client file descriptor queue has %zu items"
, n_queue_fds)
;
710 for (unsigned int i = 0; i
6.1
'i' is < field 'count'
< l->thread.count
; i++)
7
Loop condition is true. Entering loop body
8
Assuming 'i' is >= field 'count'
9
Loop condition is false. Execution continues on line 713
711 create_thread(l, &l->thread.threads[i], n_queue_fds);
712
713 const unsigned int total_conns = l->thread.max_fd * l->thread.count;
714#ifdef __x86_64__1
715 static_assert(sizeof(struct lwan_connection) == 32,extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(struct lwan_connection) ==
32) ? 2 : -1; })]
716 "Two connections per cache line")extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(struct lwan_connection) ==
32) ? 2 : -1; })]
;
717 /*
718 * Pre-schedule each file descriptor, to reduce some operations in the
719 * fast path.
720 *
721 * Since struct lwan_connection is guaranteed to be 32-byte long, two of
722 * them can fill up a cache line. Assume siblings share cache lines and
723 * use the CPU topology to group two connections per cache line in such
724 * a way that false sharing is avoided.
725 */
726 uint32_t n_threads = (uint32_t)lwan_nextpow2((size_t)((l->thread.count - 1) * 2));
727 uint32_t *schedtbl = alloca(n_threads * sizeof(uint32_t))__builtin_alloca (n_threads * sizeof(uint32_t));
728
729 topology_to_schedtbl(l, schedtbl, n_threads);
10
Calling 'topology_to_schedtbl'
730
731 n_threads--; /* Transform count into mask for AND below */
732 adjust_threads_affinity(l, schedtbl, n_threads);
733 for (unsigned int i = 0; i < total_conns; i++)
734 l->conns[i].thread = &l->thread.threads[schedtbl[i & n_threads]];
735#else
736 for (unsigned int i = 0; i < total_conns; i++)
737 l->conns[i].thread = &l->thread.threads[i % l->thread.count];
738#endif
739
740 pthread_barrier_wait(&l->thread.barrier);
741
742 lwan_status_debug("Worker threads created and ready to serve")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 742, __FUNCTION__, "Worker threads created and ready to serve"
)
;
743}
744
745void lwan_thread_shutdown(struct lwan *l)
746{
747 lwan_status_debug("Shutting down threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 747, __FUNCTION__, "Shutting down threads")
;
748
749 for (unsigned int i = 0; i < l->thread.count; i++) {
750 struct lwan_thread *t = &l->thread.threads[i];
751
752 close(t->epoll_fd);
753 lwan_thread_nudge(t);
754 }
755
756 pthread_barrier_wait(&l->thread.barrier);
757 pthread_barrier_destroy(&l->thread.barrier);
758
759 for (unsigned int i = 0; i < l->thread.count; i++) {
760 struct lwan_thread *t = &l->thread.threads[i];
761
762 close(t->pipe_fd[0]);
763#if !defined(HAVE_EVENTFD)
764 close(t->pipe_fd[1]);
765#endif
766
767 pthread_join(l->thread.threads[i].self, NULL((void*)0));
768 spsc_queue_free(&t->pending_fds);
769 timeouts_close(t->wheel);
770 }
771
772 free(l->thread.threads);
773}