Bug Summary

File:lwan-thread.c
Warning:line 661, 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-181412-1291097-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);
138
139 if (LIKELY(conn->flags & CONN_IS_KEEP_ALIVE)__builtin_expect((!!(conn->flags & CONN_IS_KEEP_ALIVE)
), (1))
) {
140 if (next_request && *next_request) {
141 conn->flags |= CONN_CORK;
142 coro_yield(coro, CONN_CORO_WANT_WRITE);
143 } else {
144 conn->flags &= ~CONN_CORK;
145 coro_yield(coro, CONN_CORO_WANT_READ);
146 }
147 } else {
148 graceful_close(lwan, conn, request_buffer);
149 break;
150 }
151
152 lwan_strbuf_reset(&strbuf);
153 coro_deferred_run(coro, init_gen);
154
155 /* Only allow flags from config. */
156 flags = request.flags & (REQUEST_PROXIED | REQUEST_ALLOW_CORS);
157 next_request = helper.next_request;
158 }
159
160 coro_yield(coro, CONN_CORO_ABORT);
161 __builtin_unreachable();
162}
163
164static ALWAYS_INLINEinline __attribute__((always_inline)) uint32_t
165conn_flags_to_epoll_events(enum lwan_connection_flags flags)
166{
167 static const uint32_t map[CONN_EVENTS_MASK + 1] = {
168 [0 /* Suspended (timer or await) */] = EPOLLRDHUPEPOLLRDHUP,
169 [CONN_EVENTS_WRITE] = EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP,
170 [CONN_EVENTS_READ] = EPOLLINEPOLLIN | EPOLLRDHUPEPOLLRDHUP,
171 [CONN_EVENTS_READ_WRITE] = EPOLLINEPOLLIN | EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP,
172 };
173
174 return map[flags & CONN_EVENTS_MASK];
175}
176
177static void update_epoll_flags(int fd,
178 struct lwan_connection *conn,
179 int epoll_fd,
180 enum lwan_connection_coro_yield yield_result)
181{
182 static const enum lwan_connection_flags or_mask[CONN_CORO_MAX] = {
183 [CONN_CORO_YIELD] = 0,
184
185 [CONN_CORO_WANT_READ_WRITE] = CONN_EVENTS_READ_WRITE,
186 [CONN_CORO_WANT_READ] = CONN_EVENTS_READ,
187 [CONN_CORO_WANT_WRITE] = CONN_EVENTS_WRITE,
188
189 /* While the coro is suspended, we're not interested in either EPOLLIN
190 * or EPOLLOUT events. We still want to track this fd in epoll, though,
191 * so unset both so that only EPOLLRDHUP (plus the implicitly-set ones)
192 * are set. */
193 [CONN_CORO_SUSPEND_TIMER] = CONN_SUSPENDED_TIMER,
194 [CONN_CORO_SUSPEND_ASYNC_AWAIT] = CONN_SUSPENDED_ASYNC_AWAIT,
195
196 /* Ideally, when suspending a coroutine, the current flags&CONN_EVENTS_MASK
197 * would have to be stored and restored -- however, resuming as if the
198 * client coroutine is interested in a write event always guarantees that
199 * they'll be resumed as they're TCP sockets. There's a good chance that
200 * trying to read from a socket after resuming a coroutine will succeed,
201 * but if it doesn't because read() returns -EAGAIN, the I/O wrappers will
202 * yield with CONN_CORO_WANT_READ anyway. */
203 [CONN_CORO_RESUME] = CONN_EVENTS_WRITE,
204 };
205 static const enum lwan_connection_flags and_mask[CONN_CORO_MAX] = {
206 [CONN_CORO_YIELD] = ~0,
207
208 [CONN_CORO_WANT_READ_WRITE] = ~0,
209 [CONN_CORO_WANT_READ] = ~CONN_EVENTS_WRITE,
210 [CONN_CORO_WANT_WRITE] = ~CONN_EVENTS_READ,
211
212 [CONN_CORO_SUSPEND_TIMER] = ~(CONN_EVENTS_READ_WRITE | CONN_SUSPENDED_ASYNC_AWAIT),
213 [CONN_CORO_SUSPEND_ASYNC_AWAIT] = ~(CONN_EVENTS_READ_WRITE | CONN_SUSPENDED_TIMER),
214 [CONN_CORO_RESUME] = ~CONN_SUSPENDED,
215 };
216 enum lwan_connection_flags prev_flags = conn->flags;
217
218 conn->flags |= or_mask[yield_result];
219 conn->flags &= and_mask[yield_result];
220
221 if (conn->flags == prev_flags)
222 return;
223
224 struct epoll_event event = {
225 .events = conn_flags_to_epoll_events(conn->flags),
226 .data.ptr = conn,
227 };
228
229 if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event) < 0)__builtin_expect(((epoll_ctl(epoll_fd, 3, fd, &event) <
0)), (0))
)
230 lwan_status_perror("epoll_ctl")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 230, __FUNCTION__, "epoll_ctl")
;
231}
232
233static void clear_async_await_flag(void *data)
234{
235 struct lwan_connection *async_fd_conn = data;
236
237 async_fd_conn->flags &= ~CONN_ASYNC_AWAIT;
238}
239
240static enum lwan_connection_coro_yield
241resume_async(struct timeout_queue *tq,
242 enum lwan_connection_coro_yield yield_result,
243 int64_t from_coro,
244 struct lwan_connection *conn,
245 int epoll_fd)
246{
247 static const enum lwan_connection_flags to_connection_flags[] = {
248 [CONN_CORO_ASYNC_AWAIT_READ] = CONN_EVENTS_READ,
249 [CONN_CORO_ASYNC_AWAIT_WRITE] = CONN_EVENTS_WRITE,
250 [CONN_CORO_ASYNC_AWAIT_READ_WRITE] = CONN_EVENTS_READ_WRITE,
251 };
252 int await_fd = (int)((uint64_t)from_coro >> 32);
253 enum lwan_connection_flags flags;
254 int op;
255
256 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"
, 256, __extension__ __PRETTY_FUNCTION__); }))
;
257 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"
, 258, __extension__ __PRETTY_FUNCTION__); }))
258 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"
, 258, __extension__ __PRETTY_FUNCTION__); }))
;
259
260 flags = to_connection_flags[yield_result];
261
262 struct lwan_connection *await_fd_conn = &tq->lwan->conns[await_fd];
263 if (LIKELY(await_fd_conn->flags & CONN_ASYNC_AWAIT)__builtin_expect((!!(await_fd_conn->flags & CONN_ASYNC_AWAIT
)), (1))
) {
264 if (LIKELY((await_fd_conn->flags & CONN_EVENTS_MASK) == flags)__builtin_expect((!!((await_fd_conn->flags & CONN_EVENTS_MASK
) == flags)), (1))
)
265 return CONN_CORO_SUSPEND_ASYNC_AWAIT;
266
267 op = EPOLL_CTL_MOD3;
268 } else {
269 op = EPOLL_CTL_ADD1;
270 flags |= CONN_ASYNC_AWAIT;
271 coro_defer(conn->coro, clear_async_await_flag, await_fd_conn);
272 }
273
274 struct epoll_event event = {.events = conn_flags_to_epoll_events(flags),
275 .data.ptr = conn};
276 if (LIKELY(!epoll_ctl(epoll_fd, op, await_fd, &event))__builtin_expect((!!(!epoll_ctl(epoll_fd, op, await_fd, &
event))), (1))
) {
277 await_fd_conn->flags &= ~CONN_EVENTS_MASK;
278 await_fd_conn->flags |= flags;
279 return CONN_CORO_SUSPEND_ASYNC_AWAIT;
280 }
281
282 return CONN_CORO_ABORT;
283}
284
285static ALWAYS_INLINEinline __attribute__((always_inline)) void resume_coro(struct timeout_queue *tq,
286 struct lwan_connection *conn,
287 int epoll_fd)
288{
289 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"
, 289, __extension__ __PRETTY_FUNCTION__); }))
;
290
291 int64_t from_coro = coro_resume(conn->coro);
292 enum lwan_connection_coro_yield yield_result = from_coro & 0xffffffff;
293
294 if (UNLIKELY(yield_result >= CONN_CORO_ASYNC)__builtin_expect(((yield_result >= CONN_CORO_ASYNC)), (0)))
295 yield_result = resume_async(tq, yield_result, from_coro, conn, epoll_fd);
296
297 if (UNLIKELY(yield_result == CONN_CORO_ABORT)__builtin_expect(((yield_result == CONN_CORO_ABORT)), (0)))
298 return timeout_queue_expire(tq, conn);
299
300 return update_epoll_flags(lwan_connection_get_fd(tq->lwan, conn), conn,
301 epoll_fd, yield_result);
302}
303
304static void update_date_cache(struct lwan_thread *thread)
305{
306 time_t now = time(NULL((void*)0));
307
308 lwan_format_rfc_time(now, thread->date.date);
309 lwan_format_rfc_time(now + (time_t)thread->lwan->config.expires,
310 thread->date.expires);
311}
312
313static ALWAYS_INLINEinline __attribute__((always_inline)) void spawn_coro(struct lwan_connection *conn,
314 struct coro_switcher *switcher,
315 struct timeout_queue *tq)
316{
317 struct lwan_thread *t = conn->thread;
318
319 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"
, 319, __extension__ __PRETTY_FUNCTION__); }))
;
320 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"
, 320, __extension__ __PRETTY_FUNCTION__); }))
;
321 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"
, 321, __extension__ __PRETTY_FUNCTION__); }))
;
322 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"
, 323, __extension__ __PRETTY_FUNCTION__); }))
323 (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"
, 323, __extension__ __PRETTY_FUNCTION__); }))
;
324
325 *conn = (struct lwan_connection) {
326 .coro = coro_new(switcher, process_request_coro, conn),
327 .flags = CONN_EVENTS_READ,
328 .time_to_expire = tq->current_time + tq->move_to_last_bump,
329 .thread = t,
330 };
331 if (UNLIKELY(!conn->coro)__builtin_expect(((!conn->coro)), (0))) {
332 conn->flags = 0;
333 lwan_status_error("Could not create coroutine")lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 333, __FUNCTION__, "Could not create coroutine")
;
334 return;
335 }
336
337 timeout_queue_insert(tq, conn);
338}
339
340static void accept_nudge(int pipe_fd,
341 struct lwan_thread *t,
342 struct lwan_connection *conns,
343 struct timeout_queue *tq,
344 struct coro_switcher *switcher,
345 int epoll_fd)
346{
347 uint64_t event;
348 int new_fd;
349
350 /* Errors are ignored here as pipe_fd serves just as a way to wake the
351 * thread from epoll_wait(). It's fine to consume the queue at this
352 * point, regardless of the error type. */
353 (void)read(pipe_fd, &event, sizeof(event));
354
355 while (spsc_queue_pop(&t->pending_fds, &new_fd)) {
356 struct lwan_connection *conn = &conns[new_fd];
357 struct epoll_event ev = {
358 .data.ptr = conn,
359 .events = conn_flags_to_epoll_events(CONN_EVENTS_READ),
360 };
361
362 if (LIKELY(!epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd, &ev))__builtin_expect((!!(!epoll_ctl(epoll_fd, 1, new_fd, &ev)
)), (1))
)
363 spawn_coro(conn, switcher, tq);
364 }
365
366 timeouts_add(t->wheel, &tq->timeout, 1000);
367}
368
369static bool_Bool process_pending_timers(struct timeout_queue *tq,
370 struct lwan_thread *t,
371 int epoll_fd)
372{
373 struct timeout *timeout;
374 bool_Bool should_expire_timers = false0;
375
376 while ((timeout = timeouts_get(t->wheel))) {
377 struct lwan_request *request;
378
379 if (timeout == &tq->timeout) {
380 should_expire_timers = true1;
381 continue;
382 }
383
384 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))
;
385
386 update_epoll_flags(request->fd, request->conn, epoll_fd,
387 CONN_CORO_RESUME);
388 }
389
390 if (should_expire_timers) {
391 timeout_queue_expire_waiting(tq);
392
393 /* tq timeout expires every 1000ms if there are connections, so
394 * update the date cache at this point as well. */
395 update_date_cache(t);
396
397 if (!timeout_queue_empty(tq)) {
398 timeouts_add(t->wheel, &tq->timeout, 1000);
399 return true1;
400 }
401
402 timeouts_del(t->wheel, &tq->timeout);
403 }
404
405 return false0;
406}
407
408static int
409turn_timer_wheel(struct timeout_queue *tq, struct lwan_thread *t, int epoll_fd)
410{
411 timeout_t wheel_timeout;
412 struct timespec now;
413
414 if (UNLIKELY(clock_gettime(monotonic_clock_id, &now) < 0)__builtin_expect(((clock_gettime(monotonic_clock_id, &now
) < 0)), (0))
)
415 lwan_status_critical("Could not get monotonic time")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 415, __FUNCTION__, "Could not get monotonic time")
;
416
417 timeouts_update(t->wheel,
418 (timeout_t)(now.tv_sec * 1000 + now.tv_nsec / 1000000));
419
420 wheel_timeout = timeouts_timeout(t->wheel);
421 if (UNLIKELY((int64_t)wheel_timeout < 0)__builtin_expect((((int64_t)wheel_timeout < 0)), (0)))
422 goto infinite_timeout;
423
424 if (wheel_timeout == 0) {
425 if (!process_pending_timers(tq, t, epoll_fd))
426 goto infinite_timeout;
427
428 wheel_timeout = timeouts_timeout(t->wheel);
429 if (wheel_timeout == 0)
430 goto infinite_timeout;
431 }
432
433 return (int)wheel_timeout;
434
435infinite_timeout:
436 return -1;
437}
438
439static void *thread_io_loop(void *data)
440{
441 struct lwan_thread *t = data;
442 int epoll_fd = t->epoll_fd;
443 const int read_pipe_fd = t->pipe_fd[0];
444 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; })
;
445 struct lwan *lwan = t->lwan;
446 struct epoll_event *events;
447 struct coro_switcher switcher;
448 struct timeout_queue tq;
449
450 lwan_status_debug("Worker thread #%zd starting",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 451, __FUNCTION__, "Worker thread #%zd starting", t - t->
lwan->thread.threads + 1)
451 t - t->lwan->thread.threads + 1)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 451, __FUNCTION__, "Worker thread #%zd starting", t - t->
lwan->thread.threads + 1)
;
452 lwan_set_thread_name("worker");
453
454 events = calloc((size_t)max_events, sizeof(*events));
455 if (UNLIKELY(!events)__builtin_expect(((!events)), (0)))
456 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"
, 456, __FUNCTION__, "Could not allocate memory for events")
;
457
458 update_date_cache(t);
459
460 timeout_queue_init(&tq, lwan);
461
462 pthread_barrier_wait(&lwan->thread.barrier);
463
464 for (;;) {
465 int timeout = turn_timer_wheel(&tq, t, epoll_fd);
466 int n_fds = epoll_wait(epoll_fd, events, max_events, timeout);
467
468 if (UNLIKELY(n_fds < 0)__builtin_expect(((n_fds < 0)), (0))) {
469 if (errno(*__errno_location ()) == EBADF9 || errno(*__errno_location ()) == EINVAL22)
470 break;
471 continue;
472 }
473
474 for (struct epoll_event *event = events; n_fds--; event++) {
475 struct lwan_connection *conn;
476
477 if (UNLIKELY(!event->data.ptr)__builtin_expect(((!event->data.ptr)), (0))) {
478 accept_nudge(read_pipe_fd, t, lwan->conns, &tq, &switcher,
479 epoll_fd);
480 continue;
481 }
482
483 conn = event->data.ptr;
484
485 if (UNLIKELY(event->events & (EPOLLRDHUP | EPOLLHUP))__builtin_expect(((event->events & (EPOLLRDHUP | EPOLLHUP
))), (0))
) {
486 timeout_queue_expire(&tq, conn);
487 continue;
488 }
489
490 resume_coro(&tq, conn, epoll_fd);
491 timeout_queue_move_to_last(&tq, conn);
492 }
493 }
494
495 pthread_barrier_wait(&lwan->thread.barrier);
496
497 timeout_queue_expire_all(&tq);
498 free(events);
499
500 return NULL((void*)0);
501}
502
503static void create_thread(struct lwan *l, struct lwan_thread *thread,
504 const size_t n_queue_fds)
505{
506 int ignore;
507 pthread_attr_t attr;
508
509 memset(thread, 0, sizeof(*thread));
510 thread->lwan = l;
511
512 thread->wheel = timeouts_open(&ignore);
513 if (!thread->wheel)
514 lwan_status_critical("Could not create timer wheel")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 514, __FUNCTION__, "Could not create timer wheel")
;
515
516 if ((thread->epoll_fd = epoll_create1(EPOLL_CLOEXECEPOLL_CLOEXEC)) < 0)
517 lwan_status_critical_perror("epoll_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 517, __FUNCTION__, "epoll_create")
;
518
519 if (pthread_attr_init(&attr))
520 lwan_status_critical_perror("pthread_attr_init")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 520, __FUNCTION__, "pthread_attr_init")
;
521
522 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEMPTHREAD_SCOPE_SYSTEM))
523 lwan_status_critical_perror("pthread_attr_setscope")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 523, __FUNCTION__, "pthread_attr_setscope")
;
524
525 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLEPTHREAD_CREATE_JOINABLE))
526 lwan_status_critical_perror("pthread_attr_setdetachstate")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 526, __FUNCTION__, "pthread_attr_setdetachstate")
;
527
528#if defined(HAVE_EVENTFD)
529 int efd = eventfd(0, EFD_NONBLOCKEFD_NONBLOCK | EFD_SEMAPHOREEFD_SEMAPHORE | EFD_CLOEXECEFD_CLOEXEC);
530 if (efd < 0)
531 lwan_status_critical_perror("eventfd")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 531, __FUNCTION__, "eventfd")
;
532
533 thread->pipe_fd[0] = thread->pipe_fd[1] = efd;
534#else
535 if (pipe2(thread->pipe_fd, O_NONBLOCK04000 | O_CLOEXEC02000000) < 0)
536 lwan_status_critical_perror("pipe")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 536, __FUNCTION__, "pipe")
;
537#endif
538
539 struct epoll_event event = { .events = EPOLLINEPOLLIN, .data.ptr = NULL((void*)0) };
540 if (epoll_ctl(thread->epoll_fd, EPOLL_CTL_ADD1, thread->pipe_fd[0], &event) < 0)
541 lwan_status_critical_perror("epoll_ctl")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 541, __FUNCTION__, "epoll_ctl")
;
542
543 if (pthread_create(&thread->self, &attr, thread_io_loop, thread))
544 lwan_status_critical_perror("pthread_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 544, __FUNCTION__, "pthread_create")
;
545
546 if (pthread_attr_destroy(&attr))
547 lwan_status_critical_perror("pthread_attr_destroy")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 547, __FUNCTION__, "pthread_attr_destroy")
;
548
549 if (spsc_queue_init(&thread->pending_fds, n_queue_fds) < 0) {
550 lwan_status_critical("Could not initialize pending fd "lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 551, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
551 "queue width %zu elements", n_queue_fds)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 551, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
;
552 }
553}
554
555void lwan_thread_nudge(struct lwan_thread *t)
556{
557 uint64_t event = 1;
558
559 if (UNLIKELY(write(t->pipe_fd[1], &event, sizeof(event)) < 0)__builtin_expect(((write(t->pipe_fd[1], &event, sizeof
(event)) < 0)), (0))
)
560 lwan_status_perror("write")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 560, __FUNCTION__, "write")
;
561}
562
563void lwan_thread_add_client(struct lwan_thread *t, int fd)
564{
565 for (int i = 0; i < 10; i++) {
566 bool_Bool pushed = spsc_queue_push(&t->pending_fds, fd);
567
568 if (LIKELY(pushed)__builtin_expect((!!(pushed)), (1)))
569 return;
570
571 /* Queue is full; nudge the thread to consume it. */
572 lwan_thread_nudge(t);
573 }
574
575 lwan_status_error("Dropping connection %d", fd)lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 575, __FUNCTION__, "Dropping connection %d", fd)
;
576 /* FIXME: send "busy" response now, even without receiving request? */
577 close(fd);
578}
579
580#if defined(__linux__1) && defined(__x86_64__1)
581static bool_Bool read_cpu_topology(struct lwan *l, uint32_t siblings[])
582{
583 char path[PATH_MAX4096];
584
585 for (unsigned int i = 0; i < l->n_cpus; i++) {
586 FILE *sib;
587 uint32_t id, sibling;
588 char separator;
589
590 snprintf(path, sizeof(path),
591 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
592 i);
593
594 sib = fopen(path, "re");
595 if (!sib) {
596 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"
, 597, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
597 path)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 597, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
;
598 return false0;
599 }
600
601 switch (fscanf(sib, "%u%c%u", &id, &separator, &sibling)) {
602 case 2: /* No SMT */
603 siblings[i] = id;
604 break;
605 case 3: /* SMT */
606 if (!(separator == ',' || separator == '-')) {
607 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"
, 607, __FUNCTION__, "Expecting either ',' or '-' for sibling separator"
)
;
608 __builtin_unreachable();
609 }
610
611 siblings[i] = sibling;
612 break;
613 default:
614 lwan_status_critical("%s has invalid format", path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 614, __FUNCTION__, "%s has invalid format", path)
;
615 __builtin_unreachable();
616 }
617
618
619 fclose(sib);
620 }
621
622 return true1;
623}
624
625static void
626siblings_to_schedtbl(struct lwan *l, uint32_t siblings[], uint32_t schedtbl[])
627{
628 int *seen = alloca(l->n_cpus * sizeof(int))__builtin_alloca (l->n_cpus * sizeof(int));
629 int n_schedtbl = 0;
630
631 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 634
632 seen[i] = -1;
633
634 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 643
635 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
636 seen[siblings[i]] = (int)i;
637 } else {
638 schedtbl[n_schedtbl++] = (uint32_t)seen[siblings[i]];
639 schedtbl[n_schedtbl++] = i;
640 }
641 }
642
643 if (!n_schedtbl
31.1
'n_schedtbl' is 2
)
32
Taking false branch
644 memcpy(schedtbl, seen, l->n_cpus * sizeof(int));
645}
646
647static void
648topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
649{
650 uint32_t *siblings = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
651
652 if (!read_cpu_topology(l, siblings)) {
11
Assuming the condition is false
12
Taking false branch
653 for (uint32_t i = 0; i < n_threads; i++)
654 schedtbl[i] = (i / 2) % l->thread.count;
655 } else {
656 uint32_t *affinity = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
657
658 siblings_to_schedtbl(l, siblings, affinity);
13
Calling 'siblings_to_schedtbl'
33
Returning from 'siblings_to_schedtbl'
659
660 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
661 schedtbl[i] = affinity[i % l->n_cpus];
40
Assigned value is garbage or undefined
662 }
663}
664
665static void
666adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t mask)
667{
668 for (uint32_t i = 0; i < l->thread.count; i++) {
669 cpu_set_t set;
670
671 CPU_ZERO(&set)do __builtin_memset (&set, '\0', sizeof (cpu_set_t)); while
(0)
;
672 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; }))
;
673
674 if (pthread_setaffinity_np(l->thread.threads[i].self, sizeof(set),
675 &set))
676 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"
, 676, __FUNCTION__, "Could not set affinity for thread %d", i
)
;
677 }
678}
679#elif defined(__x86_64__1)
680static void
681topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
682{
683 for (uint32_t i = 0; i < n_threads; i++)
684 schedtbl[i] = (i / 2) % l->thread.count;
685}
686
687static void
688adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t n)
689{
690}
691#endif
692
693void lwan_thread_init(struct lwan *l)
694{
695 if (pthread_barrier_init(&l->thread.barrier, NULL((void*)0),
1
Assuming the condition is false
2
Taking false branch
696 (unsigned)l->thread.count + 1))
697 lwan_status_critical("Could not create barrier")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 697, __FUNCTION__, "Could not create barrier")
;
698
699 lwan_status_debug("Initializing threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 699, __FUNCTION__, "Initializing threads")
;
700
701 l->thread.threads =
702 calloc((size_t)l->thread.count, sizeof(struct lwan_thread));
703 if (!l->thread.threads)
3
Assuming field 'threads' is non-null
4
Taking false branch
704 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"
, 704, __FUNCTION__, "Could not allocate memory for threads")
;
705
706 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
707 (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
; })
;
708 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"
, 708, __FUNCTION__, "Pending client file descriptor queue has %zu items"
, n_queue_fds)
;
709 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 712
710 create_thread(l, &l->thread.threads[i], n_queue_fds);
711
712 const unsigned int total_conns = l->thread.max_fd * l->thread.count;
713#ifdef __x86_64__1
714 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; })]
715 "Two connections per cache line")extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(struct lwan_connection) ==
32) ? 2 : -1; })]
;
716 /*
717 * Pre-schedule each file descriptor, to reduce some operations in the
718 * fast path.
719 *
720 * Since struct lwan_connection is guaranteed to be 32-byte long, two of
721 * them can fill up a cache line. Assume siblings share cache lines and
722 * use the CPU topology to group two connections per cache line in such
723 * a way that false sharing is avoided.
724 */
725 uint32_t n_threads = (uint32_t)lwan_nextpow2((size_t)((l->thread.count - 1) * 2));
726 uint32_t *schedtbl = alloca(n_threads * sizeof(uint32_t))__builtin_alloca (n_threads * sizeof(uint32_t));
727
728 topology_to_schedtbl(l, schedtbl, n_threads);
10
Calling 'topology_to_schedtbl'
729
730 n_threads--; /* Transform count into mask for AND below */
731 adjust_threads_affinity(l, schedtbl, n_threads);
732 for (unsigned int i = 0; i < total_conns; i++)
733 l->conns[i].thread = &l->thread.threads[schedtbl[i & n_threads]];
734#else
735 for (unsigned int i = 0; i < total_conns; i++)
736 l->conns[i].thread = &l->thread.threads[i % l->thread.count];
737#endif
738
739 pthread_barrier_wait(&l->thread.barrier);
740
741 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"
, 741, __FUNCTION__, "Worker threads created and ready to serve"
)
;
742}
743
744void lwan_thread_shutdown(struct lwan *l)
745{
746 lwan_status_debug("Shutting down threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 746, __FUNCTION__, "Shutting down threads")
;
747
748 for (unsigned int i = 0; i < l->thread.count; i++) {
749 struct lwan_thread *t = &l->thread.threads[i];
750
751 close(t->epoll_fd);
752 lwan_thread_nudge(t);
753 }
754
755 pthread_barrier_wait(&l->thread.barrier);
756 pthread_barrier_destroy(&l->thread.barrier);
757
758 for (unsigned int i = 0; i < l->thread.count; i++) {
759 struct lwan_thread *t = &l->thread.threads[i];
760
761 close(t->pipe_fd[0]);
762#if !defined(HAVE_EVENTFD)
763 close(t->pipe_fd[1]);
764#endif
765
766 pthread_join(l->thread.threads[i].self, NULL((void*)0));
767 spsc_queue_free(&t->pending_fds);
768 timeouts_close(t->wheel);
769 }
770
771 free(l->thread.threads);
772}