...

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

View as plain text