blob: 05f101fbb477eac0af861888d3e1aa768e2fabd3 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
/*
* BIRD Coroutines
*
* (c) 2017 Martin Mares <mj@ucw.cz>
* (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"
/*
* Implementation of coroutines based on POSIX threads
*/
#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
*/
#define ASSERT_NO_LOCK ASSERT_DIE(last_locked == NULL)
struct domain_generic {
pthread_mutex_t mutex;
struct domain_generic **prev;
struct lock_order *locked_by;
const char *name;
};
#define DOMAIN_INIT(_name) { .mutex = PTHREAD_MUTEX_INITIALIZER, .name = _name }
static struct domain_generic the_bird_domain_gen = DOMAIN_INIT("The BIRD");
DOMAIN(the_bird) the_bird_domain = { .the_bird = &the_bird_domain_gen };
struct domain_generic *
domain_new(const char *name)
{
struct domain_generic *dg = xmalloc(sizeof(struct domain_generic));
*dg = (struct domain_generic) DOMAIN_INIT(name);
return dg;
}
void
domain_free(struct domain_generic *dg)
{
pthread_mutex_destroy(&dg->mutex);
xfree(dg);
}
_Thread_local struct lock_order locking_stack = {};
_Thread_local struct domain_generic **last_locked = NULL;
void do_lock(struct domain_generic *dg, struct domain_generic **lsp)
{
if (lsp <= last_locked)
bug("Trying to lock in a bad order");
if (*lsp)
bug("Inconsistent locking stack state on lock");
pthread_mutex_lock(&dg->mutex);
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)
{
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);
}
|