Recently I was trying to understand how asynchronous preemption is 
implemented in Go 1.14 and
basically figured out the call chain.

    sysmon
    ↓
    retake
    ↓
    preemptone
    ↓
    preemptM
    ↓
    signalM(mp, sigPreempt)    //send SIGURG to mp
    ↓
    doSigPreempt(signal handler)   //if isAsyncSafePoint returns true, it 
will go on to preempt
    ↓
    ctxt.pushCall(funcPC(asyncPreempt))
    ↓
    asyncPreempt
    ↓ 
    asyncPreempt2
    ↓ 
    mcall(preemptPark) or mcall(gopreempt_m)

And I wrote a simple program to verify:
```Go
func main() {
        var wg sync.WaitGroup
        wg.Add(30)
        for i := 0; i < 30; i++ {
               go func() {
                       defer wg.Done()
                       t := 0
                       for i := 0; i < 1e8; i++ {
                              t += 2
                       }
                 }()
         }
         wg.Wait()
}
```

As we know general purpose registers RAX/RBX/... are not included in 
goroutine context.

```
type runtime.gobuf struct {
uintptr sp;
uintptr pc;
runtime.guintptr g;
void *ctxt;
runtime/internal/sys.Uintreg ret;
uintptr lr;
uintptr bp;
}
```

So when there are temporary values in these registers, it should not be 
good time to preempt. In following example, the loop takes enough long  
time to make it be preempted.

`t+=2` and `i++` use RAX as temporay register so it should't 
be asynchronous safe point. 

My problem is how Go judges which instruction is preemptable? is it 
determined at compile time?

```
//from disassemble /sr main.main.func1
17 t := 0
0x000000000047be7d <+93>: 48 c7 44 24 08 00 00 00 00 movq $0x0,0x8(%rsp)

18 for i:=0; i < 1e8; i++ {
0x000000000047be86 <+102>: 48 c7 44 24 10 00 00 00 00 movq $0x0,0x10(%rsp)
0x000000000047be8f <+111>: eb 00 jmp 0x47be91 <main.main.func1+113>
0x000000000047be91 <+113>: 48 81 7c 24 10 00 ca 9a 3b cmpq 
$0x3b9aca00,0x10(%rsp)
0x000000000047be9a <+122>: 7c 02 jl 0x47be9e <main.main.func1+126>
0x000000000047be9c <+124>: eb 1f jmp 0x47bebd <main.main.func1+157>

19 t += 2
0x000000000047be9e <+126>: 48 8b 44 24 08 mov 0x8(%rsp),%rax
0x000000000047bea3 <+131>: 48 83 c0 02 add $0x2,%rax
0x000000000047bea7 <+135>: 48 89 44 24 08 mov %rax,0x8(%rsp)
0x000000000047beac <+140>: eb 00 jmp 0x47beae <main.main.func1+142>

18 for i:=0; i < 1e8; i++ {
0x000000000047beae <+142>: 48 8b 44 24 10 mov 0x10(%rsp),%rax
0x000000000047beb3 <+147>: 48 ff c0 inc %rax
0x000000000047beb6 <+150>: 48 89 44 24 10 mov %rax,0x10(%rsp)
0x000000000047bebb <+155>: eb d4 jmp 0x47be91 <main.main.func1+113>
```


-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/eef5058e-1473-4b9a-893d-a8cfe6e0b6a4n%40googlegroups.com.

Reply via email to