github.com/tailscale/wireguard-go@v0.0.20201119-0.20210522003738-46b531feb08a/tun/wintun/dll_windows.go (about)

     1  /* SPDX-License-Identifier: MIT
     2   *
     3   * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved.
     4   */
     5  
     6  package wintun
     7  
     8  import (
     9  	"fmt"
    10  	"sync"
    11  	"sync/atomic"
    12  	"unsafe"
    13  )
    14  
    15  func newLazyDLL(name string, onLoad func(d *lazyDLL)) *lazyDLL {
    16  	return &lazyDLL{Name: name, onLoad: onLoad}
    17  }
    18  
    19  func (d *lazyDLL) NewProc(name string) *lazyProc {
    20  	return &lazyProc{dll: d, Name: name}
    21  }
    22  
    23  type lazyProc struct {
    24  	Name string
    25  	mu   sync.Mutex
    26  	dll  *lazyDLL
    27  	addr uintptr
    28  }
    29  
    30  func (p *lazyProc) Find() error {
    31  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr))) != nil {
    32  		return nil
    33  	}
    34  	p.mu.Lock()
    35  	defer p.mu.Unlock()
    36  	if p.addr != 0 {
    37  		return nil
    38  	}
    39  
    40  	err := p.dll.Load()
    41  	if err != nil {
    42  		return fmt.Errorf("Error loading %v DLL: %w", p.dll.Name, err)
    43  	}
    44  	addr, err := p.nameToAddr()
    45  	if err != nil {
    46  		return fmt.Errorf("Error getting %v address: %w", p.Name, err)
    47  	}
    48  
    49  	atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.addr)), unsafe.Pointer(addr))
    50  	return nil
    51  }
    52  
    53  func (p *lazyProc) Addr() uintptr {
    54  	err := p.Find()
    55  	if err != nil {
    56  		panic(err)
    57  	}
    58  	return p.addr
    59  }