Thread-local storage with cgo / buildmode=c-shared

192 views
Skip to first unread message

Conrado P. L. Gouvêa

unread,
Jun 20, 2018, 7:50:11 AM6/20/18
to golan...@googlegroups.com
Hi,

I'm building a C-callable Go library with c-shared. All of its functions return error codes, and I'd like to implement a "char* get_traceback(void)" function that returns the traceback of the last error returned.

The problem arises when you consider threads in the calling code. get_traceback should return the string from the last error returned in that same thread. This means that when a library function returns an error, it should write the traceback to some thread-local storage.

Is there a way to accomplish this with cgo? Would it work to create a thread-local C variable in the preamble of some .go file, and access it with the C.var syntax?
Or maybe create a map indexed by the thread ID?

And a slightly broader, related question: do functions in a c-shared library always run in the thread of the calling code?

Thanks!
Conrado

Ian Lance Taylor

unread,
Jun 20, 2018, 9:33:15 AM6/20/18
to Conrado P. L. Gouvêa, golang-nuts
On Wed, Jun 20, 2018 at 4:49 AM, Conrado P. L. Gouvêa
<conra...@gmail.com> wrote:
>
> I'm building a C-callable Go library with c-shared. All of its functions
> return error codes, and I'd like to implement a "char* get_traceback(void)"
> function that returns the traceback of the last error returned.
>
> The problem arises when you consider threads in the calling code.
> get_traceback should return the string from the last error returned in that
> same thread. This means that when a library function returns an error, it
> should write the traceback to some thread-local storage.
>
> Is there a way to accomplish this with cgo? Would it work to create a
> thread-local C variable in the preamble of some .go file, and access it with
> the C.var syntax?
> Or maybe create a map indexed by the thread ID?

I assume this is a traceback of Go code, which implies that it will be
in memory allocated using the Go heap. That means that you need to
retain a pointer to it on the Go side, or Go's garbage collector will
collect it at an unpredictable time. I see two obvious options. One
is to copy all the data into C-allocated memory, in which case you may
as well return a C pointer to the C code and let the C code store it
in thread local storage. The other is to store the data in a map on
the Go side, perhaps indexed by a simple integer, and return the
integer to C, in which case again the C side can easily store the
index in thread local storage, and call into Go to retrieve the value
if it is needed. Either way you'll need to figure out how to free a
traceback that is no longer needed. And either way I think the answer
to your question is that you should write to thread local storage in
C, not Go.

> And a slightly broader, related question: do functions in a c-shared library
> always run in the thread of the calling code?

A function called in a c-shared library will always run on the
caller's thread. Of course, any goroutines that it starts will likely
run on different threads.

Ian
Reply all
Reply to author
Forward
0 new messages