Source file
src/plugin/plugin_dlopen.go
Documentation: plugin
1
2
3
4
5
6
7
8 package plugin
9
10
35 import "C"
36
37 import (
38 "errors"
39 "sync"
40 "unsafe"
41 )
42
43 func open(name string) (*Plugin, error) {
44 cPath := make([]byte, C.PATH_MAX+1)
45 cRelName := make([]byte, len(name)+1)
46 copy(cRelName, name)
47 if C.realpath(
48 (*C.char)(unsafe.Pointer(&cRelName[0])),
49 (*C.char)(unsafe.Pointer(&cPath[0]))) == nil {
50 return nil, errors.New(`plugin.Open("` + name + `"): realpath failed`)
51 }
52
53 filepath := C.GoString((*C.char)(unsafe.Pointer(&cPath[0])))
54
55 pluginsMu.Lock()
56 if p := plugins[filepath]; p != nil {
57 pluginsMu.Unlock()
58 if p.err != "" {
59 return nil, errors.New(`plugin.Open("` + name + `"): ` + p.err + ` (previous failure)`)
60 }
61 <-p.loaded
62 return p, nil
63 }
64 var cErr *C.char
65 h := C.pluginOpen((*C.char)(unsafe.Pointer(&cPath[0])), &cErr)
66 if h == 0 {
67 pluginsMu.Unlock()
68 return nil, errors.New(`plugin.Open("` + name + `"): ` + C.GoString(cErr))
69 }
70
71
72 if len(name) > 3 && name[len(name)-3:] == ".so" {
73 name = name[:len(name)-3]
74 }
75 if plugins == nil {
76 plugins = make(map[string]*Plugin)
77 }
78 pluginpath, syms, errstr := lastmoduleinit()
79 if errstr != "" {
80 plugins[filepath] = &Plugin{
81 pluginpath: pluginpath,
82 err: errstr,
83 }
84 pluginsMu.Unlock()
85 return nil, errors.New(`plugin.Open("` + name + `"): ` + errstr)
86 }
87
88
89 p := &Plugin{
90 pluginpath: pluginpath,
91 loaded: make(chan struct{}),
92 }
93 plugins[filepath] = p
94 pluginsMu.Unlock()
95
96 initStr := make([]byte, len(pluginpath)+len("..inittask")+1)
97 copy(initStr, pluginpath)
98 copy(initStr[len(pluginpath):], "..inittask")
99
100 initTask := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&initStr[0])), &cErr)
101 if initTask != nil {
102 doInit(initTask)
103 }
104
105
106 updatedSyms := map[string]interface{}{}
107 for symName, sym := range syms {
108 isFunc := symName[0] == '.'
109 if isFunc {
110 delete(syms, symName)
111 symName = symName[1:]
112 }
113
114 fullName := pluginpath + "." + symName
115 cname := make([]byte, len(fullName)+1)
116 copy(cname, fullName)
117
118 p := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&cname[0])), &cErr)
119 if p == nil {
120 return nil, errors.New(`plugin.Open("` + name + `"): could not find symbol ` + symName + `: ` + C.GoString(cErr))
121 }
122 valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym))
123 if isFunc {
124 (*valp)[1] = unsafe.Pointer(&p)
125 } else {
126 (*valp)[1] = p
127 }
128
129
130 updatedSyms[symName] = sym
131 }
132 p.syms = updatedSyms
133
134 close(p.loaded)
135 return p, nil
136 }
137
138 func lookup(p *Plugin, symName string) (Symbol, error) {
139 if s := p.syms[symName]; s != nil {
140 return s, nil
141 }
142 return nil, errors.New("plugin: symbol " + symName + " not found in plugin " + p.pluginpath)
143 }
144
145 var (
146 pluginsMu sync.Mutex
147 plugins map[string]*Plugin
148 )
149
150
151 func lastmoduleinit() (pluginpath string, syms map[string]interface{}, errstr string)
152
153
154
155 func doInit(t unsafe.Pointer)
156
View as plain text