2013-09-16 21:57:40 +00:00
|
|
|
/*
|
|
|
|
* BIRD -- I/O and event loop
|
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
2024-10-02 17:02:53 +00:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
#include "nest/bird.h"
|
2013-09-10 10:09:36 +00:00
|
|
|
|
|
|
|
#include "lib/buffer.h"
|
2024-04-23 15:35:00 +00:00
|
|
|
#include "lib/defer.h"
|
2013-09-16 21:57:40 +00:00
|
|
|
#include "lib/lists.h"
|
2023-01-19 09:49:47 +00:00
|
|
|
#include "lib/locking.h"
|
2013-09-16 21:57:40 +00:00
|
|
|
#include "lib/resource.h"
|
|
|
|
#include "lib/event.h"
|
2017-05-30 17:12:35 +00:00
|
|
|
#include "lib/timer.h"
|
2013-09-16 21:57:40 +00:00
|
|
|
#include "lib/socket.h"
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
#include "lib/io-loop.h"
|
|
|
|
#include "sysdep/unix/io-loop.h"
|
|
|
|
#include "conf/conf.h"
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2022-07-28 17:49:03 +00:00
|
|
|
#define THREAD_STACK_SIZE 65536 /* To be lowered in near future */
|
|
|
|
|
2023-04-22 19:20:19 +00:00
|
|
|
static struct birdloop *birdloop_new_no_pickup(pool *pp, uint order, const char *name, ...);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
/*
|
|
|
|
* Nanosecond time for accounting purposes
|
|
|
|
*
|
|
|
|
* A fixed point on startup is set as zero, all other values are relative to that.
|
|
|
|
* Caution: this overflows after like 500 years or so. If you plan to run
|
|
|
|
* BIRD for such a long time, please implement some means of overflow prevention.
|
|
|
|
*/
|
|
|
|
|
2024-06-10 21:09:05 +00:00
|
|
|
#if ! HAVE_CLOCK_MONOTONIC_COARSE
|
|
|
|
#define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC
|
|
|
|
#endif
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
static struct timespec ns_begin;
|
|
|
|
|
|
|
|
static void ns_init(void)
|
|
|
|
{
|
2024-06-10 21:09:05 +00:00
|
|
|
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ns_begin))
|
2023-01-19 09:49:47 +00:00
|
|
|
bug("clock_gettime: %m");
|
|
|
|
}
|
|
|
|
|
2024-04-03 10:05:02 +00:00
|
|
|
u64 ns_now(void)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
|
|
|
struct timespec ts;
|
2024-06-10 21:09:05 +00:00
|
|
|
if (clock_gettime(CLOCK_MONOTONIC_COARSE, &ts))
|
2023-01-19 09:49:47 +00:00
|
|
|
bug("clock_gettime: %m");
|
|
|
|
|
2023-04-26 17:10:52 +00:00
|
|
|
return (u64) (ts.tv_sec - ns_begin.tv_sec) * NSEC_IN_SEC + ts.tv_nsec - ns_begin.tv_nsec;
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
|
|
|
|
2023-04-26 20:24:42 +00:00
|
|
|
static _Thread_local struct spent_time *account_target_spent_time;
|
|
|
|
static _Thread_local u64 *account_target_total;
|
|
|
|
static _Thread_local u64 account_last;
|
|
|
|
|
|
|
|
static u64 account_finish(void)
|
|
|
|
{
|
|
|
|
/* Get current time */
|
|
|
|
u64 now = ns_now();
|
|
|
|
u64 dif = now - account_last;
|
|
|
|
|
|
|
|
/* Update second by second */
|
|
|
|
if (account_target_spent_time)
|
|
|
|
{
|
|
|
|
/* Drop old time information if difference is too large */
|
|
|
|
if (NSEC_TO_SEC(account_last) + TIME_BY_SEC_SIZE - 1 < NSEC_TO_SEC(now))
|
|
|
|
account_last = (NSEC_TO_SEC(now) - TIME_BY_SEC_SIZE + 1) * NSEC_IN_SEC;
|
|
|
|
|
|
|
|
/* Zero new records */
|
|
|
|
if (NSEC_TO_SEC(account_target_spent_time->last_written_ns) + TIME_BY_SEC_SIZE < NSEC_TO_SEC(account_last))
|
|
|
|
memset(account_target_spent_time->by_sec_ns, 0, sizeof(account_target_spent_time->by_sec_ns));
|
|
|
|
else
|
|
|
|
for (u64 fclr = NSEC_TO_SEC(account_target_spent_time->last_written_ns) + 1;
|
|
|
|
fclr <= NSEC_TO_SEC(now);
|
|
|
|
fclr++)
|
|
|
|
account_target_spent_time->by_sec_ns[fclr % TIME_BY_SEC_SIZE] = 0;
|
|
|
|
|
|
|
|
/* Add times second by second */
|
|
|
|
while (NSEC_TO_SEC(account_last) != NSEC_TO_SEC(now))
|
|
|
|
{
|
|
|
|
u64 part = (NSEC_TO_SEC(account_last) + 1) * NSEC_IN_SEC - account_last;
|
|
|
|
account_target_spent_time->by_sec_ns[NSEC_TO_SEC(account_last) % TIME_BY_SEC_SIZE] += part;
|
|
|
|
account_last += part;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the last second */
|
|
|
|
account_target_spent_time->by_sec_ns[NSEC_TO_SEC(account_last) % TIME_BY_SEC_SIZE] += now - account_last;
|
|
|
|
|
|
|
|
/* Store the current time */
|
|
|
|
account_target_spent_time->last_written_ns = now;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the total */
|
|
|
|
if (account_target_total)
|
|
|
|
*account_target_total += dif;
|
|
|
|
|
|
|
|
/* Store current time */
|
|
|
|
account_last = now;
|
|
|
|
|
|
|
|
return dif;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 account_to_spent_time(struct spent_time *st)
|
|
|
|
{
|
|
|
|
u64 elapsed = account_finish();
|
|
|
|
|
|
|
|
account_target_spent_time = st;
|
|
|
|
account_target_total = &st->total_ns;
|
|
|
|
|
|
|
|
return elapsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 account_to_total(u64 *total)
|
|
|
|
{
|
|
|
|
u64 elapsed = account_finish();
|
|
|
|
|
|
|
|
account_target_spent_time = NULL;
|
|
|
|
account_target_total = total;
|
|
|
|
|
|
|
|
return elapsed;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define account_to(_arg) _Generic((_arg), \
|
|
|
|
struct spent_time *: account_to_spent_time, \
|
|
|
|
u64 *: account_to_total)(_arg)
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2013-11-19 21:33:48 +00:00
|
|
|
/*
|
|
|
|
* Current thread context
|
|
|
|
*/
|
2013-09-16 21:57:40 +00:00
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
_Thread_local struct birdloop *birdloop_current;
|
|
|
|
static _Thread_local struct birdloop *birdloop_wakeup_masked;
|
|
|
|
static _Thread_local uint birdloop_wakeup_masked_count;
|
2013-09-16 21:57:40 +00:00
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
#define LOOP_NAME(loop) domain_name((loop)->time.domain)
|
2024-06-13 14:30:51 +00:00
|
|
|
#define LATENCY_DEBUG(flags) (atomic_load_explicit(&global_runtime, memory_order_relaxed)->latency_debug & (flags))
|
2023-04-06 18:18:04 +00:00
|
|
|
|
2024-06-13 14:30:51 +00:00
|
|
|
#define LOOP_TRACE(loop, flags, fmt, args...) do { if (LATENCY_DEBUG(flags)) log(L_TRACE "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args); } while (0)
|
|
|
|
#define THREAD_TRACE(flags, ...) do { if (LATENCY_DEBUG(flags)) log(L_TRACE "Thread: " __VA_ARGS__); } while (0)
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2024-06-04 08:10:35 +00:00
|
|
|
#define LOOP_WARN(loop, fmt, args...) log(L_WARN "%s (%p): " fmt, LOOP_NAME(loop), (loop), ##args)
|
2023-04-06 18:18:04 +00:00
|
|
|
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
event_list *
|
|
|
|
birdloop_event_list(struct birdloop *loop)
|
2013-09-16 21:57:40 +00:00
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
return &loop->event_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct timeloop *
|
|
|
|
birdloop_time_loop(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
return &loop->time;
|
|
|
|
}
|
|
|
|
|
2023-04-22 19:20:19 +00:00
|
|
|
pool *
|
|
|
|
birdloop_pool(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
return loop->pool;
|
|
|
|
}
|
|
|
|
|
2024-06-26 15:19:24 +00:00
|
|
|
bool
|
2021-06-19 18:50:18 +00:00
|
|
|
birdloop_inside(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
for (struct birdloop *c = birdloop_current; c; c = c->prev_loop)
|
|
|
|
if (loop == c)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
return 0;
|
2013-09-16 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2024-06-26 15:19:24 +00:00
|
|
|
bool
|
2023-01-19 09:49:47 +00:00
|
|
|
birdloop_in_this_thread(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
return pthread_equal(pthread_self(), loop->thread->thread_id);
|
|
|
|
}
|
|
|
|
|
2013-11-19 21:33:48 +00:00
|
|
|
/*
|
|
|
|
* Wakeup code for birdloop
|
|
|
|
*/
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2022-09-20 15:01:50 +00:00
|
|
|
void
|
|
|
|
pipe_new(struct pipe *p)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2024-10-02 17:02:53 +00:00
|
|
|
int flags = O_NONBLOCK | O_CLOEXEC;
|
|
|
|
#if HAVE_PIPE2
|
|
|
|
int rv = pipe2(p->fd, flags);
|
|
|
|
if (rv < 0)
|
|
|
|
die("pipe2: %m");
|
|
|
|
#else
|
2022-09-20 15:01:50 +00:00
|
|
|
int rv = pipe(p->fd);
|
2013-09-10 10:09:36 +00:00
|
|
|
if (rv < 0)
|
|
|
|
die("pipe: %m");
|
|
|
|
|
2024-10-02 17:02:53 +00:00
|
|
|
if (fcntl(p->fd[0], F_SETFL, flags) < 0)
|
2013-09-10 10:09:36 +00:00
|
|
|
die("fcntl(O_NONBLOCK): %m");
|
|
|
|
|
2024-10-02 17:02:53 +00:00
|
|
|
if (fcntl(p->fd[1], F_SETFL, flags) < 0)
|
2013-09-10 10:09:36 +00:00
|
|
|
die("fcntl(O_NONBLOCK): %m");
|
2024-10-02 17:02:53 +00:00
|
|
|
#endif
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
void
|
2022-09-20 15:01:50 +00:00
|
|
|
pipe_drain(struct pipe *p)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2022-09-20 15:01:50 +00:00
|
|
|
while (1) {
|
|
|
|
char buf[64];
|
|
|
|
int rv = read(p->fd[0], buf, sizeof(buf));
|
|
|
|
if ((rv < 0) && (errno == EAGAIN))
|
2013-09-10 10:09:36 +00:00
|
|
|
return;
|
2022-09-20 15:01:50 +00:00
|
|
|
|
|
|
|
if (rv == 0)
|
|
|
|
bug("wakeup read eof");
|
|
|
|
if ((rv < 0) && (errno != EINTR))
|
|
|
|
bug("wakeup read: %m");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pipe_read_one(struct pipe *p)
|
|
|
|
{
|
|
|
|
while (1) {
|
|
|
|
char v;
|
|
|
|
int rv = read(p->fd[0], &v, sizeof(v));
|
|
|
|
if (rv == 1)
|
|
|
|
return 1;
|
|
|
|
if ((rv < 0) && (errno == EAGAIN))
|
|
|
|
return 0;
|
|
|
|
if (rv > 1)
|
|
|
|
bug("wakeup read more bytes than expected: %d", rv);
|
|
|
|
if (rv == 0)
|
|
|
|
bug("wakeup read eof");
|
|
|
|
if (errno != EINTR)
|
|
|
|
bug("wakeup read: %m");
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
void
|
2022-09-20 15:01:50 +00:00
|
|
|
pipe_kick(struct pipe *p)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2022-09-20 15:01:50 +00:00
|
|
|
char v = 1;
|
2013-09-10 10:09:36 +00:00
|
|
|
int rv;
|
|
|
|
|
2022-09-20 15:01:50 +00:00
|
|
|
while (1) {
|
|
|
|
rv = write(p->fd[1], &v, sizeof(v));
|
2023-01-19 09:49:47 +00:00
|
|
|
if ((rv >= 0) || (errno == EAGAIN))
|
2013-09-10 10:09:36 +00:00
|
|
|
return;
|
2022-09-20 15:01:50 +00:00
|
|
|
if (errno != EINTR)
|
|
|
|
bug("wakeup write: %m");
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-20 15:01:50 +00:00
|
|
|
void
|
2023-02-24 08:13:35 +00:00
|
|
|
pipe_pollin(struct pipe *p, struct pfd *pfd)
|
2022-09-20 15:01:50 +00:00
|
|
|
{
|
2023-02-24 08:13:35 +00:00
|
|
|
BUFFER_PUSH(pfd->pfd) = (struct pollfd) {
|
|
|
|
.fd = p->fd[0],
|
|
|
|
.events = POLLIN,
|
|
|
|
};
|
|
|
|
BUFFER_PUSH(pfd->loop) = NULL;
|
2022-09-20 15:01:50 +00:00
|
|
|
}
|
|
|
|
|
2023-05-09 21:31:47 +00:00
|
|
|
void
|
|
|
|
pipe_free(struct pipe *p)
|
|
|
|
{
|
|
|
|
close(p->fd[0]);
|
|
|
|
close(p->fd[1]);
|
|
|
|
}
|
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
static inline void
|
2023-01-19 09:49:47 +00:00
|
|
|
wakeup_init(struct bird_thread *loop)
|
2013-09-16 21:57:40 +00:00
|
|
|
{
|
2022-09-20 15:01:50 +00:00
|
|
|
pipe_new(&loop->wakeup);
|
2013-09-16 21:57:40 +00:00
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
static inline void
|
2023-01-19 09:49:47 +00:00
|
|
|
wakeup_drain(struct bird_thread *loop)
|
2013-09-16 21:57:40 +00:00
|
|
|
{
|
2022-09-20 15:01:50 +00:00
|
|
|
pipe_drain(&loop->wakeup);
|
2013-09-16 21:57:40 +00:00
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
static inline void
|
2023-01-19 09:49:47 +00:00
|
|
|
wakeup_do_kick(struct bird_thread *loop)
|
2013-09-16 21:57:40 +00:00
|
|
|
{
|
2022-09-20 15:01:50 +00:00
|
|
|
pipe_kick(&loop->wakeup);
|
2013-09-16 21:57:40 +00:00
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-05-09 21:31:47 +00:00
|
|
|
static inline void
|
|
|
|
wakeup_free(struct bird_thread *loop)
|
|
|
|
{
|
|
|
|
pipe_free(&loop->wakeup);
|
|
|
|
}
|
|
|
|
|
2024-09-10 09:25:59 +00:00
|
|
|
static inline void
|
|
|
|
wakeup_forked(struct bird_thread *thr)
|
|
|
|
{
|
|
|
|
struct pipe new;
|
|
|
|
pipe_new(&new);
|
|
|
|
|
|
|
|
/* This is kinda sketchy but there is probably
|
|
|
|
* no actual architecture where copying an int
|
|
|
|
* would create an invalid inbetween value */
|
|
|
|
struct pipe old = thr->wakeup;
|
|
|
|
thr->wakeup = new;
|
|
|
|
synchronize_rcu();
|
|
|
|
|
|
|
|
pipe_free(&old);
|
|
|
|
}
|
|
|
|
|
2024-06-26 15:19:24 +00:00
|
|
|
static inline bool
|
2023-02-24 08:13:35 +00:00
|
|
|
birdloop_try_ping(struct birdloop *loop, u32 ltt)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Somebody else is already pinging, be idempotent */
|
|
|
|
if (ltt & LTT_PING)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "already being pinged");
|
2023-02-24 08:13:35 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Thread moving is an implicit ping */
|
|
|
|
if (ltt & LTT_MOVE)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "ping while moving");
|
2023-02-24 08:13:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No more flags allowed */
|
|
|
|
ASSERT_DIE(!ltt);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* No ping when not picked up */
|
|
|
|
if (!loop->thread)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "not picked up yet, can't ping");
|
2023-02-24 08:13:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No ping when masked */
|
2021-06-19 18:50:18 +00:00
|
|
|
if (loop == birdloop_wakeup_masked)
|
2023-02-24 08:13:35 +00:00
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "wakeup masked, can't ping");
|
2021-06-19 18:50:18 +00:00
|
|
|
birdloop_wakeup_masked_count++;
|
2023-02-24 08:13:35 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Send meta event to ping */
|
|
|
|
if ((loop != loop->thread->meta) && (loop != &main_birdloop))
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "Ping by meta event to %p", loop->thread->meta);
|
2023-02-24 08:13:35 +00:00
|
|
|
ev_send_loop(loop->thread->meta, &loop->event);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-05-05 14:08:50 +00:00
|
|
|
/* Do the real ping of Meta or Main */
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_WAKEUP, "sending pipe ping");
|
2023-02-24 08:13:35 +00:00
|
|
|
wakeup_do_kick(loop->thread);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
birdloop_do_ping(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
/* Register our ping effort */
|
|
|
|
u32 ltt = atomic_fetch_or_explicit(&loop->thread_transition, LTT_PING, memory_order_acq_rel);
|
|
|
|
|
|
|
|
/* Try to ping in multiple ways */
|
|
|
|
if (birdloop_try_ping(loop, ltt))
|
|
|
|
atomic_fetch_and_explicit(&loop->thread_transition, ~LTT_PING, memory_order_acq_rel);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2022-07-28 17:49:03 +00:00
|
|
|
void
|
|
|
|
birdloop_ping(struct birdloop *loop)
|
|
|
|
{
|
2023-02-24 08:13:35 +00:00
|
|
|
if (!birdloop_inside(loop))
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "ping from outside");
|
2022-07-28 17:49:03 +00:00
|
|
|
birdloop_do_ping(loop);
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "ping from inside, pending=%d", loop->ping_pending);
|
2023-02-24 08:13:35 +00:00
|
|
|
if (!loop->ping_pending)
|
|
|
|
loop->ping_pending++;
|
|
|
|
}
|
2022-07-28 17:49:03 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2013-11-19 21:33:48 +00:00
|
|
|
/*
|
|
|
|
* Sockets
|
|
|
|
*/
|
2013-09-16 21:57:40 +00:00
|
|
|
|
2013-09-10 10:09:36 +00:00
|
|
|
static void
|
|
|
|
sockets_init(struct birdloop *loop)
|
|
|
|
{
|
2013-09-16 21:57:40 +00:00
|
|
|
init_list(&loop->sock_list);
|
|
|
|
loop->sock_num = 0;
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
void
|
|
|
|
socket_changed(sock *s)
|
|
|
|
{
|
|
|
|
struct birdloop *loop = s->loop;
|
|
|
|
ASSERT_DIE(birdloop_inside(loop));
|
|
|
|
|
2024-06-10 12:11:51 +00:00
|
|
|
LOOP_TRACE(loop, DL_SOCKETS, "socket %p changed", s);
|
2023-04-30 20:17:42 +00:00
|
|
|
loop->sock_changed = 1;
|
2023-04-02 17:15:22 +00:00
|
|
|
birdloop_ping(loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
birdloop_add_socket(struct birdloop *loop, sock *s)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-04-02 17:15:22 +00:00
|
|
|
ASSERT_DIE(birdloop_inside(loop));
|
|
|
|
ASSERT_DIE(!s->loop);
|
|
|
|
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SOCKETS, "adding socket %p (total=%d)", s, loop->sock_num);
|
2013-09-10 10:09:36 +00:00
|
|
|
add_tail(&loop->sock_list, &s->n);
|
|
|
|
loop->sock_num++;
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
s->loop = loop;
|
2013-09-10 10:09:36 +00:00
|
|
|
s->index = -1;
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
socket_changed(s);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2024-08-27 13:04:32 +00:00
|
|
|
sock *stored_sock; /* mainloop hack */
|
2023-04-02 17:15:22 +00:00
|
|
|
|
2013-09-10 10:09:36 +00:00
|
|
|
void
|
2023-04-02 17:15:22 +00:00
|
|
|
birdloop_remove_socket(struct birdloop *loop, sock *s)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-04-02 17:15:22 +00:00
|
|
|
ASSERT_DIE(!enlisted(&s->n) == !s->loop);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
if (!s->loop)
|
2022-10-04 11:20:04 +00:00
|
|
|
return;
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
ASSERT_DIE(birdloop_inside(loop));
|
|
|
|
ASSERT_DIE(s->loop == loop);
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
/* Decouple the socket from the loop at all. */
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SOCKETS, "removing socket %p (total=%d)", s, loop->sock_num);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
if (loop->sock_active == s)
|
|
|
|
loop->sock_active = sk_next(s);
|
|
|
|
|
|
|
|
if ((loop == &main_birdloop) && (s == stored_sock))
|
|
|
|
stored_sock = sk_next(s);
|
|
|
|
|
2013-09-10 10:09:36 +00:00
|
|
|
rem_node(&s->n);
|
|
|
|
loop->sock_num--;
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
socket_changed(s);
|
|
|
|
|
|
|
|
s->loop = NULL;
|
2023-01-19 09:49:47 +00:00
|
|
|
s->index = -1;
|
2023-04-02 17:15:22 +00:00
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
void
|
|
|
|
sk_reloop(sock *s, struct birdloop *loop)
|
|
|
|
{
|
|
|
|
ASSERT_DIE(birdloop_inside(loop));
|
|
|
|
ASSERT_DIE(birdloop_inside(s->loop));
|
|
|
|
|
|
|
|
if (loop == s->loop)
|
|
|
|
return;
|
|
|
|
|
|
|
|
birdloop_remove_socket(s->loop, s);
|
|
|
|
birdloop_add_socket(loop, s);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sk_pause_rx(struct birdloop *loop, sock *s)
|
|
|
|
{
|
|
|
|
ASSERT_DIE(birdloop_inside(loop));
|
2024-09-24 10:51:01 +00:00
|
|
|
ASSERT_DIE(!s->rx_paused);
|
|
|
|
ASSERT_DIE(s->rx_hook);
|
|
|
|
s->rx_paused = s->rx_hook;
|
2023-04-02 17:15:22 +00:00
|
|
|
s->rx_hook = NULL;
|
|
|
|
socket_changed(s);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2024-09-24 10:51:01 +00:00
|
|
|
sk_resume_rx(struct birdloop *loop, sock *s)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-04-02 17:15:22 +00:00
|
|
|
ASSERT_DIE(birdloop_inside(loop));
|
2024-09-24 10:51:01 +00:00
|
|
|
ASSERT_DIE(s->rx_paused);
|
|
|
|
ASSERT_DIE(!s->rx_hook);
|
|
|
|
s->rx_hook = s->rx_paused;
|
|
|
|
s->rx_paused = NULL;
|
2023-04-02 17:15:22 +00:00
|
|
|
socket_changed(s);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint sk_want_events(sock *s)
|
2023-04-02 17:15:22 +00:00
|
|
|
{ return (s->rx_hook ? POLLIN : 0) | (sk_tx_pending(s) ? POLLOUT : 0); }
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
void
|
|
|
|
sockets_prepare(struct birdloop *loop, struct pfd *pfd)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
|
|
|
node *n;
|
2013-09-16 21:57:40 +00:00
|
|
|
WALK_LIST(n, loop->sock_list)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2024-04-26 10:14:33 +00:00
|
|
|
SKIP_BACK_DECLARE(sock, s, n, n);
|
2023-02-24 08:13:35 +00:00
|
|
|
uint w = sk_want_events(s);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
if (!w)
|
|
|
|
{
|
|
|
|
s->index = -1;
|
|
|
|
continue;
|
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
s->index = pfd->pfd.used;
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SOCKETS, "socket %p poll index is %d", s, s->index);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
BUFFER_PUSH(pfd->pfd) = (struct pollfd) {
|
|
|
|
.fd = s->fd,
|
|
|
|
.events = sk_want_events(s),
|
|
|
|
};
|
|
|
|
BUFFER_PUSH(pfd->loop) = loop;
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int sk_read(sock *s, int revents);
|
|
|
|
int sk_write(sock *s);
|
2023-04-02 17:15:22 +00:00
|
|
|
void sk_err(sock *s, int revents);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2024-06-10 12:11:51 +00:00
|
|
|
static void
|
2024-06-26 15:19:24 +00:00
|
|
|
sockets_fire(struct birdloop *loop, bool read, bool write)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
2023-04-02 17:15:22 +00:00
|
|
|
if (EMPTY_LIST(loop->sock_list))
|
2024-06-10 12:11:51 +00:00
|
|
|
return;
|
2023-04-02 17:15:22 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
times_update();
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
struct pollfd *pfd = loop->thread->pfd->pfd.data;
|
2023-04-02 17:15:22 +00:00
|
|
|
loop->sock_active = SKIP_BACK(sock, n, HEAD(loop->sock_list));
|
|
|
|
|
|
|
|
while (loop->sock_active)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
2023-04-02 17:15:22 +00:00
|
|
|
sock *s = loop->sock_active;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
int rev;
|
|
|
|
if ((s->index >= 0) && (rev = pfd[s->index].revents) && !(rev & POLLNVAL))
|
|
|
|
{
|
|
|
|
int e = 1;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2024-06-10 12:11:51 +00:00
|
|
|
if (write && (rev & POLLOUT))
|
2023-04-02 17:15:22 +00:00
|
|
|
{
|
2024-06-10 12:11:51 +00:00
|
|
|
/* Write until task limit is up */
|
|
|
|
while ((s == loop->sock_active) && (e = sk_write(s)) && task_still_in_limit())
|
2023-04-02 17:15:22 +00:00
|
|
|
;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
if (s != loop->sock_active)
|
|
|
|
continue;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
if (!sk_tx_pending(s))
|
2023-04-30 20:17:42 +00:00
|
|
|
loop->thread->sock_changed = 1;
|
2023-04-02 17:15:22 +00:00
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2024-06-10 12:11:51 +00:00
|
|
|
/* Read until task limit is up */
|
|
|
|
if (read && (rev & POLLIN))
|
2024-06-20 17:39:09 +00:00
|
|
|
while ((s == loop->sock_active) && s->rx_hook && sk_read(s, rev) && (s->fast_rx || task_still_in_limit()))
|
2024-06-10 12:11:51 +00:00
|
|
|
;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
if (s != loop->sock_active)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(rev & (POLLOUT | POLLIN)) && (rev & POLLERR))
|
|
|
|
sk_err(s, rev);
|
|
|
|
|
|
|
|
if (s != loop->sock_active)
|
|
|
|
continue;
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
2023-04-02 17:15:22 +00:00
|
|
|
|
|
|
|
loop->sock_active = sk_next(s);
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Threads
|
|
|
|
*/
|
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
static void bird_thread_start_event(void *_data);
|
2024-06-09 09:29:47 +00:00
|
|
|
static void bird_thread_busy_set(struct bird_thread *thr, int val);
|
2023-04-17 09:37:29 +00:00
|
|
|
|
2024-08-29 08:10:37 +00:00
|
|
|
struct birdloop_pickup_group pickup_groups[2] = {
|
2023-04-17 09:37:29 +00:00
|
|
|
{
|
|
|
|
/* all zeroes */
|
2024-09-09 20:19:05 +00:00
|
|
|
.start_threads.hook = bird_thread_start_event,
|
2023-04-17 09:37:29 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
/* FIXME: make this dynamic, now it copies the loop_max_latency value from proto/bfd/config.Y */
|
|
|
|
.max_latency = 10 MS,
|
2023-04-21 13:26:06 +00:00
|
|
|
.start_threads.hook = bird_thread_start_event,
|
|
|
|
.start_threads.data = &pickup_groups[1],
|
2023-04-17 09:37:29 +00:00
|
|
|
},
|
|
|
|
};
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2024-08-29 08:10:37 +00:00
|
|
|
_Thread_local struct bird_thread *this_thread;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
static void
|
2023-04-17 09:37:29 +00:00
|
|
|
birdloop_set_thread(struct birdloop *loop, struct bird_thread *thr, struct birdloop_pickup_group *group)
|
2023-02-24 08:13:35 +00:00
|
|
|
{
|
2023-04-06 18:18:04 +00:00
|
|
|
struct bird_thread *old = loop->thread;
|
|
|
|
ASSERT_DIE(!thr != !old);
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Signal our moving effort */
|
|
|
|
u32 ltt = atomic_fetch_or_explicit(&loop->thread_transition, LTT_MOVE, memory_order_acq_rel);
|
|
|
|
ASSERT_DIE((ltt & LTT_MOVE) == 0);
|
|
|
|
|
2023-05-05 14:08:50 +00:00
|
|
|
/* Wait until all previously started pings end */
|
2023-02-24 08:13:35 +00:00
|
|
|
while (ltt & LTT_PING)
|
|
|
|
{
|
|
|
|
birdloop_yield();
|
|
|
|
ltt = atomic_load_explicit(&loop->thread_transition, memory_order_acquire);
|
|
|
|
ASSERT_DIE(ltt & LTT_MOVE);
|
|
|
|
}
|
|
|
|
/* Now we are free of running pings */
|
|
|
|
|
2023-05-05 14:08:50 +00:00
|
|
|
if (!thr)
|
|
|
|
{
|
|
|
|
/* Unschedule from Meta */
|
|
|
|
ev_postpone(&loop->event);
|
|
|
|
tm_stop(&loop->timer);
|
|
|
|
|
|
|
|
/* Request local socket reload */
|
|
|
|
this_thread->sock_changed = 1;
|
|
|
|
}
|
|
|
|
|
2023-04-30 20:17:42 +00:00
|
|
|
/* Update the thread value */
|
|
|
|
loop->thread = thr;
|
|
|
|
|
2023-05-05 14:08:50 +00:00
|
|
|
/* Allow pings */
|
|
|
|
atomic_fetch_and_explicit(&loop->thread_transition, ~LTT_MOVE, memory_order_acq_rel);
|
|
|
|
|
2023-04-30 20:17:42 +00:00
|
|
|
/* Put into appropriate lists */
|
|
|
|
if (thr)
|
2023-04-06 18:18:04 +00:00
|
|
|
{
|
|
|
|
thr->loop_count++;
|
2023-05-05 13:19:14 +00:00
|
|
|
add_tail(&thr->loops, &loop->n);
|
2023-05-07 21:40:38 +00:00
|
|
|
|
|
|
|
if (!EMPTY_LIST(loop->sock_list))
|
|
|
|
thr->sock_changed = 1;
|
2023-04-30 20:17:42 +00:00
|
|
|
ev_send_loop(loop->thread->meta, &loop->event);
|
2023-04-06 18:18:04 +00:00
|
|
|
}
|
2023-02-24 08:13:35 +00:00
|
|
|
else
|
|
|
|
{
|
2023-04-30 20:17:42 +00:00
|
|
|
/* Put into pickup list */
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-17 09:37:29 +00:00
|
|
|
add_tail(&group->loops, &loop->n);
|
2023-05-07 21:40:38 +00:00
|
|
|
group->loop_unassigned_count++;
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
2024-06-09 09:29:47 +00:00
|
|
|
|
|
|
|
loop->last_transition_ns = ns_now();
|
2023-04-30 20:17:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
bird_thread_pickup_next(struct birdloop_pickup_group *group)
|
|
|
|
{
|
|
|
|
/* This thread goes to the end of the pickup list */
|
|
|
|
rem_node(&this_thread->n);
|
|
|
|
add_tail(&group->threads, &this_thread->n);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-04-30 20:17:42 +00:00
|
|
|
/* If there are more loops to be picked up, wakeup the next thread in order */
|
|
|
|
if (!EMPTY_LIST(group->loops))
|
|
|
|
wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
|
2024-06-26 15:19:24 +00:00
|
|
|
static bool
|
2024-06-09 09:29:47 +00:00
|
|
|
birdloop_hot_potato(struct birdloop *loop)
|
|
|
|
{
|
2024-06-25 15:48:25 +00:00
|
|
|
if (!loop)
|
|
|
|
return 0;
|
|
|
|
|
2024-06-09 09:29:47 +00:00
|
|
|
return ns_now() - loop->last_transition_ns < 1 S TO_NS;
|
|
|
|
}
|
|
|
|
|
2023-05-07 21:40:38 +00:00
|
|
|
static void
|
2023-04-17 09:37:29 +00:00
|
|
|
birdloop_take(struct birdloop_pickup_group *group)
|
2023-02-24 08:13:35 +00:00
|
|
|
{
|
|
|
|
struct birdloop *loop = NULL;
|
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-30 20:17:42 +00:00
|
|
|
|
2024-06-08 22:43:14 +00:00
|
|
|
if (this_thread->busy_active &&
|
|
|
|
(group->thread_busy_count < group->thread_count) &&
|
2024-06-09 09:29:47 +00:00
|
|
|
(this_thread->loop_count > 1) &&
|
2024-06-27 06:26:00 +00:00
|
|
|
(EMPTY_LIST(group->loops) ||
|
|
|
|
!birdloop_hot_potato(HEAD(group->loops))))
|
2023-04-30 20:17:42 +00:00
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SCHEDULING, "Loop drop requested (tbc=%d, tc=%d, lc=%d)",
|
|
|
|
group->thread_busy_count, group->thread_count, this_thread->loop_count);
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-05-05 13:19:14 +00:00
|
|
|
|
2024-06-25 15:48:25 +00:00
|
|
|
uint dropped = 0;
|
2024-06-27 06:26:00 +00:00
|
|
|
node *n, *_nxt;
|
|
|
|
WALK_LIST2_DELSAFE(loop, n, _nxt, this_thread->loops, n)
|
2023-05-05 13:19:14 +00:00
|
|
|
{
|
|
|
|
birdloop_enter(loop);
|
2024-06-09 09:29:47 +00:00
|
|
|
if (ev_active(&loop->event) && !loop->stopped && !birdloop_hot_potato(loop))
|
2023-04-30 20:17:42 +00:00
|
|
|
{
|
|
|
|
/* Pass to another thread */
|
|
|
|
rem_node(&loop->n);
|
2023-05-05 13:19:14 +00:00
|
|
|
this_thread->loop_count--;
|
2024-06-25 15:48:25 +00:00
|
|
|
LOOP_TRACE(loop, DL_SCHEDULING, "Dropping from thread, remaining %u loops here", this_thread->loop_count);
|
2023-05-05 13:19:14 +00:00
|
|
|
|
|
|
|
/* This also unschedules the loop from Meta */
|
2023-04-30 20:17:42 +00:00
|
|
|
birdloop_set_thread(loop, NULL, group);
|
2023-05-05 13:19:14 +00:00
|
|
|
|
2024-06-25 15:48:25 +00:00
|
|
|
dropped++;
|
2024-06-27 06:26:00 +00:00
|
|
|
if ((dropped * dropped) / 2 > this_thread->loop_count)
|
2024-06-25 15:48:25 +00:00
|
|
|
{
|
|
|
|
birdloop_leave(loop);
|
2023-05-07 21:40:38 +00:00
|
|
|
|
2024-06-25 15:48:25 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
|
|
|
bird_thread_pickup_next(group);
|
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2023-04-30 20:17:42 +00:00
|
|
|
}
|
2023-05-05 13:19:14 +00:00
|
|
|
birdloop_leave(loop);
|
|
|
|
}
|
2023-04-30 20:17:42 +00:00
|
|
|
|
2024-06-08 22:43:14 +00:00
|
|
|
if (dropped)
|
2024-06-25 15:48:25 +00:00
|
|
|
{
|
|
|
|
this_thread->meta->last_transition_ns = ns_now();
|
2024-06-08 22:43:14 +00:00
|
|
|
return;
|
2024-06-25 15:48:25 +00:00
|
|
|
}
|
2024-06-08 22:43:14 +00:00
|
|
|
|
2024-06-09 09:29:47 +00:00
|
|
|
this_thread->busy_counter = 0;
|
|
|
|
bird_thread_busy_set(this_thread, 0);
|
2024-06-08 22:43:14 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-30 20:17:42 +00:00
|
|
|
}
|
2023-05-07 21:40:38 +00:00
|
|
|
|
2024-06-08 22:43:14 +00:00
|
|
|
if (!EMPTY_LIST(group->loops))
|
2023-02-24 08:13:35 +00:00
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SCHEDULING, "Loop take requested");
|
|
|
|
|
2023-05-07 21:40:38 +00:00
|
|
|
/* Take a proportional amount of loops from the pickup list and unlock */
|
|
|
|
uint thread_count = group->thread_count + 1;
|
|
|
|
if (group->thread_busy_count < group->thread_count)
|
|
|
|
thread_count -= group->thread_busy_count;
|
|
|
|
|
2024-06-27 06:26:00 +00:00
|
|
|
uint assign = birdloop_hot_potato(this_thread->meta) ? 1 :
|
|
|
|
1 + group->loop_unassigned_count / thread_count;
|
|
|
|
|
2023-05-07 21:40:38 +00:00
|
|
|
for (uint i=0; !EMPTY_LIST(group->loops) && i<assign; i++)
|
|
|
|
{
|
|
|
|
loop = SKIP_BACK(struct birdloop, n, HEAD(group->loops));
|
|
|
|
rem_node(&loop->n);
|
|
|
|
group->loop_unassigned_count--;
|
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
|
|
|
|
|
|
|
birdloop_enter(loop);
|
|
|
|
birdloop_set_thread(loop, this_thread, group);
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SCHEDULING, "Picked up by thread");
|
2023-05-07 21:40:38 +00:00
|
|
|
|
|
|
|
node *n;
|
|
|
|
WALK_LIST(n, loop->sock_list)
|
|
|
|
SKIP_BACK(sock, n, n)->index = -1;
|
|
|
|
|
|
|
|
birdloop_leave(loop);
|
|
|
|
|
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
|
|
|
}
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-04-30 20:17:42 +00:00
|
|
|
bird_thread_pickup_next(group);
|
2024-06-27 06:26:00 +00:00
|
|
|
|
|
|
|
if (assign)
|
|
|
|
this_thread->meta->last_transition_ns = ns_now();
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
2023-05-07 21:40:38 +00:00
|
|
|
|
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
poll_timeout(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
timer *t = timers_first(&loop->time);
|
|
|
|
if (!t)
|
2024-06-10 08:38:56 +00:00
|
|
|
{
|
|
|
|
THREAD_TRACE(DL_SCHEDULING, "No timers, no events in meta");
|
2023-02-24 08:13:35 +00:00
|
|
|
return -1;
|
2024-06-10 08:38:56 +00:00
|
|
|
}
|
2023-02-24 08:13:35 +00:00
|
|
|
|
|
|
|
btime remains = tm_remains(t);
|
2024-06-10 08:38:56 +00:00
|
|
|
int timeout = remains TO_MS + ((remains TO_MS) MS < remains);
|
|
|
|
|
|
|
|
THREAD_TRACE(DL_SCHEDULING, "Next meta timer in %d ms for %s", timeout,
|
|
|
|
LOOP_NAME(SKIP_BACK(struct birdloop, timer, t)));
|
|
|
|
|
|
|
|
return timeout;
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
|
2023-04-30 20:17:42 +00:00
|
|
|
static void
|
2023-05-05 13:19:14 +00:00
|
|
|
bird_thread_busy_set(struct bird_thread *thr, int val)
|
2023-04-30 20:17:42 +00:00
|
|
|
{
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, thr->group->domain);
|
2023-05-05 13:19:14 +00:00
|
|
|
if (thr->busy_active = val)
|
2023-04-30 20:17:42 +00:00
|
|
|
thr->group->thread_busy_count++;
|
|
|
|
else
|
|
|
|
thr->group->thread_busy_count--;
|
2023-05-05 13:19:14 +00:00
|
|
|
ASSERT_DIE(thr->group->thread_busy_count <= thr->group->thread_count);
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, thr->group->domain);
|
2023-04-30 20:17:42 +00:00
|
|
|
}
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
static void *
|
|
|
|
bird_thread_main(void *arg)
|
|
|
|
{
|
|
|
|
struct bird_thread *thr = this_thread = arg;
|
|
|
|
|
2024-05-31 18:43:15 +00:00
|
|
|
rcu_thread_start();
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-04-26 20:24:42 +00:00
|
|
|
account_to(&thr->overhead);
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
birdloop_enter(thr->meta);
|
2024-04-03 10:05:02 +00:00
|
|
|
this_birdloop = thr->meta;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SCHEDULING, "Started");
|
|
|
|
|
2024-05-08 16:55:01 +00:00
|
|
|
tmp_init(thr->pool);
|
2023-04-21 13:26:06 +00:00
|
|
|
init_list(&thr->loops);
|
|
|
|
|
2024-04-23 15:35:00 +00:00
|
|
|
defer_init(lp_new(thr->pool));
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
thr->sock_changed = 1;
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
struct pfd pfd;
|
|
|
|
BUFFER_INIT(pfd.pfd, thr->pool, 16);
|
|
|
|
BUFFER_INIT(pfd.loop, thr->pool, 16);
|
|
|
|
thr->pfd = &pfd;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
2023-04-06 18:18:04 +00:00
|
|
|
u64 thr_loop_start = ns_now();
|
2023-02-24 08:13:35 +00:00
|
|
|
int timeout;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Schedule all loops with timed out timers */
|
2024-08-28 13:43:15 +00:00
|
|
|
timers_fire(&thr->meta->time);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2024-06-25 15:48:25 +00:00
|
|
|
/* Pickup new loops */
|
|
|
|
birdloop_take(thr->group);
|
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
/* Compute maximal time per loop */
|
|
|
|
u64 thr_before_run = ns_now();
|
|
|
|
if (thr->loop_count > 0)
|
2024-05-31 19:22:07 +00:00
|
|
|
{
|
2023-04-06 18:18:04 +00:00
|
|
|
thr->max_loop_time_ns = (thr->max_latency_ns / 2 - (thr_before_run - thr_loop_start)) / (u64) thr->loop_count;
|
2024-06-07 07:05:11 +00:00
|
|
|
if (thr->max_loop_time_ns NS > 300 MS)
|
|
|
|
thr->max_loop_time_ns = 300 MS TO_NS;
|
2024-05-31 19:22:07 +00:00
|
|
|
}
|
2023-04-06 18:18:04 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Run all scheduled loops */
|
|
|
|
int more_events = ev_run_list(&thr->meta->event_list);
|
|
|
|
if (more_events)
|
|
|
|
{
|
2024-06-10 08:38:56 +00:00
|
|
|
THREAD_TRACE(DL_SCHEDULING, "More metaevents to run from %s",
|
|
|
|
LOOP_NAME(SKIP_BACK(struct birdloop, event,
|
|
|
|
atomic_load_explicit(&thr->meta->event_list.receiver, memory_order_relaxed)))
|
|
|
|
);
|
2023-02-24 08:13:35 +00:00
|
|
|
timeout = 0;
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
2023-02-24 08:13:35 +00:00
|
|
|
else
|
|
|
|
timeout = poll_timeout(thr->meta);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Run priority events before sleeping */
|
|
|
|
ev_run_list(&thr->priority_events);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Do we have to refresh sockets? */
|
2023-04-02 17:15:22 +00:00
|
|
|
if (thr->sock_changed)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SOCKETS, "Recalculating socket poll");
|
2023-04-02 17:15:22 +00:00
|
|
|
thr->sock_changed = 0;
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
BUFFER_FLUSH(pfd.pfd);
|
|
|
|
BUFFER_FLUSH(pfd.loop);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
pipe_pollin(&thr->wakeup, &pfd);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
node *nn;
|
2023-05-07 21:40:38 +00:00
|
|
|
struct birdloop *loop;
|
2023-01-19 09:49:47 +00:00
|
|
|
WALK_LIST2(loop, nn, thr->loops, n)
|
|
|
|
{
|
|
|
|
birdloop_enter(loop);
|
2023-02-24 08:13:35 +00:00
|
|
|
sockets_prepare(loop, &pfd);
|
2023-01-19 09:49:47 +00:00
|
|
|
birdloop_leave(loop);
|
|
|
|
}
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
ASSERT_DIE(pfd.loop.used == pfd.pfd.used);
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SOCKETS, "Total %d sockets", pfd.pfd.used);
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
|
|
|
|
2024-06-09 09:29:47 +00:00
|
|
|
/* Check thread busy indicator */
|
|
|
|
int idle_force = (timeout < 0) || (timeout > 300);
|
|
|
|
int busy_now = (timeout < 5) && !idle_force;
|
|
|
|
|
2024-06-18 09:02:51 +00:00
|
|
|
/* Nothing to do right now but there may be some loops for pickup */
|
2024-06-09 09:29:47 +00:00
|
|
|
if (idle_force)
|
|
|
|
{
|
|
|
|
LOCK_DOMAIN(attrs, thr->group->domain);
|
|
|
|
if (!EMPTY_LIST(thr->group->loops))
|
|
|
|
timeout = 0;
|
|
|
|
UNLOCK_DOMAIN(attrs, thr->group->domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (busy_now && !thr->busy_active && (++thr->busy_counter == 4))
|
|
|
|
bird_thread_busy_set(thr, 1);
|
|
|
|
|
|
|
|
if (!busy_now && thr->busy_active && (idle_force || (--thr->busy_counter == 0)))
|
|
|
|
{
|
|
|
|
thr->busy_counter = 0;
|
|
|
|
bird_thread_busy_set(thr, 0);
|
|
|
|
}
|
2023-04-30 20:17:42 +00:00
|
|
|
|
|
|
|
account_to(&this_thread->idle);
|
2023-11-01 17:23:43 +00:00
|
|
|
birdloop_leave(thr->meta);
|
2023-01-19 09:49:47 +00:00
|
|
|
poll_retry:;
|
2023-02-24 08:13:35 +00:00
|
|
|
int rv = poll(pfd.pfd.data, pfd.pfd.used, timeout);
|
2023-01-19 09:49:47 +00:00
|
|
|
if (rv < 0)
|
|
|
|
{
|
|
|
|
if (errno == EINTR || errno == EAGAIN)
|
|
|
|
goto poll_retry;
|
|
|
|
bug("poll in %p: %m", thr);
|
|
|
|
}
|
|
|
|
|
2023-04-30 20:17:42 +00:00
|
|
|
account_to(&this_thread->overhead);
|
2023-11-01 17:23:43 +00:00
|
|
|
birdloop_enter(thr->meta);
|
2023-04-30 20:17:42 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
/* Drain wakeup fd */
|
2023-02-24 08:13:35 +00:00
|
|
|
if (pfd.pfd.data[0].revents & POLLIN)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_WAKEUP, "Ping received");
|
2023-01-19 09:49:47 +00:00
|
|
|
ASSERT_DIE(rv > 0);
|
|
|
|
rv--;
|
|
|
|
wakeup_drain(thr);
|
|
|
|
}
|
|
|
|
|
2023-05-05 14:08:50 +00:00
|
|
|
/* Unset ping information for Meta */
|
2023-02-24 08:13:35 +00:00
|
|
|
atomic_fetch_and_explicit(&thr->meta->thread_transition, ~LTT_PING, memory_order_acq_rel);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Schedule loops with active sockets */
|
|
|
|
if (rv)
|
|
|
|
for (uint i = 1; i < pfd.pfd.used; i++)
|
|
|
|
if (pfd.pfd.data[i].revents)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(pfd.loop.data[i], DL_SOCKETS, "socket id %d got revents=0x%x", i, pfd.pfd.data[i].revents);
|
2023-02-24 08:13:35 +00:00
|
|
|
ev_send_loop(thr->meta, &pfd.loop.data[i]->event);
|
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
2023-02-24 08:13:35 +00:00
|
|
|
|
|
|
|
bug("An infinite loop has ended.");
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2023-01-19 09:49:47 +00:00
|
|
|
bird_thread_cleanup(void *_thr)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-01-19 09:49:47 +00:00
|
|
|
struct bird_thread *thr = _thr;
|
2023-05-09 21:31:47 +00:00
|
|
|
struct birdloop *meta = thr->meta;
|
2023-01-19 09:49:47 +00:00
|
|
|
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-05-09 21:31:47 +00:00
|
|
|
/* Wait until the thread actually finishes */
|
|
|
|
ASSERT_DIE(meta);
|
|
|
|
birdloop_enter(meta);
|
|
|
|
birdloop_leave(meta);
|
|
|
|
|
|
|
|
/* No more wakeup */
|
|
|
|
wakeup_free(thr);
|
2023-05-05 13:19:14 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
/* Thread attributes no longer needed */
|
|
|
|
pthread_attr_destroy(&thr->thread_attr);
|
2023-05-09 21:31:47 +00:00
|
|
|
|
|
|
|
/* Free the meta loop */
|
|
|
|
thr->meta->thread = NULL;
|
|
|
|
thr->meta = NULL;
|
|
|
|
birdloop_free(meta);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
static struct bird_thread *
|
2023-04-17 09:37:29 +00:00
|
|
|
bird_thread_start(struct birdloop_pickup_group *group)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
|
|
|
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
struct birdloop *meta = birdloop_new_no_pickup(&root_pool, DOMAIN_ORDER(meta), "Thread Meta");
|
|
|
|
pool *p = birdloop_pool(meta);
|
|
|
|
|
|
|
|
birdloop_enter(meta);
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
struct bird_thread *thr = mb_allocz(p, sizeof(*thr));
|
|
|
|
thr->pool = p;
|
|
|
|
thr->cleanup_event = (event) { .hook = bird_thread_cleanup, .data = thr, };
|
2023-04-17 09:37:29 +00:00
|
|
|
thr->group = group;
|
|
|
|
thr->max_latency_ns = (group->max_latency ?: 5 S) TO_NS;
|
2023-04-21 13:26:06 +00:00
|
|
|
thr->meta = meta;
|
|
|
|
thr->meta->thread = thr;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
wakeup_init(thr);
|
|
|
|
ev_init_list(&thr->priority_events, NULL, "Thread direct event list");
|
|
|
|
|
2023-04-17 09:37:29 +00:00
|
|
|
add_tail(&group->threads, &thr->n);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
int e = 0;
|
|
|
|
|
|
|
|
if (e = pthread_attr_init(&thr->thread_attr))
|
|
|
|
die("pthread_attr_init() failed: %M", e);
|
|
|
|
|
|
|
|
/* We don't have to worry about thread stack size so much.
|
|
|
|
if (e = pthread_attr_setstacksize(&thr->thread_attr, THREAD_STACK_SIZE))
|
|
|
|
die("pthread_attr_setstacksize(%u) failed: %M", THREAD_STACK_SIZE, e);
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (e = pthread_attr_setdetachstate(&thr->thread_attr, PTHREAD_CREATE_DETACHED))
|
|
|
|
die("pthread_attr_setdetachstate(PTHREAD_CREATE_DETACHED) failed: %M", e);
|
|
|
|
|
|
|
|
if (e = pthread_create(&thr->thread_id, &thr->thread_attr, bird_thread_main, thr))
|
|
|
|
die("pthread_create() failed: %M", e);
|
|
|
|
|
2023-04-27 08:42:11 +00:00
|
|
|
group->thread_count++;
|
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-04-21 13:26:06 +00:00
|
|
|
birdloop_leave(meta);
|
2023-01-19 09:49:47 +00:00
|
|
|
return thr;
|
|
|
|
}
|
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
static void
|
|
|
|
bird_thread_start_event(void *_data)
|
|
|
|
{
|
|
|
|
struct birdloop_pickup_group *group = _data;
|
2024-09-09 20:19:05 +00:00
|
|
|
if (group)
|
|
|
|
bird_thread_start(group);
|
2023-04-21 13:26:06 +00:00
|
|
|
}
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
static struct birdloop *thread_dropper;
|
|
|
|
static event *thread_dropper_event;
|
|
|
|
static uint thread_dropper_goal;
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-05-05 13:19:14 +00:00
|
|
|
static void
|
|
|
|
bird_thread_dropper_free(void *data)
|
|
|
|
{
|
|
|
|
struct birdloop *tdl_stop = data;
|
|
|
|
birdloop_free(tdl_stop);
|
|
|
|
}
|
|
|
|
|
2013-09-10 10:09:36 +00:00
|
|
|
static void
|
2023-01-19 09:49:47 +00:00
|
|
|
bird_thread_shutdown(void * _ UNUSED)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-04-17 09:37:29 +00:00
|
|
|
struct birdloop_pickup_group *group = this_thread->group;
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-27 08:42:11 +00:00
|
|
|
int dif = group->thread_count - thread_dropper_goal;
|
2023-01-19 09:49:47 +00:00
|
|
|
struct birdloop *tdl_stop = NULL;
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
if (dif > 0)
|
|
|
|
ev_send_loop(thread_dropper, thread_dropper_event);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tdl_stop = thread_dropper;
|
|
|
|
thread_dropper = NULL;
|
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SCHEDULING, "Thread pickup size differs from dropper goal by %d%s", dif, tdl_stop ? ", stopping" : "");
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
if (tdl_stop)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2023-05-05 13:19:14 +00:00
|
|
|
birdloop_stop_self(tdl_stop, bird_thread_dropper_free, tdl_stop);
|
2023-01-19 09:49:47 +00:00
|
|
|
return;
|
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
struct bird_thread *thr = this_thread;
|
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-05-05 13:19:14 +00:00
|
|
|
/* Leave the thread-picker list to get no more loops */
|
2023-01-19 09:49:47 +00:00
|
|
|
rem_node(&thr->n);
|
2023-04-27 08:42:11 +00:00
|
|
|
group->thread_count--;
|
2023-05-05 13:19:14 +00:00
|
|
|
|
|
|
|
/* Fix the busy count */
|
|
|
|
if (thr->busy_active)
|
|
|
|
group->thread_busy_count--;
|
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-05-05 13:19:14 +00:00
|
|
|
/* Leave the thread-dropper loop as we aren't going to return. */
|
|
|
|
birdloop_leave(thread_dropper);
|
|
|
|
|
2023-05-09 21:31:47 +00:00
|
|
|
/* Last try to run the priority event list; ruin it then to be extra sure */
|
|
|
|
ev_run_list(&this_thread->priority_events);
|
|
|
|
memset(&this_thread->priority_events, 0xa5, sizeof(this_thread->priority_events));
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
/* Drop loops including the thread dropper itself */
|
|
|
|
while (!EMPTY_LIST(thr->loops))
|
2023-04-30 20:17:42 +00:00
|
|
|
{
|
|
|
|
struct birdloop *loop = HEAD(thr->loops);
|
|
|
|
|
|
|
|
/* Remove loop from this thread's list */
|
2023-05-05 13:19:14 +00:00
|
|
|
this_thread->loop_count--;
|
2023-04-30 20:17:42 +00:00
|
|
|
rem_node(&loop->n);
|
|
|
|
|
|
|
|
/* Unset loop's thread */
|
2023-05-05 13:19:14 +00:00
|
|
|
birdloop_set_thread(loop, NULL, group);
|
2023-04-30 20:17:42 +00:00
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
/* Let others know about new loops */
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-17 09:37:29 +00:00
|
|
|
if (!EMPTY_LIST(group->loops))
|
|
|
|
wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-05-09 21:31:47 +00:00
|
|
|
/* Request thread cleanup from main loop */
|
|
|
|
ev_send_loop(&main_birdloop, &thr->cleanup_event);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
/* Local pages not needed anymore */
|
|
|
|
flush_local_pages();
|
|
|
|
|
|
|
|
/* Unregister from RCU */
|
2024-05-31 18:43:15 +00:00
|
|
|
rcu_thread_stop();
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-05-09 21:31:47 +00:00
|
|
|
/* Now we can be cleaned up */
|
|
|
|
birdloop_leave(thr->meta);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
/* Exit! */
|
2024-06-07 10:12:00 +00:00
|
|
|
THREAD_TRACE(DL_SCHEDULING, "Stopped");
|
2023-01-19 09:49:47 +00:00
|
|
|
pthread_exit(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2024-09-03 10:24:27 +00:00
|
|
|
bird_thread_commit(struct thread_config *new)
|
2023-01-19 09:49:47 +00:00
|
|
|
{
|
|
|
|
ASSERT_DIE(birdloop_inside(&main_birdloop));
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2024-09-03 10:24:27 +00:00
|
|
|
if (!new->count)
|
|
|
|
new->count = 1;
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
while (1)
|
|
|
|
{
|
2023-04-17 09:37:29 +00:00
|
|
|
struct birdloop_pickup_group *group = &pickup_groups[0];
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-17 09:37:29 +00:00
|
|
|
|
2024-09-03 10:24:27 +00:00
|
|
|
int dif = group->thread_count - (thread_dropper_goal = new->count);
|
2024-06-26 15:19:24 +00:00
|
|
|
bool thread_dropper_running = !!thread_dropper;
|
2023-01-19 09:49:47 +00:00
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-04-21 13:26:06 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
if (dif < 0)
|
2021-06-19 18:50:18 +00:00
|
|
|
{
|
2023-04-17 09:37:29 +00:00
|
|
|
bird_thread_start(group);
|
2023-01-19 09:49:47 +00:00
|
|
|
continue;
|
2021-06-19 18:50:18 +00:00
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
if ((dif > 0) && !thread_dropper_running)
|
|
|
|
{
|
2023-04-22 19:20:19 +00:00
|
|
|
struct birdloop *tdl = birdloop_new(&root_pool, DOMAIN_ORDER(control), group->max_latency, "Thread dropper");
|
2023-05-05 13:19:14 +00:00
|
|
|
birdloop_enter(tdl);
|
2023-01-19 09:49:47 +00:00
|
|
|
event *tde = ev_new_init(tdl->pool, bird_thread_shutdown, NULL);
|
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-01-19 09:49:47 +00:00
|
|
|
thread_dropper = tdl;
|
|
|
|
thread_dropper_event = tde;
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
ev_send_loop(thread_dropper, thread_dropper_event);
|
2023-05-05 13:19:14 +00:00
|
|
|
birdloop_leave(tdl);
|
2023-01-19 09:49:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-21 18:56:19 +00:00
|
|
|
/* Cleanup after last thread */
|
|
|
|
static void
|
|
|
|
bird_thread_sync_finish(void *_sync)
|
|
|
|
{
|
|
|
|
ASSERT_THE_BIRD_LOCKED;
|
|
|
|
struct bird_thread_syncer *sync = _sync;
|
|
|
|
|
|
|
|
/* Keep necessary pointers locally */
|
|
|
|
pool *p = sync->pool;
|
|
|
|
DOMAIN(control) lock = sync->lock;
|
|
|
|
LOCK_DOMAIN(control, lock);
|
|
|
|
|
|
|
|
/* This invalidates the `sync` pointer */
|
|
|
|
CALL(sync->finish, sync);
|
|
|
|
|
|
|
|
/* Free pool and domain */
|
|
|
|
rp_free(p);
|
|
|
|
UNLOCK_DOMAIN(control, lock);
|
|
|
|
DOMAIN_FREE(control, lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Process regular one thread hook */
|
|
|
|
static void
|
|
|
|
bird_thread_sync_one(void *_sync)
|
|
|
|
{
|
|
|
|
struct bird_thread_syncer *sync = _sync;
|
|
|
|
|
|
|
|
LOCK_DOMAIN(control, sync->lock);
|
|
|
|
CALL(sync->hook, sync);
|
|
|
|
sync->done++;
|
|
|
|
if (sync->done == sync->total)
|
|
|
|
ev_send_loop(&main_birdloop, ev_new_init(sync->pool, bird_thread_sync_finish, sync));
|
|
|
|
UNLOCK_DOMAIN(control, sync->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
bird_thread_sync_all(struct bird_thread_syncer *sync,
|
|
|
|
void (*hook)(struct bird_thread_syncer *),
|
|
|
|
void (*done)(struct bird_thread_syncer *), const char *name)
|
|
|
|
{
|
|
|
|
sync->lock = DOMAIN_NEW(control);
|
|
|
|
LOCK_DOMAIN(control, sync->lock);
|
|
|
|
|
|
|
|
sync->pool = rp_new(&root_pool, sync->lock.control, name);
|
|
|
|
sync->hook = hook;
|
|
|
|
sync->finish = done;
|
|
|
|
|
|
|
|
for (int i=0; i<2; i++)
|
|
|
|
{
|
|
|
|
struct birdloop_pickup_group *group = &pickup_groups[i];
|
|
|
|
|
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
|
|
|
|
|
|
|
struct bird_thread *thr;
|
|
|
|
WALK_LIST(thr, group->threads)
|
|
|
|
{
|
|
|
|
sync->total++;
|
|
|
|
ev_send(&thr->priority_events, ev_new_init(sync->pool, bird_thread_sync_one, sync));
|
|
|
|
wakeup_do_kick(thr);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNLOCK_DOMAIN(control, sync->lock);
|
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
|
2024-06-26 15:19:24 +00:00
|
|
|
bool task_still_in_limit(void)
|
2024-04-03 10:05:02 +00:00
|
|
|
{
|
2024-06-08 21:43:37 +00:00
|
|
|
static u64 main_counter = 0;
|
|
|
|
if (this_birdloop == &main_birdloop)
|
|
|
|
return (++main_counter % 2048); /* This is a hack because of no accounting in mainloop */
|
|
|
|
else
|
|
|
|
return ns_now() < account_last + this_thread->max_loop_time_ns;
|
2024-04-03 10:05:02 +00:00
|
|
|
}
|
|
|
|
|
2024-06-26 15:19:24 +00:00
|
|
|
bool task_before_halftime(void)
|
2024-06-08 18:06:52 +00:00
|
|
|
{
|
|
|
|
return ns_now() < account_last + this_thread->max_loop_time_ns / 2;
|
|
|
|
}
|
|
|
|
|
2023-08-21 18:56:19 +00:00
|
|
|
|
2013-11-19 21:33:48 +00:00
|
|
|
/*
|
|
|
|
* Birdloop
|
|
|
|
*/
|
2013-09-16 21:57:40 +00:00
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
static struct bird_thread main_thread;
|
|
|
|
struct birdloop main_birdloop = { .thread = &main_thread, };
|
2024-04-03 10:05:02 +00:00
|
|
|
_Thread_local struct birdloop *this_birdloop;
|
2021-06-19 18:50:18 +00:00
|
|
|
|
|
|
|
static void birdloop_enter_locked(struct birdloop *loop);
|
|
|
|
|
|
|
|
void
|
|
|
|
birdloop_init(void)
|
|
|
|
{
|
2023-01-19 09:49:47 +00:00
|
|
|
ns_init();
|
|
|
|
|
2023-04-17 09:37:29 +00:00
|
|
|
for (int i=0; i<2; i++)
|
|
|
|
{
|
|
|
|
struct birdloop_pickup_group *group = &pickup_groups[i];
|
|
|
|
|
2023-05-05 18:35:55 +00:00
|
|
|
group->domain = DOMAIN_NEW(attrs);
|
|
|
|
DOMAIN_SETUP(attrs, group->domain, "Loop Pickup", NULL);
|
2023-04-17 09:37:29 +00:00
|
|
|
init_list(&group->loops);
|
|
|
|
init_list(&group->threads);
|
|
|
|
}
|
2023-01-19 09:49:47 +00:00
|
|
|
|
|
|
|
wakeup_init(main_birdloop.thread);
|
2021-06-19 18:50:18 +00:00
|
|
|
|
|
|
|
main_birdloop.time.domain = the_bird_domain.the_bird;
|
|
|
|
main_birdloop.time.loop = &main_birdloop;
|
|
|
|
|
|
|
|
times_update();
|
|
|
|
timers_init(&main_birdloop.time, &root_pool);
|
|
|
|
|
|
|
|
birdloop_enter_locked(&main_birdloop);
|
2024-04-03 10:05:02 +00:00
|
|
|
this_birdloop = &main_birdloop;
|
2024-04-05 12:11:38 +00:00
|
|
|
this_thread = &main_thread;
|
2024-04-23 15:35:00 +00:00
|
|
|
|
|
|
|
defer_init(lp_new(&root_pool));
|
2021-06-19 18:50:18 +00:00
|
|
|
}
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
static void
|
|
|
|
birdloop_stop_internal(struct birdloop *loop)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SCHEDULING, "Stopping");
|
2023-04-02 17:15:22 +00:00
|
|
|
|
|
|
|
/* Block incoming pings */
|
|
|
|
u32 ltt = atomic_load_explicit(&loop->thread_transition, memory_order_acquire);
|
|
|
|
while (!atomic_compare_exchange_strong_explicit(
|
|
|
|
&loop->thread_transition, <t, LTT_PING,
|
|
|
|
memory_order_acq_rel, memory_order_acquire))
|
|
|
|
;
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
/* Flush remaining events */
|
|
|
|
ASSERT_DIE(!ev_run_list(&loop->event_list));
|
|
|
|
|
|
|
|
/* Drop timers */
|
|
|
|
timer *t;
|
|
|
|
while (t = timers_first(&loop->time))
|
|
|
|
tm_stop(t);
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
/* Drop sockets */
|
|
|
|
sock *s;
|
|
|
|
WALK_LIST_FIRST2(s, n, loop->sock_list)
|
|
|
|
birdloop_remove_socket(loop, s);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
|
|
|
/* Unschedule from Meta */
|
|
|
|
ev_postpone(&loop->event);
|
|
|
|
tm_stop(&loop->timer);
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
/* Remove from thread loop list */
|
2023-04-27 08:42:11 +00:00
|
|
|
ASSERT_DIE(loop->thread == this_thread);
|
2023-02-24 08:13:35 +00:00
|
|
|
rem_node(&loop->n);
|
2023-04-02 17:15:22 +00:00
|
|
|
loop->thread = NULL;
|
|
|
|
|
2023-04-27 08:42:11 +00:00
|
|
|
/* Uncount from thread group */
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, this_thread->group->domain);
|
2023-04-27 08:42:11 +00:00
|
|
|
this_thread->group->loop_count--;
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, this_thread->group->domain);
|
2023-04-27 08:42:11 +00:00
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
/* Leave the loop context without causing any other fuss */
|
|
|
|
ASSERT_DIE(!ev_active(&loop->event));
|
|
|
|
loop->ping_pending = 0;
|
2023-04-26 20:24:42 +00:00
|
|
|
account_to(&this_thread->overhead);
|
2024-04-03 10:05:02 +00:00
|
|
|
this_birdloop = this_thread->meta;
|
2023-02-24 08:13:35 +00:00
|
|
|
birdloop_leave(loop);
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
/* Request local socket reload */
|
2023-04-30 20:17:42 +00:00
|
|
|
this_thread->sock_changed = 1;
|
2023-04-02 17:15:22 +00:00
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
/* Call the stopped hook from the main loop */
|
|
|
|
loop->event.hook = loop->stopped;
|
|
|
|
loop->event.data = loop->stop_data;
|
|
|
|
ev_send_loop(&main_birdloop, &loop->event);
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
birdloop_run(void *_loop)
|
|
|
|
{
|
|
|
|
/* Run priority events before the loop is executed */
|
|
|
|
ev_run_list(&this_thread->priority_events);
|
|
|
|
|
|
|
|
struct birdloop *loop = _loop;
|
2023-04-26 20:24:42 +00:00
|
|
|
account_to(&loop->locking);
|
2023-02-24 08:13:35 +00:00
|
|
|
birdloop_enter(loop);
|
2024-04-03 10:05:02 +00:00
|
|
|
this_birdloop = loop;
|
2024-05-17 21:21:38 +00:00
|
|
|
|
|
|
|
/* Wait until pingers end to wait for all events to actually arrive */
|
|
|
|
for (u32 ltt;
|
|
|
|
ltt = atomic_load_explicit(&loop->thread_transition, memory_order_acquire);
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ASSERT_DIE(ltt == LTT_PING);
|
|
|
|
birdloop_yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now we can actually do some work */
|
2023-04-26 20:24:42 +00:00
|
|
|
u64 dif = account_to(&loop->working);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2024-06-13 14:30:51 +00:00
|
|
|
struct global_runtime *gr = atomic_load_explicit(&global_runtime, memory_order_relaxed);
|
|
|
|
if (dif > this_thread->max_loop_time_ns + gr->latency_limit TO_NS)
|
2024-06-04 08:10:35 +00:00
|
|
|
LOOP_WARN(loop, "locked %lu us after its scheduled end time", dif NS TO_US);
|
2023-04-26 17:34:29 +00:00
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
uint repeat, loop_runs = 0;
|
|
|
|
do {
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SCHEDULING, "Regular run (%d)", loop_runs);
|
2023-04-06 18:18:04 +00:00
|
|
|
loop_runs++;
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
if (loop->stopped)
|
|
|
|
/* Birdloop left inside the helper function */
|
|
|
|
return birdloop_stop_internal(loop);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2024-06-10 12:11:51 +00:00
|
|
|
/* Process socket TX */
|
|
|
|
sockets_fire(loop, 0, 1);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
/* Run timers */
|
2024-08-28 13:43:15 +00:00
|
|
|
timers_fire(&loop->time);
|
2023-02-24 08:13:35 +00:00
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
/* Run events */
|
2024-06-10 12:11:51 +00:00
|
|
|
repeat = ev_run_list(&loop->event_list);
|
|
|
|
|
|
|
|
/* Process socket RX */
|
|
|
|
sockets_fire(loop, 1, 0);
|
2023-04-06 18:18:04 +00:00
|
|
|
|
2024-06-27 06:37:05 +00:00
|
|
|
/* Flush deferred events */
|
|
|
|
while (ev_run_list(&loop->defer_list))
|
|
|
|
repeat++;
|
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
/* Check end time */
|
2024-04-03 10:05:02 +00:00
|
|
|
} while (repeat && task_still_in_limit());
|
2023-02-24 08:13:35 +00:00
|
|
|
|
|
|
|
/* Request meta timer */
|
|
|
|
timer *t = timers_first(&loop->time);
|
|
|
|
if (t)
|
|
|
|
tm_start_in(&loop->timer, tm_remains(t), this_thread->meta);
|
|
|
|
else
|
|
|
|
tm_stop(&loop->timer);
|
|
|
|
|
2023-04-06 18:18:04 +00:00
|
|
|
/* Request re-run if needed */
|
|
|
|
if (repeat)
|
|
|
|
ev_send_loop(this_thread->meta, &loop->event);
|
|
|
|
|
2023-04-02 17:15:22 +00:00
|
|
|
/* Collect socket change requests */
|
2023-04-30 20:17:42 +00:00
|
|
|
this_thread->sock_changed |= loop->sock_changed;
|
2023-04-02 17:15:22 +00:00
|
|
|
loop->sock_changed = 0;
|
|
|
|
|
2023-04-26 20:24:42 +00:00
|
|
|
account_to(&this_thread->overhead);
|
2024-04-03 10:05:02 +00:00
|
|
|
this_birdloop = this_thread->meta;
|
2023-02-24 08:13:35 +00:00
|
|
|
birdloop_leave(loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
birdloop_run_timer(timer *tm)
|
|
|
|
{
|
|
|
|
struct birdloop *loop = tm->data;
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_TIMERS, "Meta timer ready, requesting run");
|
2023-02-24 08:13:35 +00:00
|
|
|
ev_send_loop(loop->thread->meta, &loop->event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct birdloop *
|
2023-04-22 19:20:19 +00:00
|
|
|
birdloop_vnew_internal(pool *pp, uint order, struct birdloop_pickup_group *group, const char *name, va_list args)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2024-06-27 06:42:11 +00:00
|
|
|
struct domain_generic *dg = domain_new(order);
|
2023-04-21 13:26:06 +00:00
|
|
|
DG_LOCK(dg);
|
2021-06-19 18:50:18 +00:00
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
pool *p = rp_vnewf(pp, dg, name, args);
|
2013-09-10 10:09:36 +00:00
|
|
|
struct birdloop *loop = mb_allocz(p, sizeof(struct birdloop));
|
2013-09-16 21:57:40 +00:00
|
|
|
loop->pool = p;
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
loop->time.domain = dg;
|
|
|
|
loop->time.loop = loop;
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
atomic_store_explicit(&loop->thread_transition, 0, memory_order_relaxed);
|
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
birdloop_enter_locked(loop);
|
2013-09-10 10:09:36 +00:00
|
|
|
|
2024-06-07 10:12:00 +00:00
|
|
|
ev_init_list(&loop->event_list, loop, p->name);
|
2017-05-30 17:12:35 +00:00
|
|
|
timers_init(&loop->time, p);
|
2013-09-10 10:09:36 +00:00
|
|
|
sockets_init(loop);
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
loop->event = (event) { .hook = birdloop_run, .data = loop, };
|
|
|
|
loop->timer = (timer) { .hook = birdloop_run_timer, .data = loop, };
|
|
|
|
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SCHEDULING, "New loop: %s", p->name);
|
|
|
|
|
2023-04-22 19:20:19 +00:00
|
|
|
if (group)
|
2023-02-24 08:13:35 +00:00
|
|
|
{
|
2023-05-05 18:35:55 +00:00
|
|
|
LOCK_DOMAIN(attrs, group->domain);
|
2023-04-27 08:42:11 +00:00
|
|
|
group->loop_count++;
|
2024-05-31 11:02:27 +00:00
|
|
|
group->loop_unassigned_count++;
|
2023-04-17 09:37:29 +00:00
|
|
|
add_tail(&group->loops, &loop->n);
|
|
|
|
if (EMPTY_LIST(group->threads))
|
2023-04-21 13:26:06 +00:00
|
|
|
ev_send(&global_event_list, &group->start_threads);
|
2023-05-13 18:33:35 +00:00
|
|
|
else
|
|
|
|
wakeup_do_kick(SKIP_BACK(struct bird_thread, n, HEAD(group->threads)));
|
2023-05-05 18:35:55 +00:00
|
|
|
UNLOCK_DOMAIN(attrs, group->domain);
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
loop->n.next = loop->n.prev = &loop->n;
|
2021-06-19 18:50:18 +00:00
|
|
|
|
|
|
|
birdloop_leave(loop);
|
|
|
|
|
2013-10-05 18:12:28 +00:00
|
|
|
return loop;
|
|
|
|
}
|
2013-09-16 21:57:40 +00:00
|
|
|
|
2023-04-22 19:20:19 +00:00
|
|
|
static struct birdloop *
|
|
|
|
birdloop_new_no_pickup(pool *pp, uint order, const char *name, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
va_start(args, name);
|
|
|
|
struct birdloop *loop = birdloop_vnew_internal(pp, order, NULL, name, args);
|
|
|
|
va_end(args);
|
|
|
|
return loop;
|
|
|
|
}
|
|
|
|
|
2023-02-24 08:13:35 +00:00
|
|
|
struct birdloop *
|
2023-04-22 19:20:19 +00:00
|
|
|
birdloop_new(pool *pp, uint order, btime max_latency, const char *name, ...)
|
2023-02-24 08:13:35 +00:00
|
|
|
{
|
2023-04-22 19:20:19 +00:00
|
|
|
va_list args;
|
|
|
|
va_start(args, name);
|
|
|
|
struct birdloop *loop = birdloop_vnew_internal(pp, order, max_latency ? &pickup_groups[1] : &pickup_groups[0], name, args);
|
|
|
|
va_end(args);
|
|
|
|
return loop;
|
2023-02-24 08:13:35 +00:00
|
|
|
}
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
static void
|
|
|
|
birdloop_do_stop(struct birdloop *loop, void (*stopped)(void *data), void *data)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_SCHEDULING, "Stop requested");
|
2023-04-02 17:15:22 +00:00
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
loop->stopped = stopped;
|
|
|
|
loop->stop_data = data;
|
2023-02-24 08:13:35 +00:00
|
|
|
|
|
|
|
birdloop_do_ping(loop);
|
2021-06-19 18:50:18 +00:00
|
|
|
}
|
|
|
|
|
2013-10-05 18:12:28 +00:00
|
|
|
void
|
2021-06-19 18:50:18 +00:00
|
|
|
birdloop_stop(struct birdloop *loop, void (*stopped)(void *data), void *data)
|
2013-10-05 18:12:28 +00:00
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
DG_LOCK(loop->time.domain);
|
|
|
|
birdloop_do_stop(loop, stopped, data);
|
|
|
|
DG_UNLOCK(loop->time.domain);
|
2013-10-05 18:12:28 +00:00
|
|
|
}
|
2013-09-16 21:57:40 +00:00
|
|
|
|
2013-10-05 18:12:28 +00:00
|
|
|
void
|
2021-06-19 18:50:18 +00:00
|
|
|
birdloop_stop_self(struct birdloop *loop, void (*stopped)(void *data), void *data)
|
2013-10-05 18:12:28 +00:00
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
ASSERT_DIE(loop == birdloop_current);
|
|
|
|
ASSERT_DIE(DG_IS_LOCKED(loop->time.domain));
|
2013-10-05 18:12:28 +00:00
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
birdloop_do_stop(loop, stopped, data);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2013-11-19 21:33:48 +00:00
|
|
|
void
|
|
|
|
birdloop_free(struct birdloop *loop)
|
|
|
|
{
|
2023-04-02 17:15:22 +00:00
|
|
|
ASSERT_DIE(loop->thread == NULL);
|
2022-07-28 17:49:03 +00:00
|
|
|
|
2023-04-21 13:26:06 +00:00
|
|
|
struct domain_generic *dg = loop->time.domain;
|
|
|
|
DG_LOCK(dg);
|
2023-04-20 19:08:38 +00:00
|
|
|
rp_free(loop->pool);
|
2023-04-21 13:26:06 +00:00
|
|
|
DG_UNLOCK(dg);
|
|
|
|
domain_free(dg);
|
2013-11-19 21:33:48 +00:00
|
|
|
}
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
static void
|
|
|
|
birdloop_enter_locked(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
ASSERT_DIE(DG_IS_LOCKED(loop->time.domain));
|
|
|
|
ASSERT_DIE(!birdloop_inside(loop));
|
|
|
|
|
|
|
|
/* Store the old context */
|
|
|
|
loop->prev_loop = birdloop_current;
|
|
|
|
|
|
|
|
/* Put the new context */
|
|
|
|
birdloop_current = loop;
|
|
|
|
}
|
2013-10-05 18:12:28 +00:00
|
|
|
|
2013-09-10 10:09:36 +00:00
|
|
|
void
|
|
|
|
birdloop_enter(struct birdloop *loop)
|
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
DG_LOCK(loop->time.domain);
|
|
|
|
return birdloop_enter_locked(loop);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
birdloop_leave_locked(struct birdloop *loop)
|
|
|
|
{
|
|
|
|
/* Check the current context */
|
|
|
|
ASSERT_DIE(birdloop_current == loop);
|
|
|
|
|
2022-07-28 17:49:03 +00:00
|
|
|
/* Send pending pings */
|
|
|
|
if (loop->ping_pending)
|
|
|
|
{
|
2024-06-07 10:12:00 +00:00
|
|
|
LOOP_TRACE(loop, DL_PING, "sending pings on leave");
|
2022-07-28 17:49:03 +00:00
|
|
|
loop->ping_pending = 0;
|
|
|
|
birdloop_do_ping(loop);
|
|
|
|
}
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
/* Restore the old context */
|
|
|
|
birdloop_current = loop->prev_loop;
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
birdloop_leave(struct birdloop *loop)
|
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
birdloop_leave_locked(loop);
|
|
|
|
DG_UNLOCK(loop->time.domain);
|
2013-09-10 10:09:36 +00:00
|
|
|
}
|
|
|
|
|
2013-09-16 21:57:40 +00:00
|
|
|
void
|
|
|
|
birdloop_mask_wakeups(struct birdloop *loop)
|
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
ASSERT_DIE(birdloop_wakeup_masked == NULL);
|
|
|
|
birdloop_wakeup_masked = loop;
|
2013-09-16 21:57:40 +00:00
|
|
|
}
|
2013-09-10 10:09:36 +00:00
|
|
|
|
|
|
|
void
|
2013-09-16 21:57:40 +00:00
|
|
|
birdloop_unmask_wakeups(struct birdloop *loop)
|
2013-09-10 10:09:36 +00:00
|
|
|
{
|
2021-06-19 18:50:18 +00:00
|
|
|
ASSERT_DIE(birdloop_wakeup_masked == loop);
|
|
|
|
birdloop_wakeup_masked = NULL;
|
|
|
|
if (birdloop_wakeup_masked_count)
|
2023-01-19 09:49:47 +00:00
|
|
|
wakeup_do_kick(loop->thread);
|
2021-06-19 18:50:18 +00:00
|
|
|
|
|
|
|
birdloop_wakeup_masked_count = 0;
|
2013-09-16 21:57:40 +00:00
|
|
|
}
|
|
|
|
|
2021-11-12 21:58:40 +00:00
|
|
|
void
|
|
|
|
birdloop_yield(void)
|
|
|
|
{
|
|
|
|
usleep(100);
|
|
|
|
}
|
2024-04-05 12:11:38 +00:00
|
|
|
|
|
|
|
void
|
2024-06-27 06:37:05 +00:00
|
|
|
ev_send_defer(event *e)
|
2024-04-05 12:11:38 +00:00
|
|
|
{
|
|
|
|
if (this_thread == &main_thread)
|
|
|
|
ev_send_loop(&main_birdloop, e);
|
|
|
|
else
|
2024-06-27 06:37:05 +00:00
|
|
|
ev_send(&this_birdloop->defer_list, e);
|
2024-04-05 12:11:38 +00:00
|
|
|
}
|
2024-09-10 09:25:59 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Minimalist mainloop with no sockets
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
birdloop_minimalist_main(void)
|
|
|
|
{
|
|
|
|
/* In case we got forked (hack for Flock) */
|
|
|
|
wakeup_forked(&main_thread);
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
/* Unset ping information */
|
|
|
|
atomic_fetch_and_explicit(&main_birdloop.thread_transition, ~LTT_PING, memory_order_acq_rel);
|
|
|
|
|
|
|
|
times_update();
|
|
|
|
ev_run_list(&global_event_list);
|
|
|
|
ev_run_list(&global_work_list);
|
|
|
|
ev_run_list(&main_birdloop.event_list);
|
|
|
|
timers_fire(&main_birdloop.time);
|
|
|
|
|
|
|
|
bool events =
|
|
|
|
!ev_list_empty(&global_event_list) ||
|
|
|
|
!ev_list_empty(&global_work_list) ||
|
|
|
|
!ev_list_empty(&main_birdloop.event_list);
|
|
|
|
|
|
|
|
int poll_tout = (events ? 0 : 3000); /* Time in milliseconds */
|
|
|
|
timer *t;
|
|
|
|
if (t = timers_first(&main_birdloop.time))
|
|
|
|
{
|
|
|
|
times_update();
|
|
|
|
int timeout = (tm_remains(t) TO_MS) + 1;
|
|
|
|
poll_tout = MIN(poll_tout, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct pollfd pfd = {
|
|
|
|
.fd = main_birdloop.thread->wakeup.fd[0],
|
|
|
|
.events = POLLIN,
|
|
|
|
};
|
|
|
|
|
|
|
|
int rv = poll(&pfd, 1, poll_tout);
|
|
|
|
if ((rv < 0) && (errno != EINTR) && (errno != EAGAIN))
|
|
|
|
bug("poll in main birdloop: %m");
|
|
|
|
|
|
|
|
/* Drain wakeup fd */
|
|
|
|
if (pfd.revents & POLLIN)
|
|
|
|
{
|
|
|
|
THREAD_TRACE(DL_WAKEUP, "Ping received");
|
|
|
|
ASSERT_DIE(rv == 1);
|
|
|
|
wakeup_drain(main_birdloop.thread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|