diff options
author | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
---|---|---|
committer | Michael Stapelberg <stapelberg@debian.org> | 2014-06-19 09:22:53 +0200 |
commit | 8a39ee361feb9bf46d728ff1ba4f07ca1d9610b1 (patch) | |
tree | 4449f2036cccf162e8417cc5841a35815b3e7ac5 /src/pkg/syscall/so_solaris.go | |
parent | c8bf49ef8a92e2337b69c14b9b88396efe498600 (diff) | |
download | golang-upstream/1.3.tar.gz |
Imported Upstream version 1.3upstream/1.3
Diffstat (limited to 'src/pkg/syscall/so_solaris.go')
-rw-r--r-- | src/pkg/syscall/so_solaris.go | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/src/pkg/syscall/so_solaris.go b/src/pkg/syscall/so_solaris.go new file mode 100644 index 000000000..659cd67c1 --- /dev/null +++ b/src/pkg/syscall/so_solaris.go @@ -0,0 +1,260 @@ +// 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 syscall + +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) +func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) +func dlclose(handle uintptr) (err Errno) +func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno) +func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno) + +// 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 syscall.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 syscall.Errno. +func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { + p.mustFind() + return p.proc.Call(a...) +} |