github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/sys/unix/so_solaris.go (about)

     1  // Copyright 2011 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 unix
     6  
     7  import (
     8  	"sync"
     9  	"sync/atomic"
    10  	"syscall"
    11  	"unsafe"
    12  )
    13  
    14  // soError describes reasons for shared library load failures.
    15  type soError struct {
    16  	Err     error
    17  	ObjName string
    18  	Msg     string
    19  }
    20  
    21  func (e *soError) Error() string { return e.Msg }
    22  
    23  // Implemented in runtime/syscall_solaris.goc.
    24  func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
    25  func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
    26  func dlclose(handle uintptr) (err syscall.Errno)
    27  func dlopen(name *uint8, mode uintptr) (handle uintptr, err syscall.Errno)
    28  func dlsym(handle uintptr, name *uint8) (proc uintptr, err syscall.Errno)
    29  
    30  // A so implements access to a single shared library object.
    31  type so struct {
    32  	Name   string
    33  	Handle uintptr
    34  }
    35  
    36  // loadSO loads shared library file into memory.
    37  func loadSO(name string) (*so, error) {
    38  	namep, err := BytePtrFromString(name)
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	h, e := dlopen(namep, 1) // RTLD_LAZY
    43  	if e != 0 {
    44  		return nil, &soError{
    45  			Err:     e,
    46  			ObjName: name,
    47  			Msg:     "Failed to load " + name + ": " + e.Error(),
    48  		}
    49  	}
    50  	d := &so{
    51  		Name:   name,
    52  		Handle: uintptr(h),
    53  	}
    54  	return d, nil
    55  }
    56  
    57  // mustLoadSO is like loadSO but panics if load operation fails.
    58  func mustLoadSO(name string) *so {
    59  	d, e := loadSO(name)
    60  	if e != nil {
    61  		panic(e)
    62  	}
    63  	return d
    64  }
    65  
    66  // FindProc searches shared library d for procedure named name and returns
    67  // *proc if found. It returns an error if the search fails.
    68  func (d *so) FindProc(name string) (*proc, error) {
    69  	namep, err := BytePtrFromString(name)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	a, _ := dlsym(uintptr(d.Handle), namep)
    74  	if a == 0 {
    75  		return nil, &soError{
    76  			Err:     ENOSYS,
    77  			ObjName: name,
    78  			Msg:     "Failed to find " + name + " procedure in " + d.Name,
    79  		}
    80  	}
    81  	p := &proc{
    82  		SO:   d,
    83  		Name: name,
    84  		addr: a,
    85  	}
    86  	return p, nil
    87  }
    88  
    89  // MustFindProc is like FindProc but panics if search fails.
    90  func (d *so) MustFindProc(name string) *proc {
    91  	p, e := d.FindProc(name)
    92  	if e != nil {
    93  		panic(e)
    94  	}
    95  	return p
    96  }
    97  
    98  // Release unloads shared library d from memory.
    99  func (d *so) Release() (err error) {
   100  	return dlclose(d.Handle)
   101  }
   102  
   103  // A proc implements access to a procedure inside a shared library.
   104  type proc struct {
   105  	SO   *so
   106  	Name string
   107  	addr uintptr
   108  }
   109  
   110  // Addr returns the address of the procedure represented by p.
   111  // The return value can be passed to Syscall to run the procedure.
   112  func (p *proc) Addr() uintptr {
   113  	return p.addr
   114  }
   115  
   116  // Call executes procedure p with arguments a. It will panic, if more then
   117  // 6 arguments are supplied.
   118  //
   119  // The returned error is always non-nil, constructed from the result of
   120  // GetLastError.  Callers must inspect the primary return value to decide
   121  // whether an error occurred (according to the semantics of the specific
   122  // function being called) before consulting the error. The error will be
   123  // guaranteed to contain syscall.Errno.
   124  func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   125  	switch len(a) {
   126  	case 0:
   127  		return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
   128  	case 1:
   129  		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
   130  	case 2:
   131  		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
   132  	case 3:
   133  		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
   134  	case 4:
   135  		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
   136  	case 5:
   137  		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
   138  	case 6:
   139  		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
   140  	default:
   141  		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
   142  	}
   143  	return
   144  }
   145  
   146  // A lazySO implements access to a single shared library.  It will delay
   147  // the load of the shared library until the first call to its Handle method
   148  // or to one of its lazyProc's Addr method.
   149  type lazySO struct {
   150  	mu   sync.Mutex
   151  	so   *so // non nil once SO is loaded
   152  	Name string
   153  }
   154  
   155  // Load loads single shared file d.Name into memory. It returns an error if
   156  // fails.  Load will not try to load SO, if it is already loaded into memory.
   157  func (d *lazySO) Load() error {
   158  	// Non-racy version of:
   159  	// if d.so == nil {
   160  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
   161  		d.mu.Lock()
   162  		defer d.mu.Unlock()
   163  		if d.so == nil {
   164  			so, e := loadSO(d.Name)
   165  			if e != nil {
   166  				return e
   167  			}
   168  			// Non-racy version of:
   169  			// d.so = so
   170  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
   171  		}
   172  	}
   173  	return nil
   174  }
   175  
   176  // mustLoad is like Load but panics if search fails.
   177  func (d *lazySO) mustLoad() {
   178  	e := d.Load()
   179  	if e != nil {
   180  		panic(e)
   181  	}
   182  }
   183  
   184  // Handle returns d's module handle.
   185  func (d *lazySO) Handle() uintptr {
   186  	d.mustLoad()
   187  	return uintptr(d.so.Handle)
   188  }
   189  
   190  // NewProc returns a lazyProc for accessing the named procedure in the SO d.
   191  func (d *lazySO) NewProc(name string) *lazyProc {
   192  	return &lazyProc{l: d, Name: name}
   193  }
   194  
   195  // newLazySO creates new lazySO associated with SO file.
   196  func newLazySO(name string) *lazySO {
   197  	return &lazySO{Name: name}
   198  }
   199  
   200  // A lazyProc implements access to a procedure inside a lazySO.
   201  // It delays the lookup until the Addr method is called.
   202  type lazyProc struct {
   203  	mu   sync.Mutex
   204  	Name string
   205  	l    *lazySO
   206  	proc *proc
   207  }
   208  
   209  // Find searches the shared library for procedure named p.Name. It returns an
   210  // error if search fails. Find will not search procedure, if it is already
   211  // found and loaded into memory.
   212  func (p *lazyProc) Find() error {
   213  	// Non-racy version of:
   214  	// if p.proc == nil {
   215  	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
   216  		p.mu.Lock()
   217  		defer p.mu.Unlock()
   218  		if p.proc == nil {
   219  			e := p.l.Load()
   220  			if e != nil {
   221  				return e
   222  			}
   223  			proc, e := p.l.so.FindProc(p.Name)
   224  			if e != nil {
   225  				return e
   226  			}
   227  			// Non-racy version of:
   228  			// p.proc = proc
   229  			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
   230  		}
   231  	}
   232  	return nil
   233  }
   234  
   235  // mustFind is like Find but panics if search fails.
   236  func (p *lazyProc) mustFind() {
   237  	e := p.Find()
   238  	if e != nil {
   239  		panic(e)
   240  	}
   241  }
   242  
   243  // Addr returns the address of the procedure represented by p.
   244  // The return value can be passed to Syscall to run the procedure.
   245  func (p *lazyProc) Addr() uintptr {
   246  	p.mustFind()
   247  	return p.proc.Addr()
   248  }
   249  
   250  // Call executes procedure p with arguments a. It will panic, if more then
   251  // 6 arguments are supplied.
   252  //
   253  // The returned error is always non-nil, constructed from the result of
   254  // GetLastError.  Callers must inspect the primary return value to decide
   255  // whether an error occurred (according to the semantics of the specific
   256  // function being called) before consulting the error. The error will be
   257  // guaranteed to contain syscall.Errno.
   258  func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
   259  	p.mustFind()
   260  	return p.proc.Call(a...)
   261  }