Use atomic op for setting cached host obj.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/52b1f981 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/52b1f981 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/52b1f981 Branch: refs/heads/master Commit: 52b1f981408a7820ad0384593d4c1c61a147e7bb Parents: 2dab35a Author: Marvin Humphrey <[email protected]> Authored: Sun Feb 8 21:02:15 2015 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Sun Feb 8 21:02:15 2015 -0800 ---------------------------------------------------------------------- runtime/perl/xs/XSBind.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/52b1f981/runtime/perl/xs/XSBind.c ---------------------------------------------------------------------- diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 659ab35..d29d1ec 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -27,6 +27,7 @@ #include "Clownfish/Method.h" #include "Clownfish/Test/TestThreads.h" #include "Clownfish/TestHarness/TestBatchRunner.h" +#include "Clownfish/Util/Atomic.h" #include "Clownfish/Util/StringHelper.h" #include "Clownfish/Util/NumberUtils.h" #include "Clownfish/Util/Memory.h" @@ -645,9 +646,28 @@ S_lazy_init_host_obj(cfish_Obj *self) { * will assume responsibility for maintaining the refcount. ref.host_obj * starts off with a refcount of 1, so we need to transfer any refcounts * in excess of that. */ - size_t old_refcount = self->ref.count; - self->ref.host_obj = inner_obj; - SvREFCNT(inner_obj) += (old_refcount >> XSBIND_REFCOUNT_SHIFT) - 1; + cfish_ref_t old_ref = self->ref; + size_t excess = (old_ref.count >> XSBIND_REFCOUNT_SHIFT) - 1; + SvREFCNT(inner_obj) += excess; + + // Overwrite refcount with host object. + cfish_Class *klass = self->klass; + if (SI_immortal(klass) || SI_threadsafe_but_not_immortal(klass)) { + if (!cfish_Atomic_cas_ptr((void**)&self->ref, old_ref.host_obj, inner_obj)) { + // Another thread beat us to it. Now we have a Perl object to defuse. + SvSTASH_set(inner_obj, NULL); + SvREFCNT_dec((SV*)stash); + SvOBJECT_off(inner_obj); + SvREFCNT(inner_obj) -= excess; + SvREFCNT_dec(inner_obj); +#if (PERL_VERSION <= 16) + PL_sv_objcount--; +#endif + } + } + else { + self->ref.host_obj = inner_obj; + } } uint32_t
