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, initTasks, 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 doInit(initTasks)
96
97
98 updatedSyms := map[string]any{}
99 for symName, sym := range syms {
100 isFunc := symName[0] == '.'
101 if isFunc {
102 delete(syms, symName)
103 symName = symName[1:]
104 }
105
106 fullName := pluginpath + "." + symName
107 cname := make([]byte, len(fullName)+1)
108 copy(cname, fullName)
109
110 p := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&cname[0])), &cErr)
111 if p == nil {
112 return nil, errors.New(`plugin.Open("` + name + `"): could not find symbol ` + symName + `: ` + C.GoString(cErr))
113 }
114 valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym))
115 if isFunc {
116 (*valp)[1] = unsafe.Pointer(&p)
117 } else {
118 (*valp)[1] = p
119 }
120
121
122 updatedSyms[symName] = sym
123 }
124 p.syms = updatedSyms
125
126 close(p.loaded)
127 return p, nil
128 }
129
130 func lookup(p *Plugin, symName string) (Symbol, error) {
131 if s := p.syms[symName]; s != nil {
132 return s, nil
133 }
134 return nil, errors.New("plugin: symbol " + symName + " not found in plugin " + p.pluginpath)
135 }
136
137 var (
138 pluginsMu sync.Mutex
139 plugins map[string]*Plugin
140 )
141
142
143 func lastmoduleinit() (pluginpath string, syms map[string]any, inittasks []*initTask, errstr string)
144
145
146
147
148 func doInit(t []*initTask)
149
150 type initTask struct {
151
152
153 }
154
View as plain text