better FFI demo: compute fibonacci numbers using FFI'ed libgmp.
R=r
DELTA=281 (255 added, 19 deleted, 7 changed)
OCL=33815
CL=33820
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;
- w->next = nil;
- f = malloc(sizeof *f);
- memset(f, 0, sizeof *f);
- f->work = w;
- noteclear(&f->note);
- notewakeup(&f->note);
- if(pthread_create(&p, nil, go_pthread, f) < 0) {
- fprintf(stderr, "pthread_create: %s\n", strerror(errno));
- *(int*)0 = 0;
- }
+ // kick off new servers with work to do
+ for(w=cgo.whead; w; w=next) {
+ next = w;
+ w->next = nil;
+ f = malloc(sizeof *f);
+ memset(f, 0, sizeof *f);
+ f->work = w;
+ noteclear(&f->note);
+ notewakeup(&f->note);
+ if(pthread_create(&p, nil, go_pthread, f) < 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(errno));
+ *(int*)0 = 0;
}
- cgo.whead = nil;
- cgo.wtail = nil;
+ }
+ cgo.whead = nil;
+ cgo.wtail = nil;
- // kick off one more server to sit idle
+ // 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;
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);
}
}
--- /dev/null
+// 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);
+}
+
--- /dev/null
+# 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
+
--- /dev/null
+// 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);
+}
+
--- /dev/null
+// 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
+
--- /dev/null
+// 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));
+ }
+}