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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
/*
* Copyright (c) 2013 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Lockless synchronization.
*/
#ifndef _KERN_LLSYNC_H
#define _KERN_LLSYNC_H
#include <kern/list.h>
#include <kern/macros.h>
#include <kern/llsync_i.h>
#include <kern/thread.h>
#include <machine/mb.h>
struct llsync_work;
/*
* Type for work functions.
*
* Works are guaranteed to process in thread context and can block, but
* must not sleep for long durations.
*/
typedef void (*llsync_fn_t)(struct llsync_work *);
/*
* Deferred work.
*
* This structure should be embedded in objects protected with lockless
* synchronization. It stores the work function and is passed to it as its
* only parameter. The function can then find the containing object with
* structof and release it.
*/
struct llsync_work {
struct list node;
llsync_fn_t fn;
};
/*
* Safely assign a pointer.
*
* This macro enforces memory ordering. It should be used to reference
* objects once they're completely built, so that readers accessing the
* pointer obtain consistent data.
*/
#define llsync_assign_ptr(ptr, value) \
MACRO_BEGIN \
mb_store(); \
(ptr) = (value); \
MACRO_END
/*
* Safely access a pointer.
*
* No memory barrier, rely on data dependency to enforce ordering.
*/
#define llsync_read_ptr(ptr) (ptr)
static inline void
llsync_read_lock(void)
{
thread_preempt_disable();
}
static inline void
llsync_read_unlock(void)
{
thread_preempt_enable();
}
/*
* Reset the checkpoint flag of a processor.
*
* Called from interrupt context.
*/
static inline void
llsync_reset_checkpoint(unsigned int cpu)
{
llsync_cpu_checkpoints[cpu].checked = 0;
}
/*
* Report that a processor has reached a checkpoint.
*
* Called during context switch.
*/
static inline void
llsync_checkin(unsigned int cpu)
{
llsync_cpu_checkpoints[cpu].checked = 1;
}
/*
* Initialize the llsync module.
*/
void llsync_setup(void);
/*
* Report that a processor will be regularly checking in.
*/
void llsync_register_cpu(unsigned int cpu);
/*
* Report that a processor has entered a state in which checking in becomes
* irrelevant (e.g. the idle loop).
*/
void llsync_unregister_cpu(unsigned int cpu);
/*
* Commit a pending checkpoint.
*
* Checking in is a light processor-local operation. Committing a checkpoint
* is a heavier global one, and is performed less often, normally during the
* system timer interrupt.
*/
void llsync_commit_checkpoint(unsigned int cpu);
/*
* Defer an operation until all existing read-side references are dropped,
* without blocking.
*/
void llsync_defer(struct llsync_work *work, llsync_fn_t fn);
/*
* Wait for all existing read-side references to be dropped.
*
* This function sleeps, and may do so for a moderately long duration (a few
* system timer ticks).
*/
void llsync_wait(void);
#endif /* _KERN_LLSYNC_H */
|