rsc.io/go@v0.0.0-20150416155037-e040fd465409/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._GetVersion GetVersion%0 "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  	_GetQueuedCompletionStatus,
    68  	_GetStdHandle,
    69  	_GetSystemInfo,
    70  	_GetThreadContext,
    71  	_GetVersion,
    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 info systeminfo
   132  	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
   133  	return int32(info.dwnumberofprocessors)
   134  }
   135  
   136  const (
   137  	currentProcess = ^uintptr(0) // -1 = current process
   138  	currentThread  = ^uintptr(1) // -2 = current thread
   139  )
   140  
   141  func getVersion() (major, minor byte) {
   142  	v := uint32(stdcall0(_GetVersion))
   143  	low := uint16(v)
   144  	return byte(low), byte(low >> 8)
   145  }
   146  
   147  // in sys_windows_386.s and sys_windows_amd64.s
   148  func externalthreadhandler()
   149  
   150  func osinit() {
   151  	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
   152  
   153  	setBadSignalMsg()
   154  
   155  	loadOptionalSyscalls()
   156  
   157  	disableWER()
   158  
   159  	externalthreadhandlerp = funcPC(externalthreadhandler)
   160  
   161  	initExceptionHandler()
   162  
   163  	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
   164  
   165  	stdcall1(_timeBeginPeriod, 1)
   166  
   167  	ncpu = getproccount()
   168  
   169  	// Windows dynamic priority boosting assumes that a process has different types
   170  	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
   171  	// equivalent threads that all do a mix of GUI, IO, computations, etc.
   172  	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
   173  	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
   174  }
   175  
   176  //go:nosplit
   177  func getRandomData(r []byte) {
   178  	const (
   179  		prov_rsa_full       = 1
   180  		crypt_verifycontext = 0xF0000000
   181  	)
   182  	var handle uintptr
   183  	n := 0
   184  	if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
   185  		if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 {
   186  			n = len(r)
   187  		}
   188  		stdcall2(_CryptReleaseContext, handle, 0)
   189  	}
   190  	extendRandom(r, n)
   191  }
   192  
   193  func goenvs() {
   194  	// strings is a pointer to environment variable pairs in the form:
   195  	//     "envA=valA\x00envB=valB\x00\x00" (in UTF-16)
   196  	// Two consecutive zero bytes end the list.
   197  	strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
   198  	p := (*[1 << 24]uint16)(strings)[:]
   199  
   200  	n := 0
   201  	for from, i := 0, 0; true; i++ {
   202  		if p[i] == 0 {
   203  			// empty string marks the end
   204  			if i == from {
   205  				break
   206  			}
   207  			from = i + 1
   208  			n++
   209  		}
   210  	}
   211  	envs = make([]string, n)
   212  
   213  	for i := range envs {
   214  		envs[i] = gostringw(&p[0])
   215  		for p[0] != 0 {
   216  			p = p[1:]
   217  		}
   218  		p = p[1:] // skip nil byte
   219  	}
   220  
   221  	stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
   222  }
   223  
   224  //go:nosplit
   225  func exit(code int32) {
   226  	stdcall1(_ExitProcess, uintptr(code))
   227  }
   228  
   229  //go:nosplit
   230  func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
   231  	const (
   232  		_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
   233  		_STD_ERROR_HANDLE  = ^uintptr(11) // -12
   234  	)
   235  	var handle uintptr
   236  	switch fd {
   237  	case 1:
   238  		handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
   239  	case 2:
   240  		handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
   241  	default:
   242  		// assume fd is real windows handle.
   243  		handle = fd
   244  	}
   245  	var written uint32
   246  	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
   247  	return int32(written)
   248  }
   249  
   250  //go:nosplit
   251  func semasleep(ns int64) int32 {
   252  	// store ms in ns to save stack space
   253  	if ns < 0 {
   254  		ns = _INFINITE
   255  	} else {
   256  		ns = int64(timediv(ns, 1000000, nil))
   257  		if ns == 0 {
   258  			ns = 1
   259  		}
   260  	}
   261  	if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
   262  		return -1 // timeout
   263  	}
   264  	return 0
   265  }
   266  
   267  //go:nosplit
   268  func semawakeup(mp *m) {
   269  	stdcall1(_SetEvent, mp.waitsema)
   270  }
   271  
   272  //go:nosplit
   273  func semacreate() uintptr {
   274  	return stdcall4(_CreateEventA, 0, 0, 0, 0)
   275  }
   276  
   277  // May run with m.p==nil, so write barriers are not allowed.
   278  //go:nowritebarrier
   279  func newosproc(mp *m, stk unsafe.Pointer) {
   280  	const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
   281  	thandle := stdcall6(_CreateThread, 0, 0x20000,
   282  		funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
   283  		_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
   284  	if thandle == 0 {
   285  		println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")")
   286  		throw("runtime.newosproc")
   287  	}
   288  }
   289  
   290  // Called to initialize a new m (including the bootstrap m).
   291  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   292  func mpreinit(mp *m) {
   293  }
   294  
   295  // Called to initialize a new m (including the bootstrap m).
   296  // Called on the new thread, can not allocate memory.
   297  func minit() {
   298  	var thandle uintptr
   299  	stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
   300  	atomicstoreuintptr(&getg().m.thread, thandle)
   301  }
   302  
   303  // Called from dropm to undo the effect of an minit.
   304  func unminit() {
   305  	tp := &getg().m.thread
   306  	stdcall1(_CloseHandle, *tp)
   307  	*tp = 0
   308  }
   309  
   310  // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
   311  type _KSYSTEM_TIME struct {
   312  	LowPart   uint32
   313  	High1Time int32
   314  	High2Time int32
   315  }
   316  
   317  const (
   318  	_INTERRUPT_TIME = 0x7ffe0008
   319  	_SYSTEM_TIME    = 0x7ffe0014
   320  )
   321  
   322  //go:nosplit
   323  func systime(addr uintptr) int64 {
   324  	timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
   325  
   326  	var t _KSYSTEM_TIME
   327  	for i := 1; i < 10000; i++ {
   328  		// these fields must be read in that order (see URL above)
   329  		t.High1Time = timeaddr.High1Time
   330  		t.LowPart = timeaddr.LowPart
   331  		t.High2Time = timeaddr.High2Time
   332  		if t.High1Time == t.High2Time {
   333  			return int64(t.High1Time)<<32 | int64(t.LowPart)
   334  		}
   335  		if (i % 100) == 0 {
   336  			osyield()
   337  		}
   338  	}
   339  	systemstack(func() {
   340  		throw("interrupt/system time is changing too fast")
   341  	})
   342  	return 0
   343  }
   344  
   345  //go:nosplit
   346  func unixnano() int64 {
   347  	return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
   348  }
   349  
   350  //go:nosplit
   351  func nanotime() int64 {
   352  	return systime(_INTERRUPT_TIME) * 100
   353  }
   354  
   355  // Calling stdcall on os stack.
   356  // May run during STW, so write barriers are not allowed.
   357  //go:nowritebarrier
   358  //go:nosplit
   359  func stdcall(fn stdFunction) uintptr {
   360  	gp := getg()
   361  	mp := gp.m
   362  	mp.libcall.fn = uintptr(unsafe.Pointer(fn))
   363  
   364  	if mp.profilehz != 0 {
   365  		// leave pc/sp for cpu profiler
   366  		// gp is on allg, so this WB can be eliminated.
   367  		setGNoWriteBarrier(&mp.libcallg, gp)
   368  		mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
   369  		// sp must be the last, because once async cpu profiler finds
   370  		// all three values to be non-zero, it will use them
   371  		mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
   372  	}
   373  	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
   374  	mp.libcallsp = 0
   375  	return mp.libcall.r1
   376  }
   377  
   378  //go:nosplit
   379  func stdcall0(fn stdFunction) uintptr {
   380  	mp := getg().m
   381  	mp.libcall.n = 0
   382  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
   383  	return stdcall(fn)
   384  }
   385  
   386  //go:nosplit
   387  func stdcall1(fn stdFunction, a0 uintptr) uintptr {
   388  	mp := getg().m
   389  	mp.libcall.n = 1
   390  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   391  	return stdcall(fn)
   392  }
   393  
   394  //go:nosplit
   395  func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
   396  	mp := getg().m
   397  	mp.libcall.n = 2
   398  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   399  	return stdcall(fn)
   400  }
   401  
   402  //go:nosplit
   403  func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
   404  	mp := getg().m
   405  	mp.libcall.n = 3
   406  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   407  	return stdcall(fn)
   408  }
   409  
   410  //go:nosplit
   411  func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
   412  	mp := getg().m
   413  	mp.libcall.n = 4
   414  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   415  	return stdcall(fn)
   416  }
   417  
   418  //go:nosplit
   419  func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
   420  	mp := getg().m
   421  	mp.libcall.n = 5
   422  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   423  	return stdcall(fn)
   424  }
   425  
   426  //go:nosplit
   427  func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
   428  	mp := getg().m
   429  	mp.libcall.n = 6
   430  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   431  	return stdcall(fn)
   432  }
   433  
   434  //go:nosplit
   435  func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
   436  	mp := getg().m
   437  	mp.libcall.n = 7
   438  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   439  	return stdcall(fn)
   440  }
   441  
   442  // in sys_windows_386.s and sys_windows_amd64.s
   443  func usleep1(usec uint32)
   444  
   445  //go:nosplit
   446  func osyield() {
   447  	usleep1(1)
   448  }
   449  
   450  //go:nosplit
   451  func usleep(us uint32) {
   452  	// Have 1us units; want 100ns units.
   453  	usleep1(10 * us)
   454  }
   455  
   456  func ctrlhandler1(_type uint32) uint32 {
   457  	var s uint32
   458  
   459  	switch _type {
   460  	case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
   461  		s = _SIGINT
   462  	default:
   463  		return 0
   464  	}
   465  
   466  	if sigsend(s) {
   467  		return 1
   468  	}
   469  	exit(2) // SIGINT, SIGTERM, etc
   470  	return 0
   471  }
   472  
   473  // in sys_windows_386.s and sys_windows_amd64.s
   474  func profileloop()
   475  
   476  var profiletimer uintptr
   477  
   478  func profilem(mp *m) {
   479  	var r *context
   480  	rbuf := make([]byte, unsafe.Sizeof(*r)+15)
   481  
   482  	tls := &mp.tls[0]
   483  	if mp == &m0 {
   484  		tls = &tls0[0]
   485  	}
   486  	gp := *((**g)(unsafe.Pointer(tls)))
   487  
   488  	// align Context to 16 bytes
   489  	r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
   490  	r.contextflags = _CONTEXT_CONTROL
   491  	stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
   492  	sigprof(r.ip(), r.sp(), 0, gp, mp)
   493  }
   494  
   495  func profileloop1(param uintptr) uint32 {
   496  	stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
   497  
   498  	for {
   499  		stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
   500  		first := (*m)(atomicloadp(unsafe.Pointer(&allm)))
   501  		for mp := first; mp != nil; mp = mp.alllink {
   502  			thread := atomicloaduintptr(&mp.thread)
   503  			// Do not profile threads blocked on Notes,
   504  			// this includes idle worker threads,
   505  			// idle timer thread, idle heap scavenger, etc.
   506  			if thread == 0 || mp.profilehz == 0 || mp.blocked {
   507  				continue
   508  			}
   509  			stdcall1(_SuspendThread, thread)
   510  			if mp.profilehz != 0 && !mp.blocked {
   511  				profilem(mp)
   512  			}
   513  			stdcall1(_ResumeThread, thread)
   514  		}
   515  	}
   516  }
   517  
   518  var cpuprofilerlock mutex
   519  
   520  func resetcpuprofiler(hz int32) {
   521  	lock(&cpuprofilerlock)
   522  	if profiletimer == 0 {
   523  		timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
   524  		atomicstoreuintptr(&profiletimer, timer)
   525  		thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
   526  		stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
   527  		stdcall1(_CloseHandle, thread)
   528  	}
   529  	unlock(&cpuprofilerlock)
   530  
   531  	ms := int32(0)
   532  	due := ^int64(^uint64(1 << 63))
   533  	if hz > 0 {
   534  		ms = 1000 / hz
   535  		if ms == 0 {
   536  			ms = 1
   537  		}
   538  		due = int64(ms) * -10000
   539  	}
   540  	stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
   541  	atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
   542  }
   543  
   544  func memlimit() uintptr {
   545  	return 0
   546  }