Mir
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
basic_observers.h
Go to the documentation of this file.
1 /*
2  * Copyright © 2014 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored By: Alan Griffiths <alan@octopull.co.uk>
17  */
18 
19 #ifndef MIR_BASIC_OBSERVERS_H_
20 #define MIR_BASIC_OBSERVERS_H_
21 
23 
24 #include <atomic>
25 #include <memory>
26 
27 namespace mir
28 {
29 template<class Observer>
31 {
32 protected:
33  void add(std::shared_ptr<Observer> const& observer);
34  void remove(std::shared_ptr<Observer> const& observer);
35  void for_each(std::function<void(std::shared_ptr<Observer> const& observer)> const& f);
36 
37 private:
38  struct ListItem
39  {
40  ListItem() {}
42  std::shared_ptr<Observer> observer;
43  std::atomic<ListItem*> next{nullptr};
44 
45  ~ListItem() { delete next.load(); }
46  } head;
47 };
48 
49 template<class Observer>
51  std::function<void(std::shared_ptr<Observer> const& observer)> const& f)
52 {
53  ListItem* current_item = &head;
54 
55  while (current_item)
56  {
57  RecursiveReadLock lock{current_item->mutex};
58 
59  // We need to take a copy in case we recursively remove during call
60  if (auto const copy_of_observer = current_item->observer) f(copy_of_observer);
61 
62  current_item = current_item->next;
63  }
64 }
65 
66 template<class Observer>
67 void BasicObservers<Observer>::add(std::shared_ptr<Observer> const& observer)
68 {
69  ListItem* current_item = &head;
70 
71  do
72  {
73  // Note: we release the read lock to avoid two threads calling add at
74  // the same time mutually blocking the other's upgrade to write lock.
75  {
76  RecursiveReadLock lock{current_item->mutex};
77  if (current_item->observer) continue;
78  }
79 
80  RecursiveWriteLock lock{current_item->mutex};
81 
82  if (!current_item->observer)
83  {
84  current_item->observer = observer;
85  return;
86  }
87  }
88  while (current_item->next && (current_item = current_item->next));
89 
90  // No empty Items so append a new one
91  auto new_item = new ListItem;
92  new_item->observer = observer;
93 
94  for (ListItem* expected{nullptr};
95  !current_item->next.compare_exchange_weak(expected, new_item);
96  expected = nullptr)
97  {
98  if (expected) current_item = expected;
99  }
100 }
101 
102 template<class Observer>
103 void BasicObservers<Observer>::remove(std::shared_ptr<Observer> const& observer)
104 {
105  ListItem* current_item = &head;
106 
107  do
108  {
109  {
110  RecursiveReadLock lock{current_item->mutex};
111  if (current_item->observer != observer) continue;
112  }
113 
114  RecursiveWriteLock lock{current_item->mutex};
115 
116  if (current_item->observer == observer)
117  {
118  current_item->observer.reset();
119  return;
120  }
121  }
122  while ((current_item = current_item->next));
123 }
124 }
125 
126 #endif /* MIR_BASIC_OBSERVERS_H_ */
All things Mir.
Definition: aging_buffer.h:24
Definition: recursive_read_write_mutex.h:56
a recursive read-write mutex.
Definition: recursive_read_write_mutex.h:31
void for_each(std::function< void(std::shared_ptr< Observer > const &observer)> const &f)
Definition: basic_observers.h:50
Definition: basic_observers.h:30
void remove(std::shared_ptr< Observer > const &observer)
Definition: basic_observers.h:103
Definition: recursive_read_write_mutex.h:66
void add(std::shared_ptr< Observer > const &observer)
Definition: basic_observers.h:67

Copyright © 2012,2013 Canonical Ltd.
Generated on Fri Oct 10 14:07:14 UTC 2014