Bug Summary

File:lwan-thread.c
Warning:line 546, column 9
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++)
506 seen[i] = -1;
507
508 for (uint32_t i = 0; i < l->n_cpus; i++) {
509 if (seen[siblings[i]] < 0) {
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)
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
Taking true branch
527 for (uint32_t i = 0; i < n_threads; i++)
10
Assuming 'i' is >= 'n_threads'
11
Loop condition is false. Execution continues on line 527
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);
533
534 for (uint32_t i = 0; i < n_threads; i++)
535 schedtbl[i] = affinity[i % l->n_cpus];
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++) {
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
543 cpu_set_t set;
544
545 CPU_ZERO(&set)do __builtin_memset (&set, '\0', sizeof (cpu_set_t)); while
(0)
;
16
Loop condition is false. Exiting loop
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; }))
;
17
Assigned value is garbage or undefined
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'
12
Returning from 'topology_to_schedtbl'
600
601 n_threads--; /* Transform count into mask for AND below */
602 adjust_threads_affinity(l, schedtbl, n_threads);
13
Calling 'adjust_threads_affinity'
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}