| | |
| | |
| | |
| |
|
| | |
| |
|
| | package plugin |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | import "C" |
| |
|
| | import ( |
| | "errors" |
| | "sync" |
| | "unsafe" |
| | ) |
| |
|
| | func open(name string) (*Plugin, error) { |
| | cPath := make([]byte, C.PATH_MAX+1) |
| | cRelName := make([]byte, len(name)+1) |
| | copy(cRelName, name) |
| | if C.realpath( |
| | (*C.char)(unsafe.Pointer(&cRelName[0])), |
| | (*C.char)(unsafe.Pointer(&cPath[0]))) == nil { |
| | return nil, errors.New(`plugin.Open("` + name + `"): realpath failed`) |
| | } |
| |
|
| | filepath := C.GoString((*C.char)(unsafe.Pointer(&cPath[0]))) |
| |
|
| | pluginsMu.Lock() |
| | if p := plugins[filepath]; p != nil { |
| | pluginsMu.Unlock() |
| | if p.err != "" { |
| | return nil, errors.New(`plugin.Open("` + name + `"): ` + p.err + ` (previous failure)`) |
| | } |
| | <-p.loaded |
| | return p, nil |
| | } |
| | var cErr *C.char |
| | h := C.pluginOpen((*C.char)(unsafe.Pointer(&cPath[0])), &cErr) |
| | if h == 0 { |
| | pluginsMu.Unlock() |
| | return nil, errors.New(`plugin.Open("` + name + `"): ` + C.GoString(cErr)) |
| | } |
| | |
| | |
| | if len(name) > 3 && name[len(name)-3:] == ".so" { |
| | name = name[:len(name)-3] |
| | } |
| | if plugins == nil { |
| | plugins = make(map[string]*Plugin) |
| | } |
| | pluginpath, syms, initTasks, errstr := lastmoduleinit() |
| | if errstr != "" { |
| | plugins[filepath] = &Plugin{ |
| | pluginpath: pluginpath, |
| | err: errstr, |
| | } |
| | pluginsMu.Unlock() |
| | return nil, errors.New(`plugin.Open("` + name + `"): ` + errstr) |
| | } |
| | |
| | |
| | p := &Plugin{ |
| | pluginpath: pluginpath, |
| | loaded: make(chan struct{}), |
| | } |
| | plugins[filepath] = p |
| | pluginsMu.Unlock() |
| |
|
| | doInit(initTasks) |
| |
|
| | |
| | updatedSyms := map[string]any{} |
| | for symName, sym := range syms { |
| | isFunc := symName[0] == '.' |
| | if isFunc { |
| | delete(syms, symName) |
| | symName = symName[1:] |
| | } |
| |
|
| | fullName := pluginpath + "." + symName |
| | cname := make([]byte, len(fullName)+1) |
| | copy(cname, fullName) |
| |
|
| | p := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&cname[0])), &cErr) |
| | if p == nil { |
| | return nil, errors.New(`plugin.Open("` + name + `"): could not find symbol ` + symName + `: ` + C.GoString(cErr)) |
| | } |
| | valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&sym)) |
| | if isFunc { |
| | (*valp)[1] = unsafe.Pointer(&p) |
| | } else { |
| | (*valp)[1] = p |
| | } |
| | |
| | |
| | updatedSyms[symName] = sym |
| | } |
| | p.syms = updatedSyms |
| |
|
| | close(p.loaded) |
| | return p, nil |
| | } |
| |
|
| | func lookup(p *Plugin, symName string) (Symbol, error) { |
| | if s := p.syms[symName]; s != nil { |
| | return s, nil |
| | } |
| | return nil, errors.New("plugin: symbol " + symName + " not found in plugin " + p.pluginpath) |
| | } |
| |
|
| | var ( |
| | pluginsMu sync.Mutex |
| | plugins map[string]*Plugin |
| | ) |
| |
|
| | |
| | func lastmoduleinit() (pluginpath string, syms map[string]any, inittasks []*initTask, errstr string) |
| |
|
| | |
| | |
| | |
| | func doInit(t []*initTask) |
| |
|
| | type initTask struct { |
| | |
| | |
| | } |
| |
|