Bug Summary

File:lwan-thread.c
Warning:line 683, 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.1 -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.1/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-09-09-035814-2101835-1 -x c /home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c
1/*
2 * lwan - simple web server
3 * Copyright (c) 2012, 2013 Leandro A. F. Pereira <leandro@hardinfo.org>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
18 * USA.
19 */
20
21#define _GNU_SOURCE
22#include <assert.h>
23#include <errno(*__errno_location ()).h>
24#include <fcntl.h>
25#include <pthread.h>
26#include <sched.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sys/epoll.h>
30#include <sys/ioctl.h>
31#include <sys/socket.h>
32#include <unistd.h>
33
34#if defined(HAVE_EVENTFD)
35#include <sys/eventfd.h>
36#endif
37
38#include "lwan-private.h"
39#include "lwan-tq.h"
40#include "list.h"
41
42static void lwan_strbuf_free_defer(void *data)
43{
44 lwan_strbuf_free((struct lwan_strbuf *)data);
45}
46
47static void graceful_close(struct lwan *l,
48 struct lwan_connection *conn,
49 char buffer[static DEFAULT_BUFFER_SIZE4096])
50{
51 int fd = lwan_connection_get_fd(l, conn);
52
53 while (TIOCOUTQ0x5411) {
54 /* This ioctl isn't probably doing what it says on the tin; the details
55 * are subtle, but it seems to do the trick to allow gracefully closing
56 * the connection in some cases with minimal system calls. */
57 int bytes_waiting;
58 int r = ioctl(fd, TIOCOUTQ0x5411, &bytes_waiting);
59
60 if (!r && !bytes_waiting) /* See note about close(2) below. */
61 return;
62 if (r < 0 && errno(*__errno_location ()) == EINTR4)
63 continue;
64
65 break;
66 }
67
68 if (UNLIKELY(shutdown(fd, SHUT_WR) < 0)__builtin_expect(((shutdown(fd, SHUT_WR) < 0)), (0))) {
69 if (UNLIKELY(errno == ENOTCONN)__builtin_expect((((*__errno_location ()) == 107)), (0)))
70 return;
71 }
72
73 for (int tries = 0; tries < 20; tries++) {
74 ssize_t r = read(fd, buffer, DEFAULT_BUFFER_SIZE4096);
75
76 if (!r)
77 break;
78
79 if (r < 0) {
80 switch (errno(*__errno_location ())) {
81 case EAGAIN11:
82 coro_yield(conn->coro, CONN_CORO_WANT_READ);
83 /* Fallthrough */
84 case EINTR4:
85 continue;
86 default:
87 return;
88 }
89 }
90
91 coro_yield(conn->coro, CONN_CORO_YIELD);
92 }
93
94 /* close(2) will be called when the coroutine yields with CONN_CORO_ABORT */
95}
96
97__attribute__((noreturn)) static int process_request_coro(struct coro *coro,
98 void *data)
99{
100 /* NOTE: This function should not return; coro_yield should be used
101 * instead. This ensures the storage for `strbuf` is alive when the
102 * coroutine ends and lwan_strbuf_free() is called. */
103 struct lwan_connection *conn = data;
104 struct lwan *lwan = conn->thread->lwan;
105 int fd = lwan_connection_get_fd(lwan, conn);
106 enum lwan_request_flags flags = lwan->config.request_flags;
107 struct lwan_strbuf strbuf = LWAN_STRBUF_STATIC_INIT(struct lwan_strbuf) { .buffer = "" };
108 char request_buffer[DEFAULT_BUFFER_SIZE4096];
109 struct lwan_value buffer = {.value = request_buffer, .len = 0};
110 char *next_request = NULL((void*)0);
111 char *header_start[N_HEADER_START64];
112 struct lwan_proxy proxy;
113 const int error_when_n_packets = lwan_calculate_n_packets(DEFAULT_BUFFER_SIZE4096);
114
115 coro_defer(coro, lwan_strbuf_free_defer, &strbuf);
116
117 const size_t init_gen = 1; /* 1 call to coro_defer() */
118 assert(init_gen == coro_deferred_get_generation(coro))((void) sizeof ((init_gen == coro_deferred_get_generation(coro
)) ? 1 : 0), __extension__ ({ if (init_gen == coro_deferred_get_generation
(coro)) ; else __assert_fail ("init_gen == coro_deferred_get_generation(coro)"
, "/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 118, __extension__ __PRETTY_FUNCTION__); }))
;
119
120 while (true1) {
121 struct lwan_request_parser_helper helper = {
122 .buffer = &buffer,
123 .next_request = next_request,
124 .error_when_n_packets = error_when_n_packets,
125 .header_start = header_start,
126 };
127 struct lwan_request request = {.conn = conn,
128 .global_response_headers = &lwan->headers,
129 .fd = fd,
130 .response = {.buffer = &strbuf},
131 .flags = flags,
132 .proxy = &proxy,
133 .helper = &helper};
134
135 lwan_process_request(lwan, &request);
136
137 /* Run the deferred instructions now (except those used to initialize
138 * the coroutine), so that if the connection is gracefully closed,
139 * the storage for ``helper'' is still there. */
140 coro_deferred_run(coro, init_gen);
141
142 if (UNLIKELY(!(conn->flags & CONN_IS_KEEP_ALIVE))__builtin_expect(((!(conn->flags & CONN_IS_KEEP_ALIVE)
)), (0))
) {
143 graceful_close(lwan, conn, request_buffer);
144 break;
145 }
146
147 if (next_request && *next_request) {
148 conn->flags |= CONN_CORK;
149 coro_yield(coro, CONN_CORO_WANT_WRITE);
150 } else {
151 conn->flags &= ~CONN_CORK;
152 coro_yield(coro, CONN_CORO_WANT_READ);
153 }
154
155 lwan_strbuf_reset(&strbuf);
156
157 /* Only allow flags from config. */
158 flags = request.flags & (REQUEST_PROXIED | REQUEST_ALLOW_CORS);
159 next_request = helper.next_request;
160 }
161
162 coro_yield(coro, CONN_CORO_ABORT);
163 __builtin_unreachable();
164}
165
166static ALWAYS_INLINEinline __attribute__((always_inline)) uint32_t
167conn_flags_to_epoll_events(enum lwan_connection_flags flags)
168{
169 static const uint32_t map[CONN_EVENTS_MASK + 1] = {
170 [0 /* Suspended (timer or await) */] = EPOLLRDHUPEPOLLRDHUP,
171 [CONN_EVENTS_WRITE] = EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP,
172 [CONN_EVENTS_READ] = EPOLLINEPOLLIN | EPOLLRDHUPEPOLLRDHUP,
173 [CONN_EVENTS_READ_WRITE] = EPOLLINEPOLLIN | EPOLLOUTEPOLLOUT | EPOLLRDHUPEPOLLRDHUP,
174 };
175
176 return map[flags & CONN_EVENTS_MASK];
177}
178
179static void update_epoll_flags(int fd,
180 struct lwan_connection *conn,
181 int epoll_fd,
182 enum lwan_connection_coro_yield yield_result)
183{
184 static const enum lwan_connection_flags or_mask[CONN_CORO_MAX] = {
185 [CONN_CORO_YIELD] = 0,
186
187 [CONN_CORO_WANT_READ_WRITE] = CONN_EVENTS_READ_WRITE,
188 [CONN_CORO_WANT_READ] = CONN_EVENTS_READ,
189 [CONN_CORO_WANT_WRITE] = CONN_EVENTS_WRITE,
190
191 /* While the coro is suspended, we're not interested in either EPOLLIN
192 * or EPOLLOUT events. We still want to track this fd in epoll, though,
193 * so unset both so that only EPOLLRDHUP (plus the implicitly-set ones)
194 * are set. */
195 [CONN_CORO_SUSPEND_TIMER] = CONN_SUSPENDED_TIMER,
196 [CONN_CORO_SUSPEND_ASYNC_AWAIT] = CONN_SUSPENDED_ASYNC_AWAIT,
197
198 /* Ideally, when suspending a coroutine, the current flags&CONN_EVENTS_MASK
199 * would have to be stored and restored -- however, resuming as if the
200 * client coroutine is interested in a write event always guarantees that
201 * they'll be resumed as they're TCP sockets. There's a good chance that
202 * trying to read from a socket after resuming a coroutine will succeed,
203 * but if it doesn't because read() returns -EAGAIN, the I/O wrappers will
204 * yield with CONN_CORO_WANT_READ anyway. */
205 [CONN_CORO_RESUME] = CONN_EVENTS_WRITE,
206 };
207 static const enum lwan_connection_flags and_mask[CONN_CORO_MAX] = {
208 [CONN_CORO_YIELD] = ~0,
209
210 [CONN_CORO_WANT_READ_WRITE] = ~0,
211 [CONN_CORO_WANT_READ] = ~CONN_EVENTS_WRITE,
212 [CONN_CORO_WANT_WRITE] = ~CONN_EVENTS_READ,
213
214 [CONN_CORO_SUSPEND_TIMER] = ~(CONN_EVENTS_READ_WRITE | CONN_SUSPENDED_ASYNC_AWAIT),
215 [CONN_CORO_SUSPEND_ASYNC_AWAIT] = ~(CONN_EVENTS_READ_WRITE | CONN_SUSPENDED_TIMER),
216 [CONN_CORO_RESUME] = ~CONN_SUSPENDED,
217 };
218 enum lwan_connection_flags prev_flags = conn->flags;
219
220 conn->flags |= or_mask[yield_result];
221 conn->flags &= and_mask[yield_result];
222
223 if (conn->flags == prev_flags)
224 return;
225
226 struct epoll_event event = {
227 .events = conn_flags_to_epoll_events(conn->flags),
228 .data.ptr = conn,
229 };
230
231 if (UNLIKELY(epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event) < 0)__builtin_expect(((epoll_ctl(epoll_fd, 3, fd, &event) <
0)), (0))
)
232 lwan_status_perror("epoll_ctl")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 232, __FUNCTION__, "epoll_ctl")
;
233}
234
235static void clear_async_await_flag(void *data)
236{
237 struct lwan_connection *async_fd_conn = data;
238
239 async_fd_conn->flags &= ~CONN_ASYNC_AWAIT;
240}
241
242static enum lwan_connection_coro_yield
243resume_async(struct timeout_queue *tq,
244 enum lwan_connection_coro_yield yield_result,
245 int64_t from_coro,
246 struct lwan_connection *conn,
247 int epoll_fd)
248{
249 static const enum lwan_connection_flags to_connection_flags[] = {
250 [CONN_CORO_ASYNC_AWAIT_READ] = CONN_EVENTS_READ,
251 [CONN_CORO_ASYNC_AWAIT_WRITE] = CONN_EVENTS_WRITE,
252 [CONN_CORO_ASYNC_AWAIT_READ_WRITE] = CONN_EVENTS_READ_WRITE,
253 };
254 int await_fd = (int)((uint64_t)from_coro >> 32);
255 enum lwan_connection_flags flags;
256 int op;
257
258 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"
, 258, __extension__ __PRETTY_FUNCTION__); }))
;
259 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"
, 260, __extension__ __PRETTY_FUNCTION__); }))
260 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"
, 260, __extension__ __PRETTY_FUNCTION__); }))
;
261
262 flags = to_connection_flags[yield_result];
263
264 struct lwan_connection *await_fd_conn = &tq->lwan->conns[await_fd];
265 if (LIKELY(await_fd_conn->flags & CONN_ASYNC_AWAIT)__builtin_expect((!!(await_fd_conn->flags & CONN_ASYNC_AWAIT
)), (1))
) {
266 if (LIKELY((await_fd_conn->flags & CONN_EVENTS_MASK) == flags)__builtin_expect((!!((await_fd_conn->flags & CONN_EVENTS_MASK
) == flags)), (1))
)
267 return CONN_CORO_SUSPEND_ASYNC_AWAIT;
268
269 op = EPOLL_CTL_MOD3;
270 } else {
271 op = EPOLL_CTL_ADD1;
272 flags |= CONN_ASYNC_AWAIT;
273 coro_defer(conn->coro, clear_async_await_flag, await_fd_conn);
274 }
275
276 struct epoll_event event = {.events = conn_flags_to_epoll_events(flags),
277 .data.ptr = conn};
278 if (LIKELY(!epoll_ctl(epoll_fd, op, await_fd, &event))__builtin_expect((!!(!epoll_ctl(epoll_fd, op, await_fd, &
event))), (1))
) {
279 await_fd_conn->flags &= ~CONN_EVENTS_MASK;
280 await_fd_conn->flags |= flags;
281 return CONN_CORO_SUSPEND_ASYNC_AWAIT;
282 }
283
284 return CONN_CORO_ABORT;
285}
286
287static ALWAYS_INLINEinline __attribute__((always_inline)) void resume_coro(struct timeout_queue *tq,
288 struct lwan_connection *conn,
289 int epoll_fd)
290{
291 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"
, 291, __extension__ __PRETTY_FUNCTION__); }))
;
292
293 int64_t from_coro = coro_resume(conn->coro);
294 enum lwan_connection_coro_yield yield_result = from_coro & 0xffffffff;
295
296 if (UNLIKELY(yield_result >= CONN_CORO_ASYNC)__builtin_expect(((yield_result >= CONN_CORO_ASYNC)), (0)))
297 yield_result = resume_async(tq, yield_result, from_coro, conn, epoll_fd);
298
299 if (UNLIKELY(yield_result == CONN_CORO_ABORT)__builtin_expect(((yield_result == CONN_CORO_ABORT)), (0)))
300 return timeout_queue_expire(tq, conn);
301
302 return update_epoll_flags(lwan_connection_get_fd(tq->lwan, conn), conn,
303 epoll_fd, yield_result);
304}
305
306static void update_date_cache(struct lwan_thread *thread)
307{
308 time_t now = time(NULL((void*)0));
309
310 lwan_format_rfc_time(now, thread->date.date);
311 lwan_format_rfc_time(now + (time_t)thread->lwan->config.expires,
312 thread->date.expires);
313}
314
315static ALWAYS_INLINEinline __attribute__((always_inline)) void spawn_coro(struct lwan_connection *conn,
316 struct coro_switcher *switcher,
317 struct timeout_queue *tq)
318{
319 struct lwan_thread *t = conn->thread;
320
321 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"
, 321, __extension__ __PRETTY_FUNCTION__); }))
;
322 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"
, 322, __extension__ __PRETTY_FUNCTION__); }))
;
323 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"
, 323, __extension__ __PRETTY_FUNCTION__); }))
;
324 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"
, 325, __extension__ __PRETTY_FUNCTION__); }))
325 (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"
, 325, __extension__ __PRETTY_FUNCTION__); }))
;
326
327 *conn = (struct lwan_connection) {
328 .coro = coro_new(switcher, process_request_coro, conn),
329 .flags = CONN_EVENTS_READ,
330 .time_to_expire = tq->current_time + tq->move_to_last_bump,
331 .thread = t,
332 };
333 if (UNLIKELY(!conn->coro)__builtin_expect(((!conn->coro)), (0))) {
334 conn->flags = 0;
335 lwan_status_error("Could not create coroutine")lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 335, __FUNCTION__, "Could not create coroutine")
;
336 return;
337 }
338
339 timeout_queue_insert(tq, conn);
340}
341
342static void accept_nudge(int pipe_fd,
343 struct lwan_thread *t,
344 struct lwan_connection *conns,
345 struct timeout_queue *tq,
346 struct coro_switcher *switcher,
347 int epoll_fd)
348{
349 uint64_t event;
350 int new_fd;
351
352 /* Errors are ignored here as pipe_fd serves just as a way to wake the
353 * thread from epoll_wait(). It's fine to consume the queue at this
354 * point, regardless of the error type. */
355 (void)read(pipe_fd, &event, sizeof(event));
356
357 while (spsc_queue_pop(&t->pending_fds, &new_fd)) {
358 struct lwan_connection *conn = &conns[new_fd];
359 struct epoll_event ev = {
360 .data.ptr = conn,
361 .events = conn_flags_to_epoll_events(CONN_EVENTS_READ),
362 };
363
364 if (LIKELY(!epoll_ctl(epoll_fd, EPOLL_CTL_ADD, new_fd, &ev))__builtin_expect((!!(!epoll_ctl(epoll_fd, 1, new_fd, &ev)
)), (1))
)
365 spawn_coro(conn, switcher, tq);
366 }
367
368 timeouts_add(t->wheel, &tq->timeout, 1000);
369}
370
371static bool_Bool process_pending_timers(struct timeout_queue *tq,
372 struct lwan_thread *t,
373 int epoll_fd)
374{
375 struct timeout *timeout;
376 bool_Bool should_expire_timers = false0;
377
378 while ((timeout = timeouts_get(t->wheel))) {
379 struct lwan_request *request;
380
381 if (timeout == &tq->timeout) {
382 should_expire_timers = true1;
383 continue;
384 }
385
386 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))
;
387
388 update_epoll_flags(request->fd, request->conn, epoll_fd,
389 CONN_CORO_RESUME);
390 }
391
392 if (should_expire_timers) {
393 timeout_queue_expire_waiting(tq);
394
395 /* tq timeout expires every 1000ms if there are connections, so
396 * update the date cache at this point as well. */
397 update_date_cache(t);
398
399 if (!timeout_queue_empty(tq)) {
400 timeouts_add(t->wheel, &tq->timeout, 1000);
401 return true1;
402 }
403
404 timeouts_del(t->wheel, &tq->timeout);
405 }
406
407 return false0;
408}
409
410static int
411turn_timer_wheel(struct timeout_queue *tq, struct lwan_thread *t, int epoll_fd)
412{
413 timeout_t wheel_timeout;
414 struct timespec now;
415
416 if (UNLIKELY(clock_gettime(monotonic_clock_id, &now) < 0)__builtin_expect(((clock_gettime(monotonic_clock_id, &now
) < 0)), (0))
)
417 lwan_status_critical("Could not get monotonic time")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 417, __FUNCTION__, "Could not get monotonic time")
;
418
419 timeouts_update(t->wheel,
420 (timeout_t)(now.tv_sec * 1000 + now.tv_nsec / 1000000));
421
422 wheel_timeout = timeouts_timeout(t->wheel);
423 if (UNLIKELY((int64_t)wheel_timeout < 0)__builtin_expect((((int64_t)wheel_timeout < 0)), (0)))
424 goto infinite_timeout;
425
426 if (wheel_timeout == 0) {
427 if (!process_pending_timers(tq, t, epoll_fd))
428 goto infinite_timeout;
429
430 wheel_timeout = timeouts_timeout(t->wheel);
431 if (wheel_timeout == 0)
432 goto infinite_timeout;
433 }
434
435 return (int)wheel_timeout;
436
437infinite_timeout:
438 return -1;
439}
440
441static void *thread_io_loop(void *data)
442{
443 struct lwan_thread *t = data;
444 int epoll_fd = t->epoll_fd;
445 const int read_pipe_fd = t->pipe_fd[0];
446 const int max_events = LWAN_MIN((int)t->lwan->thread.max_fd, 1024)({ const __typeof__(((int)t->lwan->thread.max_fd) + 0) lwan_tmp_id6
= ((int)t->lwan->thread.max_fd); const __typeof__((1024
) + 0) lwan_tmp_id7 = (1024); lwan_tmp_id6 > lwan_tmp_id7 ?
lwan_tmp_id7 : lwan_tmp_id6; })
;
447 struct lwan *lwan = t->lwan;
448 struct epoll_event *events;
449 struct coro_switcher switcher;
450 struct timeout_queue tq;
451
452 lwan_status_debug("Worker thread #%zd starting",lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 453, __FUNCTION__, "Worker thread #%zd starting", t - t->
lwan->thread.threads + 1)
453 t - t->lwan->thread.threads + 1)lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 453, __FUNCTION__, "Worker thread #%zd starting", t - t->
lwan->thread.threads + 1)
;
454 lwan_set_thread_name("worker");
455
456 events = calloc((size_t)max_events, sizeof(*events));
457 if (UNLIKELY(!events)__builtin_expect(((!events)), (0)))
458 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"
, 458, __FUNCTION__, "Could not allocate memory for events")
;
459
460 update_date_cache(t);
461
462 timeout_queue_init(&tq, lwan);
463
464 pthread_barrier_wait(&lwan->thread.barrier);
465
466 for (;;) {
467 int timeout = turn_timer_wheel(&tq, t, epoll_fd);
468 int n_fds = epoll_wait(epoll_fd, events, max_events, timeout);
469
470 if (UNLIKELY(n_fds < 0)__builtin_expect(((n_fds < 0)), (0))) {
471 if (errno(*__errno_location ()) == EBADF9 || errno(*__errno_location ()) == EINVAL22)
472 break;
473 continue;
474 }
475
476 for (struct epoll_event *event = events; n_fds--; event++) {
477 struct lwan_connection *conn;
478
479 if (UNLIKELY(!event->data.ptr)__builtin_expect(((!event->data.ptr)), (0))) {
480 accept_nudge(read_pipe_fd, t, lwan->conns, &tq, &switcher,
481 epoll_fd);
482 continue;
483 }
484
485 conn = event->data.ptr;
486
487 if (UNLIKELY(event->events & (EPOLLRDHUP | EPOLLHUP))__builtin_expect(((event->events & (EPOLLRDHUP | EPOLLHUP
))), (0))
) {
488 timeout_queue_expire(&tq, conn);
489 continue;
490 }
491
492 resume_coro(&tq, conn, epoll_fd);
493 timeout_queue_move_to_last(&tq, conn);
494 }
495 }
496
497 pthread_barrier_wait(&lwan->thread.barrier);
498
499 timeout_queue_expire_all(&tq);
500 free(events);
501
502 return NULL((void*)0);
503}
504
505static void create_thread(struct lwan *l, struct lwan_thread *thread,
506 const size_t n_queue_fds)
507{
508 int ignore;
509 pthread_attr_t attr;
510
511 memset(thread, 0, sizeof(*thread));
512 thread->lwan = l;
513
514 thread->wheel = timeouts_open(&ignore);
515 if (!thread->wheel)
516 lwan_status_critical("Could not create timer wheel")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 516, __FUNCTION__, "Could not create timer wheel")
;
517
518 if ((thread->epoll_fd = epoll_create1(EPOLL_CLOEXECEPOLL_CLOEXEC)) < 0)
519 lwan_status_critical_perror("epoll_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 519, __FUNCTION__, "epoll_create")
;
520
521 if (pthread_attr_init(&attr))
522 lwan_status_critical_perror("pthread_attr_init")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 522, __FUNCTION__, "pthread_attr_init")
;
523
524 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEMPTHREAD_SCOPE_SYSTEM))
525 lwan_status_critical_perror("pthread_attr_setscope")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 525, __FUNCTION__, "pthread_attr_setscope")
;
526
527 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLEPTHREAD_CREATE_JOINABLE))
528 lwan_status_critical_perror("pthread_attr_setdetachstate")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 528, __FUNCTION__, "pthread_attr_setdetachstate")
;
529
530#if defined(HAVE_EVENTFD)
531 int efd = eventfd(0, EFD_NONBLOCKEFD_NONBLOCK | EFD_SEMAPHOREEFD_SEMAPHORE | EFD_CLOEXECEFD_CLOEXEC);
532 if (efd < 0)
533 lwan_status_critical_perror("eventfd")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 533, __FUNCTION__, "eventfd")
;
534
535 thread->pipe_fd[0] = thread->pipe_fd[1] = efd;
536#else
537 if (pipe2(thread->pipe_fd, O_NONBLOCK04000 | O_CLOEXEC02000000) < 0)
538 lwan_status_critical_perror("pipe")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 538, __FUNCTION__, "pipe")
;
539#endif
540
541 struct epoll_event event = { .events = EPOLLINEPOLLIN, .data.ptr = NULL((void*)0) };
542 if (epoll_ctl(thread->epoll_fd, EPOLL_CTL_ADD1, thread->pipe_fd[0], &event) < 0)
543 lwan_status_critical_perror("epoll_ctl")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 543, __FUNCTION__, "epoll_ctl")
;
544
545 if (pthread_create(&thread->self, &attr, thread_io_loop, thread))
546 lwan_status_critical_perror("pthread_create")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 546, __FUNCTION__, "pthread_create")
;
547
548 if (pthread_attr_destroy(&attr))
549 lwan_status_critical_perror("pthread_attr_destroy")lwan_status_critical_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 549, __FUNCTION__, "pthread_attr_destroy")
;
550
551 if (spsc_queue_init(&thread->pending_fds, n_queue_fds) < 0) {
552 lwan_status_critical("Could not initialize pending fd "lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 553, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
553 "queue width %zu elements", n_queue_fds)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 553, __FUNCTION__, "Could not initialize pending fd " "queue width %zu elements"
, n_queue_fds)
;
554 }
555}
556
557void lwan_thread_nudge(struct lwan_thread *t)
558{
559 uint64_t event = 1;
560
561 if (UNLIKELY(write(t->pipe_fd[1], &event, sizeof(event)) < 0)__builtin_expect(((write(t->pipe_fd[1], &event, sizeof
(event)) < 0)), (0))
)
562 lwan_status_perror("write")lwan_status_perror_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 562, __FUNCTION__, "write")
;
563}
564
565void lwan_thread_add_client(struct lwan_thread *t, int fd)
566{
567 for (int i = 0; i < 10; i++) {
568 bool_Bool pushed = spsc_queue_push(&t->pending_fds, fd);
569
570 if (LIKELY(pushed)__builtin_expect((!!(pushed)), (1)))
571 return;
572
573 /* Queue is full; nudge the thread to consume it. */
574 lwan_thread_nudge(t);
575 }
576
577 lwan_status_error("Dropping connection %d", fd)lwan_status_error_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 577, __FUNCTION__, "Dropping connection %d", fd)
;
578 /* FIXME: send "busy" response now, even without receiving request? */
579 close(fd);
580}
581
582#if defined(__linux__1) && defined(__x86_64__1)
583static bool_Bool read_cpu_topology(struct lwan *l, uint32_t siblings[])
584{
585 char path[PATH_MAX4096];
586
587 for (unsigned int i = 0; i < l->n_cpus; i++) {
20
Loop condition is true. Entering loop body
25
Loop condition is true. Entering loop body
30
Loop condition is true. Entering loop body
35
Loop condition is false. Execution continues on line 627
588 FILE *sib;
589 uint32_t id, sibling;
590 char separator;
591
592 snprintf(path, sizeof(path),
593 "/sys/devices/system/cpu/cpu%d/topology/thread_siblings_list",
594 i);
595
596 sib = fopen(path, "re");
597 if (!sib) {
21
Assuming 'sib' is non-null, which participates in a condition later
22
Taking false branch
26
Assuming 'sib' is non-null, which participates in a condition later
27
Taking false branch
31
Assuming 'sib' is non-null, which participates in a condition later
32
Taking false branch
598 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"
, 599, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
599 path)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 599, __FUNCTION__, "Could not open `%s` to determine CPU topology"
, path)
;
600 return false0;
601 }
602
603 switch (fscanf(sib, "%u%c%u", &id, &separator, &sibling)) {
23
Control jumps to 'case 2:' at line 604
28
Control jumps to 'case 2:' at line 604
33
Control jumps to 'case 2:' at line 604
604 case 2: /* No SMT */
605 siblings[i] = id;
606 break;
24
Execution continues on line 620
29
Execution continues on line 620
34
Execution continues on line 620
607 case 3: /* SMT */
608 if (!(separator == ',' || separator == '-')) {
609 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"
, 609, __FUNCTION__, "Expecting either ',' or '-' for sibling separator"
)
;
610 __builtin_unreachable();
611 }
612
613 siblings[i] = sibling;
614 break;
615 default:
616 lwan_status_critical("%s has invalid format", path)lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 616, __FUNCTION__, "%s has invalid format", path)
;
617 __builtin_unreachable();
618 }
619
620 fclose(sib);
621 }
622
623 /* Some systems may lie about the number of online CPUs (obtainable with
624 * sysconf()), but don't filter out the CPU topology information from
625 * sysfs, which might reference CPU numbers higher than the amount
626 * obtained with sysconf(). */
627 for (unsigned int i = 0; i < l->n_cpus; i++) {
36
Loop condition is true. Entering loop body
41
Loop condition is true. Entering loop body
46
Loop condition is true. Entering loop body
51
Loop condition is false. Execution continues on line 641
628 if (siblings[i] == 0xbebacafe) {
37
Assuming the condition is false
38
Taking false branch
42
Assuming the condition is false
43
Taking false branch
47
Assuming the condition is false
48
Taking false branch
629 lwan_status_warning("Could not determine sibling for CPU %d", i)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 629, __FUNCTION__, "Could not determine sibling for CPU %d"
, i)
;
630 return false0;
631 }
632
633 if (siblings[i] > l->n_cpus) {
39
Assuming the condition is false
40
Taking false branch
44
Assuming the condition is false
45
Taking false branch
49
Assuming the condition is false
50
Taking false branch
634 lwan_status_warning("CPU topology information says CPU %d exists, "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 636, __FUNCTION__, "CPU topology information says CPU %d exists, "
"but max CPUs is %d. Is Lwan running in a " "container?", siblings
[i], l->n_cpus)
635 "but max CPUs is %d. Is Lwan running in a "lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 636, __FUNCTION__, "CPU topology information says CPU %d exists, "
"but max CPUs is %d. Is Lwan running in a " "container?", siblings
[i], l->n_cpus)
636 "container?", siblings[i], l->n_cpus)lwan_status_warning_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 636, __FUNCTION__, "CPU topology information says CPU %d exists, "
"but max CPUs is %d. Is Lwan running in a " "container?", siblings
[i], l->n_cpus)
;
637 return false0;
638 }
639 }
640
641 return true1;
52
Returning the value 1, which participates in a condition later
642}
643
644static void
645siblings_to_schedtbl(struct lwan *l, uint32_t siblings[], uint32_t schedtbl[])
646{
647 int *seen = alloca(l->n_cpus * sizeof(int))__builtin_alloca (l->n_cpus * sizeof(int));
648 int n_schedtbl = 0;
649
650 for (uint32_t i = 0; i < l->n_cpus; i++)
56
Loop condition is true. Entering loop body
57
Loop condition is true. Entering loop body
58
Loop condition is true. Entering loop body
59
Loop condition is false. Execution continues on line 653
651 seen[i] = -1;
652
653 for (uint32_t i = 0; i < l->n_cpus; i++) {
60
Loop condition is true. Entering loop body
63
Loop condition is true. Entering loop body
66
Loop condition is true. Entering loop body
69
Loop condition is false. Execution continues on line 662
654 if (seen[siblings[i]] < 0) {
61
Assuming the condition is false
62
Taking false branch
64
Assuming the condition is true
65
Taking true branch
67
Assuming the condition is true
68
Taking true branch
655 seen[siblings[i]] = (int)i;
656 } else {
657 schedtbl[n_schedtbl++] = (uint32_t)seen[siblings[i]];
658 schedtbl[n_schedtbl++] = i;
659 }
660 }
661
662 if (!n_schedtbl
69.1
'n_schedtbl' is 2
)
70
Taking false branch
663 memcpy(schedtbl, seen, l->n_cpus * sizeof(int));
664}
665
666static void
667topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
668{
669 uint32_t *siblings = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
670
671 for (uint32_t i = 0; i < l->n_cpus; i++)
11
Assuming 'i' is < field 'n_cpus'
12
Loop condition is true. Entering loop body
13
Assuming 'i' is < field 'n_cpus'
14
Loop condition is true. Entering loop body
15
Assuming 'i' is < field 'n_cpus'
16
Loop condition is true. Entering loop body
17
Assuming 'i' is >= field 'n_cpus'
18
Loop condition is false. Execution continues on line 674
672 siblings[i] = 0xbebacafe;
673
674 if (!read_cpu_topology(l, siblings)) {
19
Calling 'read_cpu_topology'
53
Returning from 'read_cpu_topology'
54
Taking false branch
675 for (uint32_t i = 0; i < n_threads; i++)
676 schedtbl[i] = (i / 2) % l->thread.count;
677 } else {
678 uint32_t *affinity = alloca(l->n_cpus * sizeof(uint32_t))__builtin_alloca (l->n_cpus * sizeof(uint32_t));
679
680 siblings_to_schedtbl(l, siblings, affinity);
55
Calling 'siblings_to_schedtbl'
71
Returning from 'siblings_to_schedtbl'
681
682 for (uint32_t i = 0; i < n_threads; i++)
72
Assuming 'i' is < 'n_threads'
73
Loop condition is true. Entering loop body
74
Assuming 'i' is < 'n_threads'
75
Loop condition is true. Entering loop body
76
Assuming 'i' is < 'n_threads'
77
Loop condition is true. Entering loop body
683 schedtbl[i] = affinity[i % l->n_cpus];
78
Assigned value is garbage or undefined
684 }
685}
686
687static void
688adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t mask)
689{
690 for (uint32_t i = 0; i < l->thread.count; i++) {
691 cpu_set_t set;
692
693 CPU_ZERO(&set)do __builtin_memset (&set, '\0', sizeof (cpu_set_t)); while
(0)
;
694 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; }))
;
695
696 if (pthread_setaffinity_np(l->thread.threads[i].self, sizeof(set),
697 &set))
698 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"
, 698, __FUNCTION__, "Could not set affinity for thread %d", i
)
;
699 }
700}
701#elif defined(__x86_64__1)
702static void
703topology_to_schedtbl(struct lwan *l, uint32_t schedtbl[], uint32_t n_threads)
704{
705 for (uint32_t i = 0; i < n_threads; i++)
706 schedtbl[i] = (i / 2) % l->thread.count;
707}
708
709static void
710adjust_threads_affinity(struct lwan *l, uint32_t *schedtbl, uint32_t n)
711{
712}
713#endif
714
715void lwan_thread_init(struct lwan *l)
716{
717 if (pthread_barrier_init(&l->thread.barrier, NULL((void*)0),
1
Assuming the condition is false
2
Taking false branch
718 (unsigned)l->thread.count + 1))
719 lwan_status_critical("Could not create barrier")lwan_status_critical_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 719, __FUNCTION__, "Could not create barrier")
;
720
721 lwan_status_debug("Initializing threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 721, __FUNCTION__, "Initializing threads")
;
722
723 l->thread.threads =
724 calloc((size_t)l->thread.count, sizeof(struct lwan_thread));
725 if (!l->thread.threads)
3
Assuming field 'threads' is non-null
4
Taking false branch
726 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"
, 726, __FUNCTION__, "Could not allocate memory for threads")
;
727
728 const size_t n_queue_fds = LWAN_MIN(l->thread.max_fd / l->thread.count,({ const __typeof__((l->thread.max_fd / l->thread.count
) + 0) lwan_tmp_id8 = (l->thread.max_fd / l->thread.count
); const __typeof__(((size_t)(2 * lwan_socket_get_backlog_size
())) + 0) lwan_tmp_id9 = ((size_t)(2 * lwan_socket_get_backlog_size
())); lwan_tmp_id8 > lwan_tmp_id9 ? lwan_tmp_id9 : lwan_tmp_id8
; })
5
Assuming 'lwan_tmp_id4' is <= 'lwan_tmp_id5'
6
'?' condition is false
729 (size_t)(2 * lwan_socket_get_backlog_size()))({ const __typeof__((l->thread.max_fd / l->thread.count
) + 0) lwan_tmp_id8 = (l->thread.max_fd / l->thread.count
); const __typeof__(((size_t)(2 * lwan_socket_get_backlog_size
())) + 0) lwan_tmp_id9 = ((size_t)(2 * lwan_socket_get_backlog_size
())); lwan_tmp_id8 > lwan_tmp_id9 ? lwan_tmp_id9 : lwan_tmp_id8
; })
;
730 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"
, 730, __FUNCTION__, "Pending client file descriptor queue has %zu items"
, n_queue_fds)
;
731 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 734
732 create_thread(l, &l->thread.threads[i], n_queue_fds);
733
734 const unsigned int total_conns = l->thread.max_fd * l->thread.count;
735#ifdef __x86_64__1
736 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; })]
737 "Two connections per cache line")extern int (*__Static_assert_function (void)) [!!sizeof (struct
{ int __error_if_negative: (sizeof(struct lwan_connection) ==
32) ? 2 : -1; })]
;
738 /*
739 * Pre-schedule each file descriptor, to reduce some operations in the
740 * fast path.
741 *
742 * Since struct lwan_connection is guaranteed to be 32-byte long, two of
743 * them can fill up a cache line. Assume siblings share cache lines and
744 * use the CPU topology to group two connections per cache line in such
745 * a way that false sharing is avoided.
746 */
747 uint32_t n_threads = (uint32_t)lwan_nextpow2((size_t)((l->thread.count - 1) * 2));
748 uint32_t *schedtbl = alloca(n_threads * sizeof(uint32_t))__builtin_alloca (n_threads * sizeof(uint32_t));
749
750 topology_to_schedtbl(l, schedtbl, n_threads);
10
Calling 'topology_to_schedtbl'
751
752 n_threads--; /* Transform count into mask for AND below */
753 adjust_threads_affinity(l, schedtbl, n_threads);
754 for (unsigned int i = 0; i < total_conns; i++)
755 l->conns[i].thread = &l->thread.threads[schedtbl[i & n_threads]];
756#else
757 for (unsigned int i = 0; i < total_conns; i++)
758 l->conns[i].thread = &l->thread.threads[i % l->thread.count];
759#endif
760
761 pthread_barrier_wait(&l->thread.barrier);
762
763 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"
, 763, __FUNCTION__, "Worker threads created and ready to serve"
)
;
764}
765
766void lwan_thread_shutdown(struct lwan *l)
767{
768 lwan_status_debug("Shutting down threads")lwan_status_debug_debug("/home/buildbot/lwan-worker/clang-analyze/build/src/lib/lwan-thread.c"
, 768, __FUNCTION__, "Shutting down threads")
;
769
770 for (unsigned int i = 0; i < l->thread.count; i++) {
771 struct lwan_thread *t = &l->thread.threads[i];
772
773 close(t->epoll_fd);
774 lwan_thread_nudge(t);
775 }
776
777 pthread_barrier_wait(&l->thread.barrier);
778 pthread_barrier_destroy(&l->thread.barrier);
779
780 for (unsigned int i = 0; i < l->thread.count; i++) {
781 struct lwan_thread *t = &l->thread.threads[i];
782
783 close(t->pipe_fd[0]);
784#if !defined(HAVE_EVENTFD)
785 close(t->pipe_fd[1]);
786#endif
787
788 pthread_join(l->thread.threads[i].self, NULL((void*)0));
789 spsc_queue_free(&t->pending_fds);
790 timeouts_close(t->wheel);
791 }
792
793 free(l->thread.threads);
794}