sigdone:
RET
-// Windows runs the ctrl handler in a new thread.
TEXT runtime·ctrlhandler(SB),7,$0
+ PUSHL $runtime·ctrlhandler1(SB)
+ CALL runtime·externalthreadhandler(SB)
+ MOVL 4(SP), CX
+ ADDL $12, SP
+ JMP CX
+
+TEXT runtime·profileloop(SB),7,$0
+ PUSHL $runtime·profileloop1(SB)
+ CALL runtime·externalthreadhandler(SB)
+ MOVL 4(SP), CX
+ ADDL $12, SP
+ JMP CX
+
+TEXT runtime·externalthreadhandler(SB),7,$0
PUSHL BP
MOVL SP, BP
PUSHL BX
PUSHL SI
PUSHL DI
PUSHL 0x2c(FS)
- MOVL SP, BX
+ MOVL SP, DX
// setup dummy m, g
- SUBL $(m_fflag+4), SP // at least space for m_fflag
+ SUBL $m_end, SP // space for M
+ MOVL SP, 0(SP)
+ MOVL $m_end, 4(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
+
LEAL m_tls(SP), CX
MOVL CX, 0x2c(FS)
MOVL SP, m(CX)
- MOVL SP, DX
- SUBL $8, SP // space for g_stack{guard,base}
+ MOVL SP, BX
+ SUBL $g_end, SP // space for G
MOVL SP, g(CX)
- MOVL SP, m_g0(DX)
+ MOVL SP, m_g0(BX)
+
+ MOVL SP, 0(SP)
+ MOVL $g_end, 4(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
LEAL -4096(SP), CX
MOVL CX, g_stackguard(SP)
- MOVL BX, g_stackbase(SP)
+ MOVL DX, g_stackbase(SP)
- PUSHL 8(BP)
- CALL runtime·ctrlhandler1(SB)
+ PUSHL 16(BP) // arg for handler
+ CALL 8(BP)
POPL CX
get_tls(CX)
POPL SI
POPL BX
POPL BP
- MOVL 0(SP), CX
- ADDL $8, SP
- JMP CX
+ RET
// Called from dynamic function created by ../thread.c compilecallback,
// running on Windows stack (not Go stack).
sigdone:
RET
-// Windows runs the ctrl handler in a new thread.
-TEXT runtime·ctrlhandler(SB),7,$0
+TEXT runtime·ctrlhandler(SB),7,$8
+ MOVQ CX, 16(SP) // spill
+ MOVQ $runtime·ctrlhandler1(SB), CX
+ MOVQ CX, 0(SP)
+ CALL runtime·externalthreadhandler(SB)
+ RET
+
+TEXT runtime·profileloop(SB),7,$8
+ MOVQ $runtime·profileloop1(SB), CX
+ MOVQ CX, 0(SP)
+ CALL runtime·externalthreadhandler(SB)
+ RET
+
+TEXT runtime·externalthreadhandler(SB),7,$0
PUSHQ BP
MOVQ SP, BP
PUSHQ BX
PUSHQ SI
PUSHQ DI
PUSHQ 0x58(GS)
- MOVQ SP, BX
+ MOVQ SP, DX
// setup dummy m, g
- SUBQ $(m_fflag+4), SP // at least space for m_fflag
+ SUBQ $m_end, SP // space for M
+ MOVQ SP, 0(SP)
+ MOVQ $m_end, 8(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
+
LEAQ m_tls(SP), CX
MOVQ CX, 0x58(GS)
MOVQ SP, m(CX)
- MOVQ SP, DX
- SUBQ $16, SP // space for g_stack{guard,base}
+ MOVQ SP, BX
+ SUBQ $g_end, SP // space for G
MOVQ SP, g(CX)
- MOVQ SP, m_g0(DX)
+ MOVQ SP, m_g0(BX)
+
+ MOVQ SP, 0(SP)
+ MOVQ $g_end, 8(SP)
+ CALL runtime·memclr(SB) // smashes AX,BX,CX
LEAQ -8192(SP), CX
MOVQ CX, g_stackguard(SP)
- MOVQ BX, g_stackbase(SP)
+ MOVQ DX, g_stackbase(SP)
- PUSHQ 16(BP)
- CALL runtime·ctrlhandler1(SB)
+ PUSHQ 32(BP) // arg for handler
+ CALL 16(BP)
POPQ CX
get_tls(CX)
#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
+#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
+#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
#pragma dynimport runtime·LoadLibraryEx LoadLibraryExA "kernel32.dll"
#pragma dynimport runtime·QueryPerformanceCounter QueryPerformanceCounter "kernel32.dll"
#pragma dynimport runtime·QueryPerformanceFrequency QueryPerformanceFrequency "kernel32.dll"
+#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
+#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
+#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
+#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
+#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
extern void *runtime·CloseHandle;
extern void *runtime·CreateEvent;
extern void *runtime·CreateThread;
+extern void *runtime·CreateWaitableTimer;
+extern void *runtime·DuplicateHandle;
extern void *runtime·ExitProcess;
extern void *runtime·FreeEnvironmentStringsW;
extern void *runtime·GetEnvironmentStringsW;
extern void *runtime·GetProcAddress;
extern void *runtime·GetStdHandle;
+extern void *runtime·GetThreadContext;
extern void *runtime·LoadLibraryEx;
extern void *runtime·QueryPerformanceCounter;
extern void *runtime·QueryPerformanceFrequency;
+extern void *runtime·ResumeThread;
extern void *runtime·SetConsoleCtrlHandler;
extern void *runtime·SetEvent;
+extern void *runtime·SetThreadPriority;
+extern void *runtime·SetWaitableTimer;
+extern void *runtime·SuspendThread;
+extern void *runtime·timeBeginPeriod;
extern void *runtime·WaitForSingleObject;
extern void *runtime·WriteFile;
void
runtime·osinit(void)
{
+ // -1 = current process, -2 = current thread
+ runtime·stdcall(runtime·DuplicateHandle, 7,
+ (uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
+ (uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
runtime·stdcall(runtime·QueryPerformanceFrequency, 1, &timerfreq);
runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
+ runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
}
void
USED(g); // assuming g = m->g0
USED(fn); // assuming fn = mstart
- thandle = runtime·stdcall(runtime·CreateThread, 6, (uintptr)0, (uintptr)0, runtime·tstart_stdcall, m, (uintptr)0, (uintptr)0);
- if(thandle == 0) {
+ thandle = runtime·stdcall(runtime·CreateThread, 6,
+ nil, nil, runtime·tstart_stdcall, m, nil, nil);
+ if(thandle == nil) {
runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
runtime·throw("runtime.newosproc");
}
+ runtime·atomicstorep(&m->thread, thandle);
}
// Called to initialize a new m (including the bootstrap m).
return 0;
}
+extern void runtime·dosigprof(Context *r, G *gp);
+extern void runtime·profileloop(void);
+static void *profiletimer;
+
+static void
+profilem(M *mp)
+{
+ extern M runtime·m0;
+ extern uint32 runtime·tls0[];
+ byte rbuf[sizeof(Context)+15];
+ Context *r;
+ void *tls;
+ G *gp;
+
+ tls = mp->tls;
+ if(mp == &runtime·m0)
+ tls = runtime·tls0;
+ gp = *(G**)tls;
+
+ if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
+ // align Context to 16 bytes
+ r = (Context*)((uintptr)(&rbuf[15]) & ~15);
+ r->ContextFlags = CONTEXT_CONTROL;
+ runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
+ runtime·dosigprof(r, gp);
+ }
+}
+
+void
+runtime·profileloop1(void)
+{
+ M *mp, *allm;
+ void *thread;
+
+ runtime·stdcall(runtime·SetThreadPriority, 2,
+ (uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST);
+
+ for(;;) {
+ runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1);
+ allm = runtime·atomicloadp(&runtime·allm);
+ for(mp = allm; mp != nil; mp = mp->alllink) {
+ thread = runtime·atomicloadp(&mp->thread);
+ if(thread == nil)
+ continue;
+ runtime·stdcall(runtime·SuspendThread, 1, thread);
+ if(mp->profilehz != 0)
+ profilem(mp);
+ runtime·stdcall(runtime·ResumeThread, 1, thread);
+ }
+ }
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+ static Lock lock;
+ void *timer, *thread;
+ int32 ms;
+ int64 due;
+
+ runtime·lock(&lock);
+ if(profiletimer == nil) {
+ timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil);
+ runtime·atomicstorep(&profiletimer, timer);
+ thread = runtime·stdcall(runtime·CreateThread, 6,
+ nil, nil, runtime·profileloop, nil, nil, nil);
+ runtime·stdcall(runtime·CloseHandle, 1, thread);
+ }
+ runtime·unlock(&lock);
+
+ ms = 0;
+ due = 1LL<<63;
+ if(hz > 0) {
+ ms = 1000 / hz;
+ if(ms == 0)
+ ms = 1;
+ due = ms * -10000;
+ }
+ runtime·stdcall(runtime·SetWaitableTimer, 6,
+ profiletimer, &due, (uintptr)ms, nil, nil, nil);
+ runtime·atomicstore((uint32*)&m->profilehz, hz);
+}
+
void
os·sigpipe(void)
{