OSDN Git Service

runtime: More efficient implementation of trampolines.
[pf3gnuchains/gcc-fork.git] / libgo / runtime / runtime.h
index e43177f..94f8911 100644 (file)
@@ -6,25 +6,28 @@
 
 #include "config.h"
 
-#define _GNU_SOURCE
 #include "go-assert.h"
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <pthread.h>
 #include <semaphore.h>
+#include <ucontext.h>
 
 #ifdef HAVE_SYS_MMAN_H
 #include <sys/mman.h>
 #endif
 
+#include "array.h"
 #include "go-alloc.h"
 #include "go-panic.h"
 #include "go-string.h"
 
-typedef struct __go_string String;
-
 /* This file supports C files copied from the 6g runtime library.
    This is a version of the 6g runtime.h rewritten for gccgo's version
    of the code.  */
@@ -45,149 +48,469 @@ typedef unsigned int uintptr __attribute__ ((mode (pointer)));
 
 typedef        uint8                   bool;
 typedef        uint8                   byte;
+typedef        struct  Func            Func;
+typedef        struct  G               G;
+typedef        union   Lock            Lock;
 typedef        struct  M               M;
+typedef        union   Note            Note;
+typedef        struct  SigTab          SigTab;
 typedef        struct  MCache          MCache;
-typedef        struct  Lock            Lock;
-
-/* We use mutexes for locks.  6g uses futexes directly, and perhaps
-   someday we will do that too.  */
-
-struct Lock
-{
-       uint32 key;
-       sem_t sem;
-};
-
-/* A Note.  */
+typedef struct FixAlloc        FixAlloc;
+typedef        struct  Hchan           Hchan;
+typedef        struct  Timers          Timers;
+typedef        struct  Timer           Timer;
 
-typedef        struct  Note            Note;
-
-struct Note {
-       int32 woken;
-};
-
-/* Per CPU declarations.  */
-
-#ifdef __rtems__
-#define __thread
-#endif
+typedef        struct  __go_open_array         Slice;
+typedef        struct  __go_string             String;
+typedef struct __go_interface          Iface;
+typedef        struct  __go_empty_interface    Eface;
+typedef        struct  __go_type_descriptor    Type;
+typedef        struct  __go_defer_stack        Defer;
+typedef        struct  __go_panic_stack        Panic;
 
-extern __thread                M*      m;
+typedef struct __go_func_type          FuncType;
+typedef struct __go_map_type           MapType;
 
-extern M       m0;
+typedef struct  Traceback      Traceback;
 
-#ifdef __rtems__
-#undef __thread
-#endif
+/*
+ * per-cpu declaration.
+ */
+extern M*      runtime_m(void);
+extern G*      runtime_g(void);
 
-/* Constants.  */
+extern M       runtime_m0;
+extern G       runtime_g0;
 
+/*
+ * defined constants
+ */
+enum
+{
+       // G status
+       //
+       // If you add to this list, add to the list
+       // of "okay during garbage collection" status
+       // in mgc0.c too.
+       Gidle,
+       Grunnable,
+       Grunning,
+       Gsyscall,
+       Gwaiting,
+       Gmoribund,
+       Gdead,
+};
 enum
 {
        true    = 1,
        false   = 0,
 };
 
