This patch to libgo eliminates the __go_alloc and __go_free functions,
in favor of fully typed memory allocation (except for one remaining
call in parfor.c, which will go away later).  Implementing this was
simplified by moving the allgs slice from C to Go, which involved
moving a few functions.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 244031)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-eac28020ee4b2532d4cd43f448fe612e84e0a108
+dfe446c5a54ca0febabb81b542cc4e634c6f5c30
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: libgo/go/runtime/mprof.go
===================================================================
--- libgo/go/runtime/mprof.go   (revision 243084)
+++ libgo/go/runtime/mprof.go   (working copy)
@@ -556,7 +556,7 @@ func GoroutineProfile(p []StackRecord) (
        stopTheWorld("profile")
 
        n = 1
-       for _, gp1 := range allgs() {
+       for _, gp1 := range allgs {
                if isOK(gp1) {
                        n++
                }
@@ -571,7 +571,7 @@ func GoroutineProfile(p []StackRecord) (
                r = r[1:]
 
                // Save other goroutines.
-               for _, gp1 := range allgs() {
+               for _, gp1 := range allgs {
                        if isOK(gp1) {
                                if len(r) == 0 {
                                        // Should be impossible, but better to 
return a
Index: libgo/go/runtime/proc.go
===================================================================
--- libgo/go/runtime/proc.go    (revision 243805)
+++ libgo/go/runtime/proc.go    (working copy)
@@ -11,15 +11,18 @@ import (
 
 // Functions temporarily called by C code.
 //go:linkname newextram runtime.newextram
+//go:linkname checkdead runtime.checkdead
+//go:linkname schedtrace runtime.schedtrace
+//go:linkname allgadd runtime.allgadd
 
 // Functions temporarily in C that have not yet been ported.
 func allocm(*p, bool, *unsafe.Pointer, *uintptr) *m
 func malg(bool, bool, *unsafe.Pointer, *uintptr) *g
-func allgadd(*g)
 
 // C functions for ucontext management.
 func setGContext()
 func makeGContext(*g, unsafe.Pointer, uintptr)
+func getTraceback(me, gp *g)
 
 // main_init_done is a signal used by cgocallbackg that initialization
 // has been completed. It is made before _cgo_notify_runtime_init_done,
@@ -27,6 +30,39 @@ func makeGContext(*g, unsafe.Pointer, ui
 // it is closed, meaning cgocallbackg can reliably receive from it.
 var main_init_done chan bool
 
+var (
+       allgs    []*g
+       allglock mutex
+)
+
+func allgadd(gp *g) {
+       if readgstatus(gp) == _Gidle {
+               throw("allgadd: bad status Gidle")
+       }
+
+       lock(&allglock)
+       allgs = append(allgs, gp)
+       allglen = uintptr(len(allgs))
+
+       // Grow GC rescan list if necessary.
+       if len(allgs) > cap(work.rescan.list) {
+               lock(&work.rescan.lock)
+               l := work.rescan.list
+               // Let append do the heavy lifting, but keep the
+               // length the same.
+               work.rescan.list = append(l[:cap(l)], 0)[:len(l)]
+               unlock(&work.rescan.lock)
+       }
+       unlock(&allglock)
+}
+
+// All reads and writes of g's status go through readgstatus, casgstatus
+// castogscanstatus, casfrom_Gscanstatus.
+//go:nosplit
+func readgstatus(gp *g) uint32 {
+       return atomic.Load(&gp.atomicstatus)
+}
+
 // If asked to move to or from a Gscanstatus this will throw. Use the 
castogscanstatus
 // and casfrom_Gscanstatus instead.
 // casgstatus will loop if the g->atomicstatus is in a Gscan status until the 
routine that
@@ -328,3 +364,170 @@ func lockextra(nilokay bool) *m {
 func unlockextra(mp *m) {
        atomic.Storeuintptr(&extram, uintptr(unsafe.Pointer(mp)))
 }
+
+// Check for deadlock situation.
+// The check is based on number of running M's, if 0 -> deadlock.
+func checkdead() {
+       // For -buildmode=c-shared or -buildmode=c-archive it's OK if
+       // there are no running goroutines. The calling program is
+       // assumed to be running.
+       if islibrary || isarchive {
+               return
+       }
+
+       // If we are dying because of a signal caught on an already idle thread,
+       // freezetheworld will cause all running threads to block.
+       // And runtime will essentially enter into deadlock state,
+       // except that there is a thread that will call exit soon.
+       if panicking > 0 {
+               return
+       }
+
+       // -1 for sysmon
+       run := sched.mcount - sched.nmidle - sched.nmidlelocked - 1
+       if run > 0 {
+               return
+       }
+       if run < 0 {
+               print("runtime: checkdead: nmidle=", sched.nmidle, " 
nmidlelocked=", sched.nmidlelocked, " mcount=", sched.mcount, "\n")
+               throw("checkdead: inconsistent counts")
+       }
+
+       grunning := 0
+       lock(&allglock)
+       for i := 0; i < len(allgs); i++ {
+               gp := allgs[i]
+               if isSystemGoroutine(gp) {
+                       continue
+               }
+               s := readgstatus(gp)
+               switch s &^ _Gscan {
+               case _Gwaiting:
+                       grunning++
+               case _Grunnable,
+                       _Grunning,
+                       _Gsyscall:
+                       unlock(&allglock)
+                       print("runtime: checkdead: find g ", gp.goid, " in 
status ", s, "\n")
+                       throw("checkdead: runnable g")
+               }
+       }
+       unlock(&allglock)
+       if grunning == 0 { // possible if main goroutine calls runtime·Goexit()
+               throw("no goroutines (main called runtime.Goexit) - deadlock!")
+       }
+
+       // Maybe jump time forward for playground.
+       gp := timejump()
+       if gp != nil {
+               // Temporarily commented out for gccgo.
+               // For gccgo this code will never run anyhow.
+               // casgstatus(gp, _Gwaiting, _Grunnable)
+               // globrunqput(gp)
+               // _p_ := pidleget()
+               // if _p_ == nil {
+               //      throw("checkdead: no p for timer")
+               // }
+               // mp := mget()
+               // if mp == nil {
+               //      // There should always be a free M since
+               //      // nothing is running.
+               //      throw("checkdead: no m for timer")
+               // }
+               // nmp.nextp.set(_p_)
+               // notewakeup(&mp.park)
+               // return
+       }
+
+       getg().m.throwing = -1 // do not dump full stacks
+       throw("all goroutines are asleep - deadlock!")
+}
+
+var starttime int64
+
+func schedtrace(detailed bool) {
+       now := nanotime()
+       if starttime == 0 {
+               starttime = now
+       }
+
+       gomaxprocs := int32(GOMAXPROCS(0))
+
+       lock(&sched.lock)
+       print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " 
idleprocs=", sched.npidle, " threads=", sched.mcount, " spinningthreads=", 
sched.nmspinning, " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize)
+       if detailed {
+               print(" gcwaiting=", sched.gcwaiting, " nmidlelocked=", 
sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", 
sched.sysmonwait, "\n")
+       }
+       // We must be careful while reading data from P's, M's and G's.
+       // Even if we hold schedlock, most data can be changed concurrently.
+       // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil 
to nil.
+       for i := int32(0); i < gomaxprocs; i++ {
+               _p_ := allp[i]
+               if _p_ == nil {
+                       continue
+               }
+               mp := _p_.m.ptr()
+               h := atomic.Load(&_p_.runqhead)
+               t := atomic.Load(&_p_.runqtail)
+               if detailed {
+                       id := int32(-1)
+                       if mp != nil {
+                               id = mp.id
+                       }
+                       print("  P", i, ": status=", _p_.status, " schedtick=", 
_p_.schedtick, " syscalltick=", _p_.syscalltick, " m=", id, " runqsize=", t-h, 
" gfreecnt=", _p_.gfreecnt, "\n")
+               } else {
+                       // In non-detailed mode format lengths of per-P run 
queues as:
+                       // [len1 len2 len3 len4]
+                       print(" ")
+                       if i == 0 {
+                               print("[")
+                       }
+                       print(t - h)
+                       if i == gomaxprocs-1 {
+                               print("]\n")
+                       }
+               }
+       }
+
+       if !detailed {
+               unlock(&sched.lock)
+               return
+       }
+
+       for mp := allm(); mp != nil; mp = mp.alllink {
+               _p_ := mp.p.ptr()
+               gp := mp.curg
+               lockedg := mp.lockedg
+               id1 := int32(-1)
+               if _p_ != nil {
+                       id1 = _p_.id
+               }
+               id2 := int64(-1)
+               if gp != nil {
+                       id2 = gp.goid
+               }
+               id3 := int64(-1)
+               if lockedg != nil {
+                       id3 = lockedg.goid
+               }
+               print("  M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", 
mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" 
locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", 
mp.spinning, " blocked=", mp.blocked, " lockedg=", id3, "\n")
+       }
+
+       lock(&allglock)
+       for gi := 0; gi < len(allgs); gi++ {
+               gp := allgs[gi]
+               mp := gp.m
+               lockedm := gp.lockedm
+               id1 := int32(-1)
+               if mp != nil {
+                       id1 = mp.id
+               }
+               id2 := int32(-1)
+               if lockedm != nil {
+                       id2 = lockedm.id
+               }
+               print("  G", gp.goid, ": status=", readgstatus(gp), "(", 
gp.waitreason, ") m=", id1, " lockedm=", id2, "\n")
+       }
+       unlock(&allglock)
+       unlock(&sched.lock)
+}
Index: libgo/go/runtime/runtime2.go
===================================================================
--- libgo/go/runtime/runtime2.go        (revision 244031)
+++ libgo/go/runtime/runtime2.go        (working copy)
@@ -755,9 +755,13 @@ const _TracebackMaxFrames = 100
 
 var (
        //      emptystring string
-       //      allglen     uintptr
+
+       allglen uintptr
+
        //      allm        *m
-       //      allp        [_MaxGomaxprocs + 1]*p
+
+       allp [_MaxGomaxprocs + 1]*p
+
        //      gomaxprocs  int32
 
        panicking uint32
Index: libgo/go/runtime/stubs.go
===================================================================
--- libgo/go/runtime/stubs.go   (revision 244031)
+++ libgo/go/runtime/stubs.go   (working copy)
@@ -476,12 +476,6 @@ func UnlockOSThread()
 func lockOSThread()
 func unlockOSThread()
 func allm() *m
-func allgs() []*g
-
-//go:nosplit
-func readgstatus(gp *g) uint32 {
-       return atomic.Load(&gp.atomicstatus)
-}
 
 // Temporary for gccgo until we port malloc.go
 func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer
@@ -489,9 +483,6 @@ func persistentalloc(size, align uintptr
 // Temporary for gccgo until we port mheap.go
 func setprofilebucket(p unsafe.Pointer, b *bucket)
 
-// Currently in proc.c.
-func tracebackothers(*g)
-
 // Temporary for gccgo until we port mgc.go.
 func setgcpercent(int32) int32
 
@@ -530,9 +521,7 @@ func getZerobase() *uintptr {
 // Temporary for gccgo until we port proc.go.
 func sigprof()
 func mcount() int32
-func gcount() int32
 func goexit1()
-func schedtrace(bool)
 func freezetheworld()
 
 // Get signal trampoline, written in C.
@@ -562,6 +551,30 @@ func getCgoHasExtraM() *bool {
        return &cgoHasExtraM
 }
 
+// Temporary for gccgo until we port proc.go.
+//go:linkname getAllP runtime.getAllP
+func getAllP() **p {
+       return &allp[0]
+}
+
+// Temporary for gccgo until we port proc.go.
+//go:linkname allocg runtime.allocg
+func allocg() *g {
+       return new(g)
+}
+
+// Temporary for gccgo until we port the garbage collector.
+//go:linkname getallglen runtime.getallglen
+func getallglen() uintptr {
+       return allglen
+}
+
+// Temporary for gccgo until we port the garbage collector.
+//go:linkname getallg runtime.getallg
+func getallg(i int) *g {
+       return allgs[i]
+}
+
 // Throw and rethrow an exception.
 func throwException()
 func rethrowException()
@@ -579,3 +592,27 @@ func getPanicking() uint32 {
 
 // Temporary for gccgo until we port mcache.go.
 func allocmcache() *mcache
+
+// Temporary for gccgo until we port mgc.go.
+// This is just so that allgadd will compile.
+var work struct {
+       rescan struct {
+               lock mutex
+               list []guintptr
+       }
+}
+
+// gcount is temporary for gccgo until more of proc.go is ported.
+// This is a copy of the C function we used to use.
+func gcount() int32 {
+       n := int32(0)
+       lock(&allglock)
+       for _, gp := range allgs {
+               s := readgstatus(gp)
+               if s == _Grunnable || s == _Grunning || s == _Gsyscall || s == 
_Gwaiting {
+                       n++
+               }
+       }
+       unlock(&allglock)
+       return n
+}
Index: libgo/go/runtime/traceback_gccgo.go
===================================================================
--- libgo/go/runtime/traceback_gccgo.go (revision 243084)
+++ libgo/go/runtime/traceback_gccgo.go (working copy)
@@ -171,3 +171,58 @@ func isSystemGoroutine(gp *g) bool {
        // FIXME.
        return false
 }
+
+func tracebackothers(me *g) {
+       var tb tracebackg
+       tb.gp = me
+
+       level, _, _ := gotraceback()
+
+       // Show the current goroutine first, if we haven't already.
+       g := getg()
+       gp := g.m.curg
+       if gp != nil && gp != me {
+               print("\n")
+               goroutineheader(gp)
+               gp.traceback = &tb
+               getTraceback(me, gp)
+               printtrace(tb.locbuf[:tb.c], nil)
+               printcreatedby(gp)
+       }
+
+       lock(&allglock)
+       for _, gp := range allgs {
+               if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || 
isSystemGoroutine(gp) && level < 2 {
+                       continue
+               }
+               print("\n")
+               goroutineheader(gp)
+
+               // gccgo's only mechanism for doing a stack trace is
+               // _Unwind_Backtrace.  And that only works for the
+               // current thread, not for other random goroutines.
+               // So we need to switch context to the goroutine, get
+               // the backtrace, and then switch back.
+               //
+               // This means that if g is running or in a syscall, we
+               // can't reliably print a stack trace.  FIXME.
+
+               // Note: gp.m == g.m occurs when tracebackothers is
+               // called from a signal handler initiated during a
+               // systemstack call. The original G is still in the
+               // running state, and we want to print its stack.
+               if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
+                       print("\tgoroutine running on other thread; stack 
unavailable\n")
+                       printcreatedby(gp)
+               } else if readgstatus(gp)&^_Gscan == _Gsyscall {
+                       print("\tgoroutine in C code; stack unavailable\n")
+                       printcreatedby(gp)
+               } else {
+                       gp.traceback = &tb
+                       getTraceback(me, gp)
+                       printtrace(tb.locbuf[:tb.c], nil)
+                       printcreatedby(gp)
+               }
+       }
+       unlock(&allglock)
+}
Index: libgo/runtime/go-libmain.c
===================================================================
--- libgo/runtime/go-libmain.c  (revision 243805)
+++ libgo/runtime/go-libmain.c  (working copy)
@@ -13,7 +13,6 @@
 #include <unistd.h>
 
 #include "runtime.h"
-#include "go-alloc.h"
 #include "array.h"
 #include "arch.h"
 #include "malloc.h"
Index: libgo/runtime/go-main.c
===================================================================
--- libgo/runtime/go-main.c     (revision 243805)
+++ libgo/runtime/go-main.c     (working copy)
@@ -15,7 +15,6 @@
 #endif
 
 #include "runtime.h"
-#include "go-alloc.h"
 #include "array.h"
 #include "arch.h"
 #include "malloc.h"
Index: libgo/runtime/go-new.c
===================================================================
--- libgo/runtime/go-new.c      (revision 243084)
+++ libgo/runtime/go-new.c      (working copy)
@@ -4,7 +4,6 @@
    Use of this source code is governed by a BSD-style
    license that can be found in the LICENSE file.  */
 
-#include "go-alloc.h"
 #include "runtime.h"
 #include "arch.h"
 #include "malloc.h"
Index: libgo/runtime/go-reflect-call.c
===================================================================
--- libgo/runtime/go-reflect-call.c     (revision 243084)
+++ libgo/runtime/go-reflect-call.c     (working copy)
@@ -9,7 +9,6 @@
 #include <stdlib.h>
 
 #include "runtime.h"
-#include "go-alloc.h"
 #include "go-assert.h"
 #include "go-type.h"
 
Index: libgo/runtime/go-unwind.c
===================================================================
--- libgo/runtime/go-unwind.c   (revision 243084)
+++ libgo/runtime/go-unwind.c   (working copy)
@@ -14,7 +14,6 @@
 #include "unwind-pe.h"
 
 #include "runtime.h"
-#include "go-alloc.h"
 
 /* The code for a Go exception.  */
 
Index: libgo/runtime/heapdump.c
===================================================================
--- libgo/runtime/heapdump.c    (revision 243084)
+++ libgo/runtime/heapdump.c    (working copy)
@@ -311,8 +311,8 @@ dumpgs(void)
        uint32 i;
 
        // goroutines & stacks
-       for(i = 0; i < runtime_allglen; i++) {
-               gp = runtime_allg[i];
+       for(i = 0; i < runtime_getallglen(); i++) {
+               gp = runtime_getallg(i);
                switch(gp->atomicstatus){
                default:
                        runtime_printf("unexpected G.status %d\n", 
gp->atomicstatus);
Index: libgo/runtime/malloc.goc
===================================================================
--- libgo/runtime/malloc.goc    (revision 243084)
+++ libgo/runtime/malloc.goc    (working copy)
@@ -10,7 +10,6 @@ package runtime
 #include <stddef.h>
 #include <errno.h>
 #include <stdlib.h>
-#include "go-alloc.h"
 #include "runtime.h"
 #include "arch.h"
 #include "malloc.h"
@@ -308,107 +307,6 @@ runtime_profilealloc(void *v, uintptr si
        runtime_MProf_Malloc(v, size);
 }
 
-void*
-__go_alloc(uintptr size)
-{
-       return runtime_mallocgc(size, 0, FlagNoInvokeGC);
-}
-
-// Free the object whose base pointer is v.
-void
-__go_free(void *v)
-{
-       M *m;
-       int32 sizeclass;
-       MSpan *s;
-       MCache *c;
-       uintptr size;
-
-       if(v == nil)
-               return;
-       
-       // If you change this also change mgc0.c:/^sweep,
-       // which has a copy of the guts of free.
-
-       m = runtime_m();
-       if(m->mallocing)
-               runtime_throw("malloc/free - deadlock");
-       m->mallocing = 1;
-
-       if(!runtime_mlookup(v, nil, nil, &s)) {
-               runtime_printf("free %p: not an allocated block\n", v);
-               runtime_throw("free runtime_mlookup");
-       }
-       size = s->elemsize;
-       sizeclass = s->sizeclass;
-       // Objects that are smaller than TinySize can be allocated using tiny 
alloc,
-       // if then such object is combined with an object with finalizer, we 
will crash.
-       if(size < TinySize)
-               runtime_throw("freeing too small block");
-
-       if(runtime_debug.allocfreetrace)
-               runtime_tracefree(v, size);
-
-       // Ensure that the span is swept.
-       // If we free into an unswept span, we will corrupt GC bitmaps.
-       runtime_MSpan_EnsureSwept(s);
-
-       if(s->specials != nil)
-               runtime_freeallspecials(s, v, size);
-
-       c = m->mcache;
-       if(sizeclass == 0) {
-               // Large object.
-               s->needzero = 1;
-               // Must mark v freed before calling unmarkspan and MHeap_Free:
-               // they might coalesce v into other spans and change the bitmap 
further.
-               runtime_markfreed(v);
-               runtime_unmarkspan(v, 1<<PageShift);
-               // NOTE(rsc,dvyukov): The original implementation of efence
-               // in CL 22060046 used SysFree instead of SysFault, so that
-               // the operating system would eventually give the memory
-               // back to us again, so that an efence program could run
-               // longer without running out of memory. Unfortunately,
-               // calling SysFree here without any kind of adjustment of the
-               // heap data structures means that when the memory does
-               // come back to us, we have the wrong metadata for it, either in
-               // the MSpan structures or in the garbage collection bitmap.
-               // Using SysFault here means that the program will run out of
-               // memory fairly quickly in efence mode, but at least it won't
-               // have mysterious crashes due to confused memory reuse.
-               // It should be possible to switch back to SysFree if we also 
-               // implement and then call some kind of MHeap_DeleteSpan.
-               if(runtime_debug.efence)
-                       runtime_SysFault((void*)(s->start<<PageShift), size);
-               else
-                       runtime_MHeap_Free(&runtime_mheap, s, 1);
-               c->local_nlargefree++;
-               c->local_largefree += size;
-       } else {
-               // Small object.
-               if(size > 2*sizeof(uintptr))
-                       ((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll;       
// mark as "needs to be zeroed"
-               else if(size > sizeof(uintptr))
-                       ((uintptr*)v)[1] = 0;
-               // Must mark v freed before calling MCache_Free:
-               // it might coalesce v and other blocks into a bigger span
-               // and change the bitmap further.
-               c->local_nsmallfree[sizeclass]++;
-               c->local_cachealloc -= size;
-               if(c->alloc[sizeclass] == s) {
-                       // We own the span, so we can just add v to the freelist
-                       runtime_markfreed(v);
-                       ((MLink*)v)->next = s->freelist;
-                       s->freelist = v;
-                       s->ref--;
-               } else {
-                       // Someone else owns this span.  Add to free queue.
-                       runtime_MCache_Free(c, v, sizeclass, size);
-               }
-       }
-       m->mallocing = 0;
-}
-
 int32
 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
 {
@@ -628,9 +526,6 @@ runtime_mallocinit(void)
        // Initialize the rest of the allocator.        
        runtime_MHeap_Init(&runtime_mheap);
        runtime_m()->mcache = runtime_allocmcache();
-
-       // See if it works.
-       runtime_free(runtime_malloc(TinySize));
 }
 
 void*
Index: libgo/runtime/mgc0.c
===================================================================
--- libgo/runtime/mgc0.c        (revision 243805)
+++ libgo/runtime/mgc0.c        (working copy)
@@ -1279,7 +1279,6 @@ markroot(ParFor *desc, uint32 i)
                // For gccgo we use this for all the other global roots.
                enqueue1(&wbuf, (Obj){(byte*)&runtime_m0, sizeof runtime_m0, 
0});
                enqueue1(&wbuf, (Obj){(byte*)&runtime_g0, sizeof runtime_g0, 
0});
-               enqueue1(&wbuf, (Obj){(byte*)&runtime_allg, sizeof 
runtime_allg, 0});
                enqueue1(&wbuf, (Obj){(byte*)&runtime_allm, sizeof 
runtime_allm, 0});
                enqueue1(&wbuf, (Obj){(byte*)&runtime_allp, sizeof 
runtime_allp, 0});
                enqueue1(&wbuf, (Obj){(byte*)&work, sizeof work, 0});
@@ -1334,9 +1333,9 @@ markroot(ParFor *desc, uint32 i)
 
        default:
                // the rest is scanning goroutine stacks
-               if(i - RootCount >= runtime_allglen)
+               if(i - RootCount >= runtime_getallglen())
                        runtime_throw("markroot: bad index");
-               gp = runtime_allg[i - RootCount];
+               gp = runtime_getallg(i - RootCount);
                // remember when we've first observed the G blocked
                // needed only to output in traceback
                if((gp->atomicstatus == _Gwaiting || gp->atomicstatus == 
_Gsyscall) && gp->waitsince == 0)
@@ -2243,7 +2242,7 @@ gc(struct gc_args *args)
        work.nwait = 0;
        work.ndone = 0;
        work.nproc = runtime_gcprocs();
-       runtime_parforsetup(work.markfor, work.nproc, RootCount + 
runtime_allglen, false, &markroot_funcval);
+       runtime_parforsetup(work.markfor, work.nproc, RootCount + 
runtime_getallglen(), false, &markroot_funcval);
        if(work.nproc > 1) {
                runtime_noteclear(&work.alldone);
                runtime_helpgc(work.nproc);
Index: libgo/runtime/parfor.c
===================================================================
--- libgo/runtime/parfor.c      (revision 243084)
+++ libgo/runtime/parfor.c      (working copy)
@@ -5,6 +5,7 @@
 // Parallel for algorithm.
 
 #include "runtime.h"
+#include "malloc.h"
 #include "arch.h"
 
 struct ParForThread
@@ -27,7 +28,7 @@ runtime_parforalloc(uint32 nthrmax)
 
        // The ParFor object is followed by CacheLineSize padding
        // and then nthrmax ParForThread.
-       desc = (ParFor*)runtime_malloc(sizeof(ParFor) + CacheLineSize + nthrmax 
* sizeof(ParForThread));
+       desc = (ParFor*)runtime_mallocgc(sizeof(ParFor) + CacheLineSize + 
nthrmax * sizeof(ParForThread), 0, FlagNoInvokeGC);
        desc->thr = (ParForThread*)((byte*)(desc+1) + CacheLineSize);
        desc->nthrmax = nthrmax;
        return desc;
Index: libgo/runtime/proc.c
===================================================================
--- libgo/runtime/proc.c        (revision 243805)
+++ libgo/runtime/proc.c        (working copy)
@@ -361,6 +361,10 @@ enum
 extern Sched* runtime_getsched() __asm__ (GOSYM_PREFIX "runtime.getsched");
 extern bool* runtime_getCgoHasExtraM()
   __asm__ (GOSYM_PREFIX "runtime.getCgoHasExtraM");
+extern P** runtime_getAllP()
+  __asm__ (GOSYM_PREFIX "runtime.getAllP");
+extern G* allocg(void)
+  __asm__ (GOSYM_PREFIX "runtime.allocg");
 
 Sched* runtime_sched;
 int32  runtime_gomaxprocs;
@@ -374,11 +378,6 @@ int32      runtime_ncpu;
 bool   runtime_precisestack;
 static int32   newprocs;
 
-static Lock allglock;  // the following vars are protected by this lock or by 
stoptheworld
-G**    runtime_allg;
-uintptr runtime_allglen;
-static uintptr allgcap;
-
 bool   runtime_isarchive;
 
 void* runtime_mstart(void*);
@@ -403,7 +402,6 @@ static void startlockedm(G*);
 static void sysmon(void);
 static uint32 retake(int64);
 static void incidlelocked(int32);
-static void checkdead(void);
 static void exitsyscall0(G*);
 static void park0(G*);
 static void goexit0(G*);
@@ -421,6 +419,8 @@ static bool exitsyscallfast(void);
 
 void allgadd(G*)
   __asm__(GOSYM_PREFIX "runtime.allgadd");
+void checkdead(void)
+  __asm__(GOSYM_PREFIX "runtime.checkdead");
 
 bool runtime_isstarted;
 
@@ -482,7 +482,7 @@ runtime_schedinit(void)
                        n = _MaxGomaxprocs;
                procs = n;
        }
-       runtime_allp = 
runtime_malloc((_MaxGomaxprocs+1)*sizeof(runtime_allp[0]));
+       runtime_allp = runtime_getAllP();
        procresize(procs);
 
        // Can not enable GC until all roots are registered.
@@ -586,85 +586,25 @@ runtime_main(void* dummy __attribute__((
                *(int32*)0 = 0;
 }
 
-void
-runtime_tracebackothers(G * volatile me)
-{
-       G * volatile gp;
-       Traceback tb;
-       int32 traceback;
-       Slice slice;
-       volatile uintptr i;
-
-       tb.gp = me;
-       traceback = runtime_gotraceback(nil);
-       
-       // Show the current goroutine first, if we haven't already.
-       if((gp = g->m->curg) != nil && gp != me) {
-               runtime_printf("\n");
-               runtime_goroutineheader(gp);
-               gp->traceback = &tb;
-
-#ifdef USING_SPLIT_STACK
-               __splitstack_getcontext(&me->stackcontext[0]);
-#endif
-               getcontext(ucontext_arg(&me->context[0]));
-
-               if(gp->traceback != nil) {
-                 runtime_gogo(gp);
-               }
-
-               slice.__values = &tb.locbuf[0];
-               slice.__count = tb.c;
-               slice.__capacity = tb.c;
-               runtime_printtrace(slice, nil);
-               runtime_printcreatedby(gp);
-       }
-
-       runtime_lock(&allglock);
-       for(i = 0; i < runtime_allglen; i++) {
-               gp = runtime_allg[i];
-               if(gp == me || gp == g->m->curg || gp->atomicstatus == _Gdead)
-                       continue;
-               if(gp->issystem && traceback < 2)
-                       continue;
-               runtime_printf("\n");
-               runtime_goroutineheader(gp);
-
-               // Our only mechanism for doing a stack trace is
-               // _Unwind_Backtrace.  And that only works for the
-               // current thread, not for other random goroutines.
-               // So we need to switch context to the goroutine, get
-               // the backtrace, and then switch back.
-
-               // This means that if g is running or in a syscall, we
-               // can't reliably print a stack trace.  FIXME.
-
-               if(gp->atomicstatus == _Grunning) {
-                       runtime_printf("\tgoroutine running on other thread; 
stack unavailable\n");
-                       runtime_printcreatedby(gp);
-               } else if(gp->atomicstatus == _Gsyscall) {
-                       runtime_printf("\tgoroutine in C code; stack 
unavailable\n");
-                       runtime_printcreatedby(gp);
-               } else {
-                       gp->traceback = &tb;
+void getTraceback(G*, G*) __asm__(GOSYM_PREFIX "runtime.getTraceback");
 
+// getTraceback stores a traceback of gp in the g's traceback field
+// and then returns to me.  We expect that gp's traceback is not nil.
+// It works by saving me's current context, and checking gp's traceback field.
+// If gp's traceback field is not nil, it starts running gp.
+// In places where we call getcontext, we check the traceback field.
+// If it is not nil, we collect a traceback, and then return to the
+// goroutine stored in the traceback field, which is me.
+void getTraceback(G* me, G* gp)
+{
 #ifdef USING_SPLIT_STACK
-                       __splitstack_getcontext(&me->stackcontext[0]);
+       __splitstack_getcontext(&me->stackcontext[0]);
 #endif
-                       getcontext(ucontext_arg(&me->context[0]));
+       getcontext(ucontext_arg(&me->stackcontext[0]));
 
-                       if(gp->traceback != nil) {
-                               runtime_gogo(gp);
-                       }
-
-                       slice.__values = &tb.locbuf[0];
-                       slice.__count = tb.c;
-                       slice.__capacity = tb.c;
-                       runtime_printtrace(slice, nil);
-                       runtime_printcreatedby(gp);
-               }
+       if (gp->traceback != nil) {
+               runtime_gogo(gp);
        }
-       runtime_unlock(&allglock);
 }
 
 static void
@@ -1067,22 +1007,6 @@ runtime_allocm(P *p, bool allocatestack,
        return mp;
 }
 
-static G*
-allocg(void)
-{
-       G *gp;
-       // static Type *gtype;
-       
-       // if(gtype == nil) {
-       //      Eface e;
-       //      runtime_gc_g_ptr(&e);
-       //      gtype = ((PtrType*)e.__type_descriptor)->__element_type;
-       // }
-       // gp = runtime_cnew(gtype);
-       gp = runtime_malloc(sizeof(G));
-       return gp;
-}
-
 void setGContext(void) __asm__ (GOSYM_PREFIX "runtime.setGContext");
 
 // setGContext sets up a new goroutine context for the current g.
@@ -2129,6 +2053,7 @@ __go_go(void (*fn)(void*), void* arg)
 
                newg = runtime_malg(true, false, &sp, &malsize);
                spsize = (size_t)malsize;
+               newg->atomicstatus = _Gdead;
                allgadd(newg);
        }
 
@@ -2152,31 +2077,6 @@ __go_go(void (*fn)(void*), void* arg)
        return newg;
 }
 
-void
-allgadd(G *gp)
-{
-       G **new;
-       uintptr cap;
-
-       runtime_lock(&allglock);
-       if(runtime_allglen >= allgcap) {
-               cap = 4096/sizeof(new[0]);
-               if(cap < 2*allgcap)
-                       cap = 2*allgcap;
-               new = runtime_malloc(cap*sizeof(new[0]));
-               if(new == nil)
-                       runtime_throw("runtime: cannot allocate memory");
-               if(runtime_allg != nil) {
-                       runtime_memmove(new, runtime_allg, 
runtime_allglen*sizeof(new[0]));
-                       runtime_free(runtime_allg);
-               }
-               runtime_allg = new;
-               allgcap = cap;
-       }
-       runtime_allg[runtime_allglen++] = gp;
-       runtime_unlock(&allglock);
-}
-
 // Put on gfree list.
 // If local list is too long, transfer a batch to the global list.
 static void
@@ -2352,29 +2252,6 @@ runtime_lockedOSThread(void)
 }
 
 int32
-runtime_gcount(void)
-{
-       G *gp;
-       int32 n, s;
-       uintptr i;
-
-       n = 0;
-       runtime_lock(&allglock);
-       // TODO(dvyukov): runtime.NumGoroutine() is O(N).
-       // We do not want to increment/decrement centralized counter in 
newproc/goexit,
-       // just to make runtime.NumGoroutine() faster.
-       // Compromise solution is to introduce per-P counters of active 
goroutines.
-       for(i = 0; i < runtime_allglen; i++) {
-               gp = runtime_allg[i];
-               s = gp->atomicstatus;
-               if(s == _Grunnable || s == _Grunning || s == _Gsyscall || s == 
_Gwaiting)
-                       n++;
-       }
-       runtime_unlock(&allglock);
-       return n;
-}
-
-int32
 runtime_mcount(void)
 {
        return runtime_sched->mcount;
@@ -2638,59 +2515,6 @@ incidlelocked(int32 v)
        runtime_unlock(&runtime_sched->lock);
 }
 
-// Check for deadlock situation.
-// The check is based on number of running M's, if 0 -> deadlock.
-static void
-checkdead(void)
-{
-       G *gp;
-       int32 run, grunning, s;
-       uintptr i;
-
-       // For -buildmode=c-shared or -buildmode=c-archive it's OK if
-       // there are no running goroutines.  The calling program is
-       // assumed to be running.
-       if(runtime_isarchive) {
-               return;
-       }
-
-       // -1 for sysmon
-       run = runtime_sched->mcount - runtime_sched->nmidle - 
runtime_sched->nmidlelocked - 1;
-       if(run > 0)
-               return;
-       // If we are dying because of a signal caught on an already idle thread,
-       // freezetheworld will cause all running threads to block.
-       // And runtime will essentially enter into deadlock state,
-       // except that there is a thread that will call runtime_exit soon.
-       if(runtime_panicking() > 0)
-               return;
-       if(run < 0) {
-               runtime_printf("runtime: checkdead: nmidle=%d nmidlelocked=%d 
mcount=%d\n",
-                       runtime_sched->nmidle, runtime_sched->nmidlelocked, 
runtime_sched->mcount);
-               runtime_throw("checkdead: inconsistent counts");
-       }
-       grunning = 0;
-       runtime_lock(&allglock);
-       for(i = 0; i < runtime_allglen; i++) {
-               gp = runtime_allg[i];
-               if(gp->isbackground)
-                       continue;
-               s = gp->atomicstatus;
-               if(s == _Gwaiting)
-                       grunning++;
-               else if(s == _Grunnable || s == _Grunning || s == _Gsyscall) {
-                       runtime_unlock(&allglock);
-                       runtime_printf("runtime: checkdead: find g %D in status 
%d\n", gp->goid, s);
-                       runtime_throw("checkdead: runnable g");
-               }
-       }
-       runtime_unlock(&allglock);
-       if(grunning == 0)  // possible if main goroutine calls runtime_Goexit()
-               runtime_throw("no goroutines (main called runtime.Goexit) - 
deadlock!");
-       g->m->throwing = -1;  // do not dump full stacks
-       runtime_throw("all goroutines are asleep - deadlock!");
-}
-
 static void
 sysmon(void)
 {
@@ -2832,94 +2656,6 @@ preemptall(void)
        return false;
 }
 
-void
-runtime_schedtrace(bool detailed)
-{
-       static int64 starttime;
-       int64 now;
-       int64 id1, id2, id3;
-       int32 i, t, h;
-       uintptr gi;
-       const char *fmt;
-       M *mp, *lockedm;
-       G *gp, *lockedg;
-       P *p;
-
-       now = runtime_nanotime();
-       if(starttime == 0)
-               starttime = now;
-
-       runtime_lock(&runtime_sched->lock);
-       runtime_printf("SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d 
idlethreads=%d runqueue=%d",
-               (now-starttime)/1000000, runtime_gomaxprocs, 
runtime_sched->npidle, runtime_sched->mcount,
-               runtime_sched->nmidle, runtime_sched->runqsize);
-       if(detailed) {
-               runtime_printf(" gcwaiting=%d nmidlelocked=%d nmspinning=%d 
stopwait=%d sysmonwait=%d\n",
-                       runtime_sched->gcwaiting, runtime_sched->nmidlelocked, 
runtime_sched->nmspinning,
-                       runtime_sched->stopwait, runtime_sched->sysmonwait);
-       }
-       // We must be careful while reading data from P's, M's and G's.
-       // Even if we hold schedlock, most data can be changed concurrently.
-       // E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil 
to nil.
-       for(i = 0; i < runtime_gomaxprocs; i++) {
-               p = runtime_allp[i];
-               if(p == nil)
-                       continue;
-               mp = (M*)p->m;
-               h = runtime_atomicload(&p->runqhead);
-               t = runtime_atomicload(&p->runqtail);
-               if(detailed)
-                       runtime_printf("  P%d: status=%d schedtick=%d 
syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
-                               i, p->status, p->schedtick, p->syscalltick, mp 
? mp->id : -1, t-h, p->gfreecnt);
-               else {
-                       // In non-detailed mode format lengths of per-P run 
queues as:
-                       // [len1 len2 len3 len4]
-                       fmt = " %d";
-                       if(runtime_gomaxprocs == 1)
-                               fmt = " [%d]\n";
-                       else if(i == 0)
-                               fmt = " [%d";
-                       else if(i == runtime_gomaxprocs-1)
-                               fmt = " %d]\n";
-                       runtime_printf(fmt, t-h);
-               }
-       }
-       if(!detailed) {
-               runtime_unlock(&runtime_sched->lock);
-               return;
-       }
-       for(mp = runtime_allm; mp; mp = mp->alllink) {
-               p = (P*)mp->p;
-               gp = mp->curg;
-               lockedg = mp->lockedg;
-               id1 = -1;
-               if(p)
-                       id1 = p->id;
-               id2 = -1;
-               if(gp)
-                       id2 = gp->goid;
-               id3 = -1;
-               if(lockedg)
-                       id3 = lockedg->goid;
-               runtime_printf("  M%d: p=%D curg=%D mallocing=%d throwing=%d 
gcing=%d"
-                       " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d 
lockedg=%D\n",
-                       mp->id, id1, id2,
-                       mp->mallocing, mp->throwing, mp->gcing, mp->locks, 
mp->dying, mp->helpgc,
-                       mp->spinning, mp->blocked, id3);
-       }
-       runtime_lock(&allglock);
-       for(gi = 0; gi < runtime_allglen; gi++) {
-               gp = runtime_allg[gi];
-               mp = gp->m;
-               lockedm = gp->lockedm;
-               runtime_printf("  G%D: status=%d(%S) m=%d lockedm=%d\n",
-                       gp->goid, gp->atomicstatus, gp->waitreason, mp ? mp->id 
: -1,
-                       lockedm ? lockedm->id : -1);
-       }
-       runtime_unlock(&allglock);
-       runtime_unlock(&runtime_sched->lock);
-}
-
 // Put mp on midle list.
 // Sched must be locked.
 static void
@@ -3357,20 +3093,6 @@ runtime_go_allm()
        return &runtime_allm;
 }
 
-extern Slice runtime_go_allgs(void)
-  __asm__ (GOSYM_PREFIX "runtime.allgs");
-
-Slice
-runtime_go_allgs()
-{
-       Slice s;
-
-       s.__values = runtime_allg;
-       s.__count = runtime_allglen;
-       s.__capacity = allgcap;
-       return s;
-}
-
 intgo NumCPU(void) __asm__ (GOSYM_PREFIX "runtime.NumCPU");
 
 intgo
Index: libgo/runtime/runtime.h
===================================================================
--- libgo/runtime/runtime.h     (revision 244031)
+++ libgo/runtime/runtime.h     (working copy)
@@ -7,6 +7,7 @@
 #include "go-assert.h"
 #include <complex.h>
 #include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -22,8 +23,6 @@
 #include <sys/mman.h>
 #endif
 
-#include "go-alloc.h"
-
 #define _STRINGIFY2_(x) #x
 #define _STRINGIFY_(x) _STRINGIFY2_(x)
 #define GOSYM_PREFIX _STRINGIFY_(__USER_LABEL_PREFIX__)
@@ -233,8 +232,10 @@ enum
  */
 extern uintptr* runtime_getZerobase(void)
   __asm__(GOSYM_PREFIX "runtime.getZerobase");
-extern G**     runtime_allg;
-extern uintptr runtime_allglen;
+extern G* runtime_getallg(intgo)
+  __asm__(GOSYM_PREFIX "runtime.getallg");
+extern uintptr runtime_getallglen(void)
+  __asm__(GOSYM_PREFIX "runtime.getallglen");
 extern G*      runtime_lastg;
 extern M*      runtime_allm;
 extern P**     runtime_allp;
@@ -309,13 +310,9 @@ MCache*    runtime_allocmcache(void)
 void   runtime_freemcache(MCache*);
 void   runtime_mallocinit(void);
 void   runtime_mprofinit(void);
-#define runtime_malloc(s) __go_alloc(s)
-#define runtime_free(p) __go_free(p)
 #define runtime_getcallersp(p) __builtin_frame_address(0)
 int32  runtime_mcount(void)
   __asm__ (GOSYM_PREFIX "runtime.mcount");
-int32  runtime_gcount(void)
-  __asm__ (GOSYM_PREFIX "runtime.gcount");
 void   runtime_mcall(void(*)(G*));
 uint32 runtime_fastrand1(void) __asm__ (GOSYM_PREFIX "runtime.fastrand1");
 int32  runtime_timediv(int64, int32, int32*)
Index: libgo/runtime/runtime_c.c
===================================================================
--- libgo/runtime/runtime_c.c   (revision 244031)
+++ libgo/runtime/runtime_c.c   (working copy)
@@ -25,7 +25,8 @@ extern volatile intgo runtime_MemProfile
 
 struct gotraceback_ret {
        int32 level;
-       bool crash;
+       bool  all;
+       bool  crash;
 };
 
 extern struct gotraceback_ret gotraceback(void)

Reply via email to