From patchwork Tue Jul 23 20:26:45 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 261204 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "localhost", Issuer "www.qmailtoaster.com" (not verified)) by ozlabs.org (Postfix) with ESMTPS id 52B302C0195 for ; Wed, 24 Jul 2013 06:27:04 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; q=dns; s= default; b=GYeGqlwjOhzsutPB4UHi79FILrjxumU2SCvsE0pIMH0Rjg7sRXl6R AA/M2xJ3GRDNyVqo3ZbfUmfBt271e12alsYdfIhU3v9IQ45L2/5kq8lluVsxRaxd agIKo6Dtdo9nWUCwyYnXT5pU1vyanSj5Tan7QQQ2szQVONJCRNLJbQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; s= default; bh=5JcBrfuH+UYpjAnyhBO3ehdNhSk=; b=sc444tOc1VztyZl48i73 UDQ/o5Juaib6s7G2l1NWSDDCSGETOa2pezS9siKk+6LOj+PdSohZe+KCzEw2KETd IHJBxYGj28CSRQnweF6sD2JNlIKdTbSWgw3b+FVvGRW7P/ANfCg7Ak7nvWwG/l/1 1RRvD7rSC1J8TIDNamXXFxY= Received: (qmail 2217 invoked by alias); 23 Jul 2013 20:26:57 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 2208 invoked by uid 89); 23 Jul 2013 20:26:57 -0000 X-Spam-SWARE-Status: No, score=0.9 required=5.0 tests=BAYES_50, RCVD_IN_DNSWL_LOW, RCVD_IN_HOSTKARMA_YE, RDNS_NONE, SPF_PASS, T_TVD_MIME_NO_HEADERS autolearn=no version=3.3.1 Received: from Unknown (HELO mail-pa0-f42.google.com) (209.85.220.42) by sourceware.org (qpsmtpd/0.84/v0.84-167-ge50287c) with ESMTP; Tue, 23 Jul 2013 20:26:55 +0000 Received: by mail-pa0-f42.google.com with SMTP id lj1so24008pab.15 for ; Tue, 23 Jul 2013 13:26:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:subject:date:message-id:user-agent:mime-version :content-type:x-gm-message-state; bh=EoD1EE81FucSZ1a0cNuIF9qmS4R9rala0HqbsYJRRP0=; b=U53Ha2p+p/c1TZ8uPESsonLu/w+rtQXhQqznubt16/JTW4lrrx1TC3rTzWSrruJ9cP Y0pbvfg3TwW3ag9Jw+GN4y1Y44+CAINtdN8nnyXZbh5u1RKGLtTISNw8Yl5ChPSJTcHI d7U6UgQzqcj7LruGBL7JukpvRj9Rj4B7Ih4ERbI0TOpSg8Ca7FbkNLCz5H/vt7LIxMe1 asNH1DnXLvXNyJPPXEMXGDUvmcdOntJnxtxwnwl35F0ttEy7f2RivyF+kybTQU0NX8sW LJ64N9GbBFQnpkxUcN96tOZnquPJDhVSCzvYY3y3iiSIpyKYLChmIQwlP4gECN3tPk/P 7vWw== X-Received: by 10.66.141.232 with SMTP id rr8mr20917165pab.184.1374611208302; Tue, 23 Jul 2013 13:26:48 -0700 (PDT) Received: from iant-glaptop.roam.corp.google.com.google.com ([2620:0:1000:3204:20f6:e2ed:d547:4b4c]) by mx.google.com with ESMTPSA id om2sm43481761pbb.34.2013.07.23.13.26.46 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Tue, 23 Jul 2013 13:26:47 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: libgo patch committed: Fix cgo callbacks from non-Go threads Date: Tue, 23 Jul 2013 13:26:45 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 X-Gm-Message-State: ALoCoQmuVnq3QVCbCvgOFXzM50D8soA1tmd9/01oU478XZQgptzr6RaKTR2y3OWXYNsZRzCa/QxBbugVU312HBKuIYX4065zV8SR7kUFFQ+k3KiyXsrXDT8V2d9n24jb9uy1unX84DQX8/is4akADsM1r+WnmodBvKPDJv2fpoJI815OoacOT6JKHzpJSkNeaM1igMSUfd8SMuEdNegOQOHOgJuaNnmoBg== X-Virus-Found: No This patch to libgo fixes cgo callbacks from non-Go threads. Those threads will not have an M or G structure. This basically adjusts the support in the master Go library to work with gccgo. There are also some cgo patches required. They are in https://codereview.appspot.com/11406047/ and will be applied to the master repository when approved. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline and 4.8 branch. Ian diff -r b916a03755cf libgo/runtime/go-cgo.c --- a/libgo/runtime/go-cgo.c Mon Jul 22 21:40:43 2013 -0700 +++ b/libgo/runtime/go-cgo.c Tue Jul 23 13:19:03 2013 -0700 @@ -35,6 +35,9 @@ M* m; G* g; + if (runtime_needextram && runtime_cas (&runtime_needextram, 1, 0)) + runtime_newextram (); + m = runtime_m (); ++m->ncgocall; g = runtime_g (); @@ -71,7 +74,24 @@ void syscall_cgocallback () { + M *mp; + + mp = runtime_m (); + if (mp == NULL) + { + runtime_needm (); + mp = runtime_m (); + mp->dropextram = true; + } + runtime_exitsyscall (); + + mp = runtime_m (); + if (mp->needextram) + { + mp->needextram = 0; + runtime_newextram (); + } } /* Prepare to return to C/C++ code from a callback to Go code. */ @@ -79,7 +99,15 @@ void syscall_cgocallbackdone () { + M *mp; + runtime_entersyscall (); + mp = runtime_m (); + if (mp->dropextram && runtime_g ()->ncgo == 0) + { + mp->dropextram = false; + runtime_dropm (); + } } /* Allocate memory and save it in a list visible to the Go garbage diff -r b916a03755cf libgo/runtime/go-defer.c --- a/libgo/runtime/go-defer.c Mon Jul 22 21:40:43 2013 -0700 +++ b/libgo/runtime/go-defer.c Tue Jul 23 13:19:03 2013 -0700 @@ -42,6 +42,7 @@ { struct __go_defer_stack *d; void (*pfn) (void *); + M *m; d = g->defer; pfn = d->__pfn; @@ -51,7 +52,14 @@ (*pfn) (d->__arg); g->defer = d->__next; - __go_free (d); + + /* This may be called by a cgo callback routine to defer the + call to syscall.CgocallBackDone, in which case we will not + have a memory context. Don't try to free anything in that + case--the GC will release it later. */ + m = runtime_m (); + if (m != NULL && m->mcache != NULL) + __go_free (d); /* Since we are executing a defer function here, we know we are returning from the calling function. If the calling diff -r b916a03755cf libgo/runtime/go-panic.c --- a/libgo/runtime/go-panic.c Mon Jul 22 21:40:43 2013 -0700 +++ b/libgo/runtime/go-panic.c Tue Jul 23 13:19:03 2013 -0700 @@ -54,6 +54,7 @@ { struct __go_defer_stack *d; void (*pfn) (void *); + M *m; d = g->defer; if (d == NULL) @@ -95,7 +96,14 @@ } g->defer = d->__next; - __go_free (d); + + /* This may be called by a cgo callback routine to defer the + call to syscall.CgocallBackDone, in which case we will not + have a memory context. Don't try to free anything in that + case--the GC will release it later. */ + m = runtime_m (); + if (m != NULL && m->mcache != NULL) + __go_free (d); } /* The panic was not recovered. */ diff -r b916a03755cf libgo/runtime/proc.c --- a/libgo/runtime/proc.c Mon Jul 22 21:40:43 2013 -0700 +++ b/libgo/runtime/proc.c Tue Jul 23 13:19:03 2013 -0700 @@ -397,7 +397,8 @@ Sched runtime_sched; int32 runtime_gomaxprocs; bool runtime_singleproc; -bool runtime_iscgo; +bool runtime_iscgo = true; +uint32 runtime_needextram = 1; uint32 runtime_gcwaiting; M runtime_m0; G runtime_g0; // idle goroutine for m0 @@ -901,8 +902,8 @@ #ifdef USING_SPLIT_STACK { - int dont_block_signals = 0; - __splitstack_block_signals(&dont_block_signals, nil); + int dont_block_signals = 0; + __splitstack_block_signals(&dont_block_signals, nil); } #endif @@ -944,7 +945,7 @@ // Allocate a new m unassociated with any thread. // Can use p for allocation context if needed. M* -runtime_allocm(P *p) +runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacksize) { M *mp; @@ -961,7 +962,7 @@ mp = runtime_mal(sizeof *mp); mcommoninit(mp); - mp->g0 = runtime_malg(-1, nil, nil); + mp->g0 = runtime_malg(stacksize, ret_g0_stack, ret_g0_stacksize); if(p == m->p) releasep(); @@ -1006,6 +1007,9 @@ // // When the callback is done with the m, it calls dropm to // put the m back on the list. +// +// Unlike the gc toolchain, we start running on curg, since we are +// just going to return and let the caller continue. void runtime_needm(void) { @@ -1027,18 +1031,40 @@ mp->needextram = mp->schedlink == nil; unlockextra(mp->schedlink); - // Install m and g (= m->g0) and set the stack bounds - // to match the current stack. We don't actually know - // how big the stack is, like we don't know how big any - // scheduling stack is, but we assume there's at least 32 kB, - // which is more than enough for us. - runtime_setmg(mp, mp->g0); + // Install m and g (= m->curg). + runtime_setmg(mp, mp->curg); - // We assume that the split stack support has been initialized - // for this new thread. + // Initialize g's context as in mstart. + initcontext(); + g->status = Gsyscall; + g->entry = nil; + g->param = nil; +#ifdef USING_SPLIT_STACK + __splitstack_getcontext(&g->stack_context[0]); +#else + g->gcinitial_sp = ∓ + g->gcstack_size = 0; + g->gcnext_sp = ∓ +#endif + getcontext(&g->context); + + if(g->entry != nil) { + // Got here from mcall. + void (*pfn)(G*) = (void (*)(G*))g->entry; + G* gp = (G*)g->param; + pfn(gp); + *(int*)0x22 = 0x22; + } // Initialize this thread to use the m. runtime_minit(); + +#ifdef USING_SPLIT_STACK + { + int dont_block_signals = 0; + __splitstack_block_signals(&dont_block_signals, nil); + } +#endif } // newextram allocates an m and puts it on the extra list. @@ -1049,15 +1075,17 @@ { M *mp, *mnext; G *gp; + byte *g0_sp, *sp; + size_t g0_spsize, spsize; // Create extra goroutine locked to extra m. // The goroutine is the context in which the cgo callback will run. // The sched.pc will never be returned to, but setting it to // runtime.goexit makes clear to the traceback routines where // the goroutine stack ends. - mp = runtime_allocm(nil); - gp = runtime_malg(StackMin, nil, nil); - gp->status = Gsyscall; + mp = runtime_allocm(nil, StackMin, &g0_sp, &g0_spsize); + gp = runtime_malg(StackMin, &sp, &spsize); + gp->status = Gdead; mp->curg = gp; mp->locked = LockInternal; mp->lockedg = gp; @@ -1072,6 +1100,16 @@ runtime_unlock(&runtime_sched); gp->goid = runtime_xadd64(&runtime_sched.goidgen, 1); + // The context for gp will be set up in runtime_needm. But + // here we need to set up the context for g0. + getcontext(&mp->g0->context); + mp->g0->context.uc_stack.ss_sp = g0_sp; +#ifdef MAKECONTEXT_STACK_TOP + mp->g0->context.uc_stack.ss_sp += g0_spsize; +#endif + mp->g0->context.uc_stack.ss_size = g0_spsize; + makecontext(&mp->g0->context, kickoff, 0); + // Add m to the extra list. mnext = lockextra(true); mp->schedlink = mnext; @@ -1114,6 +1152,8 @@ mp = m; runtime_setmg(nil, nil); + mp->curg->status = Gdead; + mnext = lockextra(true); mp->schedlink = mnext; unlockextra(mp); @@ -1159,6 +1199,29 @@ runtime_atomicstorep(&runtime_extram, mp); } +static int32 +countextra() +{ + M *mp, *mc; + int32 c; + + for(;;) { + mp = runtime_atomicloadp(&runtime_extram); + if(mp == MLOCKED) { + runtime_osyield(); + continue; + } + if(!runtime_casp(&runtime_extram, mp, MLOCKED)) { + runtime_osyield(); + continue; + } + c = 0; + for(mc = mp; mc != nil; mc = mc->schedlink) + c++; + runtime_atomicstorep(&runtime_extram, mp); + return c; + } +} // Create a new m. It will start off with a call to fn, or else the scheduler. static void @@ -1166,7 +1229,7 @@ { M *mp; - mp = runtime_allocm(p); + mp = runtime_allocm(p, -1, nil, nil); mp->nextp = p; mp->mstartfn = fn; @@ -2348,7 +2411,7 @@ int32 run, grunning, s; // -1 for sysmon - run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.mlocked - 1; + run = runtime_sched.mcount - runtime_sched.nmidle - runtime_sched.mlocked - 1 - countextra(); if(run > 0) return; if(run < 0) { diff -r b916a03755cf libgo/runtime/runtime.h --- a/libgo/runtime/runtime.h Mon Jul 22 21:40:43 2013 -0700 +++ b/libgo/runtime/runtime.h Tue Jul 23 13:19:03 2013 -0700 @@ -273,6 +273,7 @@ GCStats gcstats; bool racecall; bool needextram; + bool dropextram; // for gccgo: drop after call is done. void* racepc; void (*waitunlockf)(Lock*); void* waitlock; @@ -450,6 +451,7 @@ extern M* runtime_allm; extern P** runtime_allp; extern int32 runtime_gomaxprocs; +extern uint32 runtime_needextram; extern bool runtime_singleproc; extern uint32 runtime_panicking; extern uint32 runtime_gcwaiting; // gc is waiting to run @@ -518,6 +520,8 @@ void runtime_mpreinit(M*); void runtime_minit(void); void runtime_unminit(void); +void runtime_needm(void); +void runtime_dropm(void); void runtime_signalstack(byte*, int32); MCache* runtime_allocmcache(void); void runtime_freemcache(MCache*);