github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/os_windows.c (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  #include "runtime.h"
     6  #include "type.h"
     7  #include "defs_GOOS_GOARCH.h"
     8  #include "os_GOOS.h"
     9  
    10  #pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
    11  #pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
    12  #pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
    13  #pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
    14  #pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
    15  #pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll"
    16  #pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll"
    17  #pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
    18  #pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
    19  #pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
    20  #pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
    21  #pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
    22  #pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
    23  #pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll"
    24  #pragma dynimport runtime·GetSystemTimeAsFileTime GetSystemTimeAsFileTime "kernel32.dll"
    25  #pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
    26  #pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
    27  #pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
    28  #pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
    29  #pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
    30  #pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
    31  #pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
    32  #pragma dynimport runtime·Sleep Sleep "kernel32.dll"
    33  #pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
    34  #pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
    35  #pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
    36  #pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
    37  #pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
    38  
    39  extern void *runtime·NtWaitForSingleObject;
    40  
    41  extern void *runtime·CloseHandle;
    42  extern void *runtime·CreateEvent;
    43  extern void *runtime·CreateThread;
    44  extern void *runtime·CreateWaitableTimer;
    45  extern void *runtime·CryptAcquireContextW;
    46  extern void *runtime·CryptGenRandom;
    47  extern void *runtime·CryptReleaseContext;
    48  extern void *runtime·DuplicateHandle;
    49  extern void *runtime·ExitProcess;
    50  extern void *runtime·FreeEnvironmentStringsW;
    51  extern void *runtime·GetEnvironmentStringsW;
    52  extern void *runtime·GetProcAddress;
    53  extern void *runtime·GetStdHandle;
    54  extern void *runtime·GetSystemInfo;
    55  extern void *runtime·GetSystemTimeAsFileTime;
    56  extern void *runtime·GetThreadContext;
    57  extern void *runtime·LoadLibrary;
    58  extern void *runtime·ResumeThread;
    59  extern void *runtime·SetConsoleCtrlHandler;
    60  extern void *runtime·SetEvent;
    61  extern void *runtime·SetThreadPriority;
    62  extern void *runtime·SetWaitableTimer;
    63  extern void *runtime·Sleep;
    64  extern void *runtime·SuspendThread;
    65  extern void *runtime·timeBeginPeriod;
    66  extern void *runtime·WaitForSingleObject;
    67  extern void *runtime·WriteFile;
    68  
    69  static int32
    70  getproccount(void)
    71  {
    72  	SystemInfo info;
    73  
    74  	runtime·stdcall(runtime·GetSystemInfo, 1, &info);
    75  	return info.dwNumberOfProcessors;
    76  }
    77  
    78  void
    79  runtime·osinit(void)
    80  {
    81  	// -1 = current process, -2 = current thread
    82  	runtime·stdcall(runtime·DuplicateHandle, 7,
    83  		(uintptr)-1, (uintptr)-2, (uintptr)-1, &m->thread,
    84  		(uintptr)0, (uintptr)0, (uintptr)DUPLICATE_SAME_ACCESS);
    85  	runtime·stdcall(runtime·SetConsoleCtrlHandler, 2, runtime·ctrlhandler, (uintptr)1);
    86  	runtime·stdcall(runtime·timeBeginPeriod, 1, (uintptr)1);
    87  	runtime·ncpu = getproccount();
    88  }
    89  
    90  void
    91  runtime·get_random_data(byte **rnd, int32 *rnd_len)
    92  {
    93  	uintptr handle;
    94  	*rnd = nil;
    95  	*rnd_len = 0;
    96  	if(runtime·stdcall(runtime·CryptAcquireContextW, 5, &handle, nil, nil,
    97  			   (uintptr)1 /* PROV_RSA_FULL */,
    98  			   (uintptr)0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
    99  		static byte random_data[HashRandomBytes];
   100  		if(runtime·stdcall(runtime·CryptGenRandom, 3, handle, (uintptr)HashRandomBytes, random_data)) {
   101  			*rnd = random_data;
   102  			*rnd_len = HashRandomBytes;
   103  		}
   104  		runtime·stdcall(runtime·CryptReleaseContext, 2, handle, (uintptr)0);
   105  	}
   106  }
   107  
   108  void
   109  runtime·goenvs(void)
   110  {
   111  	extern Slice syscall·envs;
   112  
   113  	uint16 *env;
   114  	String *s;
   115  	int32 i, n;
   116  	uint16 *p;
   117  
   118  	env = runtime·stdcall(runtime·GetEnvironmentStringsW, 0);
   119  
   120  	n = 0;
   121  	for(p=env; *p; n++)
   122  		p += runtime·findnullw(p)+1;
   123  
   124  	s = runtime·malloc(n*sizeof s[0]);
   125  
   126  	p = env;
   127  	for(i=0; i<n; i++) {
   128  		s[i] = runtime·gostringw(p);
   129  		p += runtime·findnullw(p)+1;
   130  	}
   131  	syscall·envs.array = (byte*)s;
   132  	syscall·envs.len = n;
   133  	syscall·envs.cap = n;
   134  
   135  	runtime·stdcall(runtime·FreeEnvironmentStringsW, 1, env);
   136  }
   137  
   138  void
   139  runtime·exit(int32 code)
   140  {
   141  	runtime·stdcall(runtime·ExitProcess, 1, (uintptr)code);
   142  }
   143  
   144  int32
   145  runtime·write(int32 fd, void *buf, int32 n)
   146  {
   147  	void *handle;
   148  	uint32 written;
   149  
   150  	written = 0;
   151  	switch(fd) {
   152  	case 1:
   153  		handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-11);
   154  		break;
   155  	case 2:
   156  		handle = runtime·stdcall(runtime·GetStdHandle, 1, (uintptr)-12);
   157  		break;
   158  	default:
   159  		return -1;
   160  	}
   161  	runtime·stdcall(runtime·WriteFile, 5, handle, buf, (uintptr)n, &written, (uintptr)0);
   162  	return written;
   163  }
   164  
   165  #define INFINITE ((uintptr)0xFFFFFFFF)
   166  
   167  int32
   168  runtime·semasleep(int64 ns)
   169  {
   170  	uintptr ms;
   171  
   172  	if(ns < 0)
   173  		ms = INFINITE;
   174  	else if(ns/1000000 > 0x7fffffffLL)
   175  		ms = 0x7fffffff;
   176  	else {
   177  		ms = ns/1000000;
   178  		if(ms == 0)
   179  			ms = 1;
   180  	}
   181  	if(runtime·stdcall(runtime·WaitForSingleObject, 2, m->waitsema, ms) != 0)
   182  		return -1;  // timeout
   183  	return 0;
   184  }
   185  
   186  void
   187  runtime·semawakeup(M *mp)
   188  {
   189  	runtime·stdcall(runtime·SetEvent, 1, mp->waitsema);
   190  }
   191  
   192  uintptr
   193  runtime·semacreate(void)
   194  {
   195  	return (uintptr)runtime·stdcall(runtime·CreateEvent, 4, (uintptr)0, (uintptr)0, (uintptr)0, (uintptr)0);
   196  }
   197  
   198  #define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
   199  
   200  void
   201  runtime·newosproc(M *mp, void *stk)
   202  {
   203  	void *thandle;
   204  
   205  	USED(stk);
   206  
   207  	thandle = runtime·stdcall(runtime·CreateThread, 6,
   208  		nil, (uintptr)0x20000, runtime·tstart_stdcall, mp,
   209  		STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
   210  	if(thandle == nil) {
   211  		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
   212  		runtime·throw("runtime.newosproc");
   213  	}
   214  	runtime·atomicstorep(&mp->thread, thandle);
   215  }
   216  
   217  // Called to initialize a new m (including the bootstrap m).
   218  // Called on the parent thread (main thread in case of bootstrap), can allocate memory.
   219  void
   220  runtime·mpreinit(M *mp)
   221  {
   222  	USED(mp);
   223  }
   224  
   225  // Called to initialize a new m (including the bootstrap m).
   226  // Called on the new thread, can not allocate memory.
   227  void
   228  runtime·minit(void)
   229  {
   230  	runtime·install_exception_handler();
   231  }
   232  
   233  // Called from dropm to undo the effect of an minit.
   234  void
   235  runtime·unminit(void)
   236  {
   237  	runtime·remove_exception_handler();
   238  }
   239  
   240  int64
   241  runtime·nanotime(void)
   242  {
   243  	int64 filetime;
   244  
   245  	runtime·stdcall(runtime·GetSystemTimeAsFileTime, 1, &filetime);
   246  
   247  	// Filetime is 100s of nanoseconds since January 1, 1601.
   248  	// Convert to nanoseconds since January 1, 1970.
   249  	return (filetime - 116444736000000000LL) * 100LL;
   250  }
   251  
   252  void
   253  time·now(int64 sec, int32 usec)
   254  {
   255  	int64 ns;
   256  
   257  	ns = runtime·nanotime();
   258  	sec = ns / 1000000000LL;
   259  	usec = ns - sec * 1000000000LL;
   260  	FLUSH(&sec);
   261  	FLUSH(&usec);
   262  }
   263  
   264  // Calling stdcall on os stack.
   265  #pragma textflag 7
   266  void *
   267  runtime·stdcall(void *fn, int32 count, ...)
   268  {
   269  	WinCall c;
   270  
   271  	c.fn = fn;
   272  	c.n = count;
   273  	c.args = (uintptr*)&count + 1;
   274  	runtime·asmcgocall(runtime·asmstdcall, &c);
   275  	return (void*)c.r1;
   276  }
   277  
   278  uint32
   279  runtime·issigpanic(uint32 code)
   280  {
   281  	switch(code) {
   282  	case EXCEPTION_ACCESS_VIOLATION:
   283  	case EXCEPTION_INT_DIVIDE_BY_ZERO:
   284  	case EXCEPTION_INT_OVERFLOW:
   285  	case EXCEPTION_FLT_DENORMAL_OPERAND:
   286  	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
   287  	case EXCEPTION_FLT_INEXACT_RESULT:
   288  	case EXCEPTION_FLT_OVERFLOW:
   289  	case EXCEPTION_FLT_UNDERFLOW:
   290  		return 1;
   291  	}
   292  	return 0;
   293  }
   294  
   295  void
   296  runtime·sigpanic(void)
   297  {
   298  	switch(g->sig) {
   299  	case EXCEPTION_ACCESS_VIOLATION:
   300  		if(g->sigcode1 < 0x1000) {
   301  			if(g->sigpc == 0)
   302  				runtime·panicstring("call of nil func value");
   303  			runtime·panicstring("invalid memory address or nil pointer dereference");
   304  		}
   305  		runtime·printf("unexpected fault address %p\n", g->sigcode1);
   306  		runtime·throw("fault");
   307  	case EXCEPTION_INT_DIVIDE_BY_ZERO:
   308  		runtime·panicstring("integer divide by zero");
   309  	case EXCEPTION_INT_OVERFLOW:
   310  		runtime·panicstring("integer overflow");
   311  	case EXCEPTION_FLT_DENORMAL_OPERAND:
   312  	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
   313  	case EXCEPTION_FLT_INEXACT_RESULT:
   314  	case EXCEPTION_FLT_OVERFLOW:
   315  	case EXCEPTION_FLT_UNDERFLOW:
   316  		runtime·panicstring("floating point error");
   317  	}
   318  	runtime·throw("fault");
   319  }
   320  
   321  extern void *runtime·sigtramp;
   322  
   323  void
   324  runtime·initsig(void)
   325  {
   326  	// following line keeps sigtramp alive at link stage
   327  	// if there's a better way please write it here
   328  	void *p = runtime·sigtramp;
   329  	USED(p);
   330  }
   331  
   332  uint32
   333  runtime·ctrlhandler1(uint32 type)
   334  {
   335  	int32 s;
   336  
   337  	switch(type) {
   338  	case CTRL_C_EVENT:
   339  	case CTRL_BREAK_EVENT:
   340  		s = SIGINT;
   341  		break;
   342  	default:
   343  		return 0;
   344  	}
   345  
   346  	if(runtime·sigsend(s))
   347  		return 1;
   348  	runtime·exit(2);	// SIGINT, SIGTERM, etc
   349  	return 0;
   350  }
   351  
   352  extern void runtime·dosigprof(Context *r, G *gp);
   353  extern void runtime·profileloop(void);
   354  static void *profiletimer;
   355  
   356  static void
   357  profilem(M *mp)
   358  {
   359  	extern M runtime·m0;
   360  	extern uint32 runtime·tls0[];
   361  	byte rbuf[sizeof(Context)+15];
   362  	Context *r;
   363  	void *tls;
   364  	G *gp;
   365  
   366  	tls = mp->tls;
   367  	if(mp == &runtime·m0)
   368  		tls = runtime·tls0;
   369  	gp = *(G**)tls;
   370  
   371  	if(gp != nil && gp != mp->g0 && gp->status != Gsyscall) {
   372  		// align Context to 16 bytes
   373  		r = (Context*)((uintptr)(&rbuf[15]) & ~15);
   374  		r->ContextFlags = CONTEXT_CONTROL;
   375  		runtime·stdcall(runtime·GetThreadContext, 2, mp->thread, r);
   376  		runtime·dosigprof(r, gp);
   377  	}
   378  }
   379  
   380  void
   381  runtime·profileloop1(void)
   382  {
   383  	M *mp, *allm;
   384  	void *thread;
   385  
   386  	runtime·stdcall(runtime·SetThreadPriority, 2,
   387  		(uintptr)-2, (uintptr)THREAD_PRIORITY_HIGHEST);
   388  
   389  	for(;;) {
   390  		runtime·stdcall(runtime·WaitForSingleObject, 2, profiletimer, (uintptr)-1);
   391  		allm = runtime·atomicloadp(&runtime·allm);
   392  		for(mp = allm; mp != nil; mp = mp->alllink) {
   393  			thread = runtime·atomicloadp(&mp->thread);
   394  			if(thread == nil)
   395  				continue;
   396  			runtime·stdcall(runtime·SuspendThread, 1, thread);
   397  			if(mp->profilehz != 0)
   398  				profilem(mp);
   399  			runtime·stdcall(runtime·ResumeThread, 1, thread);
   400  		}
   401  	}
   402  }
   403  
   404  void
   405  runtime·resetcpuprofiler(int32 hz)
   406  {
   407  	static Lock lock;
   408  	void *timer, *thread;
   409  	int32 ms;
   410  	int64 due;
   411  
   412  	runtime·lock(&lock);
   413  	if(profiletimer == nil) {
   414  		timer = runtime·stdcall(runtime·CreateWaitableTimer, 3, nil, nil, nil);
   415  		runtime·atomicstorep(&profiletimer, timer);
   416  		thread = runtime·stdcall(runtime·CreateThread, 6,
   417  			nil, nil, runtime·profileloop, nil, nil, nil);
   418  		runtime·stdcall(runtime·CloseHandle, 1, thread);
   419  	}
   420  	runtime·unlock(&lock);
   421  
   422  	ms = 0;
   423  	due = 1LL<<63;
   424  	if(hz > 0) {
   425  		ms = 1000 / hz;
   426  		if(ms == 0)
   427  			ms = 1;
   428  		due = ms * -10000;
   429  	}
   430  	runtime·stdcall(runtime·SetWaitableTimer, 6,
   431  		profiletimer, &due, (uintptr)ms, nil, nil, nil);
   432  	runtime·atomicstore((uint32*)&m->profilehz, hz);
   433  }
   434  
   435  void
   436  os·sigpipe(void)
   437  {
   438  	runtime·throw("too many writes on closed pipe");
   439  }
   440  
   441  uintptr
   442  runtime·memlimit(void)
   443  {
   444  	return 0;
   445  }
   446  
   447  void
   448  runtime·setprof(bool on)
   449  {
   450  	USED(on);
   451  }
   452  
   453  int8 runtime·badcallbackmsg[] = "runtime: cgo callback on thread not created by Go.\n";
   454  int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1;
   455  
   456  int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
   457  int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
   458  
   459  void
   460  runtime·crash(void)
   461  {
   462  	// TODO: This routine should do whatever is needed
   463  	// to make the Windows program abort/crash as it
   464  	// would if Go was not intercepting signals.
   465  	// On Unix the routine would remove the custom signal
   466  	// handler and then raise a signal (like SIGABRT).
   467  	// Something like that should happen here.
   468  	// It's okay to leave this empty for now: if crash returns
   469  	// the ordinary exit-after-panic happens.
   470  }