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