Simple revert, looks good to me, thanks Acked-by: Daniele Di Proietto <diproiet...@vmware.com>
2016-08-09 13:59 GMT-07:00 Jarno Rajahalme <ja...@ovn.org>: > This reverts commit 8bdfe1313894047d44349fa4cf4402970865950f. > > I failed to see that lib/dpif-netdev.c actually needs the concurrency > provided by pvector prior to this change. More specifically, when a > subtable is removed, concurrent lookups may skip over another subtable > swapped in to the place of the removed subtable in the vector. > > Since this was the only use of the non-concurrent pvector, it is > cleaner to revert the whole patch. > > Reported-by: Jan Scheurich <jan.scheur...@ericsson.com> > Signed-off-by: Jarno Rajahalme <ja...@ovn.org> > --- > lib/classifier.c | 30 ++++---- > lib/classifier.h | 6 +- > lib/dpif-netdev.c | 14 ++-- > lib/pvector.c | 190 +++++++++++++++++++++++------- > ------------------ > lib/pvector.h | 187 +++++++++++++++--------------- > ----------------- > tests/test-classifier.c | 12 +-- > 6 files changed, 182 insertions(+), 257 deletions(-) > > diff --git a/lib/classifier.c b/lib/classifier.c > index 8f195d5..0551146 100644 > --- a/lib/classifier.c > +++ b/lib/classifier.c > @@ -325,7 +325,7 @@ classifier_init(struct classifier *cls, const uint8_t > *flow_segments) > { > cls->n_rules = 0; > cmap_init(&cls->subtables_map); > - cpvector_init(&cls->subtables); > + pvector_init(&cls->subtables); > cls->n_flow_segments = 0; > if (flow_segments) { > while (cls->n_flow_segments < CLS_MAX_INDICES > @@ -359,7 +359,7 @@ classifier_destroy(struct classifier *cls) > } > cmap_destroy(&cls->subtables_map); > > - cpvector_destroy(&cls->subtables); > + pvector_destroy(&cls->subtables); > } > } > > @@ -658,20 +658,20 @@ classifier_replace(struct classifier *cls, const > struct cls_rule *rule, > if (n_rules == 1) { > subtable->max_priority = rule->priority; > subtable->max_count = 1; > - cpvector_insert(&cls->subtables, subtable, rule->priority); > + pvector_insert(&cls->subtables, subtable, rule->priority); > } else if (rule->priority == subtable->max_priority) { > ++subtable->max_count; > } else if (rule->priority > subtable->max_priority) { > subtable->max_priority = rule->priority; > subtable->max_count = 1; > - cpvector_change_priority(&cls->subtables, subtable, > rule->priority); > + pvector_change_priority(&cls->subtables, subtable, > rule->priority); > } > > /* Nothing was replaced. */ > cls->n_rules++; > > if (cls->publish) { > - cpvector_publish(&cls->subtables); > + pvector_publish(&cls->subtables); > } > > return NULL; > @@ -803,12 +803,12 @@ check_priority: > } > } > subtable->max_priority = max_priority; > - cpvector_change_priority(&cls->subtables, subtable, > max_priority); > + pvector_change_priority(&cls->subtables, subtable, > max_priority); > } > } > > if (cls->publish) { > - cpvector_publish(&cls->subtables); > + pvector_publish(&cls->subtables); > } > > /* free the rule. */ > @@ -959,8 +959,8 @@ classifier_lookup__(const struct classifier *cls, > ovs_version_t version, > > /* Main loop. */ > struct cls_subtable *subtable; > - CPVECTOR_FOR_EACH_PRIORITY (subtable, hard_pri + 1, 2, sizeof > *subtable, > - &cls->subtables) { > + PVECTOR_FOR_EACH_PRIORITY (subtable, hard_pri + 1, 2, sizeof > *subtable, > + &cls->subtables) { > struct cls_conjunction_set *conj_set; > > /* Skip subtables with no match, or where the match is > lower-priority > @@ -1231,8 +1231,8 @@ classifier_rule_overlaps(const struct classifier > *cls, > struct cls_subtable *subtable; > > /* Iterate subtables in the descending max priority order. */ > - CPVECTOR_FOR_EACH_PRIORITY (subtable, target->priority, 2, > - sizeof(struct cls_subtable), > &cls->subtables) { > + PVECTOR_FOR_EACH_PRIORITY (subtable, target->priority, 2, > + sizeof(struct cls_subtable), > &cls->subtables) { > struct { > struct minimask mask; > uint64_t storage[FLOW_U64S]; > @@ -1350,8 +1350,8 @@ cls_cursor_start(const struct classifier *cls, const > struct cls_rule *target, > cursor.rule = NULL; > > /* Find first rule. */ > - CPVECTOR_CURSOR_FOR_EACH (subtable, &cursor.subtables, > - &cursor.cls->subtables) { > + PVECTOR_CURSOR_FOR_EACH (subtable, &cursor.subtables, > + &cursor.cls->subtables) { > const struct cls_rule *rule = search_subtable(subtable, &cursor); > > if (rule) { > @@ -1378,7 +1378,7 @@ cls_cursor_next(struct cls_cursor *cursor) > } > } > > - CPVECTOR_CURSOR_FOR_EACH_CONTINUE (subtable, &cursor->subtables) { > + PVECTOR_CURSOR_FOR_EACH_CONTINUE (subtable, &cursor->subtables) { > rule = search_subtable(subtable, cursor); > if (rule) { > cursor->subtable = subtable; > @@ -1510,7 +1510,7 @@ destroy_subtable(struct classifier *cls, struct > cls_subtable *subtable) > { > int i; > > - cpvector_remove(&cls->subtables, subtable); > + pvector_remove(&cls->subtables, subtable); > cmap_remove(&cls->subtables_map, &subtable->cmap_node, > minimask_hash(&subtable->mask, 0)); > > diff --git a/lib/classifier.h b/lib/classifier.h > index 3ccf827..44185a3 100644 > --- a/lib/classifier.h > +++ b/lib/classifier.h > @@ -1,5 +1,5 @@ > /* > - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, > Inc. > + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -335,7 +335,7 @@ struct classifier { > uint8_t flow_segments[CLS_MAX_INDICES]; /* Flow segment boundaries > to use > * for staged lookup. */ > struct cmap subtables_map; /* Contains "struct cls_subtable"s. > */ > - struct cpvector subtables; > + struct pvector subtables; > struct cmap partitions; /* Contains "struct cls_partition"s. > */ > struct cls_trie tries[CLS_MAX_TRIES]; /* Prefix tries. */ > unsigned int n_tries; > @@ -466,7 +466,7 @@ static inline void > classifier_publish(struct classifier *cls) > { > cls->publish = true; > - cpvector_publish(&cls->subtables); > + pvector_publish(&cls->subtables); > } > > #ifdef __cplusplus > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index 1541628..fe19b38 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -163,7 +163,7 @@ struct emc_cache { > > struct dpcls { > struct cmap subtables_map; > - struct pvector *subtables; > + struct pvector subtables; > }; > > /* A rule to be inserted to the classifier. */ > @@ -4770,13 +4770,13 @@ static void > dpcls_init(struct dpcls *cls) > { > cmap_init(&cls->subtables_map); > - cls->subtables = pvector_alloc(4); > + pvector_init(&cls->subtables); > } > > static void > dpcls_destroy_subtable(struct dpcls *cls, struct dpcls_subtable *subtable) > { > - pvector_remove(cls->subtables, subtable); > + pvector_remove(&cls->subtables, subtable); > cmap_remove(&cls->subtables_map, &subtable->cmap_node, > subtable->mask.hash); > cmap_destroy(&subtable->rules); > @@ -4797,7 +4797,7 @@ dpcls_destroy(struct dpcls *cls) > dpcls_destroy_subtable(cls, subtable); > } > cmap_destroy(&cls->subtables_map); > - free(cls->subtables); > + pvector_destroy(&cls->subtables); > } > } > > @@ -4812,7 +4812,8 @@ dpcls_create_subtable(struct dpcls *cls, const > struct netdev_flow_key *mask) > cmap_init(&subtable->rules); > netdev_flow_key_clone(&subtable->mask, mask); > cmap_insert(&cls->subtables_map, &subtable->cmap_node, mask->hash); > - pvector_push_back(&cls->subtables, subtable, 0); > + pvector_insert(&cls->subtables, subtable, 0); > + pvector_publish(&cls->subtables); > > return subtable; > } > @@ -4855,6 +4856,7 @@ dpcls_remove(struct dpcls *cls, struct dpcls_rule > *rule) > if (cmap_remove(&subtable->rules, &rule->cmap_node, rule->flow.hash) > == 0) { > dpcls_destroy_subtable(cls, subtable); > + pvector_publish(&cls->subtables); > } > } > > @@ -4918,7 +4920,7 @@ dpcls_lookup(const struct dpcls *cls, const struct > netdev_flow_key keys[], > * search-key against each subtable, but when a match is found for a > * search-key, the search for that key can stop because the rules are > * non-overlapping. */ > - PVECTOR_FOR_EACH (subtable, cls->subtables) { > + PVECTOR_FOR_EACH (subtable, &cls->subtables) { > const struct netdev_flow_key *mkeys = keys; > struct dpcls_rule **mrules = rules; > map_type remains = 0; > diff --git a/lib/pvector.c b/lib/pvector.c > index 5fb1899..aaeee92 100644 > --- a/lib/pvector.c > +++ b/lib/pvector.c > @@ -21,30 +21,60 @@ > * reallocations. */ > enum { PVECTOR_EXTRA_ALLOC = 4 }; > > -struct pvector * > -pvector_alloc(size_t size) > +static struct pvector_impl * > +pvector_impl_get(const struct pvector *pvec) > { > - struct pvector *pvec; > + return ovsrcu_get(struct pvector_impl *, &pvec->impl); > +} > + > +static struct pvector_impl * > +pvector_impl_alloc(size_t size) > +{ > + struct pvector_impl *impl; > > - pvec = xmalloc(sizeof *pvec + size * sizeof pvec->vector[0]); > - pvec->size = 0; > - pvec->allocated = size; > + impl = xmalloc(sizeof *impl + size * sizeof impl->vector[0]); > + impl->size = 0; > + impl->allocated = size; > > - return pvec; > + return impl; > +} > + > +static struct pvector_impl * > +pvector_impl_dup(struct pvector_impl *old) > +{ > + struct pvector_impl *impl; > + size_t alloc = old->size + PVECTOR_EXTRA_ALLOC; > + > + impl = xmalloc(sizeof *impl + alloc * sizeof impl->vector[0]); > + impl->allocated = alloc; > + impl->size = old->size; > + memcpy(impl->vector, old->vector, old->size * sizeof old->vector[0]); > + return impl; > } > > -static struct pvector * > -pvector_dup(const struct pvector *old) > +/* Initializes 'pvec' as an empty concurrent priority vector. */ > +void > +pvector_init(struct pvector *pvec) > { > - struct pvector *pvec = pvector_alloc(old->size + PVECTOR_EXTRA_ALLOC); > + ovsrcu_set(&pvec->impl, pvector_impl_alloc(PVECTOR_EXTRA_ALLOC)); > + pvec->temp = NULL; > +} > > - pvec->size = old->size; > - memcpy(pvec->vector, old->vector, old->size * sizeof old->vector[0]); > - return pvec; > +/* Destroys 'pvec'. > + * > + * The client is responsible for destroying any data previously held in > + * 'pvec'. */ > +void > +pvector_destroy(struct pvector *pvec) > +{ > + free(pvec->temp); > + pvec->temp = NULL; > + ovsrcu_postpone(free, pvector_impl_get(pvec)); > + ovsrcu_set(&pvec->impl, NULL); /* Poison. */ > } > > -/* Iterator for callers that need the 'index' afterward. */ > -#define PVECTOR_FOR_EACH_ENTRY(ENTRY, INDEX, IMPL) \ > +/* Iterators for callers that need the 'index' afterward. */ > +#define PVECTOR_IMPL_FOR_EACH(ENTRY, INDEX, IMPL) \ > for ((INDEX) = 0; \ > (INDEX) < (IMPL)->size \ > && ((ENTRY) = &(IMPL)->vector[INDEX], true); \ > @@ -61,20 +91,20 @@ pvector_entry_cmp(const void *a_, const void *b_) > return a > b ? -1 : a < b; > } > > -void > -pvector_sort(struct pvector *pvec) > +static void > +pvector_impl_sort(struct pvector_impl *impl) > { > - qsort(pvec->vector, pvec->size, sizeof *pvec->vector, > pvector_entry_cmp); > + qsort(impl->vector, impl->size, sizeof *impl->vector, > pvector_entry_cmp); > } > > /* Returns the index of the 'ptr' in the vector, or -1 if none is found. > */ > static int > -pvector_find(const struct pvector *pvec, void *target) > +pvector_impl_find(struct pvector_impl *impl, void *target) > { > const struct pvector_entry *entry; > int index; > > - PVECTOR_FOR_EACH_ENTRY (entry, index, pvec) { > + PVECTOR_IMPL_FOR_EACH (entry, index, impl) { > if (entry->ptr == target) { > return index; > } > @@ -82,67 +112,11 @@ pvector_find(const struct pvector *pvec, void *target) > return -1; > } > > -/* May re-allocate 'impl' */ > -void > -pvector_push_back(struct pvector **pvecp, void *ptr, int priority) > -{ > - struct pvector *pvec = *pvecp; > - > - if (pvec->size == pvec->allocated) { > - pvec = pvector_dup(pvec); > - free(*pvecp); > - *pvecp = pvec; > - } > - /* Insert at the end, will be sorted later. */ > - pvec->vector[pvec->size].ptr = ptr; > - pvec->vector[pvec->size].priority = priority; > - pvec->size++; > -} > - > void > -pvector_remove(struct pvector *pvec, void *ptr) > +pvector_insert(struct pvector *pvec, void *ptr, int priority) > { > - int index; > - > - index = pvector_find(pvec, ptr); > - ovs_assert(index >= 0); > - /* Now at the index of the entry to be deleted. > - * Swap another entry in if needed, can be sorted later. */ > - pvec->size--; > - if (index != pvec->size) { > - pvec->vector[index] = pvec->vector[pvec->size]; > - } > -} > - > - > -/* Concurrent version. */ > - > -/* Initializes 'cpvec' as an empty concurrent priority vector. */ > -void > -cpvector_init(struct cpvector *cpvec) > -{ > - ovsrcu_set(&cpvec->impl, pvector_alloc(PVECTOR_EXTRA_ALLOC)); > - cpvec->temp = NULL; > -} > - > -/* Destroys 'cpvec'. > - * > - * The client is responsible for destroying any data previously held in > - * 'pvec'. */ > -void > -cpvector_destroy(struct cpvector *cpvec) > -{ > - free(cpvec->temp); > - cpvec->temp = NULL; > - ovsrcu_postpone(free, cpvector_get_pvector(cpvec)); > - ovsrcu_set(&cpvec->impl, NULL); /* Poison. */ > -} > - > -void > -cpvector_insert(struct cpvector *cpvec, void *ptr, int priority) > -{ > - struct pvector *temp = cpvec->temp; > - struct pvector *old = cpvector_get_pvector(cpvec); > + struct pvector_impl *temp = pvec->temp; > + struct pvector_impl *old = pvector_impl_get(pvec); > > ovs_assert(ptr != NULL); > > @@ -157,37 +131,53 @@ cpvector_insert(struct cpvector *cpvec, void *ptr, > int priority) > ++old->size; > } else { > if (!temp) { > - cpvec->temp = pvector_dup(old); > + temp = pvector_impl_dup(old); > + pvec->temp = temp; > + } else if (temp->size == temp->allocated) { > + temp = pvector_impl_dup(temp); > + free(pvec->temp); > + pvec->temp = temp; > } > - pvector_push_back(&cpvec->temp, ptr, priority); > + /* Insert at the end, publish will sort. */ > + temp->vector[temp->size].ptr = ptr; > + temp->vector[temp->size].priority = priority; > + temp->size += 1; > } > } > > void > -cpvector_remove(struct cpvector *cpvec, void *ptr) > +pvector_remove(struct pvector *pvec, void *ptr) > { > - struct pvector *temp = cpvec->temp; > + struct pvector_impl *temp = pvec->temp; > + int index; > > if (!temp) { > - temp = pvector_dup(cpvector_get_pvector(cpvec)); > - cpvec->temp = temp; > + temp = pvector_impl_dup(pvector_impl_get(pvec)); > + pvec->temp = temp; > } > ovs_assert(temp->size > 0); > - pvector_remove(temp, ptr); /* Publish will sort. */ > + index = pvector_impl_find(temp, ptr); > + ovs_assert(index >= 0); > + /* Now at the index of the entry to be deleted. > + * Swap another entry in if needed, publish will sort anyway. */ > + temp->size--; > + if (index != temp->size) { > + temp->vector[index] = temp->vector[temp->size]; > + } > } > > /* Change entry's 'priority' and keep the vector ordered. */ > void > -cpvector_change_priority(struct cpvector *cpvec, void *ptr, int priority) > +pvector_change_priority(struct pvector *pvec, void *ptr, int priority) > { > - struct pvector *old = cpvec->temp; > + struct pvector_impl *old = pvec->temp; > int index; > > if (!old) { > - old = cpvector_get_pvector(cpvec); > + old = pvector_impl_get(pvec); > } > > - index = pvector_find(old, ptr); > + index = pvector_impl_find(old, ptr); > > ovs_assert(index >= 0); > /* Now at the index of the entry to be updated. */ > @@ -198,10 +188,10 @@ cpvector_change_priority(struct cpvector *cpvec, > void *ptr, int priority) > || (priority < old->vector[index].priority && index < old->size - > 1 > && priority < old->vector[index + 1].priority)) { > /* Have to use a temp. */ > - if (!cpvec->temp) { > + if (!pvec->temp) { > /* Have to reallocate to reorder. */ > - cpvec->temp = pvector_dup(old); > - old = cpvec->temp; > + pvec->temp = pvector_impl_dup(old); > + old = pvec->temp; > /* Publish will sort. */ > } > } > @@ -209,13 +199,13 @@ cpvector_change_priority(struct cpvector *cpvec, > void *ptr, int priority) > } > > /* Make the modified pvector available for iteration. */ > -void cpvector_publish__(struct cpvector *cpvec) > +void pvector_publish__(struct pvector *pvec) > { > - struct pvector *temp = cpvec->temp; > + struct pvector_impl *temp = pvec->temp; > > - cpvec->temp = NULL; > - pvector_sort(temp); /* Also removes gaps. */ > - ovsrcu_postpone(free, ovsrcu_get_protected(struct pvector *, > - &cpvec->impl)); > - ovsrcu_set(&cpvec->impl, temp); > + pvec->temp = NULL; > + pvector_impl_sort(temp); /* Also removes gaps. */ > + ovsrcu_postpone(free, ovsrcu_get_protected(struct pvector_impl *, > + &pvec->impl)); > + ovsrcu_set(&pvec->impl, temp); > } > diff --git a/lib/pvector.h b/lib/pvector.h > index 00cb757..b175b21 100644 > --- a/lib/pvector.h > +++ b/lib/pvector.h > @@ -49,7 +49,7 @@ > * values, or decrement the 'size' on a copy that readers have access to. > * > * Most modifications are internally staged at the 'temp' vector, from > which > - * they can be published at 'impl' by calling cpvector_publish(). This > saves > + * they can be published at 'impl' by calling pvector_publish(). This > saves > * unnecessary memory allocations when many changes are done back-to-back. > * 'temp' may contain NULL pointers and it may be in unsorted order. It > is > * sorted before it is published at 'impl', which also removes the NULLs > from > @@ -61,17 +61,33 @@ struct pvector_entry { > void *ptr; > }; > > -/* Non-concurrent priority vector. */ > -struct pvector { > +struct pvector_impl { > size_t size; /* Number of entries in the vector. */ > size_t allocated; /* Number of allocated entries. */ > struct pvector_entry vector[]; > }; > > -struct pvector *pvector_alloc(size_t); > -void pvector_push_back(struct pvector **, void *ptr, int priority); > -void pvector_remove(struct pvector *, void *ptr); > -void pvector_sort(struct pvector *); > +/* Concurrent priority vector. */ > +struct pvector { > + OVSRCU_TYPE(struct pvector_impl *) impl; > + struct pvector_impl *temp; > +}; > + > +/* Initialization. */ > +void pvector_init(struct pvector *); > +void pvector_destroy(struct pvector *); > + > +/* Insertion and deletion. These work on 'temp'. */ > +void pvector_insert(struct pvector *, void *, int priority); > +void pvector_change_priority(struct pvector *, void *, int priority); > +void pvector_remove(struct pvector *, void *); > + > +/* Make the modified pvector available for iteration. */ > +static inline void pvector_publish(struct pvector *); > + > +/* Count. These operate on the published pvector. */ > +static inline size_t pvector_count(const struct pvector *); > +static inline bool pvector_is_empty(const struct pvector *); > > /* Iteration. > * > @@ -79,9 +95,8 @@ void pvector_sort(struct pvector *); > * Thread-safety > * ============= > * > - * These iterators operate on the non-concurrent pvector, and are not > thread > - * safe. Any entry may be skipped if entires are removed (with > - * pvector_remove()) during iteration. > + * Iteration is safe even in a pvector that is changing concurrently. > + * Multiple writers must exclude each other via e.g., a mutex. > * > * Example > * ======= > @@ -91,28 +106,32 @@ void pvector_sort(struct pvector *); > * }; > * > * struct my_node elem1, elem2, *iter; > - * struct pvector *my_pvector; > + * struct pvector my_pvector; > * > - * my_pvector = pvector_alloc(0); > + * pvector_init(&my_pvector); > * ...add data... > - * pvector_push_back(&my_pvector, &elem1, 1); > - * pvector_push_back(&my_pvector, &elem2, 2); > - * ...sort... > - * pvector_sort(my_pvector); > + * pvector_insert(&my_pvector, &elem1, 1); > + * pvector_insert(&my_pvector, &elem2, 2); > * ... > - * PVECTOR_FOR_EACH (iter, &my_cpvector) { > + * PVECTOR_FOR_EACH (iter, &my_pvector) { > * ...operate on '*iter'... > * ...elem2 to be seen before elem1... > * } > - * ...remove entries... > - * pvector_remove(my_pvector, &elem1); > * ... > - * free(my_pvector); > + * pvector_destroy(&my_pvector); > * > - * Currently there is no PVECTOR_FOR_EACH_SAFE variant. > + * There is no PVECTOR_FOR_EACH_SAFE variant as iteration is performed on > RCU > + * protected instance of the priority vector. Any concurrent > modifications > + * that would be disruptive for readers (such as deletions), will be > performed > + * on a new instance. To see any of the modifications, a new iteration > loop > + * has to be started. > * > * The PVECTOR_FOR_EACH_PRIORITY limits the iteration to entries with > higher > * than or equal to the given priority and allows for object lookahead. > + * > + * The iteration loop must be completed without entering the OVS RCU > quiescent > + * period. That is, an old iteration loop must not be continued after any > + * blocking IO (VLOG is non-blocking, so that is OK). > */ > struct pvector_cursor { > size_t size; /* Number of entries in the vector. */ > @@ -124,7 +143,7 @@ static inline struct pvector_cursor > pvector_cursor_init(const struct pvector *, > size_t n_ahead, > size_t obj_size); > static inline void *pvector_cursor_next(struct pvector_cursor *, > - int stop_at_priority, > + int lowest_priority, > size_t n_ahead, size_t obj_size); > static inline void pvector_cursor_lookahead(const struct pvector_cursor *, > int n, size_t size); > @@ -139,109 +158,29 @@ static inline void pvector_cursor_lookahead(const > struct pvector_cursor *, > for (struct pvector_cursor cursor__ = pvector_cursor_init(PVECTOR, N, > SZ); \ > ((PTR) = pvector_cursor_next(&cursor__, PRIORITY, N, SZ)) != > NULL; ) > > -#define PVECTOR_CURSOR_FOR_EACH(PTR, CURSOR, PVECTOR) \ > - for (*(CURSOR) = pvector_cursor_init(PVECTOR, 0, 0); \ > +#define PVECTOR_CURSOR_FOR_EACH(PTR, CURSOR, PVECTOR) \ > + for (*(CURSOR) = pvector_cursor_init(PVECTOR, 0, 0); \ > ((PTR) = pvector_cursor_next(CURSOR, INT_MIN, 0, 0)) != NULL; ) > > #define PVECTOR_CURSOR_FOR_EACH_CONTINUE(PTR, CURSOR) \ > for (; ((PTR) = pvector_cursor_next(CURSOR, INT_MIN, 0, 0)) != NULL; ) > > > -/* Concurrent priority vector. */ > -struct cpvector { > - OVSRCU_TYPE(struct pvector *) impl; > - struct pvector *temp; > -}; > - > -/* Initialization. */ > -void cpvector_init(struct cpvector *); > -void cpvector_destroy(struct cpvector *); > - > -/* Insertion and deletion. These work on 'temp'. */ > -void cpvector_insert(struct cpvector *, void *, int priority); > -void cpvector_change_priority(struct cpvector *, void *, int priority); > -void cpvector_remove(struct cpvector *, void *); > - > -/* Make the modified cpvector available for iteration. */ > -static inline void cpvector_publish(struct cpvector *); > - > -/* Count. These operate on the published cpvector. */ > -static inline size_t cpvector_count(const struct cpvector *); > -static inline bool cpvector_is_empty(const struct cpvector *); > - > -static inline struct pvector *cpvector_get_pvector(const struct cpvector > *); > - > -/* Iteration. > - * > - * > - * Thread-safety > - * ============= > - * > - * Iteration is safe even in a cpvector that is changing concurrently. > - * Multiple writers must exclude each other via e.g., a mutex. > - * > - * Example > - * ======= > - * > - * struct my_node { > - * int data; > - * }; > - * > - * struct my_node elem1, elem2, *iter; > - * struct cpvector my_cpvector; > - * > - * cpvector_init(&my_cpvector); > - * ...add data... > - * cpvector_insert(&my_cpvector, &elem1, 1); > - * cpvector_insert(&my_cpvector, &elem2, 2); > - * ... > - * CPVECTOR_FOR_EACH (iter, &my_cpvector) { > - * ...operate on '*iter'... > - * ...elem2 to be seen before elem1... > - * } > - * ... > - * cpvector_destroy(&my_cpvector); > - * > - * There is no CPVECTOR_FOR_EACH_SAFE variant as iteration is performed > on RCU > - * protected instance of the priority vector. Any concurrent > modifications > - * that would be disruptive for readers (such as deletions), will be > performed > - * on a new instance. To see any of the modifications, a new iteration > loop > - * has to be started. > - * > - * The CPVECTOR_FOR_EACH_PRIORITY limits the iteration to entries with > higher > - * than or equal to the given priority and allows for object lookahead. > - * > - * The iteration loop must be completed without entering the OVS RCU > quiescent > - * period. That is, an old iteration loop must not be continued after any > - * blocking IO (VLOG is non-blocking, so that is OK). > - */ > - > -#define CPVECTOR_FOR_EACH(PTR, CPVECTOR) \ > - PVECTOR_FOR_EACH(PTR, cpvector_get_pvector(CPVECTOR)) > - > -#define CPVECTOR_FOR_EACH_PRIORITY(PTR, PRIORITY, N, SZ, CPVECTOR) \ > - PVECTOR_FOR_EACH_PRIORITY(PTR, PRIORITY, N, SZ, \ > - cpvector_get_pvector(CPVECTOR)) > - > -#define CPVECTOR_CURSOR_FOR_EACH(PTR, CURSOR, CPVECTOR) \ > - PVECTOR_CURSOR_FOR_EACH(PTR, CURSOR, cpvector_get_pvector(CPVECTOR)) > - > -#define CPVECTOR_CURSOR_FOR_EACH_CONTINUE(PTR, CURSOR) \ > - PVECTOR_CURSOR_FOR_EACH_CONTINUE(PTR, CURSOR) > - > - > /* Inline implementations. */ > > static inline struct pvector_cursor > -pvector_cursor_init(const struct pvector *pvec, size_t n_ahead, > - size_t obj_size) > +pvector_cursor_init(const struct pvector *pvec, > + size_t n_ahead, size_t obj_size) > { > + const struct pvector_impl *impl; > struct pvector_cursor cursor; > > - ovs_prefetch_range(pvec->vector, pvec->size * sizeof > pvec->vector[0]); > + impl = ovsrcu_get(struct pvector_impl *, &pvec->impl); > > - cursor.size = pvec->size; > - cursor.vector = pvec->vector; > + ovs_prefetch_range(impl->vector, impl->size * sizeof > impl->vector[0]); > + > + cursor.size = impl->size; > + cursor.vector = impl->vector; > cursor.entry_idx = -1; > > for (size_t i = 0; i < n_ahead; i++) { > @@ -273,29 +212,23 @@ static inline void pvector_cursor_lookahead(const > struct pvector_cursor *cursor, > } > } > > -static inline struct pvector * > -cpvector_get_pvector(const struct cpvector *cpvec) > -{ > - return ovsrcu_get(struct pvector *, &cpvec->impl); > -} > - > -static inline size_t cpvector_count(const struct cpvector *cpvec) > +static inline size_t pvector_count(const struct pvector *pvec) > { > - return cpvector_get_pvector(cpvec)->size; > + return ovsrcu_get(struct pvector_impl *, &pvec->impl)->size; > } > > -static inline bool cpvector_is_empty(const struct cpvector *cpvec) > +static inline bool pvector_is_empty(const struct pvector *pvec) > { > - return cpvector_count(cpvec) == 0; > + return pvector_count(pvec) == 0; > } > > -void cpvector_publish__(struct cpvector *); > +void pvector_publish__(struct pvector *); > > -/* Make the modified cpvector available for iteration. */ > -static inline void cpvector_publish(struct cpvector *cpvec) > +/* Make the modified pvector available for iteration. */ > +static inline void pvector_publish(struct pvector *pvec) > { > - if (cpvec->temp) { > - cpvector_publish__(cpvec); > + if (pvec->temp) { > + pvector_publish__(pvec); > } > } > > diff --git a/tests/test-classifier.c b/tests/test-classifier.c > index cdd83f0..3a275b4 100644 > --- a/tests/test-classifier.c > +++ b/tests/test-classifier.c > @@ -1,5 +1,5 @@ > /* > - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, > Inc. > + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. > * > * Licensed under the Apache License, Version 2.0 (the "License"); > * you may not use this file except in compliance with the License. > @@ -472,12 +472,12 @@ destroy_classifier(struct classifier *cls) > } > > static void > -cpvector_verify(const struct cpvector *cpvec) > +pvector_verify(const struct pvector *pvec) > { > void *ptr OVS_UNUSED; > int prev_priority = INT_MAX; > > - CPVECTOR_FOR_EACH (ptr, cpvec) { > + PVECTOR_FOR_EACH (ptr, pvec) { > int priority = cursor__.vector[cursor__.entry_idx].priority; > if (priority > prev_priority) { > ovs_abort(0, "Priority vector is out of order (%u > %u)", > @@ -533,7 +533,7 @@ check_tables(const struct classifier *cls, int > n_tables, int n_rules, > int found_visible_but_removable = 0; > int found_rules2 = 0; > > - cpvector_verify(&cls->subtables); > + pvector_verify(&cls->subtables); > CMAP_FOR_EACH (table, cmap_node, &cls->subtables_map) { > const struct cls_match *head; > int max_priority = INT_MIN; > @@ -543,7 +543,7 @@ check_tables(const struct classifier *cls, int > n_tables, int n_rules, > const struct cls_subtable *iter; > > /* Locate the subtable from 'subtables'. */ > - CPVECTOR_FOR_EACH (iter, &cls->subtables) { > + PVECTOR_FOR_EACH (iter, &cls->subtables) { > if (iter == table) { > if (found) { > ovs_abort(0, "Subtable %p duplicated in 'subtables'.", > @@ -647,7 +647,7 @@ check_tables(const struct classifier *cls, int > n_tables, int n_rules, > } > > assert(found_tables == cmap_count(&cls->subtables_map)); > - assert(found_tables == cpvector_count(&cls->subtables)); > + assert(found_tables == pvector_count(&cls->subtables)); > assert(n_tables == -1 || n_tables == found_tables_with_visible_ > rules); > assert(n_rules == -1 || found_rules == n_rules + found_invisible); > assert(n_dups == -1 || found_dups == n_dups); > -- > 2.1.4 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev