github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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 "kernel32.dll"
    12  //go:cgo_import_dynamic runtime._CloseHandle CloseHandle "kernel32.dll"
    13  //go:cgo_import_dynamic runtime._CreateEventA CreateEventA "kernel32.dll"
    14  //go:cgo_import_dynamic runtime._CreateThread CreateThread "kernel32.dll"
    15  //go:cgo_import_dynamic runtime._CreateWaitableTimerA CreateWaitableTimerA "kernel32.dll"
    16  //go:cgo_import_dynamic runtime._CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
    17  //go:cgo_import_dynamic runtime._CryptGenRandom CryptGenRandom "advapi32.dll"
    18  //go:cgo_import_dynamic runtime._CryptReleaseContext CryptReleaseContext "advapi32.dll"
    19  //go:cgo_import_dynamic runtime._DuplicateHandle DuplicateHandle "kernel32.dll"
    20  //go:cgo_import_dynamic runtime._ExitProcess ExitProcess "kernel32.dll"
    21  //go:cgo_import_dynamic runtime._FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
    22  //go:cgo_import_dynamic runtime._GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
    23  //go:cgo_import_dynamic runtime._GetProcAddress GetProcAddress "kernel32.dll"
    24  //go:cgo_import_dynamic runtime._GetStdHandle GetStdHandle "kernel32.dll"
    25  //go:cgo_import_dynamic runtime._GetSystemInfo GetSystemInfo "kernel32.dll"
    26  //go:cgo_import_dynamic runtime._GetThreadContext GetThreadContext "kernel32.dll"
    27  //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW "kernel32.dll"
    28  //go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA "kernel32.dll"
    29  //go:cgo_import_dynamic runtime._NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
    30  //go:cgo_import_dynamic runtime._ResumeThread ResumeThread "kernel32.dll"
    31  //go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
    32  //go:cgo_import_dynamic runtime._SetEvent SetEvent "kernel32.dll"
    33  //go:cgo_import_dynamic runtime._SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
    34  //go:cgo_import_dynamic runtime._SetThreadPriority SetThreadPriority "kernel32.dll"
    35  //go:cgo_import_dynamic runtime._SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
    36  //go:cgo_import_dynamic runtime._SetWaitableTimer SetWaitableTimer "kernel32.dll"
    37  //go:cgo_import_dynamic runtime._Sleep Sleep "kernel32.dll"
    38  //go:cgo_import_dynamic runtime._SuspendThread SuspendThread "kernel32.dll"
    39  //go:cgo_import_dynamic runtime._WaitForSingleObject WaitForSingleObject "kernel32.dll"
    40  //go:cgo_import_dynamic runtime._WriteFile WriteFile "kernel32.dll"
    41  //go:cgo_import_dynamic runtime._timeBeginPeriod timeBeginPeriod "winmm.dll"
    42  
    43  var (
    44  	_AddVectoredExceptionHandler,
    45  	_CloseHandle,
    46  	_CreateEventA,
    47  	_CreateThread,
    48  	_CreateWaitableTimerA,
    49  	_CryptAcquireContextW,
    50  	_CryptGenRandom,
    51  	_CryptReleaseContext,
    52  	_DuplicateHandle,
    53  	_ExitProcess,
    54  	_FreeEnvironmentStringsW,
    55  	_GetEnvironmentStringsW,
    56  	_GetProcAddress,
    57  	_GetStdHandle,
    58  	_GetSystemInfo,
    59  	_GetThreadContext,
    60  	_LoadLibraryW,
    61  	_LoadLibraryA,
    62  	_NtWaitForSingleObject,
    63  	_ResumeThread,
    64  	_SetConsoleCtrlHandler,
    65  	_SetEvent,
    66  	_SetProcessPriorityBoost,
    67  	_SetThreadPriority,
    68  	_SetUnhandledExceptionFilter,
    69  	_SetWaitableTimer,
    70  	_Sleep,
    71  	_SuspendThread,
    72  	_WaitForSingleObject,
    73  	_WriteFile,
    74  	_timeBeginPeriod stdFunction
    75  )
    76  
    77  var _GetQueuedCompletionStatusEx stdFunction
    78  
    79  // in sys_windows_386.s and sys_windows_amd64.s
    80  func externalthreadhandler()
    81  func exceptiontramp()
    82  func firstcontinuetramp()
    83  func lastcontinuetramp()
    84  
    85  //go:nosplit
    86  func getLoadLibrary() uintptr {
    87  	return uintptr(unsafe.Pointer(_LoadLibraryW))
    88  }
    89  
    90  //go:nosplit
    91  func getGetProcAddress() uintptr {
    92  	return uintptr(unsafe.Pointer(_GetProcAddress))
    93  }
    94  
    95  func getproccount() int32 {
    96  	var info systeminfo
    97  	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
    98  	return int32(info.dwnumberofprocessors)
    99  }
   100  
   101  const (
   102  	currentProcess = ^uintptr(0) // -1 = current process
   103  	currentThread  = ^uintptr(1) // -2 = current thread
   104  )
   105  
   106  var (
   107  	kernel32Name                    = []byte("kernel32.dll\x00")
   108  	addVectoredContinueHandlerName  = []byte("AddVectoredContinueHandler\x00")
   109  	getQueuedCompletionStatusExName = []byte("GetQueuedCompletionStatusEx\x00")
   110  )
   111  
   112  func osinit() {
   113  	setBadSignalMsg()
   114  
   115  	kernel32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32Name[0])))
   116  
   117  	externalthreadhandlerp = funcPC(externalthreadhandler)
   118  
   119  	stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
   120  	addVectoredContinueHandler := uintptr(0)
   121  	if kernel32 != 0 {
   122  		addVectoredContinueHandler = stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&addVectoredContinueHandlerName[0])))
   123  	}
   124  	if addVectoredContinueHandler == 0 || unsafe.Sizeof(&kernel32) == 4 {
   125  		// use SetUnhandledExceptionFilter for windows-386 or
   126  		// if VectoredContinueHandler is unavailable.
   127  		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
   128  		stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
   129  	} else {
   130  		stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 1, funcPC(firstcontinuetramp))
   131  		stdcall2(stdFunction(unsafe.Pointer(addVectoredContinueHandler)), 0, funcPC(lastcontinuetramp))
   132  	}
   133  
   134  	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
   135  
   136  	stdcall1(_timeBeginPeriod, 1)
   137  
   138  	ncpu = getproccount()
   139  
   140  	// Windows dynamic priority boosting assumes that a process has different types
   141  	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
   142  	// equivalent threads that all do a mix of GUI, IO, computations, etc.
   143  	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
   144  	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
   145  
   146  	if kernel32 != 0 {
   147  		_GetQueuedCompletionStatusEx = stdFunction(unsafe.Pointer(stdcall2(_GetProcAddress, kernel32, uintptr(unsafe.Pointer(&getQueuedCompletionStatusExName[0])))))
   148  	}
   149  }
   150  
   151  var random_data [_HashRandomBytes]byte
   152  
   153  //go:nosplit
   154  func get_random_data(rnd *unsafe.Pointer, rnd_len *int32) {
   155  	const (
   156  		prov_rsa_full       = 1
   157  		crypt_verifycontext = 0xF0000000
   158  	)
   159  	var handle uintptr
   160  	*rnd = nil
   161  	*rnd_len = 0
   162  	if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
   163  		if stdcall3(_CryptGenRandom, handle, _HashRandomBytes, uintptr(unsafe.Pointer(&random_data[0]))) != 0 {
   164  			*rnd = unsafe.Pointer(&random_data[0])
   165  			*rnd_len = _HashRandomBytes
   166  		}
   167  		stdcall2(_CryptReleaseContext, handle, 0)
   168  	}
   169  }
   170  
   171  func goenvs() {
   172  	var p *uint16
   173  
   174  	env := (*uint16)(unsafe.Pointer(stdcall0(_GetEnvironmentStringsW)))
   175  
   176  	n := 0
   177  	for p = env; *p != 0; n++ {
   178  		p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p)))
   179  	}
   180  
   181  	envs = makeStringSlice(int(n))
   182  
   183  	p = env
   184  	for i := 0; i < n; i++ {
   185  		envs[i] = gostringw(p)
   186  		p = (*uint16)(add(unsafe.Pointer(p), uintptr(findnullw(p)+1)*unsafe.Sizeof(*p)))
   187  	}
   188  
   189  	stdcall1(_FreeEnvironmentStringsW, uintptr(unsafe.Pointer(env)))
   190  }
   191  
   192  //go:nosplit
   193  func exit(code int32) {
   194  	stdcall1(_ExitProcess, uintptr(code))
   195  }
   196  
   197  //go:nosplit
   198  func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
   199  	const (
   200  		_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
   201  		_STD_ERROR_HANDLE  = ^uintptr(11) // -12
   202  	)
   203  	var handle uintptr
   204  	switch fd {
   205  	case 1:
   206  		handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
   207  	case 2:
   208  		handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
   209  	default:
   210  		// assume fd is real windows handle.
   211  		handle = fd
   212  	}
   213  	var written uint32
   214  	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
   215  	return int32(written)
   216  }
   217  
   218  //go:nosplit
   219  func semasleep(ns int64) int32 {
   220  	// store ms in ns to save stack space
   221  	if ns < 0 {
   222  		ns = _INFINITE
   223  	} else {
   224  		ns = int64(timediv(ns, 1000000, nil))
   225  		if ns == 0 {
   226  			ns = 1
   227  		}
   228  	}
   229  	if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
   230  		return -1 // timeout
   231  	}
   232  	return 0
   233  }
   234  
   235  //go:nosplit
   236  func semawakeup(mp *m) {
   237  	stdcall1(_SetEvent, mp.waitsema)
   238  }
   239  
   240  //go:nosplit
   241  func semacreate() uintptr {
   242  	return stdcall4(_CreateEventA, 0, 0, 0, 0)
   243  }
   244  
   245  func newosproc(mp *m, stk unsafe.Pointer) {
   246  	const _STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000
   247  	thandle := stdcall6(_CreateThread, 0, 0x20000,
   248  		funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
   249  		_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
   250  	if thandle == 0 {
   251  		println("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")")
   252  		gothrow("runtime.newosproc")
   253  	}
   254  }
   255  
   256  // Called to initialize a new m (including the bootstrap m).
   257  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   258  func mpreinit(mp *m) {
   259  }
   260  
   261  // Called to initialize a new m (including the bootstrap m).
   262  // Called on the new thread, can not allocate memory.
   263  func minit() {
   264  	var thandle uintptr
   265  	stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
   266  	atomicstoreuintptr(&getg().m.thread, thandle)
   267  }
   268  
   269  // Called from dropm to undo the effect of an minit.
   270  func unminit() {
   271  	tp := &getg().m.thread
   272  	stdcall1(_CloseHandle, *tp)
   273  	*tp = 0
   274  }
   275  
   276  // Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
   277  type _KSYSTEM_TIME struct {
   278  	LowPart   uint32
   279  	High1Time int32
   280  	High2Time int32
   281  }
   282  
   283  const (
   284  	_INTERRUPT_TIME = 0x7ffe0008
   285  	_SYSTEM_TIME    = 0x7ffe0014
   286  )
   287  
   288  //go:nosplit
   289  func systime(addr uintptr) int64 {
   290  	timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
   291  
   292  	var t _KSYSTEM_TIME
   293  	for i := 1; i < 10000; i++ {
   294  		// these fields must be read in that order (see URL above)
   295  		t.High1Time = timeaddr.High1Time
   296  		t.LowPart = timeaddr.LowPart
   297  		t.High2Time = timeaddr.High2Time
   298  		if t.High1Time == t.High2Time {
   299  			return int64(t.High1Time)<<32 | int64(t.LowPart)
   300  		}
   301  		if (i % 100) == 0 {
   302  			osyield()
   303  		}
   304  	}
   305  	systemstack(func() {
   306  		gothrow("interrupt/system time is changing too fast")
   307  	})
   308  	return 0
   309  }
   310  
   311  //go:nosplit
   312  func unixnano() int64 {
   313  	return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
   314  }
   315  
   316  //go:nosplit
   317  func nanotime() int64 {
   318  	return systime(_INTERRUPT_TIME) * 100
   319  }
   320  
   321  // Calling stdcall on os stack.
   322  //go:nosplit
   323  func stdcall(fn stdFunction) uintptr {
   324  	gp := getg()
   325  	mp := gp.m
   326  	mp.libcall.fn = uintptr(unsafe.Pointer(fn))
   327  
   328  	if mp.profilehz != 0 {
   329  		// leave pc/sp for cpu profiler
   330  		mp.libcallg = gp
   331  		mp.libcallpc = getcallerpc(unsafe.Pointer(&fn))
   332  		// sp must be the last, because once async cpu profiler finds
   333  		// all three values to be non-zero, it will use them
   334  		mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
   335  	}
   336  	asmcgocall(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&mp.libcall))
   337  	mp.libcallsp = 0
   338  	return mp.libcall.r1
   339  }
   340  
   341  //go:nosplit
   342  func stdcall0(fn stdFunction) uintptr {
   343  	mp := getg().m
   344  	mp.libcall.n = 0
   345  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
   346  	return stdcall(fn)
   347  }
   348  
   349  //go:nosplit
   350  func stdcall1(fn stdFunction, a0 uintptr) uintptr {
   351  	mp := getg().m
   352  	mp.libcall.n = 1
   353  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   354  	return stdcall(fn)
   355  }
   356  
   357  //go:nosplit
   358  func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
   359  	mp := getg().m
   360  	mp.libcall.n = 2
   361  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   362  	return stdcall(fn)
   363  }
   364  
   365  //go:nosplit
   366  func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
   367  	mp := getg().m
   368  	mp.libcall.n = 3
   369  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   370  	return stdcall(fn)
   371  }
   372  
   373  //go:nosplit
   374  func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
   375  	mp := getg().m
   376  	mp.libcall.n = 4
   377  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   378  	return stdcall(fn)
   379  }
   380  
   381  //go:nosplit
   382  func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
   383  	mp := getg().m
   384  	mp.libcall.n = 5
   385  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   386  	return stdcall(fn)
   387  }
   388  
   389  //go:nosplit
   390  func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
   391  	mp := getg().m
   392  	mp.libcall.n = 6
   393  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   394  	return stdcall(fn)
   395  }
   396  
   397  //go:nosplit
   398  func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
   399  	mp := getg().m
   400  	mp.libcall.n = 7
   401  	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
   402  	return stdcall(fn)
   403  }
   404  
   405  // in sys_windows_386.s and sys_windows_amd64.s
   406  func usleep1(usec uint32)
   407  
   408  //go:nosplit
   409  func osyield() {
   410  	usleep1(1)
   411  }
   412  
   413  //go:nosplit
   414  func usleep(us uint32) {
   415  	// Have 1us units; want 100ns units.
   416  	usleep1(10 * us)
   417  }
   418  
   419  func issigpanic(code uint32) uint32 {
   420  	switch code {
   421  	default:
   422  		return 0
   423  	case _EXCEPTION_ACCESS_VIOLATION:
   424  	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
   425  	case _EXCEPTION_INT_OVERFLOW:
   426  	case _EXCEPTION_FLT_DENORMAL_OPERAND:
   427  	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
   428  	case _EXCEPTION_FLT_INEXACT_RESULT:
   429  	case _EXCEPTION_FLT_OVERFLOW:
   430  	case _EXCEPTION_FLT_UNDERFLOW:
   431  	case _EXCEPTION_BREAKPOINT:
   432  	}
   433  	return 1
   434  }
   435  
   436  func initsig() {
   437  	/*
   438  		// TODO(brainman): I don't think we need that bit of code
   439  		// following line keeps these functions alive at link stage
   440  		// if there's a better way please write it here
   441  		void *e = runtime·exceptiontramp;
   442  		void *f = runtime·firstcontinuetramp;
   443  		void *l = runtime·lastcontinuetramp;
   444  		USED(e);
   445  		USED(f);
   446  		USED(l);
   447  	*/
   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  	dosigprof(r, gp, mp)
   487  }
   488  
   489  func profileloop1() {
   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  }
   541  
   542  var (
   543  	badsignalmsg [100]byte
   544  	badsignallen int32
   545  )
   546  
   547  func setBadSignalMsg() {
   548  	const msg = "runtime: signal received on thread not created by Go.\n"
   549  	for i, c := range msg {
   550  		badsignalmsg[i] = byte(c)
   551  		badsignallen++
   552  	}
   553  }
   554  
   555  func crash() {
   556  	// TODO: This routine should do whatever is needed
   557  	// to make the Windows program abort/crash as it
   558  	// would if Go was not intercepting signals.
   559  	// On Unix the routine would remove the custom signal
   560  	// handler and then raise a signal (like SIGABRT).
   561  	// Something like that should happen here.
   562  	// It's okay to leave this empty for now: if crash returns
   563  	// the ordinary exit-after-panic happens.
   564  }