Bug Summary

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