diff --git a/src/hx/Telemetry.cpp b/src/hx/Telemetry.cpp index 3dd017322..002ba54e7 100644 --- a/src/hx/Telemetry.cpp +++ b/src/hx/Telemetry.cpp @@ -472,8 +472,8 @@ void hx::Telemetry::HXTAllocation(void* obj, size_t inSize, const char* type) // for every external call, hashes for every SDL event (Lime's // ExternalInterface.external_handler()), etc #ifndef HXCPP_PROFILE_EXTERNS - if (stack->getCurrentStackFrame()->position->className==hx::EXTERN_CLASS_NAME) { - alloc_mutex.unlock(); + // alloc_mutex is not locked yet, and an empty stack has no current frame. + if (stack->getDepth() > 0 && stack->getCurrentStackFrame()->position->className==hx::EXTERN_CLASS_NAME) { return; } #endif diff --git a/test/telemetry/TestAllocations.hx b/test/telemetry/TestAllocations.hx new file mode 100644 index 000000000..604385daa --- /dev/null +++ b/test/telemetry/TestAllocations.hx @@ -0,0 +1,46 @@ +import sys.thread.Lock; +import sys.thread.Thread; +import utest.Assert; +import utest.Test; + +class TestAllocations extends Test +{ + // Keeps what the worker thread allocates reachable, so it is never + // reclaimed after that thread's telemetry has been deleted + static var tracked:Array = []; + + // HXTAllocation skips allocations made inside a CFFI call. Skipping one + // must leave alloc_mutex usable, or the next thread to lock it blocks. + function testExternAllocationLeavesAllocationLockUsable() + { + var allocated = new Lock(); + Thread.create(function() { + untyped __global__.__hxcpp_hxt_start_telemetry(true, true); + tracked.push(allocateInExternFrame()); + tracked.push([4, 5, 6]); + allocated.release(); + }); + Assert.isTrue(allocated.wait(10.0)); + + // Stashing locks alloc_mutex, even without allocation tracking + var stashed = new Lock(); + Thread.create(function() { + untyped __global__.__hxcpp_hxt_stash_telemetry(); + stashed.release(); + }); + Assert.isTrue(stashed.wait(10.0)); + } + + // Primitives loaded with cpp.Lib.load run inside a frame like this one + // (see ExternalPrimitive in src/hx/Lib.cpp), so what they allocate takes + // the extern path in HXTAllocation + static function allocateInExternFrame():Array + { + var result:Array = null; + untyped __cpp__('{ + HX_STACK_FRAME(::hx::EXTERN_CLASS_NAME, "cffi", 0, "extern::cffi", __FILE__, __LINE__, 0) + {0} = ::Array_obj< int >::__new(3, 3); + }', result); + return result; + } +} diff --git a/test/telemetry/TestMain.hx b/test/telemetry/TestMain.hx index f13d9e28a..07aecc941 100644 --- a/test/telemetry/TestMain.hx +++ b/test/telemetry/TestMain.hx @@ -3,6 +3,6 @@ package; class TestMain { static function main(){ - utest.UTest.run([ new TestBasic() ]); + utest.UTest.run([ new TestBasic(), new TestAllocations() ]); } }