github.com/ck00004/CobaltStrikeParser-Go@v1.0.14/lib/internal/poll/splice_linux_test.go (about)

     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  package poll_test
     6  
     7  import (
     8  	"runtime"
     9  	"syscall"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/ck00004/CobaltStrikeParser-Go/lib/internal/syscall/unix"
    14  
    15  	"github.com/ck00004/CobaltStrikeParser-Go/lib/internal/poll"
    16  )
    17  
    18  // checkPipes returns true if all pipes are closed properly, false otherwise.
    19  func checkPipes(fds []int) bool {
    20  	for _, fd := range fds {
    21  		// Check if each pipe fd has been closed.
    22  		_, _, errno := syscall.Syscall(unix.FcntlSyscall, uintptr(fd), syscall.F_GETPIPE_SZ, 0)
    23  		if errno == 0 {
    24  			return false
    25  		}
    26  	}
    27  	return true
    28  }
    29  
    30  func TestSplicePipePool(t *testing.T) {
    31  	const N = 64
    32  	var (
    33  		p   *poll.SplicePipe
    34  		ps  []*poll.SplicePipe
    35  		fds []int
    36  		err error
    37  	)
    38  	for i := 0; i < N; i++ {
    39  		p, _, err = poll.GetPipe()
    40  		if err != nil {
    41  			t.Skip("failed to create pipe, skip this test")
    42  		}
    43  		_, pwfd := poll.GetPipeFds(p)
    44  		fds = append(fds, pwfd)
    45  		ps = append(ps, p)
    46  	}
    47  	for _, p = range ps {
    48  		poll.PutPipe(p)
    49  	}
    50  	ps = nil
    51  	p = nil
    52  
    53  	// Exploit the timeout of "go test" as a timer for the subsequent verification.
    54  	timeout := 5 * time.Minute
    55  	if deadline, ok := t.Deadline(); ok {
    56  		timeout = deadline.Sub(time.Now())
    57  		timeout -= timeout / 10 // Leave 10% headroom for cleanup.
    58  	}
    59  	expiredTime := time.NewTimer(timeout)
    60  	defer expiredTime.Stop()
    61  
    62  	// Trigger garbage collection repeatedly, waiting for all pipes in sync.Pool
    63  	// to either be deallocated and closed, or to time out.
    64  	for {
    65  		runtime.GC()
    66  		time.Sleep(10 * time.Millisecond)
    67  		if checkPipes(fds) {
    68  			break
    69  		}
    70  		select {
    71  		case <-expiredTime.C:
    72  			t.Fatal("at least one pipe is still open")
    73  		default:
    74  		}
    75  	}
    76  }
    77  
    78  func BenchmarkSplicePipe(b *testing.B) {
    79  	b.Run("SplicePipeWithPool", func(b *testing.B) {
    80  		for i := 0; i < b.N; i++ {
    81  			p, _, err := poll.GetPipe()
    82  			if err != nil {
    83  				continue
    84  			}
    85  			poll.PutPipe(p)
    86  		}
    87  	})
    88  	b.Run("SplicePipeWithoutPool", func(b *testing.B) {
    89  		for i := 0; i < b.N; i++ {
    90  			p := poll.NewPipe()
    91  			if p == nil {
    92  				b.Skip("newPipe returned nil")
    93  			}
    94  			poll.DestroyPipe(p)
    95  		}
    96  	})
    97  }
    98  
    99  func BenchmarkSplicePipePoolParallel(b *testing.B) {
   100  	b.RunParallel(func(pb *testing.PB) {
   101  		for pb.Next() {
   102  			p, _, err := poll.GetPipe()
   103  			if err != nil {
   104  				continue
   105  			}
   106  			poll.PutPipe(p)
   107  		}
   108  	})
   109  }
   110  
   111  func BenchmarkSplicePipeNativeParallel(b *testing.B) {
   112  	b.RunParallel(func(pb *testing.PB) {
   113  		for pb.Next() {
   114  			p := poll.NewPipe()
   115  			if p == nil {
   116  				b.Skip("newPipe returned nil")
   117  			}
   118  			poll.DestroyPipe(p)
   119  		}
   120  	})
   121  }