1
0
mirror of https://github.com/golang/go synced 2024-11-26 00:28:00 -07:00

cgocall bug fix.

better FFI demo: compute fibonacci numbers using FFI'ed libgmp.

R=r
DELTA=281  (255 added, 19 deleted, 7 changed)
OCL=33815
CL=33820
This commit is contained in:
Russ Cox 2009-08-24 21:16:15 -07:00
parent 429157848f
commit 75a38963ca
6 changed files with 257 additions and 21 deletions

View File

@ -218,7 +218,6 @@ newserver(void)
pthread_t p;
lock(&cgo.lock);
if(cgo.idle == nil) {
// kick off new servers with work to do
for(w=cgo.whead; w; w=next) {
next = w;
@ -237,6 +236,7 @@ newserver(void)
cgo.wtail = nil;
// kick off one more server to sit idle
if(cgo.idle == nil) {
f = malloc(sizeof *f);
memset(f, 0, sizeof *f);
f->next = cgo.idle;
@ -256,23 +256,41 @@ go_pthread(void *v)
CgoServer *f;
CgoWork *w;
// newserver queued us; wait for work
f = v;
goto wait;
for(;;) {
// wait for work
notesleep(&f->note);
// kick off new server to handle requests while we work
newserver();
// do work
w = f->work;
w->fn(w->arg);
notewakeup(&w->note);
f->work = nil;
// queue f on idle list
// take some work if available
lock(&cgo.lock);
if((w = cgo.whead) != nil) {
cgo.whead = w->next;
if(cgo.whead == nil)
cgo.wtail = nil;
unlock(&cgo.lock);
f->work = w;
continue;
}
// otherwise queue
f->work = nil;
noteclear(&f->note);
lock(&cgo.lock);
f->next = cgo.idle;
cgo.idle = f;
unlock(&cgo.lock);
wait:
// wait for work
notesleep(&f->note);
}
}

60
usr/rsc/gmp/6c.c Normal file
View File

@ -0,0 +1,60 @@
// 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 "cgocall.h"
typedef struct Int Int;
struct Int
{
void *v;
};
// turn on ffi
#pragma dynld initcgo initcgo "libcgo.so"
#pragma dynld cgo cgo "libcgo.so"
// pull in gmp routines, implemented in gcc.c, from gmp.so
#pragma dynld gmp_addInt gmp_addInt "gmp.so"
void (*gmp_addInt)(void*);
#pragma dynld gmp_stringInt gmp_stringInt "gmp.so"
void (*gmp_stringInt)(void*);
#pragma dynld gmp_newInt gmp_newInt "gmp.so"
void (*gmp_newInt)(void*);
#pragma dynld c_free free "gmp.so"
void (*c_free)(void*);
void
gmp·addInt(Int *z, Int *x, Int *y, Int *ret)
{
cgocall(gmp_addInt, &z);
}
void
gmp·stringInt(Int *z, String ret)
{
struct {
Int *z;
byte *p;
} a;
a.z = z;
a.p = nil;
cgocall(gmp_stringInt, &a);
ret = gostring(a.p);
cgocall(c_free, a.p);
FLUSH(&ret);
}
void
gmp·NewInt(uint64 x, Int *z)
{
if(sizeof(uintptr) != 8) *(int32*)0 = 0;
z = mallocgc(sizeof *z);
FLUSH(&z);
cgocall(gmp_newInt, &x);
}

52
usr/rsc/gmp/Makefile Normal file
View File

@ -0,0 +1,52 @@
# 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.
# FFI demo
include ../../../src/Make.$(GOARCH)
all: gmp.a gmp.so
gcc.o: gcc.c
gcc -fPIC -O2 -o gcc.o -c gcc.c
gmp.so: gcc.o
gcc -shared -o gmp.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo -lgmp
gmp.a: 6c.6 go.6
gopack grc gmp.a 6c.6 go.6
# from pkg/runtime/Makefile: TODO(rsc): how to deal with this?
# Set SIZE to 32 or 64.
SIZE_386=32
SIZE_amd64=64
SIZE_arm=32
SIZE=$(SIZE_$(GOARCH))
# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry).
CFLAGS_64=-D_64BIT
# TODO(kaib): fix register allocation to honor extern register so we
# can enable optimizations again.
CFLAGS_arm=-N
CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE)) $(CFLAGS_$(GOARCH))
6c.6: 6c.c
6c -FVw $(CFLAGS) -I$(GOROOT)/src/pkg/runtime 6c.c
go.6: go.go
6g go.go
PKG=$(GOROOT)/pkg/$(GOOS)_$(GOARCH)
install: $(PKG)/gmp.so $(PKG)/gmp.a
$(PKG)/gmp.so: gmp.so
cp gmp.so $@
$(PKG)/gmp.a: gmp.a
cp gmp.a $@
clean:
rm -f *.6 *.o *.so *.a

54
usr/rsc/gmp/gcc.c Normal file
View File

@ -0,0 +1,54 @@
// 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 <stdint.h>
#include <gmp.h>
#include <string.h>
typedef int32_t int32;
typedef uint64_t uint64;
typedef struct Int Int;
struct Int
{
mpz_t *mp;
};
void
gmp_newInt(void *v)
{
struct {
uint64 x;
Int *z;
} *a = v;
a->z->mp = malloc(sizeof *a->z->mp);
mpz_init_set_ui(*a->z->mp, a->x);
}
void
gmp_addInt(void *v)
{
struct {
Int *z;
Int *x;
Int *y;
Int *ret;
} *a = v;
a->ret = a->z;
mpz_add(*a->z->mp, *a->x->mp, *a->y->mp);
}
void
gmp_stringInt(void *v)
{
struct {
Int *z;
char *p;
} *a = v;
a->p = mpz_get_str(NULL, 10, *a->z->mp);
}

24
usr/rsc/gmp/go.go Normal file
View File

@ -0,0 +1,24 @@
// 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.
package gmp
type Int struct {
hidden *byte
}
func addInt(z, x, y *Int) *Int
func (z *Int) Add(x, y *Int) *Int {
return addInt(z, x, y)
}
func stringInt(z *Int) string
func (z *Int) String() string {
return stringInt(z)
}
func NewInt(n uint64) *Int

28
usr/rsc/gmp/main.go Normal file
View File

@ -0,0 +1,28 @@
// 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.
package main
import big "gmp"
//import "big"
import "fmt"
func Fib(n int) *big.Int {
a := big.NewInt(0);
b := big.NewInt(1);
for i := 0; i < n; i++ {
a, b = b, a;
b.Add(a, b);
}
return b;
}
func main() {
for i := 0; i <= 100; i++ {
fmt.Println(5*i, Fib(5*i));
}
}