| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // Copyright 2011 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package unix
- import (
- "sync"
- "sync/atomic"
- "unsafe"
- )
- // soError describes reasons for shared library load failures.
- type soError struct {
- Err error
- ObjName string
- Msg string
- }
- func (e *soError) Error() string { return e.Msg }
- // Implemented in runtime/syscall_solaris.goc.
- func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) // TODO: export
- func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) // TODO: export
- func dlclose(handle uintptr) (err Errno) // TODO: export
- func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno) // TODO: export
- func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno) // TODO: export
- // A so implements access to a single shared library object.
- type so struct {
- Name string
- Handle uintptr
- }
- // loadSO loads shared library file into memory.
- func loadSO(name string) (*so, error) {
- namep, err := BytePtrFromString(name)
- if err != nil {
- return nil, err
- }
- h, e := dlopen(namep, 1) // RTLD_LAZY
- if e != 0 {
- return nil, &soError{
- Err: e,
- ObjName: name,
- Msg: "Failed to load " + name + ": " + e.Error(),
- }
- }
- d := &so{
- Name: name,
- Handle: uintptr(h),
- }
- return d, nil
- }
- // mustLoadSO is like loadSO but panics if load operation fails.
- func mustLoadSO(name string) *so {
- d, e := loadSO(name)
- if e != nil {
- panic(e)
- }
- return d
- }
- // FindProc searches shared library d for procedure named name and returns
- // *proc if found. It returns an error if the search fails.
- func (d *so) FindProc(name string) (*proc, error) {
- namep, err := BytePtrFromString(name)
- if err != nil {
- return nil, err
- }
- a, _ := dlsym(uintptr(d.Handle), namep)
- if a == 0 {
- return nil, &soError{
- Err: ENOSYS,
- ObjName: name,
- Msg: "Failed to find " + name + " procedure in " + d.Name,
- }
- }
- p := &proc{
- SO: d,
- Name: name,
- addr: a,
- }
- return p, nil
- }
- // MustFindProc is like FindProc but panics if search fails.
- func (d *so) MustFindProc(name string) *proc {
- p, e := d.FindProc(name)
- if e != nil {
- panic(e)
- }
- return p
- }
- // Release unloads shared library d from memory.
- func (d *so) Release() (err error) {
- return dlclose(d.Handle)
- }
- // A proc implements access to a procedure inside a shared library.
- type proc struct {
- SO *so
- Name string
- addr uintptr
- }
- // Addr returns the address of the procedure represented by p.
- // The return value can be passed to Syscall to run the procedure.
- func (p *proc) Addr() uintptr {
- return p.addr
- }
- // Call executes procedure p with arguments a. It will panic, if more then
- // 6 arguments are supplied.
- //
- // The returned error is always non-nil, constructed from the result of
- // GetLastError. Callers must inspect the primary return value to decide
- // whether an error occurred (according to the semantics of the specific
- // function being called) before consulting the error. The error will be
- // guaranteed to contain unix.Errno.
- func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
- switch len(a) {
- case 0:
- return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
- case 1:
- return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
- case 2:
- return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
- case 3:
- return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
- case 4:
- return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
- case 5:
- return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
- case 6:
- return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
- default:
- panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
- }
- return
- }
- // A lazySO implements access to a single shared library. It will delay
- // the load of the shared library until the first call to its Handle method
- // or to one of its lazyProc's Addr method.
- type lazySO struct {
- mu sync.Mutex
- so *so // non nil once SO is loaded
- Name string
- }
- // Load loads single shared file d.Name into memory. It returns an error if
- // fails. Load will not try to load SO, if it is already loaded into memory.
- func (d *lazySO) Load() error {
- // Non-racy version of:
- // if d.so == nil {
- if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
- d.mu.Lock()
- defer d.mu.Unlock()
- if d.so == nil {
- so, e := loadSO(d.Name)
- if e != nil {
- return e
- }
- // Non-racy version of:
- // d.so = so
- atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
- }
- }
- return nil
- }
- // mustLoad is like Load but panics if search fails.
- func (d *lazySO) mustLoad() {
- e := d.Load()
- if e != nil {
- panic(e)
- }
- }
- // Handle returns d's module handle.
- func (d *lazySO) Handle() uintptr {
- d.mustLoad()
- return uintptr(d.so.Handle)
- }
- // NewProc returns a lazyProc for accessing the named procedure in the SO d.
- func (d *lazySO) NewProc(name string) *lazyProc {
- return &lazyProc{l: d, Name: name}
- }
- // newLazySO creates new lazySO associated with SO file.
- func newLazySO(name string) *lazySO {
- return &lazySO{Name: name}
- }
- // A lazyProc implements access to a procedure inside a lazySO.
- // It delays the lookup until the Addr method is called.
- type lazyProc struct {
- mu sync.Mutex
- Name string
- l *lazySO
- proc *proc
- }
- // Find searches the shared library for procedure named p.Name. It returns an
- // error if search fails. Find will not search procedure, if it is already
- // found and loaded into memory.
- func (p *lazyProc) Find() error {
- // Non-racy version of:
- // if p.proc == nil {
- if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
- p.mu.Lock()
- defer p.mu.Unlock()
- if p.proc == nil {
- e := p.l.Load()
- if e != nil {
- return e
- }
- proc, e := p.l.so.FindProc(p.Name)
- if e != nil {
- return e
- }
- // Non-racy version of:
- // p.proc = proc
- atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
- }
- }
- return nil
- }
- // mustFind is like Find but panics if search fails.
- func (p *lazyProc) mustFind() {
- e := p.Find()
- if e != nil {
- panic(e)
- }
- }
- // Addr returns the address of the procedure represented by p.
- // The return value can be passed to Syscall to run the procedure.
- func (p *lazyProc) Addr() uintptr {
- p.mustFind()
- return p.proc.Addr()
- }
- // Call executes procedure p with arguments a. It will panic, if more then
- // 6 arguments are supplied.
- //
- // The returned error is always non-nil, constructed from the result of
- // GetLastError. Callers must inspect the primary return value to decide
- // whether an error occurred (according to the semantics of the specific
- // function being called) before consulting the error. The error will be
- // guaranteed to contain unix.Errno.
- func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
- p.mustFind()
- return p.proc.Call(a...)
- }
|