cgo: make libclang code thread-safe
Этот коммит содержится в:
родитель
5b34713d41
коммит
bd8e47af80
2 изменённых файлов: 52 добавлений и 13 удалений
|
@ -21,7 +21,8 @@ int tinygo_clang_visitor(CXCursor c, CXCursor parent, CXClientData client_data);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
var globalFileInfo *fileInfo
|
// refMap stores references to types, used for clang_visitChildren.
|
||||||
|
var refMap RefMap
|
||||||
|
|
||||||
var diagnosticSeverity = [...]string{
|
var diagnosticSeverity = [...]string{
|
||||||
C.CXDiagnostic_Ignored: "ignored",
|
C.CXDiagnostic_Ignored: "ignored",
|
||||||
|
@ -119,25 +120,17 @@ func (info *fileInfo) parseFragment(fragment string, cflags []string, posFilenam
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
|
||||||
if globalFileInfo != nil {
|
ref := refMap.Put(info)
|
||||||
// There is a race condition here but that doesn't really matter as it
|
defer refMap.Remove(ref)
|
||||||
// is a sanity check anyway.
|
|
||||||
panic("libclang.go cannot be used concurrently yet")
|
|
||||||
}
|
|
||||||
globalFileInfo = info
|
|
||||||
defer func() {
|
|
||||||
globalFileInfo = nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
cursor := C.clang_getTranslationUnitCursor(unit)
|
cursor := C.clang_getTranslationUnitCursor(unit)
|
||||||
C.clang_visitChildren(cursor, (*[0]byte)(unsafe.Pointer(C.tinygo_clang_visitor)), C.CXClientData(uintptr(0)))
|
C.clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_visitor), C.CXClientData(ref))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tinygo_clang_visitor
|
//export tinygo_clang_visitor
|
||||||
func tinygo_clang_visitor(c, parent C.CXCursor, client_data C.CXClientData) C.int {
|
func tinygo_clang_visitor(c, parent C.CXCursor, client_data C.CXClientData) C.int {
|
||||||
info := globalFileInfo
|
info := refMap.Get(unsafe.Pointer(client_data)).(*fileInfo)
|
||||||
kind := C.clang_getCursorKind(c)
|
kind := C.clang_getCursorKind(c)
|
||||||
switch kind {
|
switch kind {
|
||||||
case C.CXCursor_FunctionDecl:
|
case C.CXCursor_FunctionDecl:
|
||||||
|
|
46
loader/sync.go
Обычный файл
46
loader/sync.go
Обычный файл
|
@ -0,0 +1,46 @@
|
||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #include <stdlib.h>
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
// RefMap is a convenient way to store opaque references that can be passed to
|
||||||
|
// C. It is useful if an API uses function pointers and you cannot pass a Go
|
||||||
|
// pointer but only a C pointer.
|
||||||
|
type RefMap struct {
|
||||||
|
refs map[unsafe.Pointer]interface{}
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put stores a value in the map. It can later be retrieved using Get. It must
|
||||||
|
// be removed using Remove to avoid memory leaks.
|
||||||
|
func (m *RefMap) Put(v interface{}) unsafe.Pointer {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
if m.refs == nil {
|
||||||
|
m.refs = make(map[unsafe.Pointer]interface{}, 1)
|
||||||
|
}
|
||||||
|
ref := C.malloc(1)
|
||||||
|
m.refs[ref] = v
|
||||||
|
return ref
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a stored value previously inserted with Put. Use the same
|
||||||
|
// reference as you got from Put.
|
||||||
|
func (m *RefMap) Get(ref unsafe.Pointer) interface{} {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
return m.refs[ref]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove deletes a single reference from the map.
|
||||||
|
func (m *RefMap) Remove(ref unsafe.Pointer) {
|
||||||
|
m.lock.Lock()
|
||||||
|
defer m.lock.Unlock()
|
||||||
|
delete(m.refs, ref)
|
||||||
|
C.free(ref)
|
||||||
|
}
|
Загрузка…
Создание таблицы
Сослаться в новой задаче