Skip to content

Commit

Permalink
Lock the OS thread when acessing errors
Browse files Browse the repository at this point in the history
The library stores error information in thread-local storage, which
means we need to make sure that the Go runtime doesn't switch OS
threads between the time we call a function and th time we attempt to
retrieve the error information.
  • Loading branch information
carlosmn committed Dec 18, 2013
1 parent 625ffd0 commit a40bdfd
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 0 deletions.
7 changes: 7 additions & 0 deletions checkout.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ git_checkout_opts git_checkout_opts_init() {
*/
import "C"
import (
"runtime"
"os"
)

Expand Down Expand Up @@ -59,6 +60,9 @@ func (v *Repository) Checkout(opts *CheckoutOpts) error {
var copts C.git_checkout_opts
populateCheckoutOpts(&copts, opts)

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_checkout_head(v.ptr, &copts)
if ret < 0 {
return LastError()
Expand All @@ -72,6 +76,9 @@ func (v *Repository) CheckoutIndex(index *Index, opts *CheckoutOpts) error {
var copts C.git_checkout_opts
populateCheckoutOpts(&copts, opts)

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_checkout_index(v.ptr, index.ptr, &copts)
if ret < 0 {
return LastError()
Expand Down
4 changes: 4 additions & 0 deletions commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ extern int _go_git_treewalk(git_tree *tree, git_treewalk_mode mode, void *ptr);
import "C"

import (
"runtime"
"time"
"unsafe"
)
Expand All @@ -25,6 +26,9 @@ func (c Commit) Message() string {
func (c Commit) Tree() (*Tree, error) {
var ptr *C.git_object

runtime.LockOSThread()
defer runtime.UnlockOSThread()

err := C.git_commit_tree(&ptr, c.ptr)
if err < 0 {
return nil, LastError()
Expand Down
12 changes: 12 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ func (c *Config) LookupInt32(name string) (v int32, err error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_config_get_int32(&out, c.ptr, cname)
if ret < 0 {
return 0, LastError()
Expand All @@ -32,6 +35,9 @@ func (c *Config) LookupInt64(name string) (v int64, err error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_config_get_int64(&out, c.ptr, cname)
if ret < 0 {
return 0, LastError()
Expand All @@ -45,6 +51,9 @@ func (c *Config) LookupString(name string) (v string, err error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_config_get_string(&ptr, c.ptr, cname)
if ret < 0 {
return "", LastError()
Expand All @@ -60,6 +69,9 @@ func (c *Config) Set(name, value string) (err error) {
cvalue := C.CString(value)
defer C.free(unsafe.Pointer(cvalue))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_config_set_string(c.ptr, cname, cvalue)
if ret < 0 {
return LastError()
Expand Down
11 changes: 11 additions & 0 deletions git.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import "C"
import (
"bytes"
"errors"
"runtime"
"unsafe"
"strings"
)
Expand Down Expand Up @@ -57,6 +58,9 @@ func NewOidFromString(s string) (*Oid, error) {
cs := C.CString(s)
defer C.free(unsafe.Pointer(cs))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

if C.git_oid_fromstr(o.toC(), cs) < 0 {
return nil, LastError()
}
Expand Down Expand Up @@ -109,6 +113,10 @@ func ShortenOids(ids []*Oid, minlen int) (int, error) {
defer C.git_oid_shorten_free(shorten)

var ret C.int

runtime.LockOSThread()
defer runtime.UnlockOSThread()

for _, id := range ids {
buf := make([]byte, 41)
C.git_oid_fmt((*C.char)(unsafe.Pointer(&buf[0])), id.toC())
Expand Down Expand Up @@ -162,6 +170,9 @@ func Discover(start string, across_fs bool, ceiling_dirs []string) (string, erro
retpath := (*C.char)(C.malloc(C.GIT_PATH_MAX))
defer C.free(unsafe.Pointer(retpath))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

r := C.git_repository_discover(retpath, C.GIT_PATH_MAX, cstart, cbool(across_fs), ceildirs)

if r == 0 {
Expand Down
7 changes: 7 additions & 0 deletions index.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ func (v *Index) AddByPath(path string) error {
cstr := C.CString(path)
defer C.free(unsafe.Pointer(cstr))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_index_add_bypath(v.ptr, cstr)
if ret < 0 {
return LastError()
Expand All @@ -34,6 +37,10 @@ func (v *Index) AddByPath(path string) error {

func (v *Index) WriteTree() (*Oid, error) {
oid := new(Oid)

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_index_write_tree(oid.toC(), v.ptr)
if ret < 0 {
return nil, LastError()
Expand Down
8 changes: 8 additions & 0 deletions odb.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ func (v *Odb) Exists(oid *Oid) bool {
func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {
oid = new(Oid)
hdr := (*reflect.SliceHeader)(unsafe.Pointer(&data))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_odb_write(oid.toC(), v.ptr, unsafe.Pointer(hdr.Data), C.size_t(hdr.Len), C.git_otype(otype))

if ret < 0 {
Expand All @@ -36,6 +40,10 @@ func (v *Odb) Write(data []byte, otype ObjectType) (oid *Oid, err error) {

func (v *Odb) Read(oid *Oid) (obj *OdbObject, err error) {
obj = new(OdbObject)

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_odb_read(&obj.ptr, v.ptr, oid.toC())
if ret < 0 {
return nil, LastError()
Expand Down
18 changes: 18 additions & 0 deletions packbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ type Packbuilder struct {

func (repo *Repository) NewPackbuilder() (*Packbuilder, error) {
builder := &Packbuilder{}

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_packbuilder_new(&builder.ptr, repo.ptr)
if ret != 0 {
return nil, LastError()
Expand All @@ -38,6 +42,10 @@ func (pb *Packbuilder) Free() {
func (pb *Packbuilder) Insert(id *Oid, name string) error {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_packbuilder_insert(pb.ptr, id.toC(), cname)
if ret != 0 {
return LastError()
Expand All @@ -46,6 +54,9 @@ func (pb *Packbuilder) Insert(id *Oid, name string) error {
}

func (pb *Packbuilder) InsertCommit(id *Oid) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_packbuilder_insert_commit(pb.ptr, id.toC())
if ret != 0 {
return LastError()
Expand All @@ -54,6 +65,9 @@ func (pb *Packbuilder) InsertCommit(id *Oid) error {
}

func (pb *Packbuilder) InsertTree(id *Oid) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_packbuilder_insert_tree(pb.ptr, id.toC())
if ret != 0 {
return LastError()
Expand All @@ -68,6 +82,10 @@ func (pb *Packbuilder) ObjectCount() uint32 {
func (pb *Packbuilder) WriteToFile(name string, mode os.FileMode) error {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_packbuilder_write(pb.ptr, cname, C.uint(mode.Perm()), nil, nil)
if ret != 0 {
return LastError()
Expand Down
27 changes: 27 additions & 0 deletions reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ func (v *Reference) SetSymbolicTarget(target string) (*Reference, error) {
ctarget := C.CString(target)
defer C.free(unsafe.Pointer(ctarget))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_symbolic_set_target(&ptr, v.ptr, ctarget)
if ret < 0 {
return nil, LastError()
Expand All @@ -43,6 +46,9 @@ func (v *Reference) SetSymbolicTarget(target string) (*Reference, error) {
func (v *Reference) SetTarget(target *Oid) (*Reference, error) {
var ptr *C.git_reference

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_set_target(&ptr, v.ptr, target.toC())
if ret < 0 {
return nil, LastError()
Expand All @@ -54,6 +60,9 @@ func (v *Reference) SetTarget(target *Oid) (*Reference, error) {
func (v *Reference) Resolve() (*Reference, error) {
var ptr *C.git_reference

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_resolve(&ptr, v.ptr)
if ret < 0 {
return nil, LastError()
Expand All @@ -67,6 +76,9 @@ func (v *Reference) Rename(name string, force bool) (*Reference, error) {
cname := C.CString(name)
defer C.free(unsafe.Pointer(cname))

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_rename(&ptr, v.ptr, cname, cbool(force))

if ret < 0 {
Expand All @@ -90,6 +102,9 @@ func (v *Reference) SymbolicTarget() string {
}

func (v *Reference) Delete() error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_delete(v.ptr)

if ret < 0 {
Expand Down Expand Up @@ -120,6 +135,10 @@ type ReferenceIterator struct {
// NewReferenceIterator creates a new iterator over reference names
func (repo *Repository) NewReferenceIterator() (*ReferenceIterator, error) {
var ptr *C.git_reference_iterator

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_iterator_new(&ptr, repo.ptr)
if ret < 0 {
return nil, LastError()
Expand All @@ -137,6 +156,10 @@ func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterato
cstr := C.CString(glob)
defer C.free(unsafe.Pointer(cstr))
var ptr *C.git_reference_iterator

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_iterator_glob_new(&ptr, repo.ptr, cstr)
if ret < 0 {
return nil, LastError()
Expand All @@ -151,6 +174,10 @@ func (repo *Repository) NewReferenceIteratorGlob(glob string) (*ReferenceIterato
// the returned error is git.ErrIterOver
func (v *ReferenceIterator) NextName() (string, error) {
var ptr *C.char

runtime.LockOSThread()
defer runtime.UnlockOSThread()

ret := C.git_reference_next_name(&ptr, v.ptr)
if ret == ITEROVER {
return "", ErrIterOver
Expand Down
Loading

0 comments on commit a40bdfd

Please sign in to comment.