summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Piechotka <uzytkownik2@gmail.com>2014-03-01 21:58:41 +0100
committerMaciej Piechotka <uzytkownik2@gmail.com>2014-03-01 21:58:41 +0100
commiteed6c917cfc42a2cf880a08100420ab71d365046 (patch)
tree789dcc3569757bf2e33b8a891f105bef84d4f708
parent00919a213195a661828b4d6dc68d4b26e8e105aa (diff)
downloadlibgee-eed6c917cfc42a2cf880a08100420ab71d365046.tar.gz
Fix case of releasing lock-free resources during the global cleanup
-rw-r--r--gee/hazardpointer.vala31
1 files changed, 24 insertions, 7 deletions
diff --git a/gee/hazardpointer.vala b/gee/hazardpointer.vala
index 7513751..937e08a 100644
--- a/gee/hazardpointer.vala
+++ b/gee/hazardpointer.vala
@@ -452,15 +452,22 @@ public class Gee.HazardPointer<G> { // FIXME: Make it a struct
switch (self) {
case HELPER_THREAD:
new Thread<bool> ("<<libgee hazard pointer>>", () => {
+ Context ctx = new Context (Policy.TRY_FREE);
while (true) {
Thread.yield ();
- attempt_free ();
+ pull_from_queue (ctx._to_free, ctx._to_free.is_empty);
+ ctx.try_free ();
}
});
break;
case MAIN_LOOP:
+ _global_to_free = new ArrayList<FreeNode *> ();
Idle.add (() => {
- attempt_free ();
+ Context ctx = new Context (Policy.TRY_FREE);
+ swap (ref _global_to_free, ref ctx._to_free);
+ pull_from_queue (ctx._to_free, false);
+ ctx.try_free ();
+ swap (ref _global_to_free, ref ctx._to_free);
return true;
}, Priority.LOW);
break;
@@ -469,6 +476,12 @@ public class Gee.HazardPointer<G> { // FIXME: Make it a struct
}
}
+ private static void swap<T>(ref T a, ref T b) {
+ T tmp = (owned)a;
+ a = (owned)b;
+ b = (owned)tmp;
+ }
+
/**
* Ensures that helper methods are started.
*/
@@ -482,21 +495,25 @@ public class Gee.HazardPointer<G> { // FIXME: Make it a struct
_queue = new LinkedList<ArrayList<FreeNode *>> ();
// Hack to not lie about successfull setting policy
policy = AtomicInt.add (ref release_policy, (int)(1 << (sizeof(int) * 8 - 1)));
- _global_to_free = new ArrayList<FreeNode *> ();
start ((ReleasePolicy) policy);
}
_queue_mutex.unlock ();
}
}
- private static inline void attempt_free () {
- if (_queue_mutex.trylock ()) {
+ private static inline void pull_from_queue (Collection<FreeNode *> to_free, bool do_lock) {
+ bool locked = do_lock;
+ if (do_lock) {
+ _queue_mutex.lock ();
+ } else {
+ locked = _queue_mutex.trylock ();
+ }
+ if (locked) {
Collection<ArrayList<FreeNode *>> temp = new ArrayList<ArrayList<FreeNode *>> ();
_queue.drain (temp);
_queue_mutex.unlock ();
- temp.foreach ((x) => {_global_to_free.add_all (x); return true;});
+ temp.foreach ((x) => {to_free.add_all (x); return true;});
}
- try_free (_global_to_free);
}
}