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 }