blob: 455a39e22b6613c9dccc0e0adedb6d2b0c05d835 [file] [log] [blame]
Ken Thompsonaf58f172008-07-14 14:34:27 -07001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5#include "runtime.h"
Russ Cox9b15ad82010-10-14 10:45:32 -04006#include "arch.h"
Hector Chu6bfe5f52010-01-06 17:58:55 -08007#include "defs.h"
Russ Cox1ce17912009-01-26 17:37:05 -08008#include "malloc.h"
Hector Chu6bfe5f52010-01-06 17:58:55 -08009#include "os.h"
Russ Coxd9fd1142011-02-22 17:40:40 -050010#include "stack.h"
Ken Thompsonaf58f172008-07-14 14:34:27 -070011
Russ Cox9042c2c2010-12-08 13:53:30 -050012bool runtime·iscgo;
13
Russ Cox83727cc2010-03-29 21:48:22 -070014static void unwindstack(G*, byte*);
15
Russ Coxd28acc42008-08-04 16:43:49 -070016typedef struct Sched Sched;
17
Russ Cox68b42552010-11-04 14:00:19 -040018M runtime·m0;
19G runtime·g0; // idle goroutine for m0
Russ Coxd28acc42008-08-04 16:43:49 -070020
Ken Thompsonaf58f172008-07-14 14:34:27 -070021static int32 debug = 0;
22
Russ Cox68b42552010-11-04 14:00:19 -040023int32 runtime·gcwaiting;
Russ Cox5328df62010-01-09 09:47:45 -080024
Russ Cox96824002008-08-05 14:18:47 -070025// Go scheduler
26//
27// The go scheduler's job is to match ready-to-run goroutines (`g's)
28// with waiting-for-work schedulers (`m's). If there are ready gs
29// and no waiting ms, ready() will start a new m running in a new
30// OS thread, so that all ready gs can run simultaneously, up to a limit.
31// For now, ms never go away.
32//
Russ Coxfe1e4922009-11-10 19:59:22 -080033// By default, Go keeps only one kernel thread (m) running user code
34// at a single time; other threads may be blocked in the operating system.
35// Setting the environment variable $GOMAXPROCS or calling
36// runtime.GOMAXPROCS() will change the number of user threads
37// allowed to execute simultaneously. $GOMAXPROCS is thus an
38// approximation of the maximum number of cores to use.
Russ Cox96824002008-08-05 14:18:47 -070039//
40// Even a program that can run without deadlock in a single process
41// might use more ms if given the chance. For example, the prime
Russ Cox68b42552010-11-04 14:00:19 -040042// sieve will use as many ms as there are primes (up to runtime·sched.mmax),
Russ Cox96824002008-08-05 14:18:47 -070043// allowing different stages of the pipeline to execute in parallel.
44// We could revisit this choice, only kicking off new ms for blocking
45// system calls, but that would limit the amount of parallel computation
46// that go would try to do.
47//
48// In general, one could imagine all sorts of refinements to the
49// scheduler, but the goal now is just to get something working on
50// Linux and OS X.
51
Russ Coxd28acc42008-08-04 16:43:49 -070052struct Sched {
Russ Coxd28acc42008-08-04 16:43:49 -070053 Lock;
Russ Cox96824002008-08-05 14:18:47 -070054
55 G *gfree; // available gs (status == Gdead)
Russ Coxf7f63292008-08-05 14:21:42 -070056
Russ Cox96824002008-08-05 14:18:47 -070057 G *ghead; // gs waiting to run
58 G *gtail;
59 int32 gwait; // number of gs waiting to run
60 int32 gcount; // number of gs that are alive
Russ Coxf7f63292008-08-05 14:21:42 -070061
Russ Cox96824002008-08-05 14:18:47 -070062 M *mhead; // ms waiting for work
63 int32 mwait; // number of ms waiting for work
Russ Coxefc86a72008-11-25 16:48:10 -080064 int32 mcount; // number of ms that have been created
65 int32 mcpu; // number of ms executing on cpu
66 int32 mcpumax; // max number of ms allowed on cpu
67 int32 msyscall; // number of ms in system calls
Russ Coxf7f63292008-08-05 14:21:42 -070068
Russ Cox96824002008-08-05 14:18:47 -070069 int32 predawn; // running initialization, don't run new gs.
Russ Cox3f8aa662008-12-05 15:24:18 -080070
71 Note stopped; // one g can wait here for ms to stop
Russ Coxbe629132008-12-08 17:14:08 -080072 int32 waitstop; // after setting this flag
Russ Coxd28acc42008-08-04 16:43:49 -070073};
74
Russ Cox68b42552010-11-04 14:00:19 -040075Sched runtime·sched;
Russ Cox67793502011-02-16 13:21:13 -050076int32 gomaxprocs;
Russ Coxd28acc42008-08-04 16:43:49 -070077
Russ Cox96824002008-08-05 14:18:47 -070078// Scheduling helpers. Sched must be locked.
79static void gput(G*); // put/get on ghead/gtail
80static G* gget(void);
81static void mput(M*); // put/get on mhead
Russ Cox218c3932009-07-13 17:28:39 -070082static M* mget(G*);
Russ Cox96824002008-08-05 14:18:47 -070083static void gfput(G*); // put/get on gfree
84static G* gfget(void);
Russ Coxefc86a72008-11-25 16:48:10 -080085static void matchmg(void); // match ms to gs
Russ Cox96824002008-08-05 14:18:47 -070086static void readylocked(G*); // ready, but sched is locked
Russ Cox218c3932009-07-13 17:28:39 -070087static void mnextg(M*, G*);
Russ Cox96824002008-08-05 14:18:47 -070088
89// Scheduler loop.
90static void scheduler(void);
91
Russ Coxa67258f2008-09-18 15:56:46 -070092// The bootstrap sequence is:
93//
94// call osinit
95// call schedinit
96// make & queue new G
Russ Cox68b42552010-11-04 14:00:19 -040097// call runtime·mstart
Russ Coxa67258f2008-09-18 15:56:46 -070098//
99// The new G does:
100//
101// call main·init_function
102// call initdone
103// call main·main
Russ Cox96824002008-08-05 14:18:47 -0700104void
Russ Cox68b42552010-11-04 14:00:19 -0400105runtime·schedinit(void)
Russ Cox96824002008-08-05 14:18:47 -0700106{
107 int32 n;
108 byte *p;
Russ Coxadd89dd2009-10-12 10:26:38 -0700109
Russ Cox68b42552010-11-04 14:00:19 -0400110 runtime·allm = m;
Russ Cox6eb251f2010-03-24 09:40:09 -0700111 m->nomemprof++;
Russ Coxf7f63292008-08-05 14:21:42 -0700112
Russ Cox68b42552010-11-04 14:00:19 -0400113 runtime·mallocinit();
114 runtime·goargs();
Alex Brainmana41d8542011-01-12 11:48:15 +1100115 runtime·goenvs();
Russ Cox36096242009-01-16 14:58:14 -0800116
Russ Cox0d3301a2009-12-07 15:52:14 -0800117 // For debugging:
Russ Coxda0a7d72008-12-19 03:13:39 -0800118 // Allocate internal symbol table representation now,
119 // so that we don't need to call malloc when we crash.
Russ Cox67793502011-02-16 13:21:13 -0500120 // runtime·findfunc(0);
Russ Coxe29ce172008-12-18 15:42:28 -0800121
Russ Cox67793502011-02-16 13:21:13 -0500122 runtime·gomaxprocs = 1;
Russ Cox68b42552010-11-04 14:00:19 -0400123 p = runtime·getenv("GOMAXPROCS");
124 if(p != nil && (n = runtime·atoi(p)) != 0)
Russ Cox67793502011-02-16 13:21:13 -0500125 runtime·gomaxprocs = n;
126 runtime·sched.mcpumax = runtime·gomaxprocs;
Russ Cox68b42552010-11-04 14:00:19 -0400127 runtime·sched.mcount = 1;
128 runtime·sched.predawn = 1;
Russ Cox6eb251f2010-03-24 09:40:09 -0700129
130 m->nomemprof--;
Russ Cox96824002008-08-05 14:18:47 -0700131}
132
Russ Coxa67258f2008-09-18 15:56:46 -0700133// Called after main·init_function; main·main will be called on return.
Russ Cox96824002008-08-05 14:18:47 -0700134void
Russ Cox68b42552010-11-04 14:00:19 -0400135runtime·initdone(void)
Russ Cox96824002008-08-05 14:18:47 -0700136{
Russ Cox96824002008-08-05 14:18:47 -0700137 // Let's go.
Russ Cox68b42552010-11-04 14:00:19 -0400138 runtime·sched.predawn = 0;
Russ Cox1ce17912009-01-26 17:37:05 -0800139 mstats.enablegc = 1;
Russ Cox96824002008-08-05 14:18:47 -0700140
Russ Cox96824002008-08-05 14:18:47 -0700141 // If main·init_function started other goroutines,
142 // kick off new ms to handle them, like ready
143 // would have, had it not been pre-dawn.
Russ Cox68b42552010-11-04 14:00:19 -0400144 runtime·lock(&runtime·sched);
Russ Coxefc86a72008-11-25 16:48:10 -0800145 matchmg();
Russ Cox68b42552010-11-04 14:00:19 -0400146 runtime·unlock(&runtime·sched);
Russ Cox96824002008-08-05 14:18:47 -0700147}
148
Ken Thompsonaf58f172008-07-14 14:34:27 -0700149void
Russ Cox68b42552010-11-04 14:00:19 -0400150runtime·goexit(void)
Ken Thompsonaf58f172008-07-14 14:34:27 -0700151{
Russ Cox96824002008-08-05 14:18:47 -0700152 g->status = Gmoribund;
Russ Cox68b42552010-11-04 14:00:19 -0400153 runtime·gosched();
Ken Thompsonaf58f172008-07-14 14:34:27 -0700154}
155
Ken Thompson1e1cc4e2009-01-27 12:03:53 -0800156void
Russ Cox68b42552010-11-04 14:00:19 -0400157runtime·tracebackothers(G *me)
Rob Pike3835e012008-07-28 11:29:41 -0700158{
159 G *g;
160
Russ Cox68b42552010-11-04 14:00:19 -0400161 for(g = runtime·allg; g != nil; g = g->alllink) {
Russ Coxd28acc42008-08-04 16:43:49 -0700162 if(g == me || g->status == Gdead)
Rob Pike3835e012008-07-28 11:29:41 -0700163 continue;
Russ Cox68b42552010-11-04 14:00:19 -0400164 runtime·printf("\ngoroutine %d [%d]:\n", g->goid, g->status);
165 runtime·traceback(g->sched.pc, g->sched.sp, 0, g);
Rob Pike3835e012008-07-28 11:29:41 -0700166 }
167}
168
Russ Cox96824002008-08-05 14:18:47 -0700169// Put on `g' queue. Sched must be locked.
Russ Coxd28acc42008-08-04 16:43:49 -0700170static void
Russ Cox96824002008-08-05 14:18:47 -0700171gput(G *g)
Russ Coxd28acc42008-08-04 16:43:49 -0700172{
Russ Cox218c3932009-07-13 17:28:39 -0700173 M *m;
174
175 // If g is wired, hand it off directly.
Russ Cox68b42552010-11-04 14:00:19 -0400176 if(runtime·sched.mcpu < runtime·sched.mcpumax && (m = g->lockedm) != nil) {
Russ Cox218c3932009-07-13 17:28:39 -0700177 mnextg(m, g);
178 return;
179 }
180
Russ Cox96824002008-08-05 14:18:47 -0700181 g->schedlink = nil;
Russ Cox68b42552010-11-04 14:00:19 -0400182 if(runtime·sched.ghead == nil)
183 runtime·sched.ghead = g;
Russ Coxd28acc42008-08-04 16:43:49 -0700184 else
Russ Cox68b42552010-11-04 14:00:19 -0400185 runtime·sched.gtail->schedlink = g;
186 runtime·sched.gtail = g;
187 runtime·sched.gwait++;
Russ Coxd28acc42008-08-04 16:43:49 -0700188}
189
Russ Cox96824002008-08-05 14:18:47 -0700190// Get from `g' queue. Sched must be locked.
191static G*
192gget(void)
193{
194 G *g;
Russ Coxf7f63292008-08-05 14:21:42 -0700195
Russ Cox68b42552010-11-04 14:00:19 -0400196 g = runtime·sched.ghead;
Russ Cox96824002008-08-05 14:18:47 -0700197 if(g){
Russ Cox68b42552010-11-04 14:00:19 -0400198 runtime·sched.ghead = g->schedlink;
199 if(runtime·sched.ghead == nil)
200 runtime·sched.gtail = nil;
201 runtime·sched.gwait--;
Russ Cox96824002008-08-05 14:18:47 -0700202 }
203 return g;
204}
205
206// Put on `m' list. Sched must be locked.
207static void
208mput(M *m)
209{
Russ Cox68b42552010-11-04 14:00:19 -0400210 m->schedlink = runtime·sched.mhead;
211 runtime·sched.mhead = m;
212 runtime·sched.mwait++;
Russ Cox96824002008-08-05 14:18:47 -0700213}
214
Russ Cox218c3932009-07-13 17:28:39 -0700215// Get an `m' to run `g'. Sched must be locked.
Russ Cox96824002008-08-05 14:18:47 -0700216static M*
Russ Cox218c3932009-07-13 17:28:39 -0700217mget(G *g)
Russ Cox96824002008-08-05 14:18:47 -0700218{
219 M *m;
Russ Coxf7f63292008-08-05 14:21:42 -0700220
Russ Cox218c3932009-07-13 17:28:39 -0700221 // if g has its own m, use it.
222 if((m = g->lockedm) != nil)
223 return m;
224
225 // otherwise use general m pool.
Russ Cox68b42552010-11-04 14:00:19 -0400226 if((m = runtime·sched.mhead) != nil){
227 runtime·sched.mhead = m->schedlink;
228 runtime·sched.mwait--;
Russ Cox96824002008-08-05 14:18:47 -0700229 }
230 return m;
231}
232
Russ Cox96824002008-08-05 14:18:47 -0700233// Mark g ready to run.
Russ Coxd28acc42008-08-04 16:43:49 -0700234void
Russ Cox68b42552010-11-04 14:00:19 -0400235runtime·ready(G *g)
Russ Coxd28acc42008-08-04 16:43:49 -0700236{
Russ Cox68b42552010-11-04 14:00:19 -0400237 runtime·lock(&runtime·sched);
Russ Cox96824002008-08-05 14:18:47 -0700238 readylocked(g);
Russ Cox68b42552010-11-04 14:00:19 -0400239 runtime·unlock(&runtime·sched);
Russ Coxd28acc42008-08-04 16:43:49 -0700240}
241
Russ Coxa61bb952008-09-24 14:13:07 -0700242// Mark g ready to run. Sched is already locked.
243// G might be running already and about to stop.
244// The sched lock protects g->status from changing underfoot.
Russ Cox96824002008-08-05 14:18:47 -0700245static void
246readylocked(G *g)
247{
Russ Coxa61bb952008-09-24 14:13:07 -0700248 if(g->m){
249 // Running on another machine.
250 // Ready it when it stops.
251 g->readyonstop = 1;
252 return;
253 }
Russ Coxd28acc42008-08-04 16:43:49 -0700254
Russ Cox96824002008-08-05 14:18:47 -0700255 // Mark runnable.
Russ Coxb5dfac42011-02-23 15:51:20 -0500256 if(g->status == Grunnable || g->status == Grunning || g->status == Grecovery || g->status == Gstackalloc) {
257 runtime·printf("goroutine %d has status %d\n", g->goid, g->status);
Russ Cox68b42552010-11-04 14:00:19 -0400258 runtime·throw("bad g->status in ready");
Russ Coxb5dfac42011-02-23 15:51:20 -0500259 }
Russ Cox96824002008-08-05 14:18:47 -0700260 g->status = Grunnable;
261
Russ Coxefc86a72008-11-25 16:48:10 -0800262 gput(g);
Russ Cox68b42552010-11-04 14:00:19 -0400263 if(!runtime·sched.predawn)
Russ Coxefc86a72008-11-25 16:48:10 -0800264 matchmg();
Russ Cox96824002008-08-05 14:18:47 -0700265}
266
Austin Clementsad9c6f72009-09-18 09:11:19 -0700267static void
268nop(void)
269{
270}
271
Russ Coxfe8ff952009-08-31 18:10:11 -0700272// Same as readylocked but a different symbol so that
273// debuggers can set a breakpoint here and catch all
274// new goroutines.
275static void
276newprocreadylocked(G *g)
277{
Austin Clementsad9c6f72009-09-18 09:11:19 -0700278 nop(); // avoid inlining in 6l
Russ Coxfe8ff952009-08-31 18:10:11 -0700279 readylocked(g);
280}
281
Russ Cox218c3932009-07-13 17:28:39 -0700282// Pass g to m for running.
283static void
284mnextg(M *m, G *g)
285{
Russ Cox68b42552010-11-04 14:00:19 -0400286 runtime·sched.mcpu++;
Russ Cox218c3932009-07-13 17:28:39 -0700287 m->nextg = g;
288 if(m->waitnextg) {
289 m->waitnextg = 0;
Russ Cox68b42552010-11-04 14:00:19 -0400290 runtime·notewakeup(&m->havenextg);
Russ Cox218c3932009-07-13 17:28:39 -0700291 }
292}
293
Russ Cox96824002008-08-05 14:18:47 -0700294// Get the next goroutine that m should run.
295// Sched must be locked on entry, is unlocked on exit.
Russ Coxefc86a72008-11-25 16:48:10 -0800296// Makes sure that at most $GOMAXPROCS gs are
297// running on cpus (not in system calls) at any given time.
Russ Cox96824002008-08-05 14:18:47 -0700298static G*
299nextgandunlock(void)
Ken Thompsonaf58f172008-07-14 14:34:27 -0700300{
Ken Thompsone7d549f2008-07-16 13:50:23 -0700301 G *gp;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700302
Russ Cox68b42552010-11-04 14:00:19 -0400303 if(runtime·sched.mcpu < 0)
304 runtime·throw("negative runtime·sched.mcpu");
Russ Cox218c3932009-07-13 17:28:39 -0700305
306 // If there is a g waiting as m->nextg,
Russ Cox68b42552010-11-04 14:00:19 -0400307 // mnextg took care of the runtime·sched.mcpu++.
Russ Coxefc86a72008-11-25 16:48:10 -0800308 if(m->nextg != nil) {
309 gp = m->nextg;
310 m->nextg = nil;
Russ Cox68b42552010-11-04 14:00:19 -0400311 runtime·unlock(&runtime·sched);
Russ Cox96824002008-08-05 14:18:47 -0700312 return gp;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700313 }
Russ Cox96824002008-08-05 14:18:47 -0700314
Russ Cox218c3932009-07-13 17:28:39 -0700315 if(m->lockedg != nil) {
316 // We can only run one g, and it's not available.
317 // Make sure some other cpu is running to handle
318 // the ordinary run queue.
Russ Cox68b42552010-11-04 14:00:19 -0400319 if(runtime·sched.gwait != 0)
Russ Cox218c3932009-07-13 17:28:39 -0700320 matchmg();
321 } else {
322 // Look for work on global queue.
Russ Cox68b42552010-11-04 14:00:19 -0400323 while(runtime·sched.mcpu < runtime·sched.mcpumax && (gp=gget()) != nil) {
Russ Cox218c3932009-07-13 17:28:39 -0700324 if(gp->lockedm) {
325 mnextg(gp->lockedm, gp);
326 continue;
327 }
Russ Cox68b42552010-11-04 14:00:19 -0400328 runtime·sched.mcpu++; // this m will run gp
329 runtime·unlock(&runtime·sched);
Russ Cox218c3932009-07-13 17:28:39 -0700330 return gp;
Russ Coxefc86a72008-11-25 16:48:10 -0800331 }
Russ Cox218c3932009-07-13 17:28:39 -0700332 // Otherwise, wait on global m queue.
333 mput(m);
Russ Coxefc86a72008-11-25 16:48:10 -0800334 }
Russ Cox68b42552010-11-04 14:00:19 -0400335 if(runtime·sched.mcpu == 0 && runtime·sched.msyscall == 0)
336 runtime·throw("all goroutines are asleep - deadlock!");
Russ Cox96824002008-08-05 14:18:47 -0700337 m->nextg = nil;
Russ Cox218c3932009-07-13 17:28:39 -0700338 m->waitnextg = 1;
Russ Cox68b42552010-11-04 14:00:19 -0400339 runtime·noteclear(&m->havenextg);
340 if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
341 runtime·sched.waitstop = 0;
342 runtime·notewakeup(&runtime·sched.stopped);
Russ Coxbe629132008-12-08 17:14:08 -0800343 }
Russ Cox68b42552010-11-04 14:00:19 -0400344 runtime·unlock(&runtime·sched);
Russ Coxf7f63292008-08-05 14:21:42 -0700345
Russ Cox68b42552010-11-04 14:00:19 -0400346 runtime·notesleep(&m->havenextg);
Russ Cox96824002008-08-05 14:18:47 -0700347 if((gp = m->nextg) == nil)
Russ Cox68b42552010-11-04 14:00:19 -0400348 runtime·throw("bad m->nextg in nextgoroutine");
Russ Cox96824002008-08-05 14:18:47 -0700349 m->nextg = nil;
Russ Coxd28acc42008-08-04 16:43:49 -0700350 return gp;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700351}
352
Russ Cox3f8aa662008-12-05 15:24:18 -0800353// TODO(rsc): Remove. This is only temporary,
354// for the mark and sweep collector.
355void
Russ Cox68b42552010-11-04 14:00:19 -0400356runtime·stoptheworld(void)
Russ Cox3f8aa662008-12-05 15:24:18 -0800357{
Russ Cox68b42552010-11-04 14:00:19 -0400358 runtime·lock(&runtime·sched);
359 runtime·gcwaiting = 1;
360 runtime·sched.mcpumax = 1;
361 while(runtime·sched.mcpu > 1) {
Russ Cox88ce9ce2010-04-06 13:48:31 -0700362 // It would be unsafe for multiple threads to be using
363 // the stopped note at once, but there is only
364 // ever one thread doing garbage collection,
365 // so this is okay.
Russ Cox68b42552010-11-04 14:00:19 -0400366 runtime·noteclear(&runtime·sched.stopped);
367 runtime·sched.waitstop = 1;
368 runtime·unlock(&runtime·sched);
369 runtime·notesleep(&runtime·sched.stopped);
370 runtime·lock(&runtime·sched);
Russ Cox3f8aa662008-12-05 15:24:18 -0800371 }
Russ Cox68b42552010-11-04 14:00:19 -0400372 runtime·unlock(&runtime·sched);
Russ Cox3f8aa662008-12-05 15:24:18 -0800373}
374
375// TODO(rsc): Remove. This is only temporary,
376// for the mark and sweep collector.
377void
Russ Cox68b42552010-11-04 14:00:19 -0400378runtime·starttheworld(void)
Russ Cox3f8aa662008-12-05 15:24:18 -0800379{
Russ Cox68b42552010-11-04 14:00:19 -0400380 runtime·lock(&runtime·sched);
381 runtime·gcwaiting = 0;
Russ Cox67793502011-02-16 13:21:13 -0500382 runtime·sched.mcpumax = runtime·gomaxprocs;
Russ Cox3f8aa662008-12-05 15:24:18 -0800383 matchmg();
Russ Cox68b42552010-11-04 14:00:19 -0400384 runtime·unlock(&runtime·sched);
Russ Cox3f8aa662008-12-05 15:24:18 -0800385}
386
Russ Coxa67258f2008-09-18 15:56:46 -0700387// Called to start an M.
388void
Russ Cox68b42552010-11-04 14:00:19 -0400389runtime·mstart(void)
Russ Coxa67258f2008-09-18 15:56:46 -0700390{
Russ Cox74a9fc12010-01-06 19:24:11 -0800391 if(g != m->g0)
Russ Cox68b42552010-11-04 14:00:19 -0400392 runtime·throw("bad runtime·mstart");
Russ Coxe29ce172008-12-18 15:42:28 -0800393 if(m->mcache == nil)
Russ Cox68b42552010-11-04 14:00:19 -0400394 m->mcache = runtime·allocmcache();
395 runtime·minit();
Russ Coxa67258f2008-09-18 15:56:46 -0700396 scheduler();
397}
398
Russ Cox133a1582009-10-03 10:37:12 -0700399// When running with cgo, we call libcgo_thread_start
400// to start threads for us so that we can play nicely with
401// foreign code.
402void (*libcgo_thread_start)(void*);
403
404typedef struct CgoThreadStart CgoThreadStart;
405struct CgoThreadStart
406{
407 M *m;
408 G *g;
409 void (*fn)(void);
410};
411
412// Kick off new ms as needed (up to mcpumax).
Russ Coxefc86a72008-11-25 16:48:10 -0800413// There are already `other' other cpus that will
414// start looking for goroutines shortly.
415// Sched is locked.
416static void
417matchmg(void)
418{
Russ Coxefc86a72008-11-25 16:48:10 -0800419 G *g;
420
Russ Cox41554e22009-11-17 22:00:30 -0800421 if(m->mallocing || m->gcing)
Russ Cox4dfd7fd2009-11-17 14:42:08 -0800422 return;
Russ Cox68b42552010-11-04 14:00:19 -0400423 while(runtime·sched.mcpu < runtime·sched.mcpumax && (g = gget()) != nil){
Russ Cox4dfd7fd2009-11-17 14:42:08 -0800424 M *m;
425
Russ Cox218c3932009-07-13 17:28:39 -0700426 // Find the m that will run g.
427 if((m = mget(g)) == nil){
Russ Cox68b42552010-11-04 14:00:19 -0400428 m = runtime·malloc(sizeof(M));
429 // Add to runtime·allm so garbage collector doesn't free m
Russ Cox93689d82009-10-09 15:35:33 -0700430 // when it is just in a register (R14 on amd64).
Russ Cox68b42552010-11-04 14:00:19 -0400431 m->alllink = runtime·allm;
432 runtime·allm = m;
433 m->id = runtime·sched.mcount++;
Russ Cox133a1582009-10-03 10:37:12 -0700434
Russ Cox9042c2c2010-12-08 13:53:30 -0500435 if(runtime·iscgo) {
Russ Cox133a1582009-10-03 10:37:12 -0700436 CgoThreadStart ts;
Russ Cox9042c2c2010-12-08 13:53:30 -0500437
438 if(libcgo_thread_start == nil)
439 runtime·throw("libcgo_thread_start missing");
Russ Coxf25586a2010-02-10 00:00:12 -0800440 // pthread_create will make us a stack.
Russ Cox68b42552010-11-04 14:00:19 -0400441 m->g0 = runtime·malg(-1);
Russ Cox133a1582009-10-03 10:37:12 -0700442 ts.m = m;
443 ts.g = m->g0;
Russ Cox68b42552010-11-04 14:00:19 -0400444 ts.fn = runtime·mstart;
445 runtime·runcgo(libcgo_thread_start, &ts);
Russ Coxf25586a2010-02-10 00:00:12 -0800446 } else {
Alex Brainmanf95a2f22010-09-12 11:45:16 +1000447 if(Windows)
448 // windows will layout sched stack on os stack
Russ Cox68b42552010-11-04 14:00:19 -0400449 m->g0 = runtime·malg(-1);
Alex Brainmanf95a2f22010-09-12 11:45:16 +1000450 else
Russ Cox68b42552010-11-04 14:00:19 -0400451 m->g0 = runtime·malg(8192);
452 runtime·newosproc(m, m->g0, m->g0->stackbase, runtime·mstart);
Russ Coxf25586a2010-02-10 00:00:12 -0800453 }
Russ Coxefc86a72008-11-25 16:48:10 -0800454 }
Russ Cox218c3932009-07-13 17:28:39 -0700455 mnextg(m, g);
Russ Coxefc86a72008-11-25 16:48:10 -0800456 }
457}
458
Russ Cox96824002008-08-05 14:18:47 -0700459// Scheduler loop: find g to run, run it, repeat.
460static void
Russ Cox4feda712008-08-02 22:34:04 -0700461scheduler(void)
462{
463 G* gp;
Russ Coxd28acc42008-08-04 16:43:49 -0700464
Russ Cox68b42552010-11-04 14:00:19 -0400465 runtime·lock(&runtime·sched);
466 if(runtime·gosave(&m->sched) != 0){
Russ Cox133a1582009-10-03 10:37:12 -0700467 gp = m->curg;
Russ Cox9b1507b2010-03-31 11:46:01 -0700468 if(gp->status == Grecovery) {
469 // switched to scheduler to get stack unwound.
470 // don't go through the full scheduling logic.
471 Defer *d;
472
473 d = gp->defer;
474 gp->defer = d->link;
475
Russ Cox141a4a12011-01-14 14:05:20 -0500476 // unwind to the stack frame with d's arguments in it.
477 unwindstack(gp, d->argp);
Russ Cox72157c32010-04-08 13:24:53 -0700478
Russ Cox9b1507b2010-03-31 11:46:01 -0700479 // make the deferproc for this d return again,
480 // this time returning 1. function will jump to
481 // standard return epilogue.
482 // the -2*sizeof(uintptr) makes up for the
483 // two extra words that are on the stack at
484 // each call to deferproc.
485 // (the pc we're returning to does pop pop
486 // before it tests the return value.)
Russ Cox141a4a12011-01-14 14:05:20 -0500487 // on the arm there are 2 saved LRs mixed in too.
488 if(thechar == '5')
489 gp->sched.sp = (byte*)d->argp - 4*sizeof(uintptr);
490 else
491 gp->sched.sp = (byte*)d->argp - 2*sizeof(uintptr);
Russ Cox9b1507b2010-03-31 11:46:01 -0700492 gp->sched.pc = d->pc;
Russ Cox214a55b2010-04-21 16:27:41 -0700493 gp->status = Grunning;
Russ Cox68b42552010-11-04 14:00:19 -0400494 runtime·free(d);
495 runtime·gogo(&gp->sched, 1);
Russ Cox9b1507b2010-03-31 11:46:01 -0700496 }
Russ Coxb5dfac42011-02-23 15:51:20 -0500497
498 if(gp->status == Gstackalloc) {
499 // switched to scheduler stack to call stackalloc.
500 gp->param = runtime·stackalloc((uintptr)gp->param);
501 gp->status = Grunning;
502 runtime·gogo(&gp->sched, 1);
503 }
Russ Cox133a1582009-10-03 10:37:12 -0700504
Russ Cox68b42552010-11-04 14:00:19 -0400505 // Jumped here via runtime·gosave/gogo, so didn't
506 // execute lock(&runtime·sched) above.
507 runtime·lock(&runtime·sched);
Russ Cox72154b02008-09-26 14:10:26 -0700508
Russ Cox68b42552010-11-04 14:00:19 -0400509 if(runtime·sched.predawn)
510 runtime·throw("init sleeping");
Russ Cox96824002008-08-05 14:18:47 -0700511
Russ Cox133a1582009-10-03 10:37:12 -0700512 // Just finished running gp.
Russ Coxa61bb952008-09-24 14:13:07 -0700513 gp->m = nil;
Russ Cox68b42552010-11-04 14:00:19 -0400514 runtime·sched.mcpu--;
Russ Cox218c3932009-07-13 17:28:39 -0700515
Russ Cox68b42552010-11-04 14:00:19 -0400516 if(runtime·sched.mcpu < 0)
517 runtime·throw("runtime·sched.mcpu < 0 in scheduler");
Russ Coxd28acc42008-08-04 16:43:49 -0700518 switch(gp->status){
Russ Coxd28acc42008-08-04 16:43:49 -0700519 case Grunnable:
Russ Cox96824002008-08-05 14:18:47 -0700520 case Gdead:
Russ Coxb5dfac42011-02-23 15:51:20 -0500521 case Grecovery:
522 case Gstackalloc:
Russ Cox96824002008-08-05 14:18:47 -0700523 // Shouldn't have been running!
Russ Cox68b42552010-11-04 14:00:19 -0400524 runtime·throw("bad gp->status in sched");
Russ Cox96824002008-08-05 14:18:47 -0700525 case Grunning:
526 gp->status = Grunnable;
527 gput(gp);
528 break;
529 case Gmoribund:
530 gp->status = Gdead;
Russ Cox218c3932009-07-13 17:28:39 -0700531 if(gp->lockedm) {
532 gp->lockedm = nil;
533 m->lockedg = nil;
534 }
Russ Cox83727cc2010-03-29 21:48:22 -0700535 unwindstack(gp, nil);
Russ Cox2aea4a02009-08-26 15:26:09 -0700536 gfput(gp);
Russ Cox68b42552010-11-04 14:00:19 -0400537 if(--runtime·sched.gcount == 0)
538 runtime·exit(0);
Russ Coxd28acc42008-08-04 16:43:49 -0700539 break;
540 }
Russ Coxa61bb952008-09-24 14:13:07 -0700541 if(gp->readyonstop){
542 gp->readyonstop = 0;
543 readylocked(gp);
544 }
Russ Coxd28acc42008-08-04 16:43:49 -0700545 }
546
Russ Cox68b42552010-11-04 14:00:19 -0400547 // Find (or wait for) g to run. Unlocks runtime·sched.
Russ Cox96824002008-08-05 14:18:47 -0700548 gp = nextgandunlock();
Russ Coxa61bb952008-09-24 14:13:07 -0700549 gp->readyonstop = 0;
Russ Coxd28acc42008-08-04 16:43:49 -0700550 gp->status = Grunning;
Russ Cox4feda712008-08-02 22:34:04 -0700551 m->curg = gp;
Russ Coxa61bb952008-09-24 14:13:07 -0700552 gp->m = m;
Russ Cox68b42552010-11-04 14:00:19 -0400553 if(gp->sched.pc == (byte*)runtime·goexit) { // kickoff
554 runtime·gogocall(&gp->sched, (void(*)(void))gp->entry);
Ken Thompsonb33f5d52010-10-13 13:24:14 -0700555 }
Russ Cox68b42552010-11-04 14:00:19 -0400556 runtime·gogo(&gp->sched, 1);
Russ Cox4feda712008-08-02 22:34:04 -0700557}
558
Russ Cox96824002008-08-05 14:18:47 -0700559// Enter scheduler. If g->status is Grunning,
560// re-queues g and runs everyone else who is waiting
561// before running g again. If g->status is Gmoribund,
562// kills off g.
Ken Thompsonaf58f172008-07-14 14:34:27 -0700563void
Russ Cox68b42552010-11-04 14:00:19 -0400564runtime·gosched(void)
Ken Thompsonaf58f172008-07-14 14:34:27 -0700565{
Russ Cox71108812010-01-12 10:03:02 -0800566 if(m->locks != 0)
Russ Cox68b42552010-11-04 14:00:19 -0400567 runtime·throw("gosched holding locks");
Russ Cox74a9fc12010-01-06 19:24:11 -0800568 if(g == m->g0)
Russ Cox68b42552010-11-04 14:00:19 -0400569 runtime·throw("gosched of g0");
570 if(runtime·gosave(&g->sched) == 0)
571 runtime·gogo(&m->sched, 1);
Ken Thompsonaf58f172008-07-14 14:34:27 -0700572}
573
Russ Coxefc86a72008-11-25 16:48:10 -0800574// The goroutine g is about to enter a system call.
575// Record that it's not using the cpu anymore.
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700576// This is called only from the go syscall library and cgocall,
577// not from the low-level system calls used by the runtime.
Russ Cox68b42552010-11-04 14:00:19 -0400578// Entersyscall cannot split the stack: the runtime·gosave must
Russ Coxe2bde5c2010-08-12 23:26:54 -0700579// make g->sched refer to the caller's stack pointer.
580#pragma textflag 7
Russ Coxefc86a72008-11-25 16:48:10 -0800581void
Russ Cox68b42552010-11-04 14:00:19 -0400582runtime·entersyscall(void)
Russ Cox96824002008-08-05 14:18:47 -0700583{
Russ Cox68b42552010-11-04 14:00:19 -0400584 runtime·lock(&runtime·sched);
Ian Lance Taylore1b47152010-05-06 22:07:03 -0700585 // Leave SP around for gc and traceback.
586 // Do before notewakeup so that gc
587 // never sees Gsyscall with wrong stack.
Russ Cox68b42552010-11-04 14:00:19 -0400588 runtime·gosave(&g->sched);
589 if(runtime·sched.predawn) {
590 runtime·unlock(&runtime·sched);
Russ Cox052a66b2009-07-21 19:43:27 -0700591 return;
592 }
Russ Cox3f8aa662008-12-05 15:24:18 -0800593 g->status = Gsyscall;
Russ Cox68b42552010-11-04 14:00:19 -0400594 runtime·sched.mcpu--;
595 runtime·sched.msyscall++;
596 if(runtime·sched.gwait != 0)
Russ Coxefc86a72008-11-25 16:48:10 -0800597 matchmg();
Russ Cox68b42552010-11-04 14:00:19 -0400598 if(runtime·sched.waitstop && runtime·sched.mcpu <= runtime·sched.mcpumax) {
599 runtime·sched.waitstop = 0;
600 runtime·notewakeup(&runtime·sched.stopped);
Russ Cox53e69e12009-01-27 14:01:20 -0800601 }
Russ Cox68b42552010-11-04 14:00:19 -0400602 runtime·unlock(&runtime·sched);
Russ Coxefc86a72008-11-25 16:48:10 -0800603}
604
605// The goroutine g exited its system call.
606// Arrange for it to run on a cpu again.
607// This is called only from the go syscall library, not
608// from the low-level system calls used by the runtime.
609void
Russ Cox68b42552010-11-04 14:00:19 -0400610runtime·exitsyscall(void)
Russ Coxefc86a72008-11-25 16:48:10 -0800611{
Russ Cox68b42552010-11-04 14:00:19 -0400612 runtime·lock(&runtime·sched);
613 if(runtime·sched.predawn) {
614 runtime·unlock(&runtime·sched);
Russ Cox052a66b2009-07-21 19:43:27 -0700615 return;
616 }
Russ Cox68b42552010-11-04 14:00:19 -0400617 runtime·sched.msyscall--;
618 runtime·sched.mcpu++;
Russ Coxefc86a72008-11-25 16:48:10 -0800619 // Fast path - if there's room for this m, we're done.
Russ Cox68b42552010-11-04 14:00:19 -0400620 if(runtime·sched.mcpu <= runtime·sched.mcpumax) {
Russ Cox19c18352009-12-14 19:06:20 -0800621 g->status = Grunning;
Russ Cox68b42552010-11-04 14:00:19 -0400622 runtime·unlock(&runtime·sched);
Russ Coxefc86a72008-11-25 16:48:10 -0800623 return;
624 }
Russ Cox19c18352009-12-14 19:06:20 -0800625 // Tell scheduler to put g back on the run queue:
626 // mostly equivalent to g->status = Grunning,
627 // but keeps the garbage collector from thinking
628 // that g is running right now, which it's not.
629 g->readyonstop = 1;
Russ Cox68b42552010-11-04 14:00:19 -0400630 runtime·unlock(&runtime·sched);
Russ Coxefc86a72008-11-25 16:48:10 -0800631
632 // Slow path - all the cpus are taken.
633 // The scheduler will ready g and put this m to sleep.
Russ Cox218c3932009-07-13 17:28:39 -0700634 // When the scheduler takes g away from m,
Russ Cox68b42552010-11-04 14:00:19 -0400635 // it will undo the runtime·sched.mcpu++ above.
636 runtime·gosched();
Russ Cox96824002008-08-05 14:18:47 -0700637}
638
Ian Lance Taylor2d393032011-01-08 10:22:37 -0800639// Restore the position of m's scheduler stack if we unwind the stack
640// through a cgo callback.
641static void
642runtime·unwindcgocallback(void **spaddr, void *sp)
643{
644 *spaddr = sp;
645}
646
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700647// Start scheduling g1 again for a cgo callback.
648void
Russ Cox68b42552010-11-04 14:00:19 -0400649runtime·startcgocallback(G* g1)
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700650{
Ian Lance Taylor2d393032011-01-08 10:22:37 -0800651 Defer *d;
Ian Lance Taylor2d393032011-01-08 10:22:37 -0800652
Russ Cox68b42552010-11-04 14:00:19 -0400653 runtime·lock(&runtime·sched);
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700654 g1->status = Grunning;
Russ Cox68b42552010-11-04 14:00:19 -0400655 runtime·sched.msyscall--;
656 runtime·sched.mcpu++;
657 runtime·unlock(&runtime·sched);
Ian Lance Taylor2d393032011-01-08 10:22:37 -0800658
659 // Add an entry to the defer stack which restores the old
660 // position of m's scheduler stack. This is so that if the
661 // code we are calling panics, we won't lose the space on the
662 // scheduler stack. Note that we are locked to this m here.
663 d = runtime·malloc(sizeof(*d) + 2*sizeof(void*) - sizeof(d->args));
664 d->fn = (byte*)runtime·unwindcgocallback;
665 d->siz = 2 * sizeof(uintptr);
666 ((void**)d->args)[0] = &m->sched.sp;
667 ((void**)d->args)[1] = m->sched.sp;
668 d->link = g1->defer;
669 g1->defer = d;
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700670}
671
672// Stop scheduling g1 after a cgo callback.
673void
Russ Cox68b42552010-11-04 14:00:19 -0400674runtime·endcgocallback(G* g1)
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700675{
Ian Lance Taylor2d393032011-01-08 10:22:37 -0800676 Defer *d;
677
Russ Cox68b42552010-11-04 14:00:19 -0400678 runtime·lock(&runtime·sched);
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700679 g1->status = Gsyscall;
Russ Cox68b42552010-11-04 14:00:19 -0400680 runtime·sched.mcpu--;
681 runtime·sched.msyscall++;
682 runtime·unlock(&runtime·sched);
Ian Lance Taylor2d393032011-01-08 10:22:37 -0800683
684 // Remove the entry on the defer stack added by
685 // startcgocallback.
686 d = g1->defer;
687 if (d == nil || d->fn != (byte*)runtime·unwindcgocallback)
688 runtime·throw("bad defer entry in endcgocallback");
689 g1->defer = d->link;
690 runtime·free(d);
Ian Lance Taylor2e203862010-04-09 13:30:35 -0700691}
692
Ken Thompsonaf58f172008-07-14 14:34:27 -0700693void
Russ Cox68b42552010-11-04 14:00:19 -0400694runtime·oldstack(void)
Ken Thompsonaf58f172008-07-14 14:34:27 -0700695{
Russ Cox7343e032009-06-17 15:12:16 -0700696 Stktop *top, old;
Russ Cox141a4a12011-01-14 14:05:20 -0500697 uint32 argsize;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700698 byte *sp;
Russ Cox7343e032009-06-17 15:12:16 -0700699 G *g1;
Russ Cox36c5c5b2010-03-04 15:34:25 -0800700 static int32 goid;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700701
Russ Cox7343e032009-06-17 15:12:16 -0700702//printf("oldstack m->cret=%p\n", m->cret);
Ken Thompsonaf58f172008-07-14 14:34:27 -0700703
Russ Cox7343e032009-06-17 15:12:16 -0700704 g1 = m->curg;
705 top = (Stktop*)g1->stackbase;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700706 sp = (byte*)top;
Russ Cox7343e032009-06-17 15:12:16 -0700707 old = *top;
Russ Cox141a4a12011-01-14 14:05:20 -0500708 argsize = old.argsize;
709 if(argsize > 0) {
710 sp -= argsize;
711 runtime·mcpy(top->argp, sp, argsize);
Ken Thompsonaf58f172008-07-14 14:34:27 -0700712 }
Russ Cox36c5c5b2010-03-04 15:34:25 -0800713 goid = old.gobuf.g->goid; // fault if g is bad, before gogo
Ken Thompsonaf58f172008-07-14 14:34:27 -0700714
Russ Coxafc69282011-01-25 16:35:36 -0500715 if(old.free != 0)
Russ Coxd9fd1142011-02-22 17:40:40 -0500716 runtime·stackfree(g1->stackguard - StackGuard - StackSystem, old.free);
Russ Cox7343e032009-06-17 15:12:16 -0700717 g1->stackbase = old.stackbase;
718 g1->stackguard = old.stackguard;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700719
Russ Cox68b42552010-11-04 14:00:19 -0400720 runtime·gogo(&old.gobuf, m->cret);
Russ Cox79e1db22008-12-04 08:30:54 -0800721}
722
723void
Russ Cox68b42552010-11-04 14:00:19 -0400724runtime·newstack(void)
Ken Thompsonaf58f172008-07-14 14:34:27 -0700725{
Russ Cox141a4a12011-01-14 14:05:20 -0500726 int32 framesize, argsize;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700727 Stktop *top;
728 byte *stk, *sp;
Russ Cox7343e032009-06-17 15:12:16 -0700729 G *g1;
730 Gobuf label;
Russ Coxafc69282011-01-25 16:35:36 -0500731 bool reflectcall;
732 uintptr free;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700733
Russ Cox141a4a12011-01-14 14:05:20 -0500734 framesize = m->moreframesize;
735 argsize = m->moreargsize;
Russ Cox83727cc2010-03-29 21:48:22 -0700736 g1 = m->curg;
Russ Cox6c196012010-04-05 12:51:09 -0700737
Russ Cox1fa41732011-02-01 18:34:41 -0500738 if(m->morebuf.sp < g1->stackguard - StackGuard) {
739 runtime·printf("runtime: split stack overflow: %p < %p\n", m->morebuf.sp, g1->stackguard - StackGuard);
740 runtime·throw("runtime: split stack overflow");
741 }
Russ Cox6c196012010-04-05 12:51:09 -0700742
Russ Cox141a4a12011-01-14 14:05:20 -0500743 reflectcall = framesize==1;
744 if(reflectcall)
745 framesize = 0;
746
747 if(reflectcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > g1->stackguard) {
748 // special case: called from reflect.call (framesize==1)
Russ Cox83727cc2010-03-29 21:48:22 -0700749 // to call code with an arbitrary argument size,
750 // and we have enough space on the current stack.
751 // the new Stktop* is necessary to unwind, but
752 // we don't need to create a new segment.
753 top = (Stktop*)(m->morebuf.sp - sizeof(*top));
Russ Coxd9fd1142011-02-22 17:40:40 -0500754 stk = g1->stackguard - StackGuard - StackSystem;
Russ Coxafc69282011-01-25 16:35:36 -0500755 free = 0;
Russ Cox83727cc2010-03-29 21:48:22 -0700756 } else {
757 // allocate new segment.
Russ Cox141a4a12011-01-14 14:05:20 -0500758 framesize += argsize;
Hector Chuaae5f912011-01-19 15:10:15 -0500759 framesize += StackExtra; // room for more functions, Stktop.
Russ Coxd9fd1142011-02-22 17:40:40 -0500760 if(framesize < StackMin)
761 framesize = StackMin;
762 framesize += StackSystem;
Russ Cox141a4a12011-01-14 14:05:20 -0500763 stk = runtime·stackalloc(framesize);
764 top = (Stktop*)(stk+framesize-sizeof(*top));
Russ Coxafc69282011-01-25 16:35:36 -0500765 free = framesize;
Russ Cox83727cc2010-03-29 21:48:22 -0700766 }
Russ Coxf25586a2010-02-10 00:00:12 -0800767
Russ Coxb287d7c2011-02-02 16:44:20 -0500768//runtime·printf("newstack framesize=%d argsize=%d morepc=%p moreargp=%p gobuf=%p, %p top=%p old=%p\n",
769//framesize, argsize, m->morepc, m->moreargp, m->morebuf.pc, m->morebuf.sp, top, g1->stackbase);
Russ Cox7343e032009-06-17 15:12:16 -0700770
Russ Cox7343e032009-06-17 15:12:16 -0700771 top->stackbase = g1->stackbase;
772 top->stackguard = g1->stackguard;
773 top->gobuf = m->morebuf;
Russ Cox141a4a12011-01-14 14:05:20 -0500774 top->argp = m->moreargp;
775 top->argsize = argsize;
Russ Cox83727cc2010-03-29 21:48:22 -0700776 top->free = free;
Russ Coxb287d7c2011-02-02 16:44:20 -0500777
Russ Cox9b1507b2010-03-31 11:46:01 -0700778 // copy flag from panic
779 top->panic = g1->ispanic;
780 g1->ispanic = false;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700781
Russ Cox7343e032009-06-17 15:12:16 -0700782 g1->stackbase = (byte*)top;
Russ Coxd9fd1142011-02-22 17:40:40 -0500783 g1->stackguard = stk + StackGuard + StackSystem;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700784
785 sp = (byte*)top;
Russ Cox141a4a12011-01-14 14:05:20 -0500786 if(argsize > 0) {
787 sp -= argsize;
788 runtime·mcpy(sp, m->moreargp, argsize);
789 }
790 if(thechar == '5') {
791 // caller would have saved its LR below args.
792 sp -= sizeof(void*);
793 *(void**)sp = nil;
Ken Thompsonaf58f172008-07-14 14:34:27 -0700794 }
795
Russ Cox7343e032009-06-17 15:12:16 -0700796 // Continue as if lessstack had just called m->morepc
797 // (the PC that decided to grow the stack).
798 label.sp = sp;
Russ Cox68b42552010-11-04 14:00:19 -0400799 label.pc = (byte*)runtime·lessstack;
Russ Cox7343e032009-06-17 15:12:16 -0700800 label.g = m->curg;
Russ Cox68b42552010-11-04 14:00:19 -0400801 runtime·gogocall(&label, m->morepc);
Ken Thompsonaf58f172008-07-14 14:34:27 -0700802
803 *(int32*)345 = 123; // never return
804}
805
Russ Cox95100342009-04-01 00:26:00 -0700806G*
Russ Cox68b42552010-11-04 14:00:19 -0400807runtime·malg(int32 stacksize)
Russ Cox95100342009-04-01 00:26:00 -0700808{
Russ Coxb5dfac42011-02-23 15:51:20 -0500809 G *newg;
Russ Cox95100342009-04-01 00:26:00 -0700810 byte *stk;
Russ Coxb5dfac42011-02-23 15:51:20 -0500811 int32 oldstatus;
Russ Cox95100342009-04-01 00:26:00 -0700812
Russ Coxb5dfac42011-02-23 15:51:20 -0500813 newg = runtime·malloc(sizeof(G));
Russ Coxf25586a2010-02-10 00:00:12 -0800814 if(stacksize >= 0) {
Russ Coxb5dfac42011-02-23 15:51:20 -0500815 if(g == m->g0) {
816 // running on scheduler stack already.
817 stk = runtime·stackalloc(StackSystem + stacksize);
818 } else {
819 // have to call stackalloc on scheduler stack.
820 oldstatus = g->status;
821 g->param = (void*)(StackSystem + stacksize);
822 g->status = Gstackalloc;
823 // next two lines are runtime·gosched without the check
824 // of m->locks. we're almost certainly holding a lock,
825 // but this is not a real rescheduling so it's okay.
826 if(runtime·gosave(&g->sched) == 0)
827 runtime·gogo(&m->sched, 1);
828 stk = g->param;
829 g->param = nil;
830 g->status = oldstatus;
831 }
832 newg->stack0 = stk;
833 newg->stackguard = stk + StackSystem + StackGuard;
834 newg->stackbase = stk + StackSystem + stacksize - sizeof(Stktop);
835 runtime·memclr(newg->stackbase, sizeof(Stktop));
Russ Coxf25586a2010-02-10 00:00:12 -0800836 }
Russ Coxb5dfac42011-02-23 15:51:20 -0500837 return newg;
Russ Cox95100342009-04-01 00:26:00 -0700838}
839
840/*
841 * Newproc and deferproc need to be textflag 7
842 * (no possible stack split when nearing overflow)
843 * because they assume that the arguments to fn
844 * are available sequentially beginning at &arg0.
845 * If a stack split happened, only the one word
846 * arg0 would be copied. It's okay if any functions
847 * they call split the stack below the newproc frame.
848 */
849#pragma textflag 7
850void
Russ Cox68b42552010-11-04 14:00:19 -0400851runtime·newproc(int32 siz, byte* fn, ...)
Russ Cox95100342009-04-01 00:26:00 -0700852{
Russ Cox141a4a12011-01-14 14:05:20 -0500853 byte *argp;
854
855 if(thechar == '5')
856 argp = (byte*)(&fn+2); // skip caller's saved LR
857 else
858 argp = (byte*)(&fn+1);
859 runtime·newproc1(fn, argp, siz, 0);
Russ Cox62d627f2010-02-08 21:41:54 -0800860}
861
Russ Cox4e28cfe2010-03-26 14:15:30 -0700862G*
Russ Cox68b42552010-11-04 14:00:19 -0400863runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
Russ Cox62d627f2010-02-08 21:41:54 -0800864{
Russ Coxf25586a2010-02-10 00:00:12 -0800865 byte *sp;
Russ Cox95100342009-04-01 00:26:00 -0700866 G *newg;
Russ Cox62d627f2010-02-08 21:41:54 -0800867 int32 siz;
Russ Cox95100342009-04-01 00:26:00 -0700868
Russ Cox62d627f2010-02-08 21:41:54 -0800869//printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret);
870 siz = narg + nret;
Russ Cox95100342009-04-01 00:26:00 -0700871 siz = (siz+7) & ~7;
872 if(siz > 1024)
Russ Cox68b42552010-11-04 14:00:19 -0400873 runtime·throw("runtime.newproc: too many args");
Russ Cox95100342009-04-01 00:26:00 -0700874
Russ Cox68b42552010-11-04 14:00:19 -0400875 runtime·lock(&runtime·sched);
Russ Cox95100342009-04-01 00:26:00 -0700876
877 if((newg = gfget()) != nil){
878 newg->status = Gwaiting;
Russ Coxd9fd1142011-02-22 17:40:40 -0500879 if(newg->stackguard - StackGuard - StackSystem != newg->stack0)
Russ Cox68b42552010-11-04 14:00:19 -0400880 runtime·throw("invalid stack in newg");
Russ Cox95100342009-04-01 00:26:00 -0700881 } else {
Russ Coxd9fd1142011-02-22 17:40:40 -0500882 newg = runtime·malg(StackMin);
Russ Cox95100342009-04-01 00:26:00 -0700883 newg->status = Gwaiting;
Russ Cox68b42552010-11-04 14:00:19 -0400884 newg->alllink = runtime·allg;
885 runtime·allg = newg;
Russ Cox95100342009-04-01 00:26:00 -0700886 }
Russ Cox95100342009-04-01 00:26:00 -0700887
Russ Coxf25586a2010-02-10 00:00:12 -0800888 sp = newg->stackbase;
Russ Cox95100342009-04-01 00:26:00 -0700889 sp -= siz;
Russ Cox68b42552010-11-04 14:00:19 -0400890 runtime·mcpy(sp, argp, narg);
Russ Cox141a4a12011-01-14 14:05:20 -0500891 if(thechar == '5') {
892 // caller's LR
893 sp -= sizeof(void*);
894 *(void**)sp = nil;
895 }
Russ Cox95100342009-04-01 00:26:00 -0700896
Russ Cox7343e032009-06-17 15:12:16 -0700897 newg->sched.sp = sp;
Russ Cox68b42552010-11-04 14:00:19 -0400898 newg->sched.pc = (byte*)runtime·goexit;
Russ Cox7343e032009-06-17 15:12:16 -0700899 newg->sched.g = newg;
900 newg->entry = fn;
Russ Cox95100342009-04-01 00:26:00 -0700901
Russ Cox68b42552010-11-04 14:00:19 -0400902 runtime·sched.gcount++;
903 runtime·goidgen++;
904 newg->goid = runtime·goidgen;
Russ Cox95100342009-04-01 00:26:00 -0700905
Russ Coxfe8ff952009-08-31 18:10:11 -0700906 newprocreadylocked(newg);
Russ Cox68b42552010-11-04 14:00:19 -0400907 runtime·unlock(&runtime·sched);
Russ Cox95100342009-04-01 00:26:00 -0700908
Russ Cox4e28cfe2010-03-26 14:15:30 -0700909 return newg;
Russ Cox95100342009-04-01 00:26:00 -0700910//printf(" goid=%d\n", newg->goid);
911}
912
913#pragma textflag 7
Russ Cox9b1507b2010-03-31 11:46:01 -0700914uintptr
Russ Cox68b42552010-11-04 14:00:19 -0400915runtime·deferproc(int32 siz, byte* fn, ...)
Russ Cox95100342009-04-01 00:26:00 -0700916{
917 Defer *d;
918
Russ Cox68b42552010-11-04 14:00:19 -0400919 d = runtime·malloc(sizeof(*d) + siz - sizeof(d->args));
Russ Cox95100342009-04-01 00:26:00 -0700920 d->fn = fn;
Russ Cox95100342009-04-01 00:26:00 -0700921 d->siz = siz;
Russ Cox68b42552010-11-04 14:00:19 -0400922 d->pc = runtime·getcallerpc(&siz);
Russ Cox141a4a12011-01-14 14:05:20 -0500923 if(thechar == '5')
924 d->argp = (byte*)(&fn+2); // skip caller's saved link register
925 else
926 d->argp = (byte*)(&fn+1);
927 runtime·mcpy(d->args, d->argp, d->siz);
Russ Cox95100342009-04-01 00:26:00 -0700928
929 d->link = g->defer;
930 g->defer = d;
Russ Cox9b1507b2010-03-31 11:46:01 -0700931
932 // deferproc returns 0 normally.
933 // a deferred func that stops a panic
934 // makes the deferproc return 1.
935 // the code the compiler generates always
936 // checks the return value and jumps to the
937 // end of the function if deferproc returns != 0.
938 return 0;
Russ Cox95100342009-04-01 00:26:00 -0700939}
940
941#pragma textflag 7
942void
Russ Cox68b42552010-11-04 14:00:19 -0400943runtime·deferreturn(uintptr arg0)
Russ Cox95100342009-04-01 00:26:00 -0700944{
Russ Cox95100342009-04-01 00:26:00 -0700945 Defer *d;
Russ Cox141a4a12011-01-14 14:05:20 -0500946 byte *argp, *fn;
Russ Cox95100342009-04-01 00:26:00 -0700947
948 d = g->defer;
949 if(d == nil)
950 return;
Russ Cox141a4a12011-01-14 14:05:20 -0500951 argp = (byte*)&arg0;
952 if(d->argp != argp)
Russ Cox95100342009-04-01 00:26:00 -0700953 return;
Russ Cox141a4a12011-01-14 14:05:20 -0500954 runtime·mcpy(argp, d->args, d->siz);
Russ Cox95100342009-04-01 00:26:00 -0700955 g->defer = d->link;
Russ Coxaa3222d82009-06-02 23:02:12 -0700956 fn = d->fn;
Russ Cox68b42552010-11-04 14:00:19 -0400957 runtime·free(d);
Russ Cox141a4a12011-01-14 14:05:20 -0500958 runtime·jmpdefer(fn, argp);
Russ Cox83727cc2010-03-29 21:48:22 -0700959}
960
961static void
962rundefer(void)
963{
964 Defer *d;
965
966 while((d = g->defer) != nil) {
967 g->defer = d->link;
968 reflect·call(d->fn, d->args, d->siz);
Russ Cox68b42552010-11-04 14:00:19 -0400969 runtime·free(d);
Russ Cox83727cc2010-03-29 21:48:22 -0700970 }
971}
972
973// Free stack frames until we hit the last one
Russ Cox141a4a12011-01-14 14:05:20 -0500974// or until we find the one that contains the argp.
Russ Cox83727cc2010-03-29 21:48:22 -0700975static void
976unwindstack(G *gp, byte *sp)
977{
978 Stktop *top;
979 byte *stk;
980
981 // Must be called from a different goroutine, usually m->g0.
982 if(g == gp)
Russ Cox68b42552010-11-04 14:00:19 -0400983 runtime·throw("unwindstack on self");
Russ Cox83727cc2010-03-29 21:48:22 -0700984
985 while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
986 stk = gp->stackguard - StackGuard;
987 if(stk <= sp && sp < gp->stackbase)
988 break;
989 gp->stackbase = top->stackbase;
990 gp->stackguard = top->stackguard;
Russ Coxafc69282011-01-25 16:35:36 -0500991 if(top->free != 0)
992 runtime·stackfree(stk, top->free);
Russ Cox83727cc2010-03-29 21:48:22 -0700993 }
Russ Cox72157c32010-04-08 13:24:53 -0700994
995 if(sp != nil && (sp < gp->stackguard - StackGuard || gp->stackbase < sp)) {
Russ Cox68b42552010-11-04 14:00:19 -0400996 runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase);
997 runtime·throw("bad unwindstack");
Russ Cox72157c32010-04-08 13:24:53 -0700998 }
Russ Cox83727cc2010-03-29 21:48:22 -0700999}
1000
Russ Cox9b1507b2010-03-31 11:46:01 -07001001static void
1002printpanics(Panic *p)
1003{
1004 if(p->link) {
1005 printpanics(p->link);
Russ Cox68b42552010-11-04 14:00:19 -04001006 runtime·printf("\t");
Russ Cox9b1507b2010-03-31 11:46:01 -07001007 }
Russ Cox68b42552010-11-04 14:00:19 -04001008 runtime·printf("panic: ");
1009 runtime·printany(p->arg);
Russ Cox9b1507b2010-03-31 11:46:01 -07001010 if(p->recovered)
Russ Cox68b42552010-11-04 14:00:19 -04001011 runtime·printf(" [recovered]");
1012 runtime·printf("\n");
Russ Cox9b1507b2010-03-31 11:46:01 -07001013}
1014
1015void
Russ Cox68b42552010-11-04 14:00:19 -04001016runtime·panic(Eface e)
Russ Cox9b1507b2010-03-31 11:46:01 -07001017{
1018 Defer *d;
1019 Panic *p;
1020
Russ Cox68b42552010-11-04 14:00:19 -04001021 p = runtime·mal(sizeof *p);
Russ Cox9b1507b2010-03-31 11:46:01 -07001022 p->arg = e;
1023 p->link = g->panic;
1024 p->stackbase = g->stackbase;
1025 g->panic = p;
1026
1027 for(;;) {
1028 d = g->defer;
1029 if(d == nil)
1030 break;
1031 // take defer off list in case of recursive panic
1032 g->defer = d->link;
1033 g->ispanic = true; // rock for newstack, where reflect.call ends up
Russ Cox141a4a12011-01-14 14:05:20 -05001034 reflect·call(d->fn, d->args, d->siz);
Russ Cox9b1507b2010-03-31 11:46:01 -07001035 if(p->recovered) {
1036 g->panic = p->link;
Russ Cox12307002011-01-18 14:15:11 -05001037 if(g->panic == nil) // must be done with signal
1038 g->sig = 0;
Russ Cox68b42552010-11-04 14:00:19 -04001039 runtime·free(p);
Russ Cox9b1507b2010-03-31 11:46:01 -07001040 // put recovering defer back on list
1041 // for scheduler to find.
1042 d->link = g->defer;
1043 g->defer = d;
1044 g->status = Grecovery;
Russ Cox68b42552010-11-04 14:00:19 -04001045 runtime·gosched();
1046 runtime·throw("recovery failed"); // gosched should not return
Russ Cox9b1507b2010-03-31 11:46:01 -07001047 }
Russ Cox68b42552010-11-04 14:00:19 -04001048 runtime·free(d);
Russ Cox9b1507b2010-03-31 11:46:01 -07001049 }
1050
1051 // ran out of deferred calls - old-school panic now
Russ Cox67793502011-02-16 13:21:13 -05001052 runtime·startpanic();
Russ Cox9b1507b2010-03-31 11:46:01 -07001053 printpanics(g->panic);
Russ Cox68b42552010-11-04 14:00:19 -04001054 runtime·dopanic(0);
Russ Cox9b1507b2010-03-31 11:46:01 -07001055}
1056
1057#pragma textflag 7 /* no split, or else g->stackguard is not the stack for fp */
1058void
Russ Cox141a4a12011-01-14 14:05:20 -05001059runtime·recover(byte *argp, Eface ret)
Russ Cox9b1507b2010-03-31 11:46:01 -07001060{
1061 Stktop *top, *oldtop;
1062 Panic *p;
1063
1064 // Must be a panic going on.
1065 if((p = g->panic) == nil || p->recovered)
1066 goto nomatch;
1067
1068 // Frame must be at the top of the stack segment,
1069 // because each deferred call starts a new stack
1070 // segment as a side effect of using reflect.call.
1071 // (There has to be some way to remember the
1072 // variable argument frame size, and the segment
1073 // code already takes care of that for us, so we
1074 // reuse it.)
1075 //
1076 // As usual closures complicate things: the fp that
1077 // the closure implementation function claims to have
1078 // is where the explicit arguments start, after the
1079 // implicit pointer arguments and PC slot.
1080 // If we're on the first new segment for a closure,
1081 // then fp == top - top->args is correct, but if
1082 // the closure has its own big argument frame and
1083 // allocated a second segment (see below),
1084 // the fp is slightly above top - top->args.
1085 // That condition can't happen normally though
Russ Cox141a4a12011-01-14 14:05:20 -05001086 // (stack pointers go down, not up), so we can accept
Russ Cox9b1507b2010-03-31 11:46:01 -07001087 // any fp between top and top - top->args as
1088 // indicating the top of the segment.
1089 top = (Stktop*)g->stackbase;
Russ Cox141a4a12011-01-14 14:05:20 -05001090 if(argp < (byte*)top - top->argsize || (byte*)top < argp)
Russ Cox9b1507b2010-03-31 11:46:01 -07001091 goto nomatch;
1092
1093 // The deferred call makes a new segment big enough
1094 // for the argument frame but not necessarily big
1095 // enough for the function's local frame (size unknown
1096 // at the time of the call), so the function might have
1097 // made its own segment immediately. If that's the
1098 // case, back top up to the older one, the one that
1099 // reflect.call would have made for the panic.
1100 //
1101 // The fp comparison here checks that the argument
1102 // frame that was copied during the split (the top->args
1103 // bytes above top->fp) abuts the old top of stack.
1104 // This is a correct test for both closure and non-closure code.
1105 oldtop = (Stktop*)top->stackbase;
Russ Cox141a4a12011-01-14 14:05:20 -05001106 if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize)
Russ Cox9b1507b2010-03-31 11:46:01 -07001107 top = oldtop;
1108
1109 // Now we have the segment that was created to
1110 // run this call. It must have been marked as a panic segment.
1111 if(!top->panic)
1112 goto nomatch;
1113
1114 // Okay, this is the top frame of a deferred call
1115 // in response to a panic. It can see the panic argument.
1116 p->recovered = 1;
1117 ret = p->arg;
1118 FLUSH(&ret);
1119 return;
1120
1121nomatch:
1122 ret.type = nil;
1123 ret.data = nil;
1124 FLUSH(&ret);
1125}
1126
1127
Russ Cox83727cc2010-03-29 21:48:22 -07001128// Put on gfree list. Sched must be locked.
1129static void
1130gfput(G *g)
1131{
Russ Coxd9fd1142011-02-22 17:40:40 -05001132 if(g->stackguard - StackGuard - StackSystem != g->stack0)
Russ Cox68b42552010-11-04 14:00:19 -04001133 runtime·throw("invalid stack in gfput");
1134 g->schedlink = runtime·sched.gfree;
1135 runtime·sched.gfree = g;
Russ Cox83727cc2010-03-29 21:48:22 -07001136}
1137
1138// Get from gfree list. Sched must be locked.
1139static G*
1140gfget(void)
1141{
1142 G *g;
1143
Russ Cox68b42552010-11-04 14:00:19 -04001144 g = runtime·sched.gfree;
Russ Cox83727cc2010-03-29 21:48:22 -07001145 if(g)
Russ Cox68b42552010-11-04 14:00:19 -04001146 runtime·sched.gfree = g->schedlink;
Russ Cox83727cc2010-03-29 21:48:22 -07001147 return g;
1148}
Russ Cox79e1db22008-12-04 08:30:54 -08001149
Russ Cox918afd942009-05-08 15:21:41 -07001150void
Russ Cox68b42552010-11-04 14:00:19 -04001151runtime·Breakpoint(void)
Russ Cox918afd942009-05-08 15:21:41 -07001152{
Russ Cox68b42552010-11-04 14:00:19 -04001153 runtime·breakpoint();
Russ Cox918afd942009-05-08 15:21:41 -07001154}
1155
1156void
Russ Cox68b42552010-11-04 14:00:19 -04001157runtime·Goexit(void)
Russ Cox918afd942009-05-08 15:21:41 -07001158{
Russ Cox83727cc2010-03-29 21:48:22 -07001159 rundefer();
Russ Cox68b42552010-11-04 14:00:19 -04001160 runtime·goexit();
Russ Cox918afd942009-05-08 15:21:41 -07001161}
1162
1163void
Russ Cox68b42552010-11-04 14:00:19 -04001164runtime·Gosched(void)
Russ Cox918afd942009-05-08 15:21:41 -07001165{
Russ Cox68b42552010-11-04 14:00:19 -04001166 runtime·gosched();
Russ Cox918afd942009-05-08 15:21:41 -07001167}
1168
Russ Cox218c3932009-07-13 17:28:39 -07001169void
Russ Cox68b42552010-11-04 14:00:19 -04001170runtime·LockOSThread(void)
Russ Cox218c3932009-07-13 17:28:39 -07001171{
Russ Cox68b42552010-11-04 14:00:19 -04001172 if(runtime·sched.predawn)
1173 runtime·throw("cannot wire during init");
Russ Cox218c3932009-07-13 17:28:39 -07001174 m->lockedg = g;
1175 g->lockedm = m;
1176}
1177
Rob Pike79554902009-08-06 13:07:05 -07001178// delete when scheduler is stronger
Rob Pikeeb48bfb2010-05-06 11:50:47 -07001179int32
Russ Cox68b42552010-11-04 14:00:19 -04001180runtime·gomaxprocsfunc(int32 n)
Rob Pike79554902009-08-06 13:07:05 -07001181{
Rob Pikeeb48bfb2010-05-06 11:50:47 -07001182 int32 ret;
Rob Pike79554902009-08-06 13:07:05 -07001183
Russ Cox68b42552010-11-04 14:00:19 -04001184 runtime·lock(&runtime·sched);
Russ Cox67793502011-02-16 13:21:13 -05001185 ret = runtime·gomaxprocs;
Rob Pikeeb48bfb2010-05-06 11:50:47 -07001186 if (n <= 0)
1187 n = ret;
Russ Cox67793502011-02-16 13:21:13 -05001188 runtime·gomaxprocs = n;
Russ Cox68b42552010-11-04 14:00:19 -04001189 runtime·sched.mcpumax = n;
Russ Cox88ce9ce2010-04-06 13:48:31 -07001190 // handle fewer procs?
Russ Cox68b42552010-11-04 14:00:19 -04001191 if(runtime·sched.mcpu > runtime·sched.mcpumax) {
1192 runtime·unlock(&runtime·sched);
Russ Cox88ce9ce2010-04-06 13:48:31 -07001193 // just give up the cpu.
1194 // we'll only get rescheduled once the
1195 // number has come down.
Russ Cox68b42552010-11-04 14:00:19 -04001196 runtime·gosched();
Rob Pikeeb48bfb2010-05-06 11:50:47 -07001197 return ret;
Rob Pike79554902009-08-06 13:07:05 -07001198 }
1199 // handle more procs
1200 matchmg();
Russ Cox68b42552010-11-04 14:00:19 -04001201 runtime·unlock(&runtime·sched);
Rob Pikeeb48bfb2010-05-06 11:50:47 -07001202 return ret;
Rob Pike79554902009-08-06 13:07:05 -07001203}
1204
Russ Cox218c3932009-07-13 17:28:39 -07001205void
Russ Cox68b42552010-11-04 14:00:19 -04001206runtime·UnlockOSThread(void)
Russ Cox218c3932009-07-13 17:28:39 -07001207{
1208 m->lockedg = nil;
1209 g->lockedm = nil;
1210}
1211
1212// for testing of wire, unwire
1213void
Russ Cox68b42552010-11-04 14:00:19 -04001214runtime·mid(uint32 ret)
Russ Cox218c3932009-07-13 17:28:39 -07001215{
1216 ret = m->id;
1217 FLUSH(&ret);
1218}
Keith Rarick51a21832010-12-07 18:06:31 -05001219
1220void
1221runtime·Goroutines(int32 ret)
1222{
1223 ret = runtime·sched.gcount;
1224 FLUSH(&ret);
1225}
Russ Cox4608feb2011-01-28 15:03:26 -05001226
1227int32
1228runtime·mcount(void)
1229{
1230 return runtime·sched.mcount;
1231}