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 }