+
+/* Internal routine to handle pthread mutex lock operation. This is in the PFZ.
+ * %rdi = lvalp
+ * %esi = flags
+ * %rdx = mtid
+ * %ecx = mask
+ * %r8 = tidp
+ * %r9 = &syscall_return
+ * %ebx = preempion pending flag (kernel sets nonzero if we should preempt)
+ */
+COMMPAGE_FUNCTION_START(pfz_mutex_lock_64, 64, 4)
+ pushq %rbp // set up frame for backtrace
+ movq %rsp,%rbp
+1:
+ movl PTHRW_LVAL(%rdi),%eax // get old lval from mutex
+2:
+ testl %eax,%ecx // can we acquire the lock?
+ jnz 5f // no
+
+ /* lock is available (if we act fast) */
+ lea PTHRW_INC(%rax),%r11 // copy original lval and bump sequence count
+ orl $PTHRW_EBIT, %r11d // set EBIT
+ lock
+ cmpxchgl %r11d,PTHRW_LVAL(%rdi) // try to acquire lock
+ jz 4f // got it
+3:
+ testl %ebx,%ebx // kernel trying to preempt us?
+ jz 2b // no, so loop and try again
+ COMMPAGE_CALL(_COMM_PAGE_PREEMPT,_COMM_PAGE_PFZ_MUTEX_LOCK,pfz_mutex_lock_64)
+ jmp 1b // loop to try again
+
+ /* we acquired the mutex */
+4:
+ movq %rdx,(%r8) // store mtid in mutex structure
+ movl $PTHRW_STATUS_ACQUIRED,%eax
+ popq %rbp
+ ret
+
+ /* cannot acquire mutex, so update seq count and block in kernel */
+ /* this is where we cannot tolerate preemption or being killed */
+5:
+ lea PTHRW_INC(%rax),%r11 // copy original lval and bump sequence count
+ orl $PTHRW_WBIT, %r11d // set WBIT
+ lock
+ cmpxchgl %r11d,PTHRW_LVAL(%rdi) // try to update lock status atomically
+ jnz 3b // failed
+ movq (%r8),%r10 // arg 4: tid field from mutex [NB: passed in R10]
+ movl %esi,%r8d // arg 5: flags from arg list
+ movl PTHRW_UVAL(%rdi),%edx // arg 3: uval field from mutex
+ movl %r11d,%esi // arg 2: new value of mutex lval field
+ // arg 1: LVAL/UVAL ptr already in %rdi
+6:
+ movl $(SYSCALL_CONSTRUCT_UNIX(KSYN_MLWAIT)),%eax
+ pushq %rdx // some syscalls destroy %rdx so save it
+ xorl %ebx,%ebx // clear preemption flag
+ syscall
+ popq %rdx // restore in case we need to re-execute syscall
+ jc 6b // immediately re-execute syscall if error
+ movl %eax,(%r9) // store kernel return value
+ movl $PTHRW_STATUS_SYSCALL,%eax // we made syscall
+ popq %rbp