+#!/usr/local/bin/luatrace -s
+
+trace_codename = function(codename, callback)
+ local debugid = trace.debugid(codename)
+ if debugid ~= 0 then
+ trace.single(debugid,callback)
+ else
+ printf("WARNING: Cannot locate debugid for '%s'\n", codename)
+ end
+end
+
+initial_timestamp = 0
+get_prefix = function(buf)
+ if initial_timestamp == 0 then
+ initial_timestamp = buf.timestamp
+ end
+ local secs = trace.convert_timestamp_to_nanoseconds(buf.timestamp - initial_timestamp) / 1000000000
+
+ local prefix
+ if trace.debugid_is_start(buf.debugid) then
+ prefix = "→"
+ elseif trace.debugid_is_end(buf.debugid) then
+ prefix = "←"
+ else
+ prefix = "↔"
+ end
+
+ local proc
+ proc = buf.command
+
+ return string.format("%s %6.9f %-17s [%05d.%06x] %-24s",
+ prefix, secs, proc, buf.pid, buf.threadid, buf.debugname)
+end
+
+decode_lval = function(lval)
+ local kbit = " "
+ if lval & 0x1 ~= 0 then
+ kbit = "K"
+ end
+ local ebit = " "
+ if lval & 0x2 ~= 0 then
+ ebit = "E"
+ end
+ local wbit = " "
+ if lval & 0x4 ~= 0 then
+ wbit = "W"
+ end
+
+ local count = lval >> 8
+ return string.format("[0x%06x, %s%s%s]", count, wbit, ebit, kbit)
+end
+
+decode_sval = function(sval)
+ local sbit = " "
+ if sval & 0x1 ~= 0 then
+ sbit = "S"
+ end
+ local ibit = " "
+ if sval & 0x2 ~= 0 then
+ ibit = "I"
+ end
+
+ local count = sval >> 8
+ return string.format("[0x%06x, %s%s]", count, ibit, sbit)
+end
+
+trace_codename("psynch_mutex_lock_updatebits", function(buf)
+ local prefix = get_prefix(buf)
+ if buf[4] == 0 then
+ printf("%s\tupdated lock bits, pre-kernel (addr: 0x%016x, oldlval: %s, newlval: %s)\n", prefix, buf[1], decode_lval(buf[2]), decode_lval(buf[3]))
+ else
+ printf("%s\tupdated lock bits, post-kernel (addr: 0x%016x, oldlval: %s, newlval: %s)\n", prefix, buf[1], decode_lval(buf[2]), decode_lval(buf[3]))
+ end
+end)
+
+trace_codename("psynch_mutex_unlock_updatebits", function(buf)
+ local prefix = get_prefix(buf)
+ printf("%s\tupdated unlock bits (addr: 0x%016x, oldlval: %s, newlval: %s)\n", prefix, buf[1], decode_lval(buf[2]), decode_lval(buf[3]))
+end)
+
+trace_codename("psynch_mutex_ulock", function(buf)
+ local prefix = get_prefix(buf)
+
+ if trace.debugid_is_start(buf.debugid) then
+ printf("%s\tlock busy, waiting in kernel (addr: 0x%016x, lval: %s, sval: %s, owner_tid: 0x%x)\n",
+ prefix, buf[1], decode_lval(buf[2]), decode_sval(buf[3]), buf[4])
+ elseif trace.debugid_is_end(buf.debugid) then
+ printf("%s\tlock acquired from kernel (addr: 0x%016x, updated bits: %s)\n",
+ prefix, buf[1], decode_lval(buf[2]))
+ else
+ printf("%s\tlock taken, uncontended (addr: 0x%016x, lval: %s, sval: %s)\n",
+ prefix, buf[1], decode_lval(buf[2]), decode_sval(buf[3]))
+ end
+end)
+
+trace_codename("psynch_mutex_utrylock_failed", function(buf)
+ local prefix = get_prefix(buf)
+ printf("%s\tmutex trybusy addr: 0x%016x lval: %s sval: %s owner: 0x%x\n", prefix, buf[1], decode_lval(buf[2]), decode_sval(buf[3]), buf[4])
+end)
+
+trace_codename("psynch_mutex_uunlock", function(buf)
+ local prefix = get_prefix(buf)
+
+ if trace.debugid_is_start(buf.debugid) then
+ printf("%s\tunlock, signalling kernel waiters (addr: 0x%016x, lval: %s, sval: %s, owner_tid: 0x%x)\n",
+ prefix, buf[1], decode_lval(buf[2]), decode_sval(buf[3]), buf[4])
+ elseif trace.debugid_is_end(buf.debugid) then
+ printf("%s\tunlock, waiters signalled (addr: 0x%016x, updated bits: %s)\n",
+ prefix, buf[1], decode_lval(buf[2]))
+ else
+ printf("%s\tunlock, no kernel waiters (addr: 0x%016x, lval: %s, sval: %s)\n",
+ prefix, buf[1], decode_lval(buf[2]), decode_sval(buf[3]))
+ end
+end)
+
+-- The trace codes we need aren't enabled by default
+darwin.sysctlbyname("kern.pthread_debug_tracing", 1)
+completion_handler = function()
+ darwin.sysctlbyname("kern.pthread_debug_tracing", 0)
+end
+trace.set_completion_handler(completion_handler)