mirror of
https://github.com/golang/go
synced 2024-11-21 21:14:47 -07:00
runtime: eliminate handle churn when churning channels on Windows
The Windows implementation of the net package churns through a couple of channels for every read/write operation. This translates into a lot of time spent in the kernel creating and deleting event objects. R=rsc, dvyukov, alex.brainman, jp CC=golang-dev https://golang.org/cl/4997044
This commit is contained in:
parent
e076c502dd
commit
5c30325983
@ -603,8 +603,6 @@ runtime·gc(int32 force)
|
||||
|
||||
m->gcing = 1;
|
||||
runtime·stoptheworld();
|
||||
if(runtime·mheap.Lock.key != 0)
|
||||
runtime·throw("runtime·mheap locked during gc");
|
||||
|
||||
cachestats();
|
||||
heap0 = mstats.heap_alloc;
|
||||
|
@ -119,10 +119,10 @@ enum
|
||||
*/
|
||||
struct Lock
|
||||
{
|
||||
uint32 key;
|
||||
#ifdef __WINDOWS__
|
||||
void* event;
|
||||
M* waitm; // linked list of waiting M's
|
||||
#else
|
||||
uint32 key;
|
||||
uint32 sema; // for OS X
|
||||
#endif
|
||||
};
|
||||
@ -251,6 +251,11 @@ struct M
|
||||
uint32 freglo[16]; // D[i] lsb and F[i]
|
||||
uint32 freghi[16]; // D[i] msb and F[i+16]
|
||||
uint32 fflag; // floating point compare flags
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
void* event; // event for signalling
|
||||
M* nextwaitm; // next M waiting for lock
|
||||
#endif
|
||||
};
|
||||
|
||||
struct Stktop
|
||||
|
@ -40,14 +40,12 @@ extern void *runtime·WaitForSingleObject;
|
||||
extern void *runtime·WriteFile;
|
||||
|
||||
static int64 timerfreq;
|
||||
static void destroylock(Lock *l);
|
||||
|
||||
void
|
||||
runtime·osinit(void)
|
||||
{
|
||||
runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
|
||||
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
|
||||
runtime·destroylock = destroylock;
|
||||
}
|
||||
|
||||
void
|
||||
@ -120,22 +118,50 @@ initevent(void **pevent)
|
||||
}
|
||||
}
|
||||
|
||||
#define LOCK_HELD ((M*)-1)
|
||||
|
||||
static void
|
||||
eventlock(Lock *l)
|
||||
{
|
||||
// Allocate event if needed.
|
||||
if(l->event == 0)
|
||||
initevent(&l->event);
|
||||
if(m->event == nil)
|
||||
initevent(&m->event);
|
||||
|
||||
if(runtime·xadd(&l->key, 1) > 1) // someone else has it; wait
|
||||
runtime·stdcall(runtime·WaitForSingleObject, 2, l->event, (uintptr)-1);
|
||||
for(;;) {
|
||||
m->nextwaitm = runtime·atomicloadp(&l->waitm);
|
||||
if(m->nextwaitm == nil) {
|
||||
if(runtime·casp(&l->waitm, nil, LOCK_HELD))
|
||||
return;
|
||||
// Someone else has it.
|
||||
// l->waitm points to a linked list of M's waiting
|
||||
// for this lock, chained through m->nextwaitm.
|
||||
// Queue this M.
|
||||
} else if(runtime·casp(&l->waitm, m->nextwaitm, m))
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait.
|
||||
runtime·stdcall(runtime·WaitForSingleObject, 2, m->event, (uintptr)-1);
|
||||
}
|
||||
|
||||
static void
|
||||
eventunlock(Lock *l)
|
||||
{
|
||||
if(runtime·xadd(&l->key, -1) > 0) // someone else is waiting
|
||||
runtime·stdcall(runtime·SetEvent, 1, l->event);
|
||||
M *mp;
|
||||
|
||||
for(;;) {
|
||||
mp = runtime·atomicloadp(&l->waitm);
|
||||
if(mp == LOCK_HELD) {
|
||||
if(runtime·casp(&l->waitm, LOCK_HELD, nil))
|
||||
return;
|
||||
// Other M's are waiting for the lock.
|
||||
// Dequeue a M.
|
||||
} else if(runtime·casp(&l->waitm, mp, mp->nextwaitm))
|
||||
break;
|
||||
}
|
||||
|
||||
// Wake that M.
|
||||
runtime·stdcall(runtime·SetEvent, 1, mp->event);
|
||||
}
|
||||
|
||||
void
|
||||
@ -156,17 +182,10 @@ runtime·unlock(Lock *l)
|
||||
eventunlock(l);
|
||||
}
|
||||
|
||||
static void
|
||||
destroylock(Lock *l)
|
||||
{
|
||||
if(l->event != 0)
|
||||
runtime·stdcall(runtime·CloseHandle, 1, l->event);
|
||||
}
|
||||
|
||||
void
|
||||
runtime·noteclear(Note *n)
|
||||
{
|
||||
n->lock.key = 0; // memset(n, 0, sizeof *n)
|
||||
n->lock.waitm = nil;
|
||||
eventlock(&n->lock);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user