summaryrefslogtreecommitdiff
path: root/src/libcgo
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcgo')
-rw-r--r--src/libcgo/amd64.S36
-rw-r--r--src/libcgo/darwin_amd64.c32
-rw-r--r--src/libcgo/freebsd_amd64.c25
-rw-r--r--src/libcgo/linux_amd64.c25
4 files changed, 118 insertions, 0 deletions
diff --git a/src/libcgo/amd64.S b/src/libcgo/amd64.S
index a7adff9e9..92ded0ac2 100644
--- a/src/libcgo/amd64.S
+++ b/src/libcgo/amd64.S
@@ -43,3 +43,39 @@ EXT(crosscall_amd64):
popq %rbp
popq %rbx
ret
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void *arg, int32 argsize)
+ *
+ * Save registers and call fn with two arguments. fn is a Go function
+ * which takes parameters on the stack rather than in registers.
+ */
+.globl EXT(crosscall2)
+EXT(crosscall2):
+ subq $0x58, %rsp /* keeps stack pointer 32-byte aligned */
+ movq %rbx, 0x10(%rsp)
+ movq %rbp, 0x18(%rsp)
+ movq %r12, 0x20(%rsp)
+ movq %r13, 0x28(%rsp)
+ movq %r14, 0x30(%rsp)
+ movq %r15, 0x38(%rsp)
+
+ movq %rdi, %r12 /* fn */
+ movq %rsi, 0(%rsp) /* arg */
+ movq %rdx, 8(%rsp) /* argsize (includes padding) */
+
+ leaq 0x40(%rsp), %rdi
+ call EXT(libcgo_get_scheduler)
+ movq 0x40(%rsp), %r14 /* m */
+ movq 0x48(%rsp), %r15 /* g */
+
+ call *%r12
+
+ movq 0x10(%rsp), %rbx
+ movq 0x18(%rsp), %rbp
+ movq 0x20(%rsp), %r12
+ movq 0x28(%rsp), %r13
+ movq 0x30(%rsp), %r14
+ movq 0x38(%rsp), %r15
+ addq $0x58, %rsp
+ ret
diff --git a/src/libcgo/darwin_amd64.c b/src/libcgo/darwin_amd64.c
index 14a409f5e..2e0e12411 100644
--- a/src/libcgo/darwin_amd64.c
+++ b/src/libcgo/darwin_amd64.c
@@ -7,9 +7,19 @@
static void* threadentry(void*);
+static pthread_key_t km, kg;
+
void
initcgo(void)
{
+ if(pthread_key_create(&km, nil) < 0) {
+ fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ abort();
+ }
+ if(pthread_key_create(&kg, nil) < 0) {
+ fprintf(stderr, "libcgo: pthread_key_create failed\n");
+ abort();
+ }
}
void
@@ -44,3 +54,25 @@ threadentry(void *v)
crosscall_amd64(ts.m, ts.g, ts.fn);
return nil;
}
+
+void
+libcgo_set_scheduler(void *m, void *g)
+{
+ pthread_setspecific(km, m);
+ pthread_setspecific(kg, g);
+}
+
+struct get_scheduler_args {
+ void *m;
+ void *g;
+};
+
+void libcgo_get_scheduler(struct get_scheduler_args *)
+ __attribute__ ((visibility("hidden")));
+
+void
+libcgo_get_scheduler(struct get_scheduler_args *p)
+{
+ p->m = pthread_getspecific(km);
+ p->g = pthread_getspecific(kg);
+}
diff --git a/src/libcgo/freebsd_amd64.c b/src/libcgo/freebsd_amd64.c
index 4eb0e1ee5..4baf16ee8 100644
--- a/src/libcgo/freebsd_amd64.c
+++ b/src/libcgo/freebsd_amd64.c
@@ -47,3 +47,28 @@ threadentry(void *v)
crosscall_amd64(ts.m, ts.g, ts.fn);
return nil;
}
+
+static __thread void *libcgo_m;
+static __thread void *libcgo_g;
+
+void
+libcgo_set_scheduler(void *m, void *g)
+{
+ libcgo_m = m;
+ libcgo_g = g;
+}
+
+struct get_scheduler_args {
+ void *m;
+ void *g;
+};
+
+void libcgo_get_scheduler(struct get_scheduler_args *)
+ __attribute__ ((visibility("hidden")));
+
+void
+libcgo_get_scheduler(struct get_scheduler_args *p)
+{
+ p->m = libcgo_m;
+ p->g = libcgo_g;
+}
diff --git a/src/libcgo/linux_amd64.c b/src/libcgo/linux_amd64.c
index 14a409f5e..fc4a239fb 100644
--- a/src/libcgo/linux_amd64.c
+++ b/src/libcgo/linux_amd64.c
@@ -44,3 +44,28 @@ threadentry(void *v)
crosscall_amd64(ts.m, ts.g, ts.fn);
return nil;
}
+
+static __thread void *libcgo_m;
+static __thread void *libcgo_g;
+
+void
+libcgo_set_scheduler(void *m, void *g)
+{
+ libcgo_m = m;
+ libcgo_g = g;
+}
+
+struct get_scheduler_args {
+ void *m;
+ void *g;
+};
+
+void libcgo_get_scheduler(struct get_scheduler_args *)
+ __attribute__ ((visibility("hidden")));
+
+void
+libcgo_get_scheduler(struct get_scheduler_args *p)
+{
+ p->m = libcgo_m;
+ p->g = libcgo_g;
+}