handles, merge, odb: changes for Go 1.6 pointer passing rules #282

Merged
ianlancetaylor merged 5 commits from master into master 2016-02-18 06:10:08 -06:00
3 changed files with 60 additions and 42 deletions
Showing only changes of commit a1f25eafec - Show all commits

View File

@ -10,15 +10,14 @@ type HandleList struct {
sync.RWMutex sync.RWMutex
// stores the Go pointers // stores the Go pointers
handles []interface{} handles []interface{}
// Indicates which indices are in use, and keeps a pointer to slot int variable (the handle) // Indicates which indices are in use.
// in the Go world, so that the Go garbage collector does not free it. set map[int]bool
set map[int]*int
} }
func NewHandleList() *HandleList { func NewHandleList() *HandleList {
return &HandleList{ return &HandleList{
handles: make([]interface{}, 5), handles: make([]interface{}, 5),
set: make(map[int]*int), set: make(map[int]bool),
} }
} }
@ -26,8 +25,7 @@ func NewHandleList() *HandleList {
// list. You must only run this function while holding a write lock. // list. You must only run this function while holding a write lock.
func (v *HandleList) findUnusedSlot() int { func (v *HandleList) findUnusedSlot() int {
for i := 1; i < len(v.handles); i++ { for i := 1; i < len(v.handles); i++ {
_, isUsed := v.set[i] if !v.set[i] {
if !isUsed {
return i return i
} }
} }
@ -48,7 +46,7 @@ func (v *HandleList) Track(pointer interface{}) unsafe.Pointer {
slot := v.findUnusedSlot() slot := v.findUnusedSlot()
v.handles[slot] = pointer v.handles[slot] = pointer
v.set[slot] = &slot // Keep a pointer to slot in Go world, so it's not freed by GC. v.set[slot] = true
v.Unlock() v.Unlock()
@ -73,7 +71,7 @@ func (v *HandleList) Get(handle unsafe.Pointer) interface{} {
v.RLock() v.RLock()
if _, ok := v.set[slot]; !ok { if !v.set[slot] {
panic(fmt.Sprintf("invalid pointer handle: %p", handle)) panic(fmt.Sprintf("invalid pointer handle: %p", handle))
} }

View File

@ -6,6 +6,7 @@ package git
extern git_annotated_commit** _go_git_make_merge_head_array(size_t len); extern git_annotated_commit** _go_git_make_merge_head_array(size_t len);
extern void _go_git_annotated_commit_array_set(git_annotated_commit** array, git_annotated_commit* ptr, size_t n); extern void _go_git_annotated_commit_array_set(git_annotated_commit** array, git_annotated_commit* ptr, size_t n);
extern git_annotated_commit* _go_git_annotated_commit_array_get(git_annotated_commit** array, size_t n); extern git_annotated_commit* _go_git_annotated_commit_array_get(git_annotated_commit** array, size_t n);
extern int _go_git_merge_file(git_merge_file_result*, char*, size_t, char*, unsigned int, char*, size_t, char*, unsigned int, char*, size_t, char*, unsigned int, git_merge_file_options*);
*/ */
import "C" import "C"
@ -320,24 +321,6 @@ type MergeFileInput struct {
Contents []byte Contents []byte
} }
// populate a C struct with merge file input, make sure to use freeMergeFileInput to clean up allocs
func populateCMergeFileInput(c *C.git_merge_file_input, input MergeFileInput) *C.char {
c.path = C.CString(input.Path)
var toFree *C.char
if input.Contents != nil {
toFree = C.CString(string(input.Contents))
c.ptr = toFree
c.size = C.size_t(len(input.Contents))
}
c.mode = C.uint(input.Mode)
return toFree
}
func freeCMergeFileInput(c *C.git_merge_file_input, toFree *C.char) {
C.free(unsafe.Pointer(c.path))
C.free(unsafe.Pointer(toFree))
}
type MergeFileFlags int type MergeFileFlags int
const ( const (
@ -382,16 +365,26 @@ func freeCMergeFileOptions(c *C.git_merge_file_options) {
func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInput, options *MergeFileOptions) (*MergeFileResult, error) { func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInput, options *MergeFileOptions) (*MergeFileResult, error) {
var cancestor C.git_merge_file_input ancestorPath := C.CString(ancestor.Path)
var cours C.git_merge_file_input defer C.free(unsafe.Pointer(ancestorPath))
var ctheirs C.git_merge_file_input var ancestorContents *byte
if len(ancestor.Contents) > 0 {
ancestorContents = &ancestor.Contents[0]
}
t := populateCMergeFileInput(&cancestor, ancestor) oursPath := C.CString(ours.Path)
defer freeCMergeFileInput(&cancestor, t) defer C.free(unsafe.Pointer(oursPath))
t = populateCMergeFileInput(&cours, ours) var oursContents *byte
defer freeCMergeFileInput(&cours, t) if len(ours.Contents) > 0 {
t = populateCMergeFileInput(&ctheirs, theirs) oursContents = &ours.Contents[0]
defer freeCMergeFileInput(&ctheirs, t) }
theirsPath := C.CString(theirs.Path)
defer C.free(unsafe.Pointer(theirsPath))
var theirsContents *byte
if len(theirs.Contents) > 0 {
theirsContents = &theirs.Contents[0]
}
var copts *C.git_merge_file_options var copts *C.git_merge_file_options
if options != nil { if options != nil {
@ -408,7 +401,11 @@ func MergeFile(ancestor MergeFileInput, ours MergeFileInput, theirs MergeFileInp
defer runtime.UnlockOSThread() defer runtime.UnlockOSThread()
var result C.git_merge_file_result var result C.git_merge_file_result
ecode := C.git_merge_file(&result, &cancestor, &cours, &ctheirs, copts) ecode := C._go_git_merge_file(&result,
(*C.char)(unsafe.Pointer(ancestorContents)), C.size_t(len(ancestor.Contents)), ancestorPath, C.uint(ancestor.Mode),
(*C.char)(unsafe.Pointer(oursContents)), C.size_t(len(ours.Contents)), oursPath, C.uint(ours.Mode),
(*C.char)(unsafe.Pointer(theirsContents)), C.size_t(len(theirs.Contents)), theirsPath, C.uint(theirs.Mode),
copts)
if ecode < 0 { if ecode < 0 {
return nil, MakeGitError(ecode) return nil, MakeGitError(ecode)
} }

View File

@ -141,4 +141,27 @@ int _go_git_tag_foreach(git_repository *repo, void *payload)
return git_tag_foreach(repo, (git_tag_foreach_cb)&gitTagForeachCb, payload); return git_tag_foreach(repo, (git_tag_foreach_cb)&gitTagForeachCb, payload);
} }
int _go_git_merge_file(git_merge_file_result* out, char* ancestorContents, size_t ancestorLen, char* ancestorPath, unsigned int ancestorMode, char* oursContents, size_t oursLen, char* oursPath, unsigned int oursMode, char* theirsContents, size_t theirsLen, char* theirsPath, unsigned int theirsMode, git_merge_file_options* copts) {
git_merge_file_input ancestor = GIT_MERGE_FILE_INPUT_INIT;
git_merge_file_input ours = GIT_MERGE_FILE_INPUT_INIT;
git_merge_file_input theirs = GIT_MERGE_FILE_INPUT_INIT;
ancestor.ptr = ancestorContents;
ancestor.size = ancestorLen;
ancestor.path = ancestorPath;
ancestor.mode = ancestorMode;
ours.ptr = oursContents;
ours.size = oursLen;
ours.path = oursPath;
ours.mode = oursMode;
theirs.ptr = theirsContents;
theirs.size = theirsLen;
theirs.path = theirsPath;
theirs.mode = theirsMode;
return git_merge_file(out, &ancestor, &ours, &theirs, copts);
}
/* EOF */ /* EOF */