Bug Summary

File:lwan-thread.c
Warning:line 535, 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 -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -fno-plt -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/clang/8.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/8.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-unused-parameter -std=gnu99 -fdebug-compilation-dir /home/buildbot/lwan-worker/clang-analyze/build/src/lib -ferror-limit 19 -fmessage-length 0 -stack-protector 2 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /home/buildbot/lwan-worker/clang-analyze/CLANG/2019-04-21-155637-4402-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c -faddrsig
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/socket.h>
31#include <unistd.h>
32
33#if defined(HAVE_EVENTFD)
34#include <sys/eventfd.h>
35#endif
36
37#include "lwan-private.h"
38#include "lwan-dq.h"
39#include "list.h"
40
41static const uint32_t events_by_write_flag[] = {
42 EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP | EPOLLERREPOLLERR,
43 EPOLLINEPOLLIN | EPOLLRDHUPEPOLLRDHUP | EPOLLERREPOLLERR
44};
45
46static ALWAYS_INLINEinline __attribute__((always_inline)) int min(const int a, const int b) { return a < b ? a : b; }
47
48#define REQUEST_FLAG(bool_, name_) \
49 ((enum lwan_request_flags)(((uint32_t)lwan->config.bool_) \
50 << REQUEST_##name_##_SHIFT))
51static_assert(sizeof(enum lwan_request_flags) == sizeof(uint32_t),extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(enum lwan_request_flags) ==
sizeof(uint32_t)) ? 2 : -1; })]
52 "lwan_request_flags has the same size as uint32_t")extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(enum lwan_request_flags) ==
sizeof(uint32_t)) ? 2 : -1; })]
;
53
54static void lwan_strbuf_free_defer(void *data)
55{
56 lwan_strbuf_free((struct lwan_strbuf *)data);
57}
58
59__attribute__((noreturn)) static int process_request_coro(struct coro *coro,
60 void *data)
61{
62 /* NOTE: This function should not return; coro_yield should be used
63 * instead. This ensures the storage for `strbuf` is alive when the
64 * coroutine ends and lwan_strbuf_free() is called. */
65 struct lwan_connection *conn = data;
66 const enum lwan_request_flags flags_filter =
67 (REQUEST_PROXIED | REQUEST_ALLOW_CORS);
68 struct lwan_strbuf strbuf;
69 struct lwan *lwan = conn->thread->lwan;
70 int fd = lwan_connection_get_fd(lwan, conn);
71 char request_buffer[DEFAULT_BUFFER_SIZE4096];
72 struct lwan_value buffer = {.value = request_buffer, .len = 0};
73 char *next_request = NULL((void*)0);
74 enum lwan_request_flags flags = 0;
75 struct lwan_proxy proxy;
76
77 if (UNLIKELY(!lwan_strbuf_init(&strbuf))__builtin_expect(((!lwan_strbuf_init(&strbuf))), (0))) {
78 coro_yield(coro, CONN_CORO_ABORT);
79 __builtin_unreachable();
80 }
81 coro_defer(coro, lwan_strbuf_free_defer, &strbuf);
82
83 flags |= REQUEST_FLAG(proxy_protocol, ALLOW_PROXY_REQS) |
84 REQUEST_FLAG(allow_cors, ALLOW_CORS);
85
86 while (true1) {
87 struct lwan_request request = {.conn = conn,
88 .fd = fd,
89 .response = {.buffer = &strbuf},
90 .flags = flags,
91 .proxy = &proxy};
92
93 assert(conn->flags & CONN_IS_ALIVE)((void) sizeof ((conn->flags & CONN_IS_ALIVE) ? 1 : 0)
, __extension__ ({ if (conn->flags & CONN_IS_ALIVE) ; else
__assert_fail ("conn->flags & CONN_IS_ALIVE", "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 93, __extension__ __PRETTY_FUNCTION__); }))
;
94
95 size_t generation = coro_deferred_get_generation(coro);
96 next_request =
97 lwan_process_request(lwan, &request, &buffer, next_request);
98 coro_deferred_run(coro, generation);
99
100 if (LIKELY(conn->flags & CONN_KEEP_ALIVE)__builtin_expect((!!(conn->flags & CONN_KEEP_ALIVE)), (
1))
) {
101 if (next_request && *next_request)
102 conn->flags |= CONN_FLIP_FLAGS;
103
104 coro_yield(coro, CONN_CORO_MAY_RESUME);
105 } else {
106 shutdown(fd, SHUT_RDWRSHUT_RDWR);
107 coro_yield(coro, CONN_CORO_ABORT);
108 }
109
110 lwan_strbuf_reset(&strbuf);
111 flags = request.flags & flags_filter;
112 }
113}
114
115#undef REQUEST_FLAG
116
117static void update_epoll_flags(struct death_queue *dq,
118 struct lwan_connection *conn,
119 int epoll_fd,
120 enum lwan_connection_coro_yield yield_result)
121{
122 uint32_t events = 0;
123 bool_Bool write_events;
124
125 if (UNLIKELY(conn->flags & CONN_RESUMED_FROM_TIMER)__builtin_expect(((conn->flags & CONN_RESUMED_FROM_TIMER
)), (0))
) {
126 conn->flags &= ~(CONN_RESUMED_FROM_TIMER | CONN_WRITE_EVENTS);
127 write_events = false0;
128 } else if (UNLIKELY(conn->flags & CONN_SUSPENDED_BY_TIMER)__builtin_expect(((conn->flags & CONN_SUSPENDED_BY_TIMER
)), (0))
) {
129 /* CONN_WRITE_EVENTS shouldn't be flipped in this case. */
130 events = EPOLLERREPOLLERR | EPOLLRDHUPEPOLLRDHUP;
131 } else if (conn->flags & CONN_MUST_READ) {
132 write_events = true1;
133 } else {
134 bool_Bool should_resume_coro = (yield_result == CONN_CORO_MAY_RESUME);
135
136 if (should_resume_coro)
137 conn->flags |= CONN_SHOULD_RESUME_CORO;
138 else
139 conn->flags &= ~CONN_SHOULD_RESUME_CORO;
140
141 write_events = (conn->flags & CONN_WRITE_EVENTS);
142 if (should_resume_coro == write_events)
143 return;
144 }
145
146 if (LIKELY(!events)__builtin_expect((!!(!events)), (1))) {
147 events = events_by_write_flag[write_events];
148 conn->flags ^= CONN_WRITE_EVENTS;
149 }
150
151 struct epoll_event event = {.events = events, .data.ptr = conn};
152
153 int fd = lwan_connection_get_fd(dq->lwan, conn);
154 if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event) < 0)__builtin_expect(((epoll_ctl(epoll_fd, 3, fd, &event) <
0)), (0))
)
155 lwan_status_perror("epoll_ctl")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 155, __FUNCTION__, "epoll_ctl")
;
156}
157
158static ALWAYS_INLINEinline __attribute__((always_inline)) void resume_coro_if_needed(struct death_queue *dq,
159 struct lwan_connection *conn,
160 int epoll_fd)
161{
162 const enum lwan_connection_flags update_mask =
163 CONN_FLIP_FLAGS | CONN_RESUMED_FROM_TIMER | CONN_SUSPENDED_BY_TIMER;
164
165 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"
, 165, __extension__ __PRETTY_FUNCTION__); }))
;
166
167 if (!(conn->flags & CONN_SHOULD_RESUME_CORO))
168 return;
169
170 enum lwan_connection_coro_yield yield_result = coro_resume(conn->coro);
171 /* CONN_CORO_ABORT is -1, but comparing with 0 is cheaper */
172 if (UNLIKELY(yield_result < CONN_CORO_MAY_RESUME)__builtin_expect(((yield_result < CONN_CORO_MAY_RESUME)), (
0))
) {
173 death_queue_kill(dq, conn);
174 return;
175 }
176
177 if (conn->flags & update_mask) {
178 conn->flags &= ~CONN_FLIP_FLAGS;
179 update_epoll_flags(dq, conn, epoll_fd, yield_result);
180 }
181}
182
183static void update_date_cache(struct lwan_thread *thread)
184{
185 time_t now = time(NULL((void*)0));
186
187 lwan_format_rfc_time(now, thread->date.date);
188 lwan_format_rfc_time(now + (time_t)thread->lwan->config.expires,
189 thread->date.expires);
190}
191
192static ALWAYS_INLINEinline __attribute__((always_inline)) void spawn_coro(struct lwan_connection *conn,
193 struct coro_switcher *switcher,
194 struct death_queue *dq)
195{
196 struct lwan_thread *t = conn->thread;
197
198 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"
, 198, __extension__ __PRETTY_FUNCTION__); }))
;
199 assert(!(conn->flags & CONN_IS_ALIVE))((void) sizeof ((!(conn->flags & CONN_IS_ALIVE)) ? 1 :
0), __extension__ ({ if (!(conn->flags & CONN_IS_ALIVE
)) ; else __assert_fail ("!(conn->flags & CONN_IS_ALIVE)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 199, __extension__ __PRETTY_FUNCTION__); }))
;
200 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"
, 200, __extension__ __PRETTY_FUNCTION__); }))
;
201 assert((uintptr_t)t >= (uintptr_t)dq->lwan->thread.threads)((void) sizeof (((uintptr_t)t >= (uintptr_t)dq->lwan->
thread.threads) ? 1 : 0), __extension__ ({ if ((uintptr_t)t >=
(uintptr_t)dq->lwan->thread.threads) ; else __assert_fail
("(uintptr_t)t >= (uintptr_t)dq->lwan->thread.threads"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 201, __extension__ __PRETTY_FUNCTION__); }))
;
202 assert((uintptr_t)t <((void) sizeof (((uintptr_t)t < (uintptr_t)(dq->lwan->
thread.threads + dq->lwan->thread.count)) ? 1 : 0), __extension__
({ if ((uintptr_t)t < (uintptr_t)(dq->lwan->thread.
threads + dq->lwan->thread.count)) ; else __assert_fail
("(uintptr_t)t < (uintptr_t)(dq->lwan->thread.threads + dq->lwan->thread.count)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 203, __extension__ __PRETTY_FUNCTION__); }))
203 (uintptr_t)(dq->lwan->thread.threads + dq->lwan->thread.count))((void) sizeof (((uintptr_t)t < (uintptr_t)(dq->lwan->
thread.threads + dq->lwan->thread.count)) ? 1 : 0), __extension__
({ if ((uintptr_t)t < (uintptr_t)(dq->lwan->thread.
threads + dq->lwan->thread.count)) ; else __assert_fail
("(uintptr_t)t < (uintptr_t)(dq->lwan->thread.threads + dq->lwan->thread.count)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 203, __extension__ __PRETTY_FUNCTION__); }))
;
204
205 *conn = (struct lwan_connection) {
206 .coro = coro_new(switcher, process_request_coro, conn),
207 .flags = CONN_IS_ALIVE | CONN_SHOULD_RESUME_CORO,
208 .time_to_die = dq->time + dq->keep_alive_timeout,
209 .thread = t,
210 };
211 if (UNLIKELY(!conn->coro)__builtin_expect(((!conn->coro)), (0))) {
212 conn->flags = 0;
213 lwan_status_error("Could not create coroutine")lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 213, __FUNCTION__, "Could not create coroutine")
;
214 return;
215 }
216
217 death_queue_insert(dq, conn);
218}
219
220static void accept_nudge(int pipe_fd,
221 struct lwan_thread *t,
222 struct lwan_connection *conns,
223 struct death_queue *dq,
224 struct coro_switcher *switcher,
225 int epoll_fd)
226{
227 uint64_t event;
228 int new_fd;
229
230 /* Errors are ignored here as pipe_fd serves just as a way to wake the
231 * thread from epoll_wait(). It's fine to consume the queue at this
232 * point, regardless of the error type. */
233 (void)read(pipe_fd, &event, sizeof(event));
234
235 while (spsc_queue_pop(&t->pending_fds, &new_fd)) {
236 struct lwan_connection *conn = &conns[new_fd];
237 struct epoll_event ev = {.events = events_by_write_flag[1],
238 .data.ptr = conn};
239
240 if (LIKELY(!epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd, &ev))__builtin_expect((!!(!epoll_ctl(epoll_fd, 1, new_fd, &ev)
)), (1))
)
241 spawn_coro(conn, switcher, dq);
242 }
243
244 timeouts_add(t->wheel, &dq->timeout, 1000);
245}
246
247static bool_Bool process_pending_timers(struct death_queue *dq,
248 struct lwan_thread *t,
249 int epoll_fd)
250{
251 struct timeout *timeout;
252 bool_Bool processed_dq_timeout = false0;
253
254 while ((timeout = timeouts_get(t->wheel))) {
255 struct lwan_request *request;
256
257 if (timeout == &dq->timeout) {
258 death_queue_kill_waiting(dq);
259 processed_dq_timeout = true1;
260 continue;
261 }
262
263 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))
;
264
265 request->conn->flags &= ~CONN_SUSPENDED_BY_TIMER;
266 request->conn->flags |= CONN_RESUMED_FROM_TIMER;
267 update_epoll_flags(dq, request->conn, epoll_fd, CONN_CORO_MAY_RESUME);
268 }
269
270 if (processed_dq_timeout) {
271 /* dq timeout expires every 1000ms if there are connections, so
272 * update the date cache at this point as well. */
273 update_date_cache(t);
274
275 if (!death_queue_empty(dq)) {
276 timeouts_add(t->wheel, &dq->timeout, 1000);
277 return true1;
278 }
279
280 timeouts_del(t->wheel, &dq->timeout);
281 }
282
283 return false0;
284}
285
286static int
287turn_timer_wheel(struct death_queue *dq, struct lwan_thread *t, int epoll_fd)
288{
289 timeout_t wheel_timeout;
290 struct timespec now;
291
292 if (UNLIKELY(clock_gettime(monotonic_clock_id, &now) < 0)__builtin_expect(((clock_gettime(monotonic_clock_id, &now
) < 0)), (0))
)
293 lwan_status_critical("Could not get monotonic time")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 293, __FUNCTION__, "Could not get monotonic time")
;
294
295 timeouts_update(t->wheel,
296 (timeout_t)(now.tv_sec * 1000 + now.tv_nsec / 1000000));
297
298 wheel_timeout = timeouts_timeout(t->wheel);
299 if (UNLIKELY((int64_t)wheel_timeout < 0)__builtin_expect((((int64_t)wheel_timeout < 0)), (0)))
300 goto infinite_timeout;
301
302 if (wheel_timeout == 0) {
303 if (!process_pending_timers(dq, t, epoll_fd))
304 goto infinite_timeout;
305
306 wheel_timeout = timeouts_timeout(t->wheel);
307 if (wheel_timeout == 0)
308 goto infinite_timeout;
309 }
310
311 return (int)wheel_timeout;
312
313infinite_timeout:
314 return -1;
315}
316
317static void *thread_io_loop(void *data)
318{
319 struct lwan_thread *t = data;
320 int epoll_fd = t->epoll_fd;
321 const int read_pipe_fd = t->pipe_fd[0];
322 const int max_events = min((int)t->lwan->thread.max_fd, 1024);
323 struct lwan *lwan = t->lwan;
324 struct epoll_event *events;
325 struct coro_switcher switcher;
326 struct death_queue dq;
327
328 lwan_status_debug("Starting IO loop on thread #%d",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 330, __FUNCTION__, "Starting IO loop on thread #%d", (unsigned
short)(ptrdiff_t)(t - t->lwan->thread.threads) + 1)
329 (unsigned short)(ptrdiff_t)(t - t->lwan->thread.threads) +lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 330, __FUNCTION__, "Starting IO loop on thread #%d", (unsigned
short)(ptrdiff_t)(t - t->lwan->thread.threads) + 1)
330 1)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 330, __FUNCTION__, "Starting IO loop on thread #%d", (unsigned
short)(ptrdiff_t)(t - t->lwan->thread.threads) + 1)
;
331 lwan_set_thread_name("worker");
332
333 events = calloc((size_t)max_events, sizeof(*events));
334 if (UNLIKELY(!events)__builtin_expect(((!events)), (0)))
335 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"
, 335, __FUNCTION__, "Could not allocate memory for events")
;
336
337 update_date_cache(t);
338
339 death_queue_init(&dq, lwan);
340
341 pthread_barrier_wait(&lwan->thread.barrier);
342
343 for (;;) {
344 int timeout = turn_timer_wheel(&dq, t, epoll_fd);
345 int n_fds = epoll_wait(epoll_fd, events, max_events, timeout);
346
347 if (UNLIKELY(n_fds < 0)__builtin_expect(((n_fds < 0)), (0))) {
348 if (errno(*__errno_location ()) == EBADF9 || errno(*__errno_location ()) == EINVAL22)
349 break;
350 continue;
351 }
352
353 for (struct epoll_event *event = events; n_fds--; event++) {
354 struct lwan_connection *conn;
355
356 if (UNLIKELY(!event->data.ptr)__builtin_expect(((!event->data.ptr)), (0))) {
357 accept_nudge(read_pipe_fd, t, lwan->conns, &dq, &switcher,
358 epoll_fd);
359 continue;
360 }
361
362 conn = event->data.ptr;
363
364 if (UNLIKELY(event->events & (EPOLLRDHUP | EPOLLHUP))__builtin_expect(((event->events & (EPOLLRDHUP | EPOLLHUP
))), (0))
) {
365 death_queue_kill(&dq, conn);
366 continue;
367 }
368
369 resume_coro_if_needed(&dq, conn, epoll_fd);
370 death_queue_move_to_last(&dq, conn);
371 }
372 }
373
374 pthread_barrier_wait(&lwan->thread.barrier);
375
376 death_queue_kill_all(&dq);
377 free(events);
378
379 return NULL((void*)0);
380}
381
382static void create_thread(struct lwan *l, struct lwan_thread *thread)
383{
384 int ignore;
385 pthread_attr_t attr;
386
387 memset(thread, 0, sizeof(*thread));
388 thread->lwan = l;
389
390 thread->wheel = timeouts_open(&ignore);
391 if (!thread->wheel)
392 lwan_status_critical("Could not create timer wheel")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 392, __FUNCTION__, "Could not create timer wheel")
;
393
394 if ((thread->epoll_fd = epoll_create1(EPOLL_CLOEXECEPOLL_CLOEXEC)) < 0)
395 lwan_status_critical_perror("epoll_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 395, __FUNCTION__, "epoll_create")
;
396
397 if (pthread_attr_init(&attr))
398 lwan_status_critical_perror("pthread_attr_init")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 398, __FUNCTION__, "pthread_attr_init")
;
399
400 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEMPTHREAD_SCOPE_SYSTEM))
401 lwan_status_critical_perror("pthread_attr_setscope")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 401, __FUNCTION__, "pthread_attr_setscope")
;
402
403 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLEPTHREAD_CREATE_JOINABLE))
404 lwan_status_critical_perror("pthread_attr_setdetachstate")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 404, __FUNCTION__, "pthread_attr_setdetachstate")
;
405
406#if defined(HAVE_EVENTFD)
407 int efd = eventfd(0, EFD_NONBLOCKEFD_NONBLOCK | EFD_SEMAPHOREEFD_SEMAPHORE | EFD_CLOEXECEFD_CLOEXEC);
408 if (efd < 0)
409 lwan_status_critical_perror("eventfd")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 409, __FUNCTION__, "eventfd")
;
410
411 thread->pipe_fd[0] = thread->pipe_fd[1] = efd;
412#else
413 if (pipe2(thread->pipe_fd, O_NONBLOCK04000 | O_CLOEXEC02000000) < 0)
414 lwan_status_critical_perror("pipe")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 414, __FUNCTION__, "pipe")
;
415#endif
416
417 struct epoll_event event = { .events = EPOLLINEPOLLIN, .data.ptr = NULL((void*)0) };
418 if (epoll_ctl(thread->epoll_fd, EPOLL_CTL_ADD1, thread->pipe_fd[0], &event) < 0)
419 lwan_status_critical_perror("epoll_ctl")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 419, __FUNCTION__, "epoll_ctl")
;
420
421 if (pthread_create(&thread->self, &attr, thread_io_loop, thread))
422 lwan_status_critical_perror("pthread_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 422, __FUNCTION__, "pthread_create")
;
423
424 if (pthread_attr_destroy(&attr))
425 lwan_status_critical_perror("pthread_attr_destroy")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 425, __FUNCTION__, "pthread_attr_destroy")
;
426
427 size_t n_queue_fds = thread->lwan->thread.max_fd;
428 if (n_queue_fds > 128)
429 n_queue_fds = 128;
430 if (spsc_queue_init(&thread->pending_fds, n_queue_fds) < 0) {
431 lwan_status_critical("Could not initialize pending fd "lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 432, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
432 "queue width %zu elements", n_queue_fds)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 432, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
;
433 }
434}
435
436void lwan_thread_nudge(struct lwan_thread *t)
437{
438 uint64_t event = 1;
439
440 if (UNLIKELY(write(t->pipe_fd[1], &event, sizeof(event)) < 0)__builtin_expect(((write(t->pipe_fd[1], &event, sizeof
(event)) < 0)), (0))
)
441 lwan_status_perror("write")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 441, __FUNCTION__, "write")
;
442}
443
444void lwan_thread_add_client(struct lwan_thread *t, int fd)
445{
446 for (int i = 0; i < 10; i++) {
447 bool_Bool pushed = spsc_queue_push(&t->pending_fds, fd);
448
449 if (LIKELY(pushed)__builtin_expect((!!(pushed)), (1)))
450 return;
451
452 /* Queue is full; nudge the thread to consume it. */
453 lwan_thread_nudge(t);
454 }
455
456 lwan_status_error("Dropping connection %d", fd)lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 456, __FUNCTION__, "Dropping connection %d", fd)
;
457 /* FIXME: send "busy" response now, even without receiving request? */
458 close(fd);
459}
460
461#if defined(__linux__1) && defined(__x86_64__1)
462static bool_Bool read_cpu_topology(struct lwan *l, uint32_t siblings[])
463{
464 char path[PATH_MAX4096];
465
466 for (unsigned short i = 0; i < l->n_cpus; i++) {
467 FILE *sib;
468 uint32_t id, sibling;
469
470 snprintf(path, sizeof(path),
471 "/sys/devices/system/cpu/cpu%hd/topology/thread_siblings_list",
472 i);
473
474 sib = fopen(path, "re");
475 if (!sib) {
476 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"
, 477, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
477 path)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 477, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
;
478 return false0;
479 }
480
481 switch (fscanf(sib, "%u-%u", &id, &sibling)) {
482 case 1: /* No SMT */
483 siblings[i] = id;
484 break;
485 case 2: /* SMT */
486 siblings[i] = sibling;
487 break;
488 default:
489 lwan_status_critical("%s has invalid format", path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 489, __FUNCTION__, "%s has invalid format", path)
;
490 __builtin_unreachable();
491 }
492
493 fclose(sib);
494 }
495
496 return true1;
497}
498
499static void
500siblings_to_schedtbl(struct lwan *l, uint32_t siblings[], uint32_t schedtbl[])
501{
502 int *seen = alloca(l->n_cpus * sizeof(int))__builtin_alloca (l->n_cpus * sizeof(int));
503 int n_schedtbl = 0;
504
505 for (uint32_t i = 0; i < l->n_cpus; i++)
12
Assuming the condition is true
13
Loop condition is true. Entering loop body
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
16
Assuming the condition is true
17
Loop condition is true. Entering loop body
18
Assuming the condition is false
19
Loop condition is false. Execution continues on line 508
506 seen[i] = -1;
507
508 for (uint32_t i = 0; i < l->n_cpus; i++) {
20
Loop condition is true. Entering loop body
22
Loop condition is true. Entering loop body
24
Loop condition is true. Entering loop body
26
Loop condition is false. Execution continues on line 517
509 if (seen[siblings[i]] < 0) {
21
Taking false branch
23
Taking true branch
25
Taking true branch
510 seen[siblings[i]] = (int)i;
511 } else {
512 schedtbl[n_schedtbl++] = (uint32_t)seen[siblings[i]];
513 schedtbl[n_schedtbl++] = i;
514 }
515 }
516
517 if (!n_schedtbl)
27
Taking false branch
518 memcpy(schedtbl, seen, l->n_cpus * sizeof(int));
519}
520
521static void
522topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
523{
524 uint32_t *siblings = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
525
526 if (!read_cpu_topology(l, siblings)) {
9
Assuming the condition is false
10
Taking false branch
527 for (uint32_t i = 0; i < n_threads; i++)
528 schedtbl[i] = (i / 2) % l->thread.count;
529 } else {
530 uint32_t *affinity = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
531
532 siblings_to_schedtbl(l, siblings, affinity);
11
Calling 'siblings_to_schedtbl'
28
Returning from 'siblings_to_schedtbl'
533
534 for (uint32_t i = 0; i < n_threads; i++)
29
Assuming 'i' is < 'n_threads'
30
Loop condition is true. Entering loop body
31
Assuming 'i' is < 'n_threads'
32
Loop condition is true. Entering loop body
33
Assuming 'i' is < 'n_threads'
34
Loop condition is true. Entering loop body
535 schedtbl[i] = affinity[i % l->n_cpus];
35
Assigned value is garbage or undefined
536 }
537}
538
539static void
540adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t mask)
541{
542 for (uint32_t i = 0; i < l->thread.count; i++) {
543 cpu_set_t set;
544
545 CPU_ZERO(&set)do __builtin_memset (&set, '\0', sizeof (cpu_set_t)); while
(0)
;
546 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; }))
;
547
548 if (pthread_setaffinity_np(l->thread.threads[i].self, sizeof(set),
549 &set))
550 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"
, 550, __FUNCTION__, "Could not set affinity for thread %d", i
)
;
551 }
552}
553#elif defined(__x86_64__1)
554static void
555topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
556{
557 for (uint32_t i = 0; i < n_threads; i++)
558 schedtbl[i] = (i / 2) % l->thread.count;
559}
560
561static void
562adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t n)
563{
564}
565#endif
566
567void lwan_thread_init(struct lwan *l)
568{
569 if (pthread_barrier_init(&l->thread.barrier, NULL((void*)0),
1
Assuming the condition is false
2
Taking false branch
570 (unsigned)l->thread.count + 1))
571 lwan_status_critical("Could not create barrier")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 571, __FUNCTION__, "Could not create barrier")
;
572
573 lwan_status_debug("Initializing threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 573, __FUNCTION__, "Initializing threads")
;
574
575 l->thread.threads =
576 calloc((size_t)l->thread.count, sizeof(struct lwan_thread));
577 if (!l->thread.threads)
3
Assuming the condition is false
4
Taking false branch
578 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"
, 578, __FUNCTION__, "Could not allocate memory for threads")
;
579
580 for (short i = 0; i < l->thread.count; i++)
5
Loop condition is true. Entering loop body
6
Assuming the condition is false
7
Loop condition is false. Execution continues on line 583
581 create_thread(l, &l->thread.threads[i]);
582
583 const unsigned int total_conns = l->thread.max_fd * l->thread.count;
584#ifdef __x86_64__1
585 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; })]
586 "Two connections per cache line")extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(struct lwan_connection) ==
32) ? 2 : -1; })]
;
587 /*
588 * Pre-schedule each file descriptor, to reduce some operations in the
589 * fast path.
590 *
591 * Since struct lwan_connection is guaranteed to be 32-byte long, two of
592 * them can fill up a cache line. Assume siblings share cache lines and
593 * use the CPU topology to group two connections per cache line in such
594 * a way that false sharing is avoided.
595 */
596 uint32_t n_threads = (uint32_t)lwan_nextpow2((size_t)((l->thread.count - 1) * 2));
597 uint32_t *schedtbl = alloca(n_threads * sizeof(uint32_t))__builtin_alloca (n_threads * sizeof(uint32_t));
598
599 topology_to_schedtbl(l, schedtbl, n_threads);
8
Calling 'topology_to_schedtbl'
600
601 n_threads--; /* Transform count into mask for AND below */
602 adjust_threads_affinity(l, schedtbl, n_threads);
603 for (unsigned int i = 0; i < total_conns; i++)
604 l->conns[i].thread = &l->thread.threads[schedtbl[i & n_threads]];
605#else
606 for (unsigned int i = 0; i < total_conns; i++)
607 l->conns[i].thread = &l->thread.threads[i % l->thread.count];
608#endif
609
610 pthread_barrier_wait(&l->thread.barrier);
611
612 lwan_status_debug("IO threads created and ready to serve")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 612, __FUNCTION__, "IO threads created and ready to serve")
;
613}
614
615void lwan_thread_shutdown(struct lwan *l)
616{
617 lwan_status_debug("Shutting down threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 617, __FUNCTION__, "Shutting down threads")
;
618
619 for (int i = 0; i < l->thread.count; i++) {
620 struct lwan_thread *t = &l->thread.threads[i];
621
622 close(t->epoll_fd);
623 lwan_thread_nudge(t);
624 }
625
626 pthread_barrier_wait(&l->thread.barrier);
627 pthread_barrier_destroy(&l->thread.barrier);
628
629 for (int i = 0; i < l->thread.count; i++) {
630 struct lwan_thread *t = &l->thread.threads[i];
631
632 close(t->pipe_fd[0]);
633#if !defined(HAVE_EVENTFD)
634 close(t->pipe_fd[1]);
635#endif
636
637 pthread_join(l->thread.threads[i].self, NULL((void*)0));
638 spsc_queue_free(&t->pending_fds);
639 timeouts_close(t->wheel);
640 }
641
642 free(l->thread.threads);
643}