blob: f608b4ad80c00183f6a5f09bab04f28b18f935f6 [file] [log] [blame]
Alex Brainmanab4578a2014-11-20 12:24:03 +11001// 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
5package runtime
6
7import (
8 "unsafe"
9)
10
Shenghou Ma6112e6e2015-03-08 23:04:48 -040011//go:cgo_import_dynamic runtime._AddVectoredExceptionHandler AddVectoredExceptionHandler%2 "kernel32.dll"
12//go:cgo_import_dynamic runtime._CloseHandle CloseHandle%1 "kernel32.dll"
13//go:cgo_import_dynamic runtime._CreateEventA CreateEventA%4 "kernel32.dll"
14//go:cgo_import_dynamic runtime._CreateIoCompletionPort CreateIoCompletionPort%4 "kernel32.dll"
15//go:cgo_import_dynamic runtime._CreateThread CreateThread%6 "kernel32.dll"
16//go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA%3 "kernel32.dll"
17//go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW%5 "advapi32.dll"
18//go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom%3 "advapi32.dll"
19//go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext%2 "advapi32.dll"
20//go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle%7 "kernel32.dll"
21//go:cgo_import_dynamic runtime._ExitProcess ExitProcess%1 "kernel32.dll"
22//go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW%1 "kernel32.dll"
23//go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW%0 "kernel32.dll"
24//go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress%2 "kernel32.dll"
25//go:cgo_import_dynamic runtime._GetQueuedCompletionStatus GetQueuedCompletionStatus%5 "kernel32.dll"
26//go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle%1 "kernel32.dll"
27//go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo%1 "kernel32.dll"
28//go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext%2 "kernel32.dll"
29//go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll"
30//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll"
31//go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject%3 "ntdll.dll"
32//go:cgo_import_dynamic runtime._ResumeThread ResumeThread%1 "kernel32.dll"
33//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
34//go:cgo_import_dynamic runtime._SetErrorMode SetErrorMode%1 "kernel32.dll"
35//go:cgo_import_dynamic runtime._SetEvent SetEvent%1 "kernel32.dll"
36//go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost%2 "kernel32.dll"
37//go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority%2 "kernel32.dll"
38//go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter%1 "kernel32.dll"
39//go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer%6 "kernel32.dll"
40//go:cgo_import_dynamic runtime._SuspendThread SuspendThread%1 "kernel32.dll"
41//go:cgo_import_dynamic runtime._VirtualAlloc VirtualAlloc%4 "kernel32.dll"
42//go:cgo_import_dynamic runtime._VirtualFree VirtualFree%3 "kernel32.dll"
43//go:cgo_import_dynamic runtime._WSAGetOverlappedResult WSAGetOverlappedResult%5 "ws2_32.dll"
44//go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject%2 "kernel32.dll"
45//go:cgo_import_dynamic runtime._WriteFile WriteFile%5 "kernel32.dll"
46//go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod%1 "winmm.dll"
Alex Brainmanab4578a2014-11-20 12:24:03 +110047
48var (
Alex Brainmane810a072015-01-14 10:42:26 +110049 // Following syscalls are available on every Windows PC.
50 // All these variables are set by the Windows executable
51 // loader before the Go program starts.
Alex Brainmanab4578a2014-11-20 12:24:03 +110052 _AddVectoredExceptionHandler,
53 _CloseHandle,
54 _CreateEventA,
Alex Brainman4a2233c2015-02-12 14:25:59 +110055 _CreateIoCompletionPort,
Alex Brainmanab4578a2014-11-20 12:24:03 +110056 _CreateThread,
57 _CreateWaitableTimerA,
58 _CryptAcquireContextW,
59 _CryptGenRandom,
60 _CryptReleaseContext,
61 _DuplicateHandle,
62 _ExitProcess,
63 _FreeEnvironmentStringsW,
64 _GetEnvironmentStringsW,
65 _GetProcAddress,
Alex Brainman4a2233c2015-02-12 14:25:59 +110066 _GetQueuedCompletionStatus,
Alex Brainmanab4578a2014-11-20 12:24:03 +110067 _GetStdHandle,
68 _GetSystemInfo,
69 _GetThreadContext,
70 _LoadLibraryW,
71 _LoadLibraryA,
72 _NtWaitForSingleObject,
73 _ResumeThread,
74 _SetConsoleCtrlHandler,
Alex Brainman03d66372014-12-31 13:46:58 +110075 _SetErrorMode,
Alex Brainmanab4578a2014-11-20 12:24:03 +110076 _SetEvent,
77 _SetProcessPriorityBoost,
78 _SetThreadPriority,
79 _SetUnhandledExceptionFilter,
80 _SetWaitableTimer,
Alex Brainmanab4578a2014-11-20 12:24:03 +110081 _SuspendThread,
Alex Brainman4a2233c2015-02-12 14:25:59 +110082 _VirtualAlloc,
83 _VirtualFree,
Alex Brainman4a2233c2015-02-12 14:25:59 +110084 _WSAGetOverlappedResult,
Alex Brainmanab4578a2014-11-20 12:24:03 +110085 _WaitForSingleObject,
86 _WriteFile,
87 _timeBeginPeriod stdFunction
Alex Brainmane810a072015-01-14 10:42:26 +110088
89 // Following syscalls are only available on some Windows PCs.
90 // We will load syscalls, if available, before using them.
91 _AddVectoredContinueHandler,
92 _GetQueuedCompletionStatusEx stdFunction
Alex Brainmanab4578a2014-11-20 12:24:03 +110093)
94
Alex Brainman414444d2015-04-09 11:32:47 +100095// Call a Windows function with stdcall conventions,
96// and switch to os stack during the call.
97func asmstdcall(fn unsafe.Pointer)
98
99var asmstdcallAddr unsafe.Pointer
100
Alex Brainmane810a072015-01-14 10:42:26 +1100101func loadOptionalSyscalls() {
102 var buf [50]byte // large enough for longest string
103 strtoptr := func(s string) uintptr {
104 buf[copy(buf[:], s)] = 0 // nil-terminated for OS
105 return uintptr(noescape(unsafe.Pointer(&buf[0])))
106 }
107 l := stdcall1(_LoadLibraryA, strtoptr("kernel32.dll"))
108 findfunc := func(name string) stdFunction {
109 f := stdcall2(_GetProcAddress, l, strtoptr(name))
110 return stdFunction(unsafe.Pointer(f))
111 }
112 if l != 0 {
113 _AddVectoredContinueHandler = findfunc("AddVectoredContinueHandler")
114 _GetQueuedCompletionStatusEx = findfunc("GetQueuedCompletionStatusEx")
115 }
116}
Alex Brainmanab4578a2014-11-20 12:24:03 +1100117
Alex Brainmanab4578a2014-11-20 12:24:03 +1100118//go:nosplit
119func getLoadLibrary() uintptr {
120 return uintptr(unsafe.Pointer(_LoadLibraryW))
121}
122
123//go:nosplit
124func getGetProcAddress() uintptr {
125 return uintptr(unsafe.Pointer(_GetProcAddress))
126}
127
128func getproccount() int32 {
129 var info systeminfo
130 stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
131 return int32(info.dwnumberofprocessors)
132}
133
134const (
135 currentProcess = ^uintptr(0) // -1 = current process
136 currentThread = ^uintptr(1) // -2 = current thread
137)
138
Alex Brainmand1af6be2015-04-13 12:02:44 +1000139// in sys_windows_386.s and sys_windows_amd64.s
140func externalthreadhandler()
141
Alex Brainmanab4578a2014-11-20 12:24:03 +1100142func osinit() {
Alex Brainman414444d2015-04-09 11:32:47 +1000143 asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
144
Alex Brainmanab4578a2014-11-20 12:24:03 +1100145 setBadSignalMsg()
146
Alex Brainmane810a072015-01-14 10:42:26 +1100147 loadOptionalSyscalls()
Alex Brainmanab4578a2014-11-20 12:24:03 +1100148
Alex Brainmanbc244002015-01-13 17:17:53 +1100149 disableWER()
Alex Brainman03d66372014-12-31 13:46:58 +1100150
Alex Brainmanab4578a2014-11-20 12:24:03 +1100151 externalthreadhandlerp = funcPC(externalthreadhandler)
152
Alex Brainmand1af6be2015-04-13 12:02:44 +1000153 initExceptionHandler()
Alex Brainmanab4578a2014-11-20 12:24:03 +1100154
155 stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
156
157 stdcall1(_timeBeginPeriod, 1)
158
159 ncpu = getproccount()
160
161 // Windows dynamic priority boosting assumes that a process has different types
162 // of dedicated threads -- GUI, IO, computational, etc. Go processes use
163 // equivalent threads that all do a mix of GUI, IO, computations, etc.
164 // In such context dynamic priority boosting does nothing but harm, so we turn it off.
165 stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
Alex Brainmanab4578a2014-11-20 12:24:03 +1100166}
167
Alex Brainmanab4578a2014-11-20 12:24:03 +1100168//go:nosplit
Keith Randall6820be22014-12-09 14:40:40 -0800169func getRandomData(r []byte) {
Alex Brainmanab4578a2014-11-20 12:24:03 +1100170 const (
171 prov_rsa_full = 1
172 crypt_verifycontext = 0xF0000000
173 )
174 var handle uintptr
Keith Randall6820be22014-12-09 14:40:40 -0800175 n := 0
Alex Brainmanab4578a2014-11-20 12:24:03 +1100176 if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
Keith Randall6820be22014-12-09 14:40:40 -0800177 if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 {
178 n = len(r)
Alex Brainmanab4578a2014-11-20 12:24:03 +1100179 }
180 stdcall2(_CryptReleaseContext, handle, 0)
181 }
Keith Randall6820be22014-12-09 14:40:40 -0800182 extendRandom(r, n)
Alex Brainmanab4578a2014-11-20 12:24:03 +1100183}
184
185func goenvs() {
Alex Brainmana88d7092015-01-13 16:43:34 +1100186 // strings is a pointer to environment variable pairs in the form:
187 // "envA=valA\x00envB=valB\x00\x00" (in UTF-16)
188 // Two consecutive zero bytes end the list.
189 strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
190 p := (*[1 << 24]uint16)(strings)[:]
Alex Brainmanab4578a2014-11-20 12:24:03 +1100191
192 n := 0
Alex Brainmana88d7092015-01-13 16:43:34 +1100193 for from, i := 0, 0; true; i++ {
194 if p[i] == 0 {
195 // empty string marks the end
196 if i == from {
197 break
198 }
199 from = i + 1
200 n++
201 }
202 }
David Crawshawec7d8a62015-03-03 12:25:36 -0500203 envs = make([]string, n)
Alex Brainmana88d7092015-01-13 16:43:34 +1100204
205 for i := range envs {
206 envs[i] = gostringw(&p[0])
207 for p[0] != 0 {
208 p = p[1:]
209 }
210 p = p[1:] // skip nil byte
Alex Brainmanab4578a2014-11-20 12:24:03 +1100211 }
212
Alex Brainmana88d7092015-01-13 16:43:34 +1100213 stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
Alex Brainmanab4578a2014-11-20 12:24:03 +1100214}
215
216//go:nosplit
217func exit(code int32) {
218 stdcall1(_ExitProcess, uintptr(code))
219}
220
221//go:nosplit
222func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
223 const (
224 _STD_OUTPUT_HANDLE = ^uintptr(10) // -11
225 _STD_ERROR_HANDLE = ^uintptr(11) // -12
226 )
227 var handle uintptr
228 switch fd {
229 case 1:
230 handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
231 case 2:
232 handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
233 default:
234 // assume fd is real windows handle.
235 handle = fd
236 }
237 var written uint32
238 stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
239 return int32(written)
240}
241
242//go:nosplit
243func semasleep(ns int64) int32 {
244 // store ms in ns to save stack space
245 if ns < 0 {
246 ns = _INFINITE
247 } else {
248 ns = int64(timediv(ns, 1000000, nil))
249 if ns == 0 {
250 ns = 1
251 }
252 }
253 if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
254 return -1 // timeout
255 }
256 return 0
257}
258
259//go:nosplit
260func semawakeup(mp *m) {
261 stdcall1(_SetEvent, mp.waitsema)
262}
263
264//go:nosplit
265func semacreate() uintptr {
266 return stdcall4(_CreateEventA, 0, 0, 0, 0)
267}
268
Austin Clements9e6f7aa2015-03-29 10:20:54 -0400269// May run with m.p==nil, so write barriers are not allowed.
Austin Clements392336f2015-03-26 15:50:22 -0400270//go:nowritebarrier
Alex Brainmanab4578a2014-11-20 12:24:03 +1100271func newosproc(mp *m, stk unsafe.Pointer) {
272 const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
273 thandle := stdcall6(_CreateThread, 0, 0x20000,
274 funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
275 _STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
276 if thandle == 0 {
Shenghou Mada11a9d2015-04-28 23:02:49 -0400277 print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
Keith Randallb2a950b2014-12-27 20:58:00 -0800278 throw("runtime.newosproc")
Alex Brainmanab4578a2014-11-20 12:24:03 +1100279 }
280}
281
282// Called to initialize a new m (including the bootstrap m).
283// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
284func mpreinit(mp *m) {
285}
286
Elias Naur84cfba12015-05-18 11:00:24 +0200287func msigsave(mp *m) {
288}
289
Alex Brainmanab4578a2014-11-20 12:24:03 +1100290// Called to initialize a new m (including the bootstrap m).
291// Called on the new thread, can not allocate memory.
292func minit() {
293 var thandle uintptr
294 stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
295 atomicstoreuintptr(&getg().m.thread, thandle)
296}
297
298// Called from dropm to undo the effect of an minit.
299func unminit() {
300 tp := &getg().m.thread
301 stdcall1(_CloseHandle, *tp)
302 *tp = 0
303}
304
305// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
306type _KSYSTEM_TIME struct {
307 LowPart uint32
308 High1Time int32
309 High2Time int32
310}
311
312const (
313 _INTERRUPT_TIME = 0x7ffe0008
314 _SYSTEM_TIME = 0x7ffe0014
315)
316
317//go:nosplit
318func systime(addr uintptr) int64 {
319 timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
320
321 var t _KSYSTEM_TIME
322 for i := 1; i < 10000; i++ {
323 // these fields must be read in that order (see URL above)
324 t.High1Time = timeaddr.High1Time
325 t.LowPart = timeaddr.LowPart
326 t.High2Time = timeaddr.High2Time
327 if t.High1Time == t.High2Time {
328 return int64(t.High1Time)<<32 | int64(t.LowPart)
329 }
330 if (i % 100) == 0 {
331 osyield()
332 }
333 }
334 systemstack(func() {
Keith Randallb2a950b2014-12-27 20:58:00 -0800335 throw("interrupt/system time is changing too fast")
Alex Brainmanab4578a2014-11-20 12:24:03 +1100336 })
337 return 0
338}
339
340//go:nosplit
341func unixnano() int64 {
342 return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
343}
344
345//go:nosplit
346func nanotime() int64 {
347 return systime(_INTERRUPT_TIME) * 100
348}
349
350// Calling stdcall on os stack.
Rick Hudson546a54b2015-03-24 11:18:46 -0400351// May run during STW, so write barriers are not allowed.
352//go:nowritebarrier
Alex Brainmanab4578a2014-11-20 12:24:03 +1100353//go:nosplit
354func stdcall(fn stdFunction) uintptr {
355 gp := getg()
356 mp := gp.m
357 mp.libcall.fn = uintptr(unsafe.Pointer(fn))
358
359 if mp.profilehz != 0 {
360 // leave pc/sp for cpu profiler
Russ Cox181e26b2015-04-17 00:21:30 -0400361 mp.libcallg.set(gp)
Alex Brainmanab4578a2014-11-20 12:24:03 +1100362 mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
363 // sp must be the last, because once async cpu profiler finds
364 // all three values to be non-zero, it will use them
365 mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
366 }
Alex Brainman9d968cb2015-04-27 17:32:23 +1000367 asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
Alex Brainmanab4578a2014-11-20 12:24:03 +1100368 mp.libcallsp = 0
369 return mp.libcall.r1
370}
371
372//go:nosplit
373func stdcall0(fn stdFunction) uintptr {
374 mp := getg().m
375 mp.libcall.n = 0
376 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
377 return stdcall(fn)
378}
379
380//go:nosplit
381func stdcall1(fn stdFunction, a0 uintptr) uintptr {
382 mp := getg().m
383 mp.libcall.n = 1
384 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
385 return stdcall(fn)
386}
387
388//go:nosplit
389func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
390 mp := getg().m
391 mp.libcall.n = 2
392 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
393 return stdcall(fn)
394}
395
396//go:nosplit
397func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
398 mp := getg().m
399 mp.libcall.n = 3
400 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
401 return stdcall(fn)
402}
403
404//go:nosplit
405func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
406 mp := getg().m
407 mp.libcall.n = 4
408 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
409 return stdcall(fn)
410}
411
412//go:nosplit
413func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
414 mp := getg().m
415 mp.libcall.n = 5
416 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
417 return stdcall(fn)
418}
419
420//go:nosplit
421func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
422 mp := getg().m
423 mp.libcall.n = 6
424 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
425 return stdcall(fn)
426}
427
428//go:nosplit
429func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
430 mp := getg().m
431 mp.libcall.n = 7
432 mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
433 return stdcall(fn)
434}
435
436// in sys_windows_386.s and sys_windows_amd64.s
437func usleep1(usec uint32)
438
439//go:nosplit
440func osyield() {
441 usleep1(1)
442}
443
444//go:nosplit
445func usleep(us uint32) {
446 // Have 1us units; want 100ns units.
447 usleep1(10 * us)
448}
449
Alex Brainmanab4578a2014-11-20 12:24:03 +1100450func ctrlhandler1(_type uint32) uint32 {
451 var s uint32
452
453 switch _type {
454 case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
455 s = _SIGINT
456 default:
457 return 0
458 }
459
460 if sigsend(s) {
461 return 1
462 }
463 exit(2) // SIGINT, SIGTERM, etc
464 return 0
465}
466
467// in sys_windows_386.s and sys_windows_amd64.s
468func profileloop()
469
470var profiletimer uintptr
471
472func profilem(mp *m) {
473 var r *context
474 rbuf := make([]byte, unsafe.Sizeof(*r)+15)
475
476 tls := &mp.tls[0]
477 if mp == &m0 {
478 tls = &tls0[0]
479 }
480 gp := *((**g)(unsafe.Pointer(tls)))
481
482 // align Context to 16 bytes
483 r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
484 r.contextflags = _CONTEXT_CONTROL
485 stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
Matthew Dempsky3c8a89d2015-02-25 14:41:21 +0900486 sigprof(r.ip(), r.sp(), 0, gp, mp)
Alex Brainmanab4578a2014-11-20 12:24:03 +1100487}
488
Alex Brainman9402e492015-04-14 10:48:05 +1000489func profileloop1(param uintptr) uint32 {
Alex Brainmanab4578a2014-11-20 12:24:03 +1100490 stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
491
492 for {
493 stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
494 first := (*m)(atomicloadp(unsafe.Pointer(&allm)))
495 for mp := first; mp != nil; mp = mp.alllink {
496 thread := atomicloaduintptr(&mp.thread)
497 // Do not profile threads blocked on Notes,
498 // this includes idle worker threads,
499 // idle timer thread, idle heap scavenger, etc.
500 if thread == 0 || mp.profilehz == 0 || mp.blocked {
501 continue
502 }
503 stdcall1(_SuspendThread, thread)
504 if mp.profilehz != 0 && !mp.blocked {
505 profilem(mp)
506 }
507 stdcall1(_ResumeThread, thread)
508 }
509 }
510}
511
512var cpuprofilerlock mutex
513
514func resetcpuprofiler(hz int32) {
515 lock(&cpuprofilerlock)
516 if profiletimer == 0 {
517 timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
518 atomicstoreuintptr(&profiletimer, timer)
519 thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
520 stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
521 stdcall1(_CloseHandle, thread)
522 }
523 unlock(&cpuprofilerlock)
524
525 ms := int32(0)
526 due := ^int64(^uint64(1 << 63))
527 if hz > 0 {
528 ms = 1000 / hz
529 if ms == 0 {
530 ms = 1
531 }
532 due = int64(ms) * -10000
533 }
534 stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
535 atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
536}
537
538func memlimit() uintptr {
539 return 0
540}