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