-/* Structures.  */
+/*
+ * structures
+ */
+union  Lock
+{
+       uint32  key;    // futex-based impl
+       M*      waitm;  // linked list of waiting M's (sema-based impl)
+};
+union  Note
+{
+       uint32  key;    // futex-based impl
+       M*      waitm;  // waiting M (sema-based impl)
+};
+struct G
+{
+       Defer*  defer;
+       Panic*  panic;
+       void*   exception;      // current exception being thrown
+       bool    is_foreign;     // whether current exception from other language
+       void    *gcstack;       // if status==Gsyscall, gcstack = stackbase to use during gc
+       uintptr gcstack_size;
+       void*   gcnext_segment;
+       void*   gcnext_sp;
+       void*   gcinitial_sp;
+       ucontext_t gcregs;
+       byte*   entry;          // initial function
+       G*      alllink;        // on allg
+       void*   param;          // passed parameter on wakeup
+       bool    fromgogo;       // reached from gogo
+       int16   status;
+       int32   goid;
+       uint32  selgen;         // valid sudog pointer
+       const char*     waitreason;     // if status==Gwaiting
+       G*      schedlink;
+       bool    readyonstop;
+       bool    ispanic;
+       M*      m;              // for debuggers, but offset not hard-coded
+       M*      lockedm;
+       M*      idlem;
+       int32   sig;
+       int32   writenbuf;
+       byte*   writebuf;
+       uintptr sigcode0;
+       uintptr sigcode1;
+       // uintptr      sigpc;
+       uintptr gopc;   // pc of go statement that created this goroutine
+
+       Traceback* traceback;
+
+       ucontext_t      context;
+       void*           stack_context[10];
+};
 
 struct M
 {
+       G*      g0;             // goroutine with scheduling stack
+       G*      gsignal;        // signal-handling G
+       G*      curg;           // current running goroutine
+       int32   id;
        int32   mallocing;
        int32   gcing;
        int32   locks;
        int32   nomemprof;
-       int32   gcing_for_prof;
-       int32   holds_finlock;
-       int32   gcing_for_finlock;
+       int32   waitnextg;
+       int32   dying;
+       int32   profilehz;
+       int32   helpgc;
+       uint32  fastrand;
+       Note    havenextg;
+       G*      nextg;
+       M*      alllink;        // on allm
+       M*      schedlink;
        MCache  *mcache;
+       G*      lockedg;
+       G*      idleg;
+       uintptr createstack[32];        // Stack that created this thread.
+       M*      nextwaitm;      // next M waiting for lock
+       uintptr waitsema;       // semaphore for parking on locks
+       uint32  waitsemacount;
+       uint32  waitsemalock;
+};
 
-       /* For the list of all threads.  */
-       struct __go_thread_id *list_entry;
+struct SigTab
+{
+       int32   sig;
+       int32   flags;
+};
+enum
+{
+       SigNotify = 1<<0,       // let signal.Notify have signal, even if from kernel
+       SigKill = 1<<1,         // if signal.Notify doesn't take it, exit quietly
+       SigThrow = 1<<2,        // if signal.Notify doesn't take it, exit loudly
+       SigPanic = 1<<3,        // if the signal is from the kernel, panic
+       SigDefault = 1<<4,      // if the signal isn't explicitly requested, don't monitor it
+};
 
-       /* For the garbage collector.  */
-       void    *gc_sp;
-       size_t  gc_len;
-       void    *gc_next_segment;
-       void    *gc_next_sp;
-       void    *gc_initial_sp;
-       struct __go_panic_defer_struct *gc_panic_defer;
+#ifndef NSIG
+#define NSIG 32
+#endif
+
+// NOTE(rsc): keep in sync with extern.go:/type.Func.
+// Eventually, the loaded symbol table should be closer to this form.
+struct Func
+{
+       String  name;
+       uintptr entry;  // entry pc
 };
 
 /* Macros.  */
+
+#ifdef GOOS_windows
+enum {
+   Windows = 1
+};
+#else
+enum {
+   Windows = 0
+};
+#endif
+
+struct Timers
+{
+       Lock;
+       G       *timerproc;
+       bool            sleeping;
+       bool            rescheduling;
+       Note    waitnote;
+       Timer   **t;
+       int32   len;
+       int32   cap;
+};
+
+// Package time knows the layout of this structure.
+// If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+struct Timer
+{
+       int32   i;              // heap index
+
+       // Timer wakes up at when, and then at when+period, ... (period > 0 only)
+       // each time calling f(now, arg) in the timer goroutine, so f must be
+       // a well-behaved function and not block.
+       int64   when;
+       int64   period;
+       void    (*f)(int64, Eface);
+       Eface   arg;
+};
+
+/*
+ * defined macros
+ *    you need super-gopher-guru privilege
+ *    to add this list.
+ */
 #define        nelem(x)        (sizeof(x)/sizeof((x)[0]))
 #define        nil             ((void*)0)
 #define USED(v)                ((void) v)
 
-/* We map throw to assert.  */
-#define runtime_throw(s) __go_assert(s == 0)
+/*
+ * external data
+ */
+G*     runtime_allg;
+G*     runtime_lastg;
+M*     runtime_allm;
+extern int32   runtime_gomaxprocs;
+extern bool    runtime_singleproc;
+extern uint32  runtime_panicking;
+extern int32   runtime_gcwaiting;              // gc is waiting to run
+int32  runtime_ncpu;
+
+/*
+ * common functions and data
+ */
+int32  runtime_findnull(const byte*);
+void   runtime_dump(byte*, int32);
 
+/*
+ * very low level c-called
+ */
+void   runtime_args(int32, byte**);
+void   runtime_osinit();
+void   runtime_goargs(void);
+void   runtime_goenvs(void);
+void   runtime_goenvs_unix(void);
+void   runtime_throw(const char*) __attribute__ ((noreturn));
+void   runtime_panicstring(const char*) __attribute__ ((noreturn));
+void   runtime_prints(const char*);
+void   runtime_printf(const char*, ...);
 void*  runtime_mal(uintptr);
+void   runtime_schedinit(void);
+void   runtime_initsig(void);
+void   runtime_sigenable(uint32 sig);
+int32  runtime_gotraceback(void);
+void   runtime_goroutineheader(G*);
+void   runtime_goroutinetrailer(G*);
+void   runtime_traceback();
+void   runtime_tracebackothers(G*);
+void   runtime_printtrace(uintptr*, int32);
+String runtime_gostringnocopy(const byte*);
+void*  runtime_mstart(void*);
+G*     runtime_malg(int32, byte**, size_t*);
+void   runtime_minit(void);
 void   runtime_mallocinit(void);
-void   runtime_initfintab(void);
+void   runtime_gosched(void);
+void   runtime_tsleep(int64);
+M*     runtime_newm(void);
+void   runtime_goexit(void);
+void   runtime_entersyscall(void) __asm__("syscall.Entersyscall");
+void   runtime_exitsyscall(void) __asm__("syscall.Exitsyscall");
 void   siginit(void);
 bool   __go_sigsend(int32 sig);
+int32  runtime_callers(int32, uintptr*, int32);
 int64  runtime_nanotime(void);
+int64  runtime_cputicks(void);
 
 void   runtime_stoptheworld(void);
-void   runtime_starttheworld(void);
-void   __go_go(void (*pfn)(void*), void*);
-void   __go_gc_goroutine_init(void*);
-void   __go_enable_gc(void);
-int    __go_run_goroutine_gc(int);
-void   __go_scanstacks(void (*scan)(byte *, int64));
-void   __go_stealcache(void);
-void   __go_cachestats(void);
+void   runtime_starttheworld(bool);
+extern uint32 runtime_worldsema;
+G*     __go_go(void (*pfn)(void*), void*);
 
 /*
  * mutual exclusion locks.  in the uncontended case,
  * as fast as spin locks (just a few user-level instructions),
  * but on the contention path they sleep in the kernel.
+ * a zeroed Lock is unlocked (no need to initialize each lock).
  */
-void   runtime_initlock(Lock*);
 void   runtime_lock(Lock*);
 void   runtime_unlock(Lock*);
-void   runtime_destroylock(Lock*);
-
-void semacquire (uint32 *) asm ("libgo_runtime.runtime.Semacquire");
-void semrelease (uint32 *) asm ("libgo_runtime.runtime.Semrelease");
 
 /*
  * sleep and wakeup on one-time events.
  * before any calls to notesleep or notewakeup,
  * must call noteclear to initialize the Note.
- * then, any number of threads can call notesleep
+ * then, exactly one thread can call notesleep
  * and exactly one thread can call notewakeup (once).
- * once notewakeup has been called, all the notesleeps
- * will return.  future notesleeps will return immediately.
+ * once notewakeup has been called, the notesleep
+ * will return.  future notesleep will return immediately.
+ * subsequent noteclear must be called only after
+ * previous notesleep has returned, e.g. it's disallowed
+ * to call noteclear straight after notewakeup.
+ *
+ * notetsleep is like notesleep but wakes up after
+ * a given number of nanoseconds even if the event
+ * has not yet happened.  if a goroutine uses notetsleep to
+ * wake up early, it must wait to call noteclear until it
+ * can be sure that no other goroutine is calling
+ * notewakeup.
  */
-void   noteclear(Note*);
-void   notesleep(Note*);
-void   notewakeup(Note*);
+void   runtime_noteclear(Note*);
+void   runtime_notesleep(Note*);
+void   runtime_notewakeup(Note*);
+void   runtime_notetsleep(Note*, int64);
+
+/*
+ * low-level synchronization for implementing the above
+ */
+uintptr        runtime_semacreate(void);
+int32  runtime_semasleep(int64);
+void   runtime_semawakeup(M*);
+// or
+void   runtime_futexsleep(uint32*, uint32, int64);
+void   runtime_futexwakeup(uint32*, uint32);
+
+/*
+ * low level C-called
+ */
+#define runtime_mmap mmap
+#define runtime_munmap munmap
+#define runtime_madvise madvise
+#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
+#define runtime_getcallerpc(p) __builtin_return_address(0)
+
+#ifdef __rtems__
+void __wrap_rtems_task_variable_add(void **);
+#endif
+
+/*
+ * Names generated by gccgo.
+ */
+#define runtime_printbool      __go_print_bool
+#define runtime_printfloat     __go_print_double
+#define runtime_printint       __go_print_int64
+#define runtime_printiface     __go_print_interface
+#define runtime_printeface     __go_print_empty_interface
+#define runtime_printstring    __go_print_string
+#define runtime_printpointer   __go_print_pointer
+#define runtime_printuint      __go_print_uint64
+#define runtime_printslice     __go_print_slice
+#define runtime_printcomplex   __go_print_complex
+
+/*
+ * runtime go-called
+ */
+void   runtime_printbool(_Bool);
+void   runtime_printfloat(double);
+void   runtime_printint(int64);
+void   runtime_printiface(Iface);
+void   runtime_printeface(Eface);
+void   runtime_printstring(String);
+void   runtime_printpc(void*);
+void   runtime_printpointer(void*);
+void   runtime_printuint(uint64);
+void   runtime_printhex(uint64);
+void   runtime_printslice(Slice);
+void   runtime_printcomplex(__complex double);
+
+struct __go_func_type;
+void reflect_call(const struct __go_func_type *, const void *, _Bool, _Bool,
+                 void **, void **)
+  asm ("reflect.call");
 
 /* Functions.  */
-#define runtime_printf printf
+#define runtime_panic __go_panic
+#define runtime_write(d, v, n) write((d), (v), (n))
 #define runtime_malloc(s) __go_alloc(s)
 #define runtime_free(p) __go_free(p)
-#define runtime_memclr(buf, size) __builtin_memset((buf), 0, (size))
 #define runtime_strcmp(s1, s2) __builtin_strcmp((s1), (s2))
-#define runtime_getenv(s) getenv(s)
-#define runtime_atoi(s) atoi(s)
 #define runtime_mcmp(a, b, s) __builtin_memcmp((a), (b), (s))
 #define runtime_memmove(a, b, s) __builtin_memmove((a), (b), (s))
+#define runtime_exit(s) exit(s)
 MCache*        runtime_allocmcache(void);
 void   free(void *v);
-struct __go_func_type;
-void   runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
-void   runtime_walkfintab(void (*fn)(void*), void (*scan)(byte *, int64));
-#define runtime_mmap mmap
-#define runtime_munmap(p, s) munmap((p), (s))
 #define runtime_cas(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+#define runtime_casp(pval, old, new) __sync_bool_compare_and_swap (pval, old, new)
