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