2021-02-04 14:52:42 +00:00
|
|
|
/*
|
2022-07-28 17:49:03 +00:00
|
|
|
* BIRD Locking
|
2021-02-04 14:52:42 +00:00
|
|
|
*
|
|
|
|
* (c) 2020 Maria Matejka <mq@jmq.cz>
|
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _GNU_SOURCE
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#undef LOCAL_DEBUG
|
|
|
|
|
|
|
|
#undef DEBUG_LOCKING
|
|
|
|
|
|
|
|
#include "lib/birdlib.h"
|
|
|
|
#include "lib/locking.h"
|
|
|
|
#include "lib/resource.h"
|
2021-02-08 08:51:59 +00:00
|
|
|
#include "lib/timer.h"
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
#include "conf/conf.h"
|
|
|
|
|
2021-02-04 14:52:42 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <semaphore.h>
|
|
|
|
#include <stdatomic.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locking subsystem
|
|
|
|
*/
|
|
|
|
|
2024-06-25 13:48:11 +00:00
|
|
|
#ifdef DEBUGGING
|
2024-06-05 11:12:12 +00:00
|
|
|
_Thread_local rw_spinlock *rw_spinlocks_taken[MAX_RWS_AT_ONCE];
|
|
|
|
_Thread_local btime rw_spinlocks_time[MAX_RWS_AT_ONCE];
|
|
|
|
_Thread_local u32 rw_spinlocks_taken_cnt;
|
|
|
|
_Thread_local u32 rw_spinlocks_taken_write;
|
2024-06-25 13:48:11 +00:00
|
|
|
#endif
|
2024-06-05 11:12:12 +00:00
|
|
|
|
2021-05-24 11:41:23 +00:00
|
|
|
_Thread_local struct lock_order locking_stack = {};
|
|
|
|
_Thread_local struct domain_generic **last_locked = NULL;
|
|
|
|
|
2021-02-04 14:52:42 +00:00
|
|
|
#define ASSERT_NO_LOCK ASSERT_DIE(last_locked == NULL)
|
|
|
|
|
|
|
|
struct domain_generic {
|
|
|
|
pthread_mutex_t mutex;
|
2021-05-24 11:41:23 +00:00
|
|
|
uint order;
|
2021-02-04 14:52:42 +00:00
|
|
|
struct domain_generic **prev;
|
|
|
|
struct lock_order *locked_by;
|
|
|
|
const char *name;
|
2023-04-24 14:10:59 +00:00
|
|
|
pool *pool;
|
2021-02-04 14:52:42 +00:00
|
|
|
};
|
|
|
|
|
2024-06-27 06:42:11 +00:00
|
|
|
#define DOMAIN_INIT(_order) { \
|
2024-05-16 08:22:19 +00:00
|
|
|
.mutex = PTHREAD_MUTEX_INITIALIZER, \
|
|
|
|
.order = _order, \
|
|
|
|
}
|
2021-02-04 14:52:42 +00:00
|
|
|
|
2024-06-27 06:42:11 +00:00
|
|
|
static struct domain_generic the_bird_domain_gen = DOMAIN_INIT(OFFSETOF(struct lock_order, the_bird));
|
2021-02-04 14:52:42 +00:00
|
|
|
|
|
|
|
DOMAIN(the_bird) the_bird_domain = { .the_bird = &the_bird_domain_gen };
|
|
|
|
|
|
|
|
struct domain_generic *
|
2024-06-27 06:42:11 +00:00
|
|
|
domain_new(uint order)
|
2021-02-04 14:52:42 +00:00
|
|
|
{
|
2021-05-24 11:41:23 +00:00
|
|
|
ASSERT_DIE(order < sizeof(struct lock_order));
|
2021-02-04 14:52:42 +00:00
|
|
|
struct domain_generic *dg = xmalloc(sizeof(struct domain_generic));
|
2024-06-27 06:42:11 +00:00
|
|
|
*dg = (struct domain_generic) DOMAIN_INIT(order);
|
2021-02-04 14:52:42 +00:00
|
|
|
return dg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
domain_free(struct domain_generic *dg)
|
|
|
|
{
|
|
|
|
pthread_mutex_destroy(&dg->mutex);
|
|
|
|
xfree(dg);
|
|
|
|
}
|
|
|
|
|
2023-01-19 09:49:47 +00:00
|
|
|
const char *
|
|
|
|
domain_name(struct domain_generic *dg)
|
|
|
|
{
|
|
|
|
return dg->name;
|
|
|
|
}
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
uint dg_order(struct domain_generic *dg)
|
|
|
|
{
|
|
|
|
return dg->order;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:10:59 +00:00
|
|
|
void
|
|
|
|
domain_setup(struct domain_generic *dg, const char *name, pool *p)
|
|
|
|
{
|
|
|
|
ASSERT_DIE(dg->pool == NULL);
|
|
|
|
dg->pool = p;
|
|
|
|
dg->name = name;
|
|
|
|
}
|
|
|
|
|
2021-02-04 14:52:42 +00:00
|
|
|
void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
|
|
|
|
{
|
2023-01-20 13:07:38 +00:00
|
|
|
struct lock_order stack_copy;
|
|
|
|
memcpy(&stack_copy, &locking_stack, sizeof(stack_copy));
|
|
|
|
struct domain_generic **lll = last_locked;
|
|
|
|
|
2024-06-27 06:42:11 +00:00
|
|
|
if (rcu_read_active())
|
|
|
|
bug("Locking forbidden while RCU reader is active");
|
2024-05-16 08:22:19 +00:00
|
|
|
|
2021-05-24 11:41:23 +00:00
|
|
|
if ((char *) lsp - (char *) &locking_stack != dg->order)
|
|
|
|
bug("Trying to lock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
|
|
|
|
|
2021-02-04 14:52:42 +00:00
|
|
|
if (lsp <= last_locked)
|
2023-01-20 13:07:38 +00:00
|
|
|
bug("Trying to lock in a bad order: %p %p", &stack_copy, lll);
|
2021-02-04 14:52:42 +00:00
|
|
|
if (*lsp)
|
|
|
|
bug("Inconsistent locking stack state on lock");
|
|
|
|
|
2021-06-19 18:50:18 +00:00
|
|
|
btime lock_begin = current_time();
|
2021-02-04 14:52:42 +00:00
|
|
|
pthread_mutex_lock(&dg->mutex);
|
2021-06-19 18:50:18 +00:00
|
|
|
btime duration = current_time() - lock_begin;
|
2024-06-13 14:30:51 +00:00
|
|
|
btime wdw = atomic_load_explicit(&global_runtime, memory_order_relaxed)->watchdog_warning;
|
|
|
|
if (wdw && (duration > wdw))
|
2021-06-19 18:50:18 +00:00
|
|
|
log(L_WARN "Locking of %s took %d ms", dg->name, (int) (duration TO_MS));
|
2021-02-04 14:52:42 +00:00
|
|
|
|
|
|
|
if (dg->prev || dg->locked_by)
|
|
|
|
bug("Previous unlock not finished correctly");
|
|
|
|
dg->prev = last_locked;
|
|
|
|
*lsp = dg;
|
|
|
|
last_locked = lsp;
|
|
|
|
dg->locked_by = &locking_stack;
|
|
|
|
}
|
|
|
|
|
|
|
|
void do_unlock(struct domain_generic *dg, struct domain_generic **lsp)
|
|
|
|
{
|
2021-05-24 11:41:23 +00:00
|
|
|
if ((char *) lsp - (char *) &locking_stack != dg->order)
|
|
|
|
bug("Trying to unlock on bad position: order=%u, lsp=%p, base=%p", dg->order, lsp, &locking_stack);
|
|
|
|
|
2021-02-04 14:52:42 +00:00
|
|
|
if (dg->locked_by != &locking_stack)
|
|
|
|
bug("Inconsistent domain state on unlock");
|
|
|
|
if ((last_locked != lsp) || (*lsp != dg))
|
|
|
|
bug("Inconsistent locking stack state on unlock");
|
|
|
|
dg->locked_by = NULL;
|
|
|
|
last_locked = dg->prev;
|
|
|
|
*lsp = NULL;
|
|
|
|
dg->prev = NULL;
|
|
|
|
pthread_mutex_unlock(&dg->mutex);
|
2024-05-16 08:22:19 +00:00
|
|
|
|
2024-06-19 10:02:34 +00:00
|
|
|
/* From here on, the dg pointer is invalid! */
|
2021-02-04 14:52:42 +00:00
|
|
|
}
|