Commit 0d3dd8fb by Ian Lance Taylor

runtime: copy cgo support from Go 1.7 runtime

    
    Remove support for _cgo_allocate.  It was removed from the gc
    toolchain in Go 1.5, so it is unlikely that anybody is trying to use it.
    
    Reviewed-on: https://go-review.googlesource.com/34557

From-SVN: r243805
parent 4daecdb6
e6fb629c5b246bceab5fc8e8613cf2cf82b1e98f
4a0bb435bbb1d1516b486d1998e8dc184576db61
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import (
"runtime/internal/atomic"
_ "unsafe"
)
// For historical reasons these functions are called as though they
// were in the syscall package.
//go:linkname Cgocall syscall.Cgocall
//go:linkname CgocallDone syscall.CgocallDone
//go:linkname CgocallBack syscall.CgocallBack
//go:linkname CgocallBackDone syscall.CgocallBackDone
// A routine that may be called by SWIG.
//go:linkname _cgo_panic _cgo_panic
// iscgo is set to true if the cgo tool sets the C variable runtime_iscgo
// to true.
var iscgo bool
// cgoHasExtraM is set on startup when an extra M is created for cgo.
// The extra M must be created before any C/C++ code calls cgocallback.
var cgoHasExtraM bool
// Cgocall prepares to call from code written in Go to code written in
// C/C++. This takes the current goroutine out of the Go scheduler, as
// though it were making a system call. Otherwise the program can
// lookup if the C code blocks. The idea is to call this function,
// then immediately call the C/C++ function. After the C/C++ function
// returns, call cgocalldone. The usual Go code would look like
// syscall.Cgocall()
// defer syscall.Cgocalldone()
// cfunction()
func Cgocall() {
lockOSThread()
mp := getg().m
mp.ncgocall++
mp.ncgo++
entersyscall(0)
}
// CgocallDone prepares to return to Go code from C/C++ code.
func CgocallDone() {
gp := getg()
if gp == nil {
throw("no g in CgocallDone")
}
gp.m.ncgo--
// If we are invoked because the C function called _cgo_panic,
// then _cgo_panic will already have exited syscall mode.
if gp.atomicstatus == _Gsyscall {
exitsyscall(0)
}
unlockOSThread()
}
// CgocallBack is used when calling from C/C++ code into Go code.
// The usual approach is
// syscall.CgocallBack()
// defer syscall.CgocallBackDone()
// gofunction()
//go:nosplit
func CgocallBack() {
if getg() == nil || getg().m == nil {
needm(0)
mp := getg().m
mp.dropextram = true
}
exitsyscall(0)
if getg().m.ncgo == 0 {
// The C call to Go came from a thread created by C.
// The C call to Go came from a thread not currently running
// any Go. In the case of -buildmode=c-archive or c-shared,
// this call may be coming in before package initialization
// is complete. Wait until it is.
<-main_init_done
}
mp := getg().m
if mp.needextram || atomic.Load(&extraMWaiters) > 0 {
mp.needextram = false
newextram()
}
}
// CgocallBackDone prepares to return to C/C++ code that has called
// into Go code.
func CgocallBackDone() {
entersyscall(0)
mp := getg().m
if mp.dropextram && mp.ncgo == 0 {
mp.dropextram = false
dropm()
}
}
// _cgo_panic may be called by SWIG code to panic.
func _cgo_panic(p *byte) {
exitsyscall(0)
panic(gostringnocopy(p))
}
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
// Support for memory sanitizer. See runtime/cgo/mmap.go.
// +build linux,amd64
package runtime
import "unsafe"
// _cgo_mmap is filled in by runtime/cgo when it is linked into the
// program, so it is only non-nil when using cgo.
//go:linkname _cgo_mmap _cgo_mmap
var _cgo_mmap unsafe.Pointer
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
if _cgo_mmap != nil {
// Make ret a uintptr so that writing to it in the
// function literal does not trigger a write barrier.
// A write barrier here could break because of the way
// that mmap uses the same value both as a pointer and
// an errno value.
// TODO: Fix mmap to return two values.
var ret uintptr
systemstack(func() {
ret = callCgoMmap(addr, n, prot, flags, fd, off)
})
return unsafe.Pointer(ret)
}
return sysMmap(addr, n, prot, flags, fd, off)
}
// sysMmap calls the mmap system call. It is implemented in assembly.
func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
// cgoMmap calls the mmap function in the runtime/cgo package on the
// callCgoMmap calls the mmap function in the runtime/cgo package
// using the GCC calling convention. It is implemented in assembly.
func callCgoMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) uintptr
......@@ -8,6 +8,44 @@ import (
"unsafe"
)
// Temporary for C code to call:
//go:linkname minit runtime.minit
// minit is called to initialize a new m (including the bootstrap m).
// Called on the new thread, cannot allocate memory.
func minit() {
// Initialize signal handling.
_g_ := getg()
var st _stack_t
sigaltstack(nil, &st)
if st.ss_flags&_SS_DISABLE != 0 {
signalstack(_g_.m.gsignalstack, _g_.m.gsignalstacksize)
_g_.m.newSigstack = true
} else {
_g_.m.newSigstack = false
}
// FIXME: We should set _g_.m.procid here.
// restore signal mask from m.sigmask and unblock essential signals
nmask := _g_.m.sigmask
for i := range sigtable {
if sigtable[i].flags&_SigUnblock != 0 {
sigdelset(&nmask, int32(i))
}
}
sigprocmask(_SIG_SETMASK, &nmask, nil)
}
// Called from dropm to undo the effect of an minit.
//go:nosplit
func unminit() {
if getg().m.newSigstack {
signalstack(nil, 0)
}
}
var urandom_dev = []byte("/dev/urandom\x00")
func getRandomData(r []byte) {
......
......@@ -479,8 +479,6 @@ type m struct {
dropextram bool // drop after call is done
gcing int32
cgomal *cgoMal // allocations via _cgo_allocate
}
type p struct {
......@@ -801,14 +799,6 @@ var (
// array.
type g_ucontext_t [(_sizeof_ucontext_t + 15) / unsafe.Sizeof(unsafe.Pointer(nil))]unsafe.Pointer
// cgoMal tracks allocations made by _cgo_allocate
// FIXME: _cgo_allocate has been removed from gc and can probably be
// removed from gccgo too.
type cgoMal struct {
next *cgoMal
alloc unsafe.Pointer
}
// sigset is the Go version of the C type sigset_t.
// _sigset_t is defined by the Makefile from <signal.h>.
type sigset _sigset_t
......@@ -327,7 +327,7 @@ func ensureSigM() {
//go:norace
//go:nowritebarrierrec
func badsignal(sig uintptr, c *sigctxt) {
needm()
needm(0)
if !sigsend(uint32(sig)) {
// A foreign thread received the signal sig, and the
// Go code does not want to handle it.
......
......@@ -17,18 +17,19 @@ import (
func sigaction(signum int32, act *_sigaction, oact *_sigaction) int32
//extern sigprocmask
func sigprocmask(how int32, set *_sigset_t, oldset *_sigset_t) int32
func sigprocmask(how int32, set *sigset, oldset *sigset) int32
// The argument should be simply *_sigset_t, but that fails on GNU/Linux
// which sometimes uses _sigset_t and sometimes uses ___sigset_t.
//extern sigfillset
func sigfillset(set unsafe.Pointer) int32
func sigfillset(set *sigset) int32
//extern sigemptyset
func sigemptyset(set *_sigset_t) int32
func sigemptyset(set *sigset) int32
//extern sigaddset
func sigaddset(set *_sigset_t, signum int32) int32
func sigaddset(set *sigset, signum int32) int32
//extern sigdelset
func sigdelset(set *sigset, signum int32) int32
//extern sigaltstack
func sigaltstack(ss *_stack_t, oss *_stack_t) int32
......@@ -57,9 +58,19 @@ func (c *sigctxt) sigcode() uint64 {
}
//go:nosplit
func msigsave(mp *m) {
sigprocmask(_SIG_SETMASK, nil, &mp.sigmask)
}
//go:nosplit
func msigrestore(sigmask sigset) {
sigprocmask(_SIG_SETMASK, &sigmask, nil)
}
//go:nosplit
func sigblock() {
var set _sigset_t
sigfillset(unsafe.Pointer(&set))
var set sigset
sigfillset(&set)
sigprocmask(_SIG_SETMASK, &set, nil)
}
......@@ -81,7 +92,7 @@ func setsig(i int32, fn uintptr, restart bool) {
if restart {
sa.sa_flags |= _SA_RESTART
}
sigfillset(unsafe.Pointer(&sa.sa_mask))
sigfillset((*sigset)(unsafe.Pointer(&sa.sa_mask)))
setSigactionHandler(&sa, fn)
sigaction(i, &sa, nil)
}
......@@ -117,10 +128,12 @@ func getsig(i int32) uintptr {
return getSigactionHandler(&sa)
}
func signalstack(p unsafe.Pointer, n uintptr)
//go:nosplit
//go:nowritebarrierrec
func updatesigmask(m sigmask) {
var mask _sigset_t
var mask sigset
sigemptyset(&mask)
for i := int32(0); i < _NSIG; i++ {
if m[(i-1)/32]&(1<<((uint(i)-1)&31)) != 0 {
......@@ -131,7 +144,7 @@ func updatesigmask(m sigmask) {
}
func unblocksig(sig int32) {
var mask _sigset_t
var mask sigset
sigemptyset(&mask)
sigaddset(&mask, sig)
sigprocmask(_SIG_UNBLOCK, &mask, nil)
......
......@@ -52,8 +52,8 @@ func sighandler(sig uint32, info *_siginfo_t, ctxt unsafe.Pointer, gp *g) {
// All signals were blocked due to the sigaction mask;
// unblock them.
var set _sigset_t
sigfillset(unsafe.Pointer(&set))
var set sigset
sigfillset(&set)
sigprocmask(_SIG_UNBLOCK, &set, nil)
sigpanic()
......
......@@ -249,6 +249,24 @@ func funcPC(f interface{}) uintptr {
}
// For gccgo, to communicate from the C code to the Go code.
//go:linkname setIsCgo runtime.setIsCgo
func setIsCgo() {
iscgo = true
}
// Temporary for gccgo until we port proc.go.
//go:linkname makeMainInitDone runtime.makeMainInitDone
func makeMainInitDone() {
main_init_done = make(chan bool)
}
// Temporary for gccgo until we port proc.go.
//go:linkname closeMainInitDone runtime.closeMainInitDone
func closeMainInitDone() {
close(main_init_done)
}
// For gccgo, to communicate from the C code to the Go code.
//go:linkname setCpuidECX runtime.setCpuidECX
func setCpuidECX(v uint32) {
cpuid_ecx = v
......@@ -301,6 +319,9 @@ var writeBarrier struct {
alignme uint64 // guarantee alignment so that compiler can use a 32 or 64-bit load
}
func queueRescan(*g) {
}
// Here for gccgo until we port atomic_pointer.go and mgc.go.
//go:nosplit
func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
......@@ -446,6 +467,8 @@ func cpuprofAdd(stk []uintptr) {
func Breakpoint()
func LockOSThread()
func UnlockOSThread()
func lockOSThread()
func unlockOSThread()
func allm() *m
func allgs() []*g
......@@ -499,8 +522,6 @@ func getZerobase() *uintptr {
}
// Temporary for gccgo until we port proc.go.
func needm()
func dropm()
func sigprof()
func mcount() int32
func gcount() int32
......@@ -529,6 +550,12 @@ func getsched() *schedt {
return &sched
}
// Temporary for gccgo until we port proc.go.
//go:linkname getCgoHasExtraM runtime.getCgoHasExtraM
func getCgoHasExtraM() *bool {
return &cgoHasExtraM
}
// Throw and rethrow an exception.
func throwException()
func rethrowException()
......
......@@ -5,193 +5,6 @@
license that can be found in the LICENSE file. */
#include "runtime.h"
#include "go-alloc.h"
#include "go-type.h"
extern void chanrecv1 (ChanType *, Hchan *, void *)
__asm__ (GOSYM_PREFIX "runtime.chanrecv1");
/* Prepare to call from code written in Go to code written in C or
C++. This takes the current goroutine out of the Go scheduler, as
though it were making a system call. Otherwise the program can
lock up if the C code goes to sleep on a mutex or for some other
reason. This idea is to call this function, then immediately call
the C/C++ function. After the C/C++ function returns, call
syscall_cgocalldone. The usual Go code would look like
syscall.Cgocall()
defer syscall.Cgocalldone()
cfunction()
*/
/* We let Go code call these via the syscall package. */
void syscall_cgocall(void) __asm__ (GOSYM_PREFIX "syscall.Cgocall");
void syscall_cgocalldone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallDone");
void syscall_cgocallback(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBack");
void syscall_cgocallbackdone(void) __asm__ (GOSYM_PREFIX "syscall.CgocallBackDone");
void
syscall_cgocall ()
{
M* m;
if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0))
runtime_newextram ();
runtime_lockOSThread();
m = runtime_m ();
++m->ncgocall;
++m->ncgo;
runtime_entersyscall (0);
}
/* Prepare to return to Go code from C/C++ code. */
void
syscall_cgocalldone ()
{
G* g;
g = runtime_g ();
__go_assert (g != NULL);
--g->m->ncgo;
if (g->m->ncgo == 0)
{
/* We are going back to Go, and we are not in a recursive call.
Let the garbage collector clean up any unreferenced
memory. */
g->m->cgomal = NULL;
}
/* If we are invoked because the C function called _cgo_panic, then
_cgo_panic will already have exited syscall mode. */
if (g->atomicstatus == _Gsyscall)
runtime_exitsyscall (0);
runtime_unlockOSThread();
}
/* Call back from C/C++ code to Go code. */
void
syscall_cgocallback ()
{
M *mp;
mp = runtime_m ();
if (mp == NULL)
{
runtime_needm ();
mp = runtime_m ();
mp->dropextram = true;
}
runtime_exitsyscall (0);
if (runtime_m ()->ncgo == 0)
{
/* The C call to Go came from a thread not currently running any
Go. In the case of -buildmode=c-archive or c-shared, this
call may be coming in before package initialization is
complete. Wait until it is. */
chanrecv1 (NULL, runtime_main_init_done, NULL);
}
mp = runtime_m ();
if (mp->needextram)
{
mp->needextram = 0;
runtime_newextram ();
}
}
/* Prepare to return to C/C++ code from a callback to Go code. */
void
syscall_cgocallbackdone ()
{
M *mp;
runtime_entersyscall (0);
mp = runtime_m ();
if (mp->dropextram && mp->ncgo == 0)
{
mp->dropextram = false;
runtime_dropm ();
}
}
/* Allocate memory and save it in a list visible to the Go garbage
collector. */
void *
alloc_saved (size_t n)
{
void *ret;
M *m;
CgoMal *c;
ret = __go_alloc (n);
m = runtime_m ();
c = (CgoMal *) __go_alloc (sizeof (CgoMal));
c->next = m->cgomal;
c->alloc = ret;
m->cgomal = c;
return ret;
}
/* These are routines used by SWIG. The gc runtime library provides
the same routines under the same name, though in that case the code
is required to import runtime/cgo. */
void *
_cgo_allocate (size_t n)
{
void *ret;
runtime_exitsyscall (0);
ret = alloc_saved (n);
runtime_entersyscall (0);
return ret;
}
extern const struct __go_type_descriptor string_type_descriptor
__asm__ (GOSYM_PREFIX "__go_tdn_string");
void
_cgo_panic (const char *p)
{
intgo len;
unsigned char *data;
String *ps;
Eface e;
const struct __go_type_descriptor *td;
runtime_exitsyscall (0);
len = __builtin_strlen (p);
data = alloc_saved (len);
__builtin_memcpy (data, p, len);
ps = alloc_saved (sizeof *ps);
ps->str = data;
ps->len = len;
td = &string_type_descriptor;
memcpy(&e._type, &td, sizeof td); /* This is a const_cast. */
e.data = ps;
/* We don't call runtime_entersyscall here, because normally what
will happen is that we will walk up the stack to a Go deferred
function that calls recover. However, this will do the wrong
thing if this panic is recovered and the stack unwinding is
caught by a C++ exception handler. It might be possible to
handle this by calling runtime_entersyscall in the personality
function in go-unwind.c. FIXME. */
runtime_panic (e);
}
/* Used for _cgo_wait_runtime_init_done. This is based on code in
runtime/cgo/gcc_libinit.c in the master library. */
......@@ -249,8 +62,3 @@ _cgo_notify_runtime_init_done (void)
// runtime_iscgo is set to true if some cgo code is linked in.
// This is done by a constructor in the cgo generated code.
_Bool runtime_iscgo;
// runtime_cgoHasExtraM is set on startup when an extra M is created
// for cgo. The extra M must be created before any C/C++ code calls
// cgocallback.
_Bool runtime_cgoHasExtraM;
......@@ -61,6 +61,7 @@ initfn (int argc, char **argv, char** env __attribute__ ((unused)))
runtime_isarchive = true;
setIsCgo ();
runtime_cpuinit ();
runtime_initsig(true);
......
......@@ -46,6 +46,9 @@ main (int argc, char **argv)
return 0;
runtime_isstarted = true;
if (runtime_iscgo)
setIsCgo ();
__go_end = (uintptr)_end;
runtime_cpuinit ();
runtime_check ();
......
......@@ -543,4 +543,3 @@ int32 runtime_setgcpercent(int32)
#define PoisonStack ((uintptr)0x6868686868686868ULL)
struct Workbuf;
void runtime_proc_scan(struct Workbuf**, void (*)(struct Workbuf**, Obj));
......@@ -1283,7 +1283,6 @@ markroot(ParFor *desc, uint32 i)
enqueue1(&wbuf, (Obj){(byte*)&runtime_allm, sizeof runtime_allm, 0});
enqueue1(&wbuf, (Obj){(byte*)&runtime_allp, sizeof runtime_allp, 0});
enqueue1(&wbuf, (Obj){(byte*)&work, sizeof work, 0});
runtime_proc_scan(&wbuf, enqueue1);
break;
case RootFinalizers:
......
......@@ -52,7 +52,7 @@ typedef uintptr uintreg;
/* Defined types. */
typedef uint8 bool;
typedef _Bool bool;
typedef uint8 byte;
typedef struct g G;
typedef struct mutex Lock;
......@@ -240,7 +240,6 @@ extern M* runtime_allm;
extern P** runtime_allp;
extern Sched* runtime_sched;
extern int32 runtime_gomaxprocs;
extern uint32 runtime_needextram;
extern uint32 runtime_panicking(void)
__asm__ (GOSYM_PREFIX "runtime.getPanicking");
extern int8* runtime_goos;
......@@ -298,15 +297,13 @@ void runtime_ready(G*);
String runtime_getenv(const char*);
int32 runtime_atoi(const byte*, intgo);
void* runtime_mstart(void*);
G* runtime_malg(int32, byte**, uintptr*);
G* runtime_malg(bool, bool, byte**, uintptr*)
__asm__(GOSYM_PREFIX "runtime.malg");
void runtime_mpreinit(M*);
void runtime_minit(void);
void runtime_unminit(void);
void runtime_needm(void)
__asm__ (GOSYM_PREFIX "runtime.needm");
void runtime_dropm(void)
__asm__ (GOSYM_PREFIX "runtime.dropm");
void runtime_signalstack(byte*, int32);
void runtime_minit(void)
__asm__ (GOSYM_PREFIX "runtime.minit");
void runtime_signalstack(byte*, uintptr)
__asm__ (GOSYM_PREFIX "runtime.signalstack");
MCache* runtime_allocmcache(void)
__asm__ (GOSYM_PREFIX "runtime.allocmcache");
void runtime_freemcache(MCache*);
......@@ -345,7 +342,8 @@ int32 runtime_round2(int32 x); // round x up to a power of 2.
void runtime_setg(G*)
__asm__ (GOSYM_PREFIX "runtime.setg");
void runtime_newextram(void);
void runtime_newextram(void)
__asm__ (GOSYM_PREFIX "runtime.newextram");
#define runtime_exit(s) exit(s)
#define runtime_breakpoint() __builtin_trap()
void runtime_gosched(void);
......@@ -523,9 +521,12 @@ void runtime_procyield(uint32)
__asm__(GOSYM_PREFIX "runtime.procyield");
void runtime_osyield(void)
__asm__(GOSYM_PREFIX "runtime.osyield");
void runtime_lockOSThread(void);
void runtime_unlockOSThread(void);
bool runtime_lockedOSThread(void);
void runtime_lockOSThread(void)
__asm__(GOSYM_PREFIX "runtime.lockOSThread");
void runtime_unlockOSThread(void)
__asm__(GOSYM_PREFIX "runtime.unlockOSThread");
bool runtime_lockedOSThread(void)
__asm__(GOSYM_PREFIX "runtime.lockedOSThread");
void runtime_printcreatedby(G*)
__asm__(GOSYM_PREFIX "runtime.printcreatedby");
......@@ -587,8 +588,6 @@ struct time_now_ret now() __asm__ (GOSYM_PREFIX "time.now")
extern void _cgo_wait_runtime_init_done (void);
extern void _cgo_notify_runtime_init_done (void);
extern _Bool runtime_iscgo;
extern _Bool runtime_cgoHasExtraM;
extern Hchan *runtime_main_init_done;
extern uintptr __go_end __attribute__ ((weak));
extern void *getitab(const struct __go_type_descriptor *,
const struct __go_type_descriptor *,
......@@ -596,5 +595,11 @@ extern void *getitab(const struct __go_type_descriptor *,
__asm__ (GOSYM_PREFIX "runtime.getitab");
extern void runtime_cpuinit(void);
extern void setIsCgo(void)
__asm__ (GOSYM_PREFIX "runtime.setIsCgo");
extern void setCpuidECX(uint32)
__asm__ (GOSYM_PREFIX "runtime.setCpuidECX");
extern void makeMainInitDone(void)
__asm__ (GOSYM_PREFIX "runtime.makeMainInitDone");
extern void closeMainInitDone(void)
__asm__ (GOSYM_PREFIX "runtime.closeMainInitDone");
......@@ -99,43 +99,12 @@ runtime_cputicks(void)
void
runtime_mpreinit(M *mp)
{
int32 stacksize = 32 * 1024; // OS X wants >=8K, Linux >=2K
#ifdef SIGSTKSZ
if(stacksize < SIGSTKSZ)
stacksize = SIGSTKSZ;
#endif
mp->gsignal = runtime_malg(stacksize, (byte**)&mp->gsignalstack, &mp->gsignalstacksize);
mp->gsignal = runtime_malg(true, true, (byte**)&mp->gsignalstack, &mp->gsignalstacksize);
mp->gsignal->m = mp;
}
// Called to initialize a new m (including the bootstrap m).
// Called on the new thread, can not allocate memory.
void
runtime_minit(void)
{
M* m;
sigset_t sigs;
// Initialize signal handling.
m = runtime_m();
runtime_signalstack(m->gsignalstack, m->gsignalstacksize);
if (sigemptyset(&sigs) != 0)
runtime_throw("sigemptyset");
pthread_sigmask(SIG_SETMASK, &sigs, nil);
}
// Called from dropm to undo the effect of an minit.
void
runtime_unminit(void)
{
runtime_signalstack(nil, 0);
}
void
runtime_signalstack(byte *p, int32 n)
runtime_signalstack(byte *p, uintptr n)
{
stack_t st;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment