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