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