github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/sys/unix/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 unix 6 7 import ( 8 "sync" 9 "sync/atomic" 10 "syscall" 11 "unsafe" 12 ) 13 14 // soError describes reasons for shared library load failures. 15 type soError struct { 16 Err error 17 ObjName string 18 Msg string 19 } 20 21 func (e *soError) Error() string { return e.Msg } 22 23 // Implemented in runtime/syscall_solaris.goc. 24 func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) 25 func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno) 26 func dlclose(handle uintptr) (err syscall.Errno) 27 func dlopen(name *uint8, mode uintptr) (handle uintptr, err syscall.Errno) 28 func dlsym(handle uintptr, name *uint8) (proc uintptr, err syscall.Errno) 29 30 // A so implements access to a single shared library object. 31 type so struct { 32 Name string 33 Handle uintptr 34 } 35 36 // loadSO loads shared library file into memory. 37 func loadSO(name string) (*so, error) { 38 namep, err := BytePtrFromString(name) 39 if err != nil { 40 return nil, err 41 } 42 h, e := dlopen(namep, 1) // RTLD_LAZY 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 if a == 0 { 75 return nil, &soError{ 76 Err: ENOSYS, 77 ObjName: name, 78 Msg: "Failed to find " + name + " procedure in " + d.Name, 79 } 80 } 81 p := &proc{ 82 SO: d, 83 Name: name, 84 addr: a, 85 } 86 return p, nil 87 } 88 89 // MustFindProc is like FindProc but panics if search fails. 90 func (d *so) MustFindProc(name string) *proc { 91 p, e := d.FindProc(name) 92 if e != nil { 93 panic(e) 94 } 95 return p 96 } 97 98 // Release unloads shared library d from memory. 99 func (d *so) Release() (err error) { 100 return dlclose(d.Handle) 101 } 102 103 // A proc implements access to a procedure inside a shared library. 104 type proc struct { 105 SO *so 106 Name string 107 addr uintptr 108 } 109 110 // Addr returns the address of the procedure represented by p. 111 // The return value can be passed to Syscall to run the procedure. 112 func (p *proc) Addr() uintptr { 113 return p.addr 114 } 115 116 // Call executes procedure p with arguments a. It will panic, if more then 117 // 6 arguments are supplied. 118 // 119 // The returned error is always non-nil, constructed from the result of 120 // GetLastError. Callers must inspect the primary return value to decide 121 // whether an error occurred (according to the semantics of the specific 122 // function being called) before consulting the error. The error will be 123 // guaranteed to contain syscall.Errno. 124 func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 125 switch len(a) { 126 case 0: 127 return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0) 128 case 1: 129 return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0) 130 case 2: 131 return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0) 132 case 3: 133 return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0) 134 case 4: 135 return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0) 136 case 5: 137 return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0) 138 case 6: 139 return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5]) 140 default: 141 panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".") 142 } 143 return 144 } 145 146 // A lazySO implements access to a single shared library. It will delay 147 // the load of the shared library until the first call to its Handle method 148 // or to one of its lazyProc's Addr method. 149 type lazySO struct { 150 mu sync.Mutex 151 so *so // non nil once SO is loaded 152 Name string 153 } 154 155 // Load loads single shared file d.Name into memory. It returns an error if 156 // fails. Load will not try to load SO, if it is already loaded into memory. 157 func (d *lazySO) Load() error { 158 // Non-racy version of: 159 // if d.so == nil { 160 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil { 161 d.mu.Lock() 162 defer d.mu.Unlock() 163 if d.so == nil { 164 so, e := loadSO(d.Name) 165 if e != nil { 166 return e 167 } 168 // Non-racy version of: 169 // d.so = so 170 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so)) 171 } 172 } 173 return nil 174 } 175 176 // mustLoad is like Load but panics if search fails. 177 func (d *lazySO) mustLoad() { 178 e := d.Load() 179 if e != nil { 180 panic(e) 181 } 182 } 183 184 // Handle returns d's module handle. 185 func (d *lazySO) Handle() uintptr { 186 d.mustLoad() 187 return uintptr(d.so.Handle) 188 } 189 190 // NewProc returns a lazyProc for accessing the named procedure in the SO d. 191 func (d *lazySO) NewProc(name string) *lazyProc { 192 return &lazyProc{l: d, Name: name} 193 } 194 195 // newLazySO creates new lazySO associated with SO file. 196 func newLazySO(name string) *lazySO { 197 return &lazySO{Name: name} 198 } 199 200 // A lazyProc implements access to a procedure inside a lazySO. 201 // It delays the lookup until the Addr method is called. 202 type lazyProc struct { 203 mu sync.Mutex 204 Name string 205 l *lazySO 206 proc *proc 207 } 208 209 // Find searches the shared library for procedure named p.Name. It returns an 210 // error if search fails. Find will not search procedure, if it is already 211 // found and loaded into memory. 212 func (p *lazyProc) Find() error { 213 // Non-racy version of: 214 // if p.proc == nil { 215 if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil { 216 p.mu.Lock() 217 defer p.mu.Unlock() 218 if p.proc == nil { 219 e := p.l.Load() 220 if e != nil { 221 return e 222 } 223 proc, e := p.l.so.FindProc(p.Name) 224 if e != nil { 225 return e 226 } 227 // Non-racy version of: 228 // p.proc = proc 229 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc)) 230 } 231 } 232 return nil 233 } 234 235 // mustFind is like Find but panics if search fails. 236 func (p *lazyProc) mustFind() { 237 e := p.Find() 238 if e != nil { 239 panic(e) 240 } 241 } 242 243 // Addr returns the address of the procedure represented by p. 244 // The return value can be passed to Syscall to run the procedure. 245 func (p *lazyProc) Addr() uintptr { 246 p.mustFind() 247 return p.proc.Addr() 248 } 249 250 // Call executes procedure p with arguments a. It will panic, if more then 251 // 6 arguments are supplied. 252 // 253 // The returned error is always non-nil, constructed from the result of 254 // GetLastError. Callers must inspect the primary return value to decide 255 // whether an error occurred (according to the semantics of the specific 256 // function being called) before consulting the error. The error will be 257 // guaranteed to contain syscall.Errno. 258 func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) { 259 p.mustFind() 260 return p.proc.Call(a...) 261 }