Last active
October 22, 2015 14:46
-
-
Save djwatson/9c268681a0dfa797990c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was actually tested with a migration signal, but should be similar with gs.