+/* Internal routine to handle pthread mutex lock operation. This is in the PFZ.
+ * %edi == ptr to LVAL/UVAL pair
+ * %esi == ptr to argument list on stack
+ * %ebx == preempion pending flag (kernel sets nonzero if we should preempt)
+ */
+COMMPAGE_FUNCTION_START(pfz_mutex_lock, 32, 4)
+ pushl %ebp // set up frame for backtrace
+ movl %esp,%ebp
+1:
+ movl 16(%esi),%ecx // get mask (ie, PTHRW_EBIT etc)
+2:
+ movl PTHRW_LVAL(%edi),%eax // get mutex LVAL
+ testl %eax,%ecx // is mutex available?
+ jnz 5f // no
+
+ /* lock is available (if we act fast) */
+ lea PTHRW_INC(%eax),%edx // copy original lval and bump sequence count
+ orl $PTHRW_EBIT, %edx // set EBIT
+ lock
+ cmpxchgl %edx,PTHRW_LVAL(%edi) // try to acquire lock for real
+ 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)
+ jmp 1b // loop to try again
+
+ /* we acquired the mutex */
+4:
+ movl 20(%esi),%eax // get ptr to TID field of mutex
+ movl 8(%esi),%ecx // get 64-bit mtid
+ movl 12(%esi),%edx
+ movl %ecx,0(%eax) // store my TID in mutex structure
+ movl %edx,4(%eax)
+ movl $PTHRW_STATUS_ACQUIRED,%eax
+ popl %ebp
+ ret
+
+ /* cannot acquire mutex, so update seq count, set "W", and block in kernel */
+ /* this is where we cannot tolerate preemption or being killed */
+5:
+ lea PTHRW_INC(%eax),%edx // copy original lval and bump sequence count
+ orl $PTHRW_WBIT, %edx // set WBIT
+ lock
+ cmpxchgl %edx,PTHRW_LVAL(%edi) // try to update lock status atomically
+ jnz 3b // failed
+ movl 20(%esi),%eax // get ptr to TID field of mutex
+ pushl 4(%esi) // arg 5: flags from arg list
+ pushl 4(%eax) // arg 4: tid field from mutex
+ pushl 0(%eax)
+ pushl PTHRW_UVAL(%edi) // arg 3: uval field from mutex
+ pushl %edx // arg 2: new value of mutex lval field
+ pushl %edi // arg 1: ptr to LVAL/UVAL pair in mutex
+ call 6f // make ksyn_mlwait call
+ jc 6f // immediately reissue syscall if error
+ movl 24(%esi),%edx // get ptr to syscall_return arg
+ movl %eax,(%edx) // save syscall return value
+ movl $PTHRW_STATUS_SYSCALL,%eax // we had to make syscall
+ addl $28,%esp // pop off syscall args and return address
+ popl %ebp // pop off frame ptr