Skip to content

Instantly share code, notes, and snippets.

@djwatson
Last active October 22, 2015 14:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save djwatson/9c268681a0dfa797990c to your computer and use it in GitHub Desktop.
Save djwatson/9c268681a0dfa797990c to your computer and use it in GitHub Desktop.
int migrate_cmpxchgcheck(intptr_t *ptr, intptr_t old, intptr_t new,
intptr_t *checkold, intptr_t checknew,
unsigned long lockval, int cpu) {
/* The preemption lock needs to be tagged:
* our tid in 32 bits, sequence counter in
* other 32 bits to avoid aba on calling tkill
*/
unsigned long newlockval = cached_tid | ((lockval+1) & 0xFFFFFFFF);
asm volatile goto(
"1:\n\t"
/* Verify that we are on the same cpu */
"cmp %7, %6\n\t"
"jne %l[restart]\n\t"
/* Try to grab the preemption lock */
"movq %5, %%rax\n\t"
"cmpxchgq %4, %3\n\t"
"jnz %l[restart]\n\t"
/* Verify any reads */
"cmp %9, %8\n\t"
"jne %l[restart]\n\t"
/* Cmpxchg the new list head */
"movq %2, %%rax\n\t"
"cmpxchgq %1, %0\n\t"
"2:\n\t"
/* We need to check the cmpxchg result -
* but we also want to optimistically
* reset the preemption lock. If we miss resetting the lock,
* just let the next pop call do it. */
"jnz %l[restart]\n\t"
"3:\n\t"
"movq %10, %3\n\t"
"jmp %l[done]\n\t"
"4:\n\t"
"jnz %l[restart]\n\t"
"5:\n\t"
".pushsection __percpu_lock_fault, \"a\"\n\t"
".quad 4b, 5b, 4b\n\t"
".quad 3b, 4b, 5b\n\t"
".quad 2b, 3b, 4b\n\t"
".quad 1b, 2b, %l[restart]\n\t"
".popsection\n\t"
:
: "m" (*ptr), "r" (new), "r" (old),
"m" (preempt_lock), "r" (newlockval), "r" (lockval),
"r" (cpu), "m" (cpu_id),
"r" (checknew), "m" (*checkold),
"r" ((preempt_lock[cpu * 8]+1) & 0xFFFFFFFF)
: "cc", "rax", "memory"
: restart, done);
done:
return 0;
restart:
return 1;
}
unsigned long migrate_preempt_lock(int cpu)
{
unsigned long lockval = preempt_lock[cpu * 8];
if ((lockval >> 32) != 0)
syscall(SYS_tkill, lockval >> 32, SIGUSR1);
return lockval;
}
static void sighandler(int sig, siginfo_t *siginfo, void *data)
{
unw_context_t context;
unw_getcontext(&context);
unw_cursor_t cursor;
unw_init_local(&cursor, &context);
while (unw_step(&cursor) > 0) {
unw_word_t ip;
unw_get_reg(&cursor, UNW_REG_IP, &ip);
void* newip = get_fault_restart_address((void *) ip);
if (newip != NULL) {
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)newip);
}
}
}
@djwatson
Copy link
Author

This was actually tested with a migration signal, but should be similar with gs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment