github.com/c0deoo1/golang1.5@v0.0.0-20220525150107-c87c805d4593/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._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"
    47  
    48  var (
    49  	// 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.
    52  	_AddVectoredExceptionHandler,
    53  	_CloseHandle,
    54  	_CreateEventA,
    55  	_CreateIoCompletionPort,
    56  	_CreateThread,
    57  	_CreateWaitableTimerA,
    58  	_CryptAcquireContextW,
    59  	_CryptGenRandom,
    60  	_CryptReleaseContext,
    61  	_DuplicateHandle,
    62  	_ExitProcess,
    63  	_FreeEnvironmentStringsW,
    64  	_GetEnvironmentStringsW,
    65  	_GetProcAddress,
    66  	_GetQueuedCompletionStatus,
    67  	_GetStdHandle,
    68  	_GetSystemInfo,
    69  	_GetThreadContext,
    70  	_LoadLibraryW,
    71  	_LoadLibraryA,
    72  	_NtWaitForSingleObject,
    73  	_ResumeThread,
    74  	_SetConsoleCtrlHandler,
    75  	_SetErrorMode,
    76  	_SetEvent,
    77  	_SetProcessPriorityBoost,
    78  	_SetThreadPriority,
    79  	_SetUnhandledExceptionFilter,
    80  	_SetWaitableTimer,
    81  	_SuspendThread,
    82  	_VirtualAlloc,
    83  	_VirtualFree,
    84  	_WSAGetOverlappedResult,
    85  	_WaitForSingleObject,
    86  	_WriteFile,
    87  	_timeBeginPeriod stdFunction
    88  
    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
    93  )
    94  
    95  // Call a Windows function with stdcall conventions,
    96  // and switch to os stack during the call.
    97  func asmstdcall(fn unsafe.Pointer)
    98  
    99  var asmstdcallAddr unsafe.Pointer
   100  
   101  func 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  }
   117  
   118  //go:nosplit
   119  func getLoadLibrary() uintptr {
   120  	return uintptr(unsafe.Pointer(_LoadLibraryW))
   121  }
   122  
   123  //go:nosplit
   124  func getGetProcAddress() uintptr {
   125  	return uintptr(unsafe.Pointer(_GetProcAddress))
   126  }
   127  
   128  func getproccount() int32 {
   129  	var info systeminfo
   130  	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
   131  	return int32(info.dwnumberofprocessors)
   132  }
   133  
   134  const (
   135  	currentProcess = ^uintptr(0) // -1 = current process
   136  	currentThread  = ^uintptr(1) // -2 = current thread
   137  )
   138  
   139  // in sys_windows_386.s and sys_windows_amd64.s
   140  func externalthreadhandler()
   141  
   142  func osinit() {
   143  	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
   144  
   145  	setBadSignalMsg()
   146  
   147  	loadOptionalSyscalls()
   148  
   149  	disableWER()
   150  
   151  	externalthreadhandlerp = funcPC(externalthreadhandler)
   152  
   153  	initExceptionHandler()
   154  
   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)
   166  }
   167  
   168  //go:nosplit
   169  func getRandomData(r []byte) {
   170  	const (
   171  		prov_rsa_full       = 1
   172  		crypt_verifycontext = 0xF0000000
   173  	)
   174  	var handle uintptr
   175  	n := 0
   176  	if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
   177  		if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 {
   178  			n = len(r)
   179  		}
   180  		stdcall2(_CryptReleaseContext, handle, 0)
   181  	}
   182  	extendRandom(r, n)
   183  }
   184  
   185  func goenvs() {
   186  	// 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)[:]
   191  
   192  	n := 0
   193  	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  	}
   203  	envs = make([]string, n)
   204  
   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
   211  	}
   212  
   213  	stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
   214  }
   215  
   216  //go:nosplit
   217  func exit(code int32) {
   218  	stdcall1(_ExitProcess, uintptr(code))
   219  }
   220  
   221  //go:nosplit
   222  func 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
   243  func 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
   260  func semawakeup(mp *m) {
   261  	stdcall1(_SetEvent, mp.waitsema)
   262  }
   263  
   264  //go:nosplit
   265  func semacreate() uintptr {
   266  	return stdcall4(_CreateEventA, 0, 0, 0, 0)
   267  }
   268  
   269  // May run with m.p==nil, so write barriers are not allowed.
   270  //go:nowritebarrier
   271  func 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 {
   277  		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
   278  		throw("runtime.newosproc")
   279  	}
   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.
   284  func mpreinit(mp *m) {
   285  }
   286  
   287  func msigsave(mp *m) {
   288  }
   289  
   290  // Called to initialize a new m (including the bootstrap m).
   291  // Called on the new thread, can not allocate memory.
   292  func 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.
   299  func 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/
   306  type _KSYSTEM_TIME struct {
   307  	LowPart   uint32
   308  	High1Time int32
   309  	High2Time int32
   310  }
   311  
   312  const (
   313  	_INTERRUPT_TIME = 0x7ffe0008
   314  	_SYSTEM_TIME    = 0x7ffe0014
   315  )
   316  
   317  //go:nosplit
   318  func 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() {
   335  		throw("interrupt/system time is changing too fast")
   336  	})
   337  	return 0
   338  }
   339  
   340  //go:nosplit
   341  func unixnano() int64 {
   342  	return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
   343  }
   344  
   345  //go:nosplit
   346  func nanotime() int64 {
   347  	return systime(_INTERRUPT_TIME) * 100
   348  }
   349  
   350  // Calling stdcall on os stack.
   351  // May run during STW, so write barriers are not allowed.
   352  //go:nowritebarrier
   353  //go:nosplit
   354  func 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
   361  		mp.libcallg.set(gp)
   362  		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  	}
   367  	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
   368  	mp.libcallsp = 0
   369  	return mp.libcall.r1
   370  }
   371  
   372  //go:nosplit
   373  func 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
   381  func 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
   389  func 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
   397  func 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
   405  func 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
   413  func 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
   421  func 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
   429  func 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
   437  func usleep1(usec uint32)
   438  
   439  //go:nosplit
   440  func osyield() {
   441  	usleep1(1)
   442  }
   443  
   444  //go:nosplit
   445  func usleep(us uint32) {
   446  	// Have 1us units; want 100ns units.
   447  	usleep1(10 * us)
   448  }
   449  
   450  func 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
   468  func profileloop()
   469  
   470  var profiletimer uintptr
   471  
   472  func 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)))
   486  	sigprof(r.ip(), r.sp(), 0, gp, mp)
   487  }
   488  
   489  func profileloop1(param uintptr) uint32 {
   490  	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  
   512  var cpuprofilerlock mutex
   513  
   514  func 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  
   538  func memlimit() uintptr {
   539  	return 0
   540  }