*pres = false;
return;
}
-
+
sg = allocsg(c);
g->param = nil;
g->status = Gwaiting;
Lock;
G *gfree; // available gs (status == Gdead)
-
+
G *ghead; // gs waiting to run
G *gtail;
int32 gwait; // number of gs waiting to run
int32 gcount; // number of gs that are alive
-
+
M *mhead; // ms waiting for work
int32 mwait; // number of ms waiting for work
int32 mcount; // number of ms that are alive
int32 mmax; // max number of ms allowed
-
+
int32 predawn; // running initialization, don't run new gs.
};
{
int32 n;
byte *p;
-
+
sched.mmax = 1;
p = getenv("gomaxprocs");
if(p != nil && (n = atoi(p)) != 0)
m0init(void)
{
int32 i;
-
+
// Let's go.
sched.predawn = 0;
sched.gcount++;
goidgen++;
newg->goid = goidgen;
-
+
readylocked(newg);
unlock(&sched);
gget(void)
{
G *g;
-
+
g = sched.ghead;
if(g){
sched.ghead = g->schedlink;
mget(void)
{
M *m;
-
+
m = sched.mhead;
if(m){
sched.mhead = m->schedlink;
gfget(void)
{
G *g;
-
+
g = sched.gfree;
if(g)
sched.gfree = g->schedlink;
// have queued itself on a channel but not yet gotten
// a chance to call sys·gosched and actually go to sleep).
notesleep(&g->stopped);
-
+
lock(&sched);
readylocked(g);
unlock(&sched);
m->nextg = g;
notewakeup(&m->havenextg);
}
-
+
// Else put g on queue, kicking off new m if needed.
else{
gput(g);
m->nextg = nil;
noteclear(&m->havenextg);
unlock(&sched);
-
+
notesleep(&m->havenextg);
if((gp = m->nextg) == nil)
throw("bad m->nextg in nextgoroutine");
// Find (or wait for) g to run. Unlocks sched.
gp = nextgandunlock();
-
+
noteclear(&gp->stopped);
gp->status = Grunning;
m->curg = gp;
M *m;
G *g;
byte *stk, *stktop;
-
+
sched.mcount++;
if(debug){
sys·printint(sched.mcount);
prints(" threads\n");
}
-
+
// Allocate m, g, stack in one chunk.
// 1024 and 104 are the magic constants
// use in rt0_amd64.s when setting up g0.
g = (G*)(m+1);
stk = (byte*)g + 104;
stktop = stk + 1024;
-
+
m->g0 = g;
g->stackguard = stk;
g->stackbase = stktop;
m->curg->stackguard = stk + 160;
sp = (byte*)top;
-
+
if(siz2 > 0) {
siz2 = (siz2+7) & ~7;
sp -= siz2;
CALL args(SB)
CALL schedinit(SB)
CALL main·init_function(SB) // initialization
-
+
// create a new goroutine to start program
PUSHQ $main·main(SB) // entry
prints("\nFaulting address: 0x"); sys·printpointer(info->si_addr);
prints("\npc: 0x"); sys·printpointer((void *)ss->__rip);
prints("\n\n");
-
+
traceback((void *)ss->__rip, (void *)ss->__rsp, (void*)ss->__r15);
tracebackothers((void*)ss->__r15);
print_thread_state(ss);
-
+
sys·exit(2);
}
// Futexsleep is allowed to wake up spuriously.
enum
-{
+{
FUTEX_WAIT = 0,
FUTEX_WAKE = 1,
-
+
EINTR = 4,
EAGAIN = 11,
};
futexsleep(uint32 *addr, uint32 val)
{
int64 ret;
-
+
ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
if(ret >= 0 || ret == -EAGAIN || ret == -EINTR)
return;
futexwakeup(uint32 *addr)
{
int64 ret;
-
+
ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
if(ret >= 0)
return;
// I don't know that futex wakeup can return
- // EAGAIN or EINTR, but if it does, it would be
+ // EAGAIN or EINTR, but if it does, it would be
// safe to loop and call futex again.
prints("futexwakeup addr=");
}
goto again;
}
-
+
// Lock was held; try to add ourselves to the waiter count.
if(!cas(&l->key, v, v+2))
goto again;
-
+
// We're accounted for, now sleep in the kernel.
//
// We avoid the obvious lock/unlock race because
// and in fact there is a futex variant that could
// accomodate that check, but let's not get carried away.)
futexsleep(&l->key, v+2);
-
+
// We're awake: remove ourselves from the count.
for(;;){
v = l->key;
if(cas(&l->key, v, v-2))
break;
}
-
+
// Try for the lock again.
goto again;
}
{
int64 ret;
int32 flags;
-
+
flags = CLONE_PARENT /* getppid doesn't change in child */
| CLONE_VM /* share memory */
| CLONE_FS /* share cwd, etc */
Bit2 = 5,
Bit3 = 4,
Bit4 = 3,
- Bit5 = 2,
+ Bit5 = 2,
T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
Runeself = 0x80,
Bad = Runeerror,
-
+
Runemax = 0x10FFFF, /* maximum rune value */
};
/*
* Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
- * This is a slower but "safe" version of the old chartorune
+ * This is a slower but "safe" version of the old chartorune
* that works on strings that are not necessarily null-terminated.
- *
+ *
* If you know for sure that your string is null-terminated,
* chartorune will be a bit faster.
*
{
int32 i, j, len;
byte *v, *bs;
-
+
bs = (byte*)s;
len = findnull(s);
for(i=0; i<envc; i++){
atoi(byte *p)
{
int32 n;
-
+
n = 0;
while('0' <= *p && *p <= '9')
n = n*10 + *p++ - '0';
throw("cas1");
if(z != 2)
throw("cas2");
-
+
z = 4;
if(cas(&z, 5, 6))
throw("cas3");
/*
* sleep and wakeup on one-time events.
- * before any calls to notesleep or notewakeup,
+ * before any calls to notesleep or notewakeup,
* must call noteclear to initialize the Note.
* then, any number of threads can call notesleep
* and exactly one thread can call notewakeup (once).
TEXT clone(SB),7,$0
MOVL flags+8(SP), DI
MOVQ stack+16(SP), SI
-
+
// Copy m, g, fn off parent stack for use by child.
// Careful: Linux system call clobbers CX and R11.
MOVQ m+24(SP), R8
CMPQ AX, $0
JEQ 2(PC)
RET
-
+
// In child, call fn on new stack
MOVQ SI, SP
MOVQ R8, R14 // m
MOVQ R9, R15 // g
CALL R12
-
+
// It shouldn't return. If it does, exi
MOVL $111, DI
MOVL $60, AX