mirror of
https://github.com/golang/go
synced 2024-11-19 00:44:40 -07:00
runtime: convert NewCallback and NewCallbackCDecl to Go
LGTM=khr R=khr, remyoudompheng CC=golang-codereviews https://golang.org/cl/132820043
This commit is contained in:
parent
ef50462378
commit
38ce599494
@ -384,8 +384,9 @@ func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
|
||||
" iface struct{}; eface struct{}; interfacetype struct{}; itab struct{};" +
|
||||
" mcache struct{}; bucket struct{}; sudog struct{}; g struct{};" +
|
||||
" hchan struct{}; chantype struct{}; waitq struct{};" +
|
||||
" note struct{};" +
|
||||
")"
|
||||
" note struct{}; wincallbackcontext struct{};" +
|
||||
"); " +
|
||||
"const ( cb_max = 2000 )"
|
||||
f, err = parser.ParseFile(fset, filename, src, 0)
|
||||
if err != nil {
|
||||
log.Fatalf("incorrect generated file: %s", err)
|
||||
|
5
src/cmd/dist/buildruntime.c
vendored
5
src/cmd/dist/buildruntime.c
vendored
@ -402,6 +402,11 @@ mkzruntimedefs(char *dir, char *file)
|
||||
|
||||
bwritestr(&out, p);
|
||||
}
|
||||
|
||||
// Some windows specific const.
|
||||
if(streq(goos, "windows")) {
|
||||
bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
|
||||
}
|
||||
|
||||
writefile(&out, file, 0);
|
||||
|
||||
|
@ -1,77 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
#include "runtime.h"
|
||||
#include "type.h"
|
||||
#include "typekind.h"
|
||||
#include "defs_GOOS_GOARCH.h"
|
||||
#include "os_GOOS.h"
|
||||
#include "zasm_GOOS_GOARCH.h"
|
||||
|
||||
typedef struct Callbacks Callbacks;
|
||||
struct Callbacks {
|
||||
Lock lock;
|
||||
WinCallbackContext* ctxt[cb_max];
|
||||
int32 n;
|
||||
};
|
||||
|
||||
static Callbacks cbs;
|
||||
|
||||
WinCallbackContext** runtime·cbctxts; // to simplify access to cbs.ctxt in sys_windows_*.s
|
||||
|
||||
// Call back from windows dll into go.
|
||||
byte *
|
||||
runtime·compilecallback(Eface fn, bool cleanstack)
|
||||
{
|
||||
FuncType *ft;
|
||||
Type *t;
|
||||
int32 argsize, i, n;
|
||||
WinCallbackContext *c;
|
||||
|
||||
if(fn.type == nil || (fn.type->kind&KindMask) != KindFunc)
|
||||
runtime·panicstring("compilecallback: not a function");
|
||||
ft = (FuncType*)fn.type;
|
||||
if(ft->out.len != 1)
|
||||
runtime·panicstring("compilecallback: function must have one output parameter");
|
||||
if(((Type**)ft->out.array)[0]->size != sizeof(uintptr))
|
||||
runtime·panicstring("compilecallback: output parameter size is wrong");
|
||||
argsize = 0;
|
||||
for(i=0; i<ft->in.len; i++) {
|
||||
t = ((Type**)ft->in.array)[i];
|
||||
if(t->size > sizeof(uintptr))
|
||||
runtime·panicstring("compilecallback: input parameter size is wrong");
|
||||
argsize += sizeof(uintptr);
|
||||
}
|
||||
|
||||
runtime·lock(&cbs.lock);
|
||||
if(runtime·cbctxts == nil)
|
||||
runtime·cbctxts = &(cbs.ctxt[0]);
|
||||
n = cbs.n;
|
||||
for(i=0; i<n; i++) {
|
||||
if(cbs.ctxt[i]->gobody == fn.data && cbs.ctxt[i]->cleanstack == cleanstack) {
|
||||
runtime·unlock(&cbs.lock);
|
||||
// runtime·callbackasm is just a series of CALL instructions
|
||||
// (each is 5 bytes long), and we want callback to arrive at
|
||||
// correspondent call instruction instead of start of
|
||||
// runtime·callbackasm.
|
||||
return (byte*)runtime·callbackasm + i * 5;
|
||||
}
|
||||
}
|
||||
if(n >= cb_max)
|
||||
runtime·throw("too many callback functions");
|
||||
c = runtime·mallocgc(sizeof *c, nil, 0);
|
||||
c->gobody = fn.data;
|
||||
c->argsize = argsize;
|
||||
c->cleanstack = cleanstack;
|
||||
if(cleanstack && argsize!=0)
|
||||
c->restorestack = argsize;
|
||||
else
|
||||
c->restorestack = 0;
|
||||
cbs.ctxt[n] = c;
|
||||
cbs.n++;
|
||||
runtime·unlock(&cbs.lock);
|
||||
|
||||
// as before
|
||||
return (byte*)runtime·callbackasm + n * 5;
|
||||
}
|
92
src/pkg/runtime/syscall_windows.go
Normal file
92
src/pkg/runtime/syscall_windows.go
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2014 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 (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type callbacks struct {
|
||||
lock
|
||||
ctxt [cb_max]*wincallbackcontext
|
||||
n int
|
||||
}
|
||||
|
||||
func (c *wincallbackcontext) isCleanstack() bool {
|
||||
return c.cleanstack == 1
|
||||
}
|
||||
|
||||
func (c *wincallbackcontext) setCleanstack(cleanstack bool) {
|
||||
if cleanstack {
|
||||
c.cleanstack = 1
|
||||
} else {
|
||||
c.cleanstack = 0
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
cbs callbacks
|
||||
cbctxts **wincallbackcontext = &cbs.ctxt[0] // to simplify access to cbs.ctxt in sys_windows_*.s
|
||||
|
||||
callbackasm byte // type isn't really byte, it's code in runtime
|
||||
)
|
||||
|
||||
// callbackasmAddr returns address of runtime.callbackasm
|
||||
// function adjusted by i.
|
||||
// runtime.callbackasm is just a series of CALL instructions
|
||||
// (each is 5 bytes long), and we want callback to arrive at
|
||||
// correspondent call instruction instead of start of
|
||||
// runtime.callbackasm.
|
||||
func callbackasmAddr(i int) uintptr {
|
||||
return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
|
||||
}
|
||||
|
||||
func compileCallback(fn eface, cleanstack bool) (code uintptr) {
|
||||
if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
|
||||
panic("compilecallback: not a function")
|
||||
}
|
||||
ft := (*functype)(unsafe.Pointer(fn._type))
|
||||
if len(ft.out) != 1 {
|
||||
panic("compilecallback: function must have one output parameter")
|
||||
}
|
||||
uintptrSize := uint(unsafe.Sizeof(uintptr(0)))
|
||||
if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize {
|
||||
panic("compilecallback: output parameter size is wrong")
|
||||
}
|
||||
argsize := uint(0)
|
||||
for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] {
|
||||
if (*t).size != uintptrSize {
|
||||
panic("compilecallback: input parameter size is wrong")
|
||||
}
|
||||
argsize += uintptrSize
|
||||
}
|
||||
|
||||
golock(&cbs.lock)
|
||||
defer gounlock(&cbs.lock)
|
||||
|
||||
n := cbs.n
|
||||
for i := 0; i < n; i++ {
|
||||
if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack {
|
||||
return callbackasmAddr(i)
|
||||
}
|
||||
}
|
||||
if n >= cb_max {
|
||||
gothrow("too many callback functions")
|
||||
}
|
||||
|
||||
c := new(wincallbackcontext)
|
||||
c.gobody = fn.data
|
||||
c.argsize = argsize
|
||||
c.setCleanstack(cleanstack)
|
||||
if cleanstack && argsize != 0 {
|
||||
c.restorestack = argsize
|
||||
} else {
|
||||
c.restorestack = 0
|
||||
}
|
||||
cbs.ctxt[n] = c
|
||||
cbs.n++
|
||||
|
||||
return callbackasmAddr(n)
|
||||
}
|
@ -36,14 +36,6 @@ func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err uintptr)
|
||||
err = 0;
|
||||
}
|
||||
|
||||
func NewCallback(fn Eface) (code uintptr) {
|
||||
code = (uintptr)runtime·compilecallback(fn, true);
|
||||
}
|
||||
|
||||
func NewCallbackCDecl(fn Eface) (code uintptr) {
|
||||
code = (uintptr)runtime·compilecallback(fn, false);
|
||||
}
|
||||
|
||||
func Syscall(fn uintptr, nargs uintptr, a1 uintptr, a2 uintptr, a3 uintptr) (r1 uintptr, r2 uintptr, err uintptr) {
|
||||
LibCall c;
|
||||
|
||||
|
13
src/pkg/syscall/asm_windows.s
Normal file
13
src/pkg/syscall/asm_windows.s
Normal file
@ -0,0 +1,13 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//
|
||||
// System calls for Windows are implemented in ../runtime/syscall_windows.goc
|
||||
//
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func compileCallback(fn interface{}, cleanstack bool) uintptr
|
||||
TEXT ·compileCallback(SB),NOSPLIT,$0
|
||||
JMP runtime·compileCallback(SB)
|
@ -1,7 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//
|
||||
// System calls for 386, Windows are implemented in ../runtime/syscall_windows.goc
|
||||
//
|
@ -1,7 +0,0 @@
|
||||
// Copyright 2009 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.
|
||||
|
||||
//
|
||||
// System calls for amd64, Windows are implemented in ../runtime/syscall_windows.goc
|
||||
//
|
@ -105,12 +105,22 @@ func (e Errno) Timeout() bool {
|
||||
return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
|
||||
}
|
||||
|
||||
// Implemented in asm_windows.s
|
||||
func compileCallback(fn interface{}, cleanstack bool) uintptr
|
||||
|
||||
// Converts a Go function to a function pointer conforming
|
||||
// to the stdcall or cdecl calling convention. This is useful when
|
||||
// to the stdcall calling convention. This is useful when
|
||||
// interoperating with Windows code requiring callbacks.
|
||||
// Implemented in ../runtime/syscall_windows.goc
|
||||
func NewCallback(fn interface{}) uintptr
|
||||
func NewCallbackCDecl(fn interface{}) uintptr
|
||||
func NewCallback(fn interface{}) uintptr {
|
||||
return compileCallback(fn, true)
|
||||
}
|
||||
|
||||
// Converts a Go function to a function pointer conforming
|
||||
// to the cdecl calling convention. This is useful when
|
||||
// interoperating with Windows code requiring callbacks.
|
||||
func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
return compileCallback(fn, false)
|
||||
}
|
||||
|
||||
// windows api calls
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user