+#define runtime_xadd(p, v) __sync_add_and_fetch (p, v)
+#define runtime_xchg(p, v) __atomic_exchange_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_atomicload(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
+#define runtime_atomicstore(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
+#define runtime_atomicloadp(p) __atomic_load_n (p, __ATOMIC_SEQ_CST)
+#define runtime_atomicstorep(p, v) __atomic_store_n (p, v, __ATOMIC_SEQ_CST)
 
 struct __go_func_type;
-void reflect_call(const struct __go_func_type *, const void *, _Bool, void **,
-                 void **)
-  asm ("libgo_reflect.reflect.call");
+bool   runtime_addfinalizer(void*, void(*fn)(void*), const struct __go_func_type *);
+#define runtime_getcallersp(p) __builtin_frame_address(1)
+int32  runtime_mcount(void);
+int32  runtime_gcount(void);
+void   runtime_dopanic(int32) __attribute__ ((noreturn));
+void   runtime_startpanic(void);
+void   runtime_ready(G*);
+const byte*    runtime_getenv(const char*);
+int32  runtime_atoi(const byte*);
+uint32 runtime_fastrand1(void);
+
+void   runtime_sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp);
+void   runtime_resetcpuprofiler(int32);
+void   runtime_setcpuprofilerate(void(*)(uintptr*, int32), int32);
+void   runtime_usleep(uint32);
 
-#ifdef __rtems__
-void __wrap_rtems_task_variable_add(void **);
-#endif
+/*
+ * runtime c-called (but written in Go)
+ */
+void   runtime_printany(Eface)
+     __asm__("runtime.Printany");
+void   runtime_newTypeAssertionError(const String*, const String*, const String*, const String*, Eface*)
+     __asm__("runtime.NewTypeAssertionError");
+void   runtime_newErrorString(String, Eface*)
+     __asm__("runtime.NewErrorString");
+
+/*
+ * wrapped for go users
+ */
+bool   runtime_isInf(float64 f, int32 sign);
+#define runtime_isNaN(f) __builtin_isnan(f)
+void   runtime_semacquire(uint32 volatile *);
+void   runtime_semrelease(uint32 volatile *);
+int32  runtime_gomaxprocsfunc(int32 n);
+void   runtime_procyield(uint32);
+void   runtime_osyield(void);
+void   runtime_LockOSThread(void) __asm__("runtime.LockOSThread");
+void   runtime_UnlockOSThread(void) __asm__("runtime.UnlockOSThread");
+
+bool   runtime_showframe(const unsigned char*);
+
+uintptr        runtime_memlimit(void);
+
+// If appropriate, ask the operating system to control whether this
+// thread should receive profiling signals.  This is only necessary on OS X.
+// An operating system should not deliver a profiling signal to a
+// thread that is not actually executing (what good is that?), but that's
+// what OS X prefers to do.  When profiling is turned on, we mask
+// away the profiling signal when threads go to sleep, so that OS X
+// is forced to deliver the signal to a thread that's actually running.
+// This is a no-op on other systems.
+void   runtime_setprof(bool);
+
+void   runtime_time_scan(void (*)(byte*, int64));
+void   runtime_trampoline_scan(void (*)(byte *, int64));
+
+void   runtime_setsig(int32, bool, bool);
+#define runtime_setitimer setitimer
+
+void   runtime_check(void);
+
+// A list of global variables that the garbage collector must scan.
+struct root_list {
+       struct root_list *next;
+       struct root {
+               void *decl;
+               size_t size;
+       } roots[];
+};
+
+void   __go_register_gc_roots(struct root_list*);
+
+// Size of stack space allocated using Go's allocator.
+// This will be 0 when using split stacks, as in that case
+// the stacks are allocated by the splitstack library.
+extern uintptr runtime_stacks_sys;
+
+extern _Bool __go_file_line (uintptr, String*, String*, int *);