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