summaryrefslogtreecommitdiff
path: root/src/pkg/syscall/so_solaris.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/syscall/so_solaris.go')
-rw-r--r--src/pkg/syscall/so_solaris.go260
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...)
+}