Black Lives Matter. Support the Equal Justice Initiative.

Source file src/runtime/abi_test.go

Documentation: runtime

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build goexperiment.regabireflect
     6  // +build goexperiment.regabireflect
     7  
     8  // This file contains tests specific to making sure the register ABI
     9  // works in a bunch of contexts in the runtime.
    10  
    11  package runtime_test
    12  
    13  import (
    14  	"internal/abi"
    15  	"internal/testenv"
    16  	"os"
    17  	"os/exec"
    18  	"runtime"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  )
    23  
    24  var regConfirmRun chan int
    25  
    26  //go:registerparams
    27  func regFinalizerPointer(v *Tint) (int, float32, [10]byte) {
    28  	regConfirmRun <- *(*int)(v)
    29  	return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    30  }
    31  
    32  //go:registerparams
    33  func regFinalizerIface(v Tinter) (int, float32, [10]byte) {
    34  	regConfirmRun <- *(*int)(v.(*Tint))
    35  	return 5151, 4.0, [10]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
    36  }
    37  
    38  func TestFinalizerRegisterABI(t *testing.T) {
    39  	testenv.MustHaveExec(t)
    40  
    41  	// Actually run the test in a subprocess because we don't want
    42  	// finalizers from other tests interfering.
    43  	if os.Getenv("TEST_FINALIZER_REGABI") != "1" {
    44  		cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestFinalizerRegisterABI", "-test.v"))
    45  		cmd.Env = append(cmd.Env, "TEST_FINALIZER_REGABI=1")
    46  		out, err := cmd.CombinedOutput()
    47  		if !strings.Contains(string(out), "PASS\n") || err != nil {
    48  			t.Fatalf("%s\n(exit status %v)", string(out), err)
    49  		}
    50  		return
    51  	}
    52  
    53  	// Optimistically clear any latent finalizers from e.g. the testing
    54  	// package before continuing.
    55  	//
    56  	// It's possible that a finalizer only becomes available to run
    57  	// after this point, which would interfere with the test and could
    58  	// cause a crash, but because we're running in a separate process
    59  	// it's extremely unlikely.
    60  	runtime.GC()
    61  	runtime.GC()
    62  
    63  	// fing will only pick the new IntRegArgs up if it's currently
    64  	// sleeping and wakes up, so wait for it to go to sleep.
    65  	success := false
    66  	for i := 0; i < 100; i++ {
    67  		if runtime.FinalizerGAsleep() {
    68  			success = true
    69  			break
    70  		}
    71  		time.Sleep(20 * time.Millisecond)
    72  	}
    73  	if !success {
    74  		t.Fatal("finalizer not asleep?")
    75  	}
    76  
    77  	argRegsBefore := runtime.SetIntArgRegs(abi.IntArgRegs)
    78  	defer runtime.SetIntArgRegs(argRegsBefore)
    79  
    80  	tests := []struct {
    81  		name         string
    82  		fin          interface{}
    83  		confirmValue int
    84  	}{
    85  		{"Pointer", regFinalizerPointer, -1},
    86  		{"Interface", regFinalizerIface, -2},
    87  	}
    88  	for i := range tests {
    89  		test := &tests[i]
    90  		t.Run(test.name, func(t *testing.T) {
    91  			regConfirmRun = make(chan int)
    92  
    93  			x := new(Tint)
    94  			*x = (Tint)(test.confirmValue)
    95  			runtime.SetFinalizer(x, test.fin)
    96  
    97  			runtime.KeepAlive(x)
    98  
    99  			// Queue the finalizer.
   100  			runtime.GC()
   101  			runtime.GC()
   102  
   103  			select {
   104  			case <-time.After(time.Second):
   105  				t.Fatal("finalizer failed to execute")
   106  			case gotVal := <-regConfirmRun:
   107  				if gotVal != test.confirmValue {
   108  					t.Fatalf("wrong finalizer executed? got %d, want %d", gotVal, test.confirmValue)
   109  				}
   110  			}
   111  		})
   112  	}
   113  }
   114  

View as plain text