github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/runtime/os1_windows.go (about)

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