]> git.proxmox.com Git - mirror_ovs.git/blame - lib/seq.c
ofp-util: Zero out padding bytes in ofputil_ipfix_stats_to_reply().
[mirror_ovs.git] / lib / seq.c
CommitLineData
55b40355 1/*
21138472 2 * Copyright (c) 2013, 2014 Nicira, Inc.
55b40355
BP
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <config.h>
18
19#include "seq.h"
20
21#include <stdbool.h>
22
c883b4e8 23#include "coverage.h"
55b40355
BP
24#include "hash.h"
25#include "hmap.h"
26#include "latch.h"
b19bab5b 27#include "openvswitch/list.h"
55b40355
BP
28#include "ovs-thread.h"
29#include "poll-loop.h"
30
c883b4e8
JR
31COVERAGE_DEFINE(seq_change);
32
55b40355
BP
33/* A sequence number object. */
34struct seq {
35 uint64_t value OVS_GUARDED;
36 struct hmap waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
37};
38
39/* A thread waiting on a particular seq. */
40struct seq_waiter {
41 struct seq *seq OVS_GUARDED; /* Seq being waited for. */
42 struct hmap_node hmap_node OVS_GUARDED; /* In 'seq->waiters'. */
43 unsigned int ovsthread_id OVS_GUARDED; /* Key in 'waiters' hmap. */
44
ca6ba700
TG
45 struct seq_thread *thread OVS_GUARDED; /* Thread preparing to wait. */
46 struct ovs_list list_node OVS_GUARDED; /* In 'thread->waiters'. */
55b40355
BP
47
48 uint64_t value OVS_GUARDED; /* seq->value we're waiting to change. */
49};
50
51/* A thread that might be waiting on one or more seqs. */
52struct seq_thread {
ca6ba700 53 struct ovs_list waiters OVS_GUARDED; /* Contains 'struct seq_waiter's. */
55b40355
BP
54 struct latch latch OVS_GUARDED; /* Wakeup latch for this thread. */
55 bool waiting OVS_GUARDED; /* True if latch_wait() already called. */
56};
57
834d6caf 58static struct ovs_mutex seq_mutex = OVS_MUTEX_INITIALIZER;
55b40355
BP
59
60static uint64_t seq_next OVS_GUARDED_BY(seq_mutex) = 1;
61
62static pthread_key_t seq_thread_key;
63
64static void seq_init(void);
65static struct seq_thread *seq_thread_get(void) OVS_REQUIRES(seq_mutex);
66static void seq_thread_exit(void *thread_) OVS_EXCLUDED(seq_mutex);
67static void seq_thread_woke(struct seq_thread *) OVS_REQUIRES(seq_mutex);
68static void seq_waiter_destroy(struct seq_waiter *) OVS_REQUIRES(seq_mutex);
69static void seq_wake_waiters(struct seq *) OVS_REQUIRES(seq_mutex);
70
71/* Creates and returns a new 'seq' object. */
72struct seq * OVS_EXCLUDED(seq_mutex)
73seq_create(void)
74{
75 struct seq *seq;
76
77 seq_init();
78
79 seq = xmalloc(sizeof *seq);
c883b4e8
JR
80
81 COVERAGE_INC(seq_change);
82
55b40355
BP
83 ovs_mutex_lock(&seq_mutex);
84 seq->value = seq_next++;
85 hmap_init(&seq->waiters);
86 ovs_mutex_unlock(&seq_mutex);
87
88 return seq;
89}
90
91/* Destroys 'seq', waking up threads that were waiting on it, if any. */
92void
93seq_destroy(struct seq *seq)
94 OVS_EXCLUDED(seq_mutex)
95{
96 ovs_mutex_lock(&seq_mutex);
97 seq_wake_waiters(seq);
98 hmap_destroy(&seq->waiters);
99 free(seq);
100 ovs_mutex_unlock(&seq_mutex);
101}
102
103/* Increments 'seq''s sequence number, waking up any threads that are waiting
104 * on 'seq'. */
105void
106seq_change(struct seq *seq)
107 OVS_EXCLUDED(seq_mutex)
108{
c883b4e8
JR
109 COVERAGE_INC(seq_change);
110
55b40355
BP
111 ovs_mutex_lock(&seq_mutex);
112 seq->value = seq_next++;
113 seq_wake_waiters(seq);
114 ovs_mutex_unlock(&seq_mutex);
115}
116
5d389d55
BP
117/* Returns 'seq''s current sequence number (which could change immediately).
118 *
119 * seq_read() and seq_wait() can be used together to yield a race-free wakeup
120 * when an object changes, even without an ability to lock the object. See
121 * Usage in seq.h for details. */
55b40355
BP
122uint64_t
123seq_read(const struct seq *seq)
124 OVS_EXCLUDED(seq_mutex)
125{
126 uint64_t value;
127
128 ovs_mutex_lock(&seq_mutex);
129 value = seq->value;
130 ovs_mutex_unlock(&seq_mutex);
131
132 return value;
133}
134
135static void
21138472 136seq_wait__(struct seq *seq, uint64_t value, const char *where)
55b40355
BP
137 OVS_REQUIRES(seq_mutex)
138{
139 unsigned int id = ovsthread_id_self();
140 uint32_t hash = hash_int(id, 0);
141 struct seq_waiter *waiter;
142
143 HMAP_FOR_EACH_IN_BUCKET (waiter, hmap_node, hash, &seq->waiters) {
144 if (waiter->ovsthread_id == id) {
145 if (waiter->value != value) {
146 /* The current value is different from the value we've already
147 * waited for, */
21138472 148 poll_immediate_wake_at(where);
55b40355
BP
149 } else {
150 /* Already waiting on 'value', nothing more to do. */
151 }
152 return;
153 }
154 }
155
156 waiter = xmalloc(sizeof *waiter);
157 waiter->seq = seq;
158 hmap_insert(&seq->waiters, &waiter->hmap_node, hash);
f4aa1da8 159 waiter->ovsthread_id = id;
55b40355
BP
160 waiter->value = value;
161 waiter->thread = seq_thread_get();
417e7e66 162 ovs_list_push_back(&waiter->thread->waiters, &waiter->list_node);
55b40355
BP
163
164 if (!waiter->thread->waiting) {
21138472 165 latch_wait_at(&waiter->thread->latch, where);
55b40355
BP
166 waiter->thread->waiting = true;
167 }
168}
169
170/* Causes the following poll_block() to wake up when 'seq''s sequence number
171 * changes from 'value'. (If 'seq''s sequence number isn't 'value', then
5d389d55
BP
172 * poll_block() won't block at all.)
173 *
174 * seq_read() and seq_wait() can be used together to yield a race-free wakeup
175 * when an object changes, even without an ability to lock the object. See
21138472
BP
176 * Usage in seq.h for details.
177 *
178 * ('where' is used in debug logging. Commonly one would use seq_wait() to
179 * automatically provide the caller's source file and line number for
180 * 'where'.) */
55b40355 181void
21138472 182seq_wait_at(const struct seq *seq_, uint64_t value, const char *where)
55b40355
BP
183 OVS_EXCLUDED(seq_mutex)
184{
185 struct seq *seq = CONST_CAST(struct seq *, seq_);
186
187 ovs_mutex_lock(&seq_mutex);
188 if (value == seq->value) {
21138472 189 seq_wait__(seq, value, where);
55b40355 190 } else {
21138472 191 poll_immediate_wake_at(where);
55b40355
BP
192 }
193 ovs_mutex_unlock(&seq_mutex);
194}
195
196/* Called by poll_block() just before it returns, this function destroys any
197 * seq_waiter objects associated with the current thread. */
198void
199seq_woke(void)
200 OVS_EXCLUDED(seq_mutex)
201{
202 struct seq_thread *thread;
203
204 seq_init();
205
206 thread = pthread_getspecific(seq_thread_key);
207 if (thread) {
208 ovs_mutex_lock(&seq_mutex);
209 seq_thread_woke(thread);
210 thread->waiting = false;
211 ovs_mutex_unlock(&seq_mutex);
212 }
213}
214\f
215static void
216seq_init(void)
217{
218 static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
219
220 if (ovsthread_once_start(&once)) {
221 xpthread_key_create(&seq_thread_key, seq_thread_exit);
222 ovsthread_once_done(&once);
223 }
224}
225
226static struct seq_thread *
227seq_thread_get(void)
228 OVS_REQUIRES(seq_mutex)
229{
230 struct seq_thread *thread = pthread_getspecific(seq_thread_key);
231 if (!thread) {
232 thread = xmalloc(sizeof *thread);
417e7e66 233 ovs_list_init(&thread->waiters);
55b40355
BP
234 latch_init(&thread->latch);
235 thread->waiting = false;
236
237 xpthread_setspecific(seq_thread_key, thread);
238 }
239 return thread;
240}
241
242static void
243seq_thread_exit(void *thread_)
244 OVS_EXCLUDED(seq_mutex)
245{
246 struct seq_thread *thread = thread_;
247
248 ovs_mutex_lock(&seq_mutex);
249 seq_thread_woke(thread);
250 latch_destroy(&thread->latch);
251 free(thread);
252 ovs_mutex_unlock(&seq_mutex);
253}
254
255static void
256seq_thread_woke(struct seq_thread *thread)
257 OVS_REQUIRES(seq_mutex)
258{
259 struct seq_waiter *waiter, *next_waiter;
260
261 LIST_FOR_EACH_SAFE (waiter, next_waiter, list_node, &thread->waiters) {
262 ovs_assert(waiter->thread == thread);
263 seq_waiter_destroy(waiter);
264 }
265 latch_poll(&thread->latch);
266}
267
268static void
269seq_waiter_destroy(struct seq_waiter *waiter)
270 OVS_REQUIRES(seq_mutex)
271{
272 hmap_remove(&waiter->seq->waiters, &waiter->hmap_node);
417e7e66 273 ovs_list_remove(&waiter->list_node);
55b40355
BP
274 free(waiter);
275}
276
277static void
278seq_wake_waiters(struct seq *seq)
279 OVS_REQUIRES(seq_mutex)
280{
281 struct seq_waiter *waiter, *next_waiter;
282
283 HMAP_FOR_EACH_SAFE (waiter, next_waiter, hmap_node, &seq->waiters) {
284 latch_set(&waiter->thread->latch);
285 seq_waiter_destroy(waiter);
286 }
287}