so_solaris.go 7.0 KB

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