Bug Summary

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