1*2810ac1bSKiyoung Kimpackage psx 2*2810ac1bSKiyoung Kim 3*2810ac1bSKiyoung Kimimport ( 4*2810ac1bSKiyoung Kim "runtime" 5*2810ac1bSKiyoung Kim "sync" 6*2810ac1bSKiyoung Kim "syscall" 7*2810ac1bSKiyoung Kim "testing" 8*2810ac1bSKiyoung Kim) 9*2810ac1bSKiyoung Kim 10*2810ac1bSKiyoung Kimfunc TestSyscall3(t *testing.T) { 11*2810ac1bSKiyoung Kim want := syscall.Getpid() 12*2810ac1bSKiyoung Kim if got, _, err := Syscall3(syscall.SYS_GETPID, 0, 0, 0); err != 0 { 13*2810ac1bSKiyoung Kim t.Errorf("failed to get PID via libpsx: %v", err) 14*2810ac1bSKiyoung Kim } else if int(got) != want { 15*2810ac1bSKiyoung Kim t.Errorf("pid mismatch: got=%d want=%d", got, want) 16*2810ac1bSKiyoung Kim } 17*2810ac1bSKiyoung Kim if got, _, err := Syscall3(syscall.SYS_CAPGET, 0, 0, 0); err != 14 { 18*2810ac1bSKiyoung Kim t.Errorf("malformed capget returned %d: %v (want 14: %v)", err, err, syscall.Errno(14)) 19*2810ac1bSKiyoung Kim } else if ^got != 0 { 20*2810ac1bSKiyoung Kim t.Errorf("malformed capget did not return -1, got=%d", got) 21*2810ac1bSKiyoung Kim } 22*2810ac1bSKiyoung Kim} 23*2810ac1bSKiyoung Kim 24*2810ac1bSKiyoung Kimfunc TestSyscall6(t *testing.T) { 25*2810ac1bSKiyoung Kim want := syscall.Getpid() 26*2810ac1bSKiyoung Kim if got, _, err := Syscall6(syscall.SYS_GETPID, 0, 0, 0, 0, 0, 0); err != 0 { 27*2810ac1bSKiyoung Kim t.Errorf("failed to get PID via libpsx: %v", err) 28*2810ac1bSKiyoung Kim } else if int(got) != want { 29*2810ac1bSKiyoung Kim t.Errorf("pid mismatch: got=%d want=%d", got, want) 30*2810ac1bSKiyoung Kim } 31*2810ac1bSKiyoung Kim if got, _, err := Syscall6(syscall.SYS_CAPGET, 0, 0, 0, 0, 0, 0); err != 14 { 32*2810ac1bSKiyoung Kim t.Errorf("malformed capget errno %d: %v (want 14: %v)", err, err, syscall.Errno(14)) 33*2810ac1bSKiyoung Kim } else if ^got != 0 { 34*2810ac1bSKiyoung Kim t.Errorf("malformed capget did not return -1, got=%d", got) 35*2810ac1bSKiyoung Kim } 36*2810ac1bSKiyoung Kim} 37*2810ac1bSKiyoung Kim 38*2810ac1bSKiyoung Kim// killAThread locks the goroutine to a thread and exits. This has the 39*2810ac1bSKiyoung Kim// effect of making the go runtime terminate the thread. 40*2810ac1bSKiyoung Kimfunc killAThread(c <-chan struct{}) { 41*2810ac1bSKiyoung Kim runtime.LockOSThread() 42*2810ac1bSKiyoung Kim <-c 43*2810ac1bSKiyoung Kim} 44*2810ac1bSKiyoung Kim 45*2810ac1bSKiyoung Kim// Test state is mirrored as expected. 46*2810ac1bSKiyoung Kimfunc TestShared(t *testing.T) { 47*2810ac1bSKiyoung Kim const prGetKeepCaps = 7 48*2810ac1bSKiyoung Kim const prSetKeepCaps = 8 49*2810ac1bSKiyoung Kim 50*2810ac1bSKiyoung Kim var wg sync.WaitGroup 51*2810ac1bSKiyoung Kim 52*2810ac1bSKiyoung Kim newTracker := func() chan<- uintptr { 53*2810ac1bSKiyoung Kim ch := make(chan uintptr) 54*2810ac1bSKiyoung Kim go func() { 55*2810ac1bSKiyoung Kim runtime.LockOSThread() 56*2810ac1bSKiyoung Kim defer wg.Done() 57*2810ac1bSKiyoung Kim tid := syscall.Gettid() 58*2810ac1bSKiyoung Kim for { 59*2810ac1bSKiyoung Kim if _, ok := <-ch; !ok { 60*2810ac1bSKiyoung Kim break 61*2810ac1bSKiyoung Kim } 62*2810ac1bSKiyoung Kim val, ok := <-ch 63*2810ac1bSKiyoung Kim if !ok { 64*2810ac1bSKiyoung Kim break 65*2810ac1bSKiyoung Kim } 66*2810ac1bSKiyoung Kim got, _, e := Syscall3(syscall.SYS_PRCTL, prGetKeepCaps, 0, 0) 67*2810ac1bSKiyoung Kim if e != 0 { 68*2810ac1bSKiyoung Kim t.Fatalf("[%d] psx:prctl(GET_KEEPCAPS) ?= %d failed: %v", tid, val, syscall.Errno(e)) 69*2810ac1bSKiyoung Kim } 70*2810ac1bSKiyoung Kim if got != val { 71*2810ac1bSKiyoung Kim t.Errorf("[%d] bad keepcaps value: got=%d, want=%d", tid, got, val) 72*2810ac1bSKiyoung Kim } 73*2810ac1bSKiyoung Kim if _, ok := <-ch; !ok { 74*2810ac1bSKiyoung Kim break 75*2810ac1bSKiyoung Kim } 76*2810ac1bSKiyoung Kim } 77*2810ac1bSKiyoung Kim }() 78*2810ac1bSKiyoung Kim return ch 79*2810ac1bSKiyoung Kim } 80*2810ac1bSKiyoung Kim 81*2810ac1bSKiyoung Kim var tracked []chan<- uintptr 82*2810ac1bSKiyoung Kim for i := 0; i <= 10; i++ { 83*2810ac1bSKiyoung Kim val := uintptr(i & 1) 84*2810ac1bSKiyoung Kim if _, _, e := Syscall3(syscall.SYS_PRCTL, prSetKeepCaps, val, 0); e != 0 { 85*2810ac1bSKiyoung Kim t.Fatalf("[%d] psx:prctl(SET_KEEPCAPS, %d) failed: %v", i, i&1, syscall.Errno(e)) 86*2810ac1bSKiyoung Kim } 87*2810ac1bSKiyoung Kim wg.Add(1) 88*2810ac1bSKiyoung Kim tracked = append(tracked, newTracker()) 89*2810ac1bSKiyoung Kim for _, ch := range tracked { 90*2810ac1bSKiyoung Kim ch <- 2 // start serialization. 91*2810ac1bSKiyoung Kim ch <- val // definitely written after change. 92*2810ac1bSKiyoung Kim ch <- 3 // end serialization. 93*2810ac1bSKiyoung Kim } 94*2810ac1bSKiyoung Kim } 95*2810ac1bSKiyoung Kim for _, ch := range tracked { 96*2810ac1bSKiyoung Kim close(ch) 97*2810ac1bSKiyoung Kim } 98*2810ac1bSKiyoung Kim wg.Wait() 99*2810ac1bSKiyoung Kim} 100*2810ac1bSKiyoung Kim 101*2810ac1bSKiyoung Kim// Test to confirm no regression against: 102*2810ac1bSKiyoung Kim// 103*2810ac1bSKiyoung Kim// https://github.com/golang/go/issues/42494 104*2810ac1bSKiyoung Kimfunc TestThreadChurn(t *testing.T) { 105*2810ac1bSKiyoung Kim const prSetKeepCaps = 8 106*2810ac1bSKiyoung Kim 107*2810ac1bSKiyoung Kim for j := 0; j < 4; j++ { 108*2810ac1bSKiyoung Kim kill := (j & 1) != 0 109*2810ac1bSKiyoung Kim sysc := (j & 2) != 0 110*2810ac1bSKiyoung Kim t.Logf("[%d] testing kill=%v, sysc=%v", j, kill, sysc) 111*2810ac1bSKiyoung Kim for i := 50; i > 0; i-- { 112*2810ac1bSKiyoung Kim if kill { 113*2810ac1bSKiyoung Kim c := make(chan struct{}) 114*2810ac1bSKiyoung Kim go killAThread(c) 115*2810ac1bSKiyoung Kim close(c) 116*2810ac1bSKiyoung Kim } 117*2810ac1bSKiyoung Kim if sysc { 118*2810ac1bSKiyoung Kim if _, _, e := Syscall3(syscall.SYS_PRCTL, prSetKeepCaps, uintptr(i&1), 0); e != 0 { 119*2810ac1bSKiyoung Kim t.Fatalf("[%d] psx:prctl(SET_KEEPCAPS, %d) failed: %v", i, i&1, syscall.Errno(e)) 120*2810ac1bSKiyoung Kim } 121*2810ac1bSKiyoung Kim } 122*2810ac1bSKiyoung Kim } 123*2810ac1bSKiyoung Kim t.Logf("[%d] PASSED kill=%v, sysc=%v", j, kill, sysc) 124*2810ac1bSKiyoung Kim } 125*2810ac1bSKiyoung Kim} 126