so_solaris.go 6.9 KB

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