diff options
Diffstat (limited to 'src/libcgo/cgocall.c')
| -rw-r--r-- | src/libcgo/cgocall.c | 308 |
1 files changed, 0 insertions, 308 deletions
diff --git a/src/libcgo/cgocall.c b/src/libcgo/cgocall.c deleted file mode 100644 index 13843d400..000000000 --- a/src/libcgo/cgocall.c +++ /dev/null @@ -1,308 +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. - -#define _GNU_SOURCE -#include <stdio.h> -#include <errno.h> -#include <linux/futex.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <pthread.h> -#include <stdint.h> -#include <string.h> -#include <stdlib.h> - -#define nil ((void*)0) - -/* - * gcc implementation of src/pkg/runtime/linux/thread.c - */ -typedef struct Lock Lock; -typedef struct Note Note; -typedef uint32_t uint32; - -struct Lock -{ - uint32 key; - uint32 sema; // ignored -}; - -struct Note -{ - Lock lock; - uint32 pad; -}; - -static struct timespec longtime = -{ - 1<<30, // 34 years - 0 -}; - -static int -cas(uint32 *val, uint32 old, uint32 new) -{ - int ret; - - __asm__ __volatile__( - "lock; cmpxchgl %2, 0(%3)\n" - "setz %%al\n" - : "=a" (ret) - : "a" (old), - "r" (new), - "r" (val) - : "memory", "cc" - ); - - return ret & 1; -} - -static void -futexsleep(uint32 *addr, uint32 val) -{ - int ret; - - ret = syscall(SYS_futex, (int*)addr, FUTEX_WAIT, val, &longtime, nil, 0); - if(ret >= 0 || errno == EAGAIN || errno == EINTR) - return; - fprintf(stderr, "futexsleep: %s\n", strerror(errno)); - *(int*)0 = 0; -} - -static void -futexwakeup(uint32 *addr) -{ - int ret; - - ret = syscall(SYS_futex, (int*)addr, FUTEX_WAKE, 1, nil, nil, 0); - if(ret >= 0) - return; - fprintf(stderr, "futexwakeup: %s\n", strerror(errno)); - *(int*)0 = 0; -} - -static void -futexlock(Lock *l) -{ - uint32 v; - -again: - v = l->key; - if((v&1) == 0){ - if(cas(&l->key, v, v|1)){ - // Lock wasn't held; we grabbed it. - return; - } - goto again; - } - - if(!cas(&l->key, v, v+2)) - goto again; - - futexsleep(&l->key, v+2); - for(;;){ - v = l->key; - if((int)v < 2) { - fprintf(stderr, "futexsleep: invalid key %d\n", (int)v); - *(int*)0 = 0; - } - if(cas(&l->key, v, v-2)) - break; - } - goto again; -} - -static void -futexunlock(Lock *l) -{ - uint32 v; - -again: - v = l->key; - if((v&1) == 0) - *(int*)0 = 0; - if(!cas(&l->key, v, v&~1)) - goto again; - - // If there were waiters, wake one. - if(v & ~1) - futexwakeup(&l->key); -} - -static void -lock(Lock *l) -{ - futexlock(l); -} - -static void -unlock(Lock *l) -{ - futexunlock(l); -} - -void -noteclear(Note *n) -{ - n->lock.key = 0; - futexlock(&n->lock); -} - -static void -notewakeup(Note *n) -{ - futexunlock(&n->lock); -} - -static void -notesleep(Note *n) -{ - futexlock(&n->lock); - futexunlock(&n->lock); -} - -/* - * runtime Cgo server. - * gcc half of src/pkg/runtime/cgocall.c - */ - -typedef struct CgoWork CgoWork; -typedef struct CgoServer CgoServer; -typedef struct Cgo Cgo; - -struct Cgo -{ - Lock lock; - CgoServer *idle; - CgoWork *whead; - CgoWork *wtail; -}; - -struct CgoServer -{ - CgoServer *next; - Note note; - CgoWork *work; -}; - -struct CgoWork -{ - CgoWork *next; - Note note; - void (*fn)(void*); - void *arg; -}; - -Cgo cgo; - -static void newserver(void); - -void -initcgo(void) -{ - newserver(); -} - -static void* go_pthread(void*); - -/* - * allocate servers to handle any work that has piled up - * and one more server to sit idle and wait for new work. - */ -static void -newserver(void) -{ - CgoServer *f; - CgoWork *w, *next; - pthread_t p; - - lock(&cgo.lock); - // 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; - - // 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; - noteclear(&f->note); - cgo.idle = f; - if(pthread_create(&p, nil, go_pthread, f) < 0) { - fprintf(stderr, "pthread_create: %s\n", strerror(errno)); - *(int*)0 = 0; - } - } - unlock(&cgo.lock); -} - -static void* -go_pthread(void *v) -{ - CgoServer *f; - CgoWork *w; - - // newserver queued us; wait for work - f = v; - goto wait; - - for(;;) { - // 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; - - // 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); - f->next = cgo.idle; - cgo.idle = f; - unlock(&cgo.lock); - -wait: - // wait for work - notesleep(&f->note); - } -} - -// Helper. - -void -_cgo_malloc(void *p) -{ - struct a { - long long n; - void *ret; - } *a = p; - - a->ret = malloc(a->n); -} |
