diff options
author | Maciej Piechotka <uzytkownik2@gmail.com> | 2014-03-01 21:58:41 +0100 |
---|---|---|
committer | Maciej Piechotka <uzytkownik2@gmail.com> | 2014-03-01 21:58:41 +0100 |
commit | eed6c917cfc42a2cf880a08100420ab71d365046 (patch) | |
tree | 789dcc3569757bf2e33b8a891f105bef84d4f708 | |
parent | 00919a213195a661828b4d6dc68d4b26e8e105aa (diff) | |
download | libgee-eed6c917cfc42a2cf880a08100420ab71d365046.tar.gz |
Fix case of releasing lock-free resources during the global cleanup
-rw-r--r-- | gee/hazardpointer.vala | 31 |
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); } } |