| // Copyright 2009 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| #include "runtime.h" |
| #include "os.h" |
| |
| #define stdcall stdcall_raw |
| |
| extern void *get_kernel_module(void); |
| |
| // Also referenced by external packages |
| void *CloseHandle; |
| void *ExitProcess; |
| void *GetStdHandle; |
| void *SetEvent; |
| void *WriteFile; |
| void *VirtualAlloc; |
| void *LoadLibraryEx; |
| void *GetProcAddress; |
| void *GetLastError; |
| |
| static void *CreateEvent; |
| static void *CreateThread; |
| static void *GetModuleHandle; |
| static void *WaitForSingleObject; |
| |
| static void* |
| get_proc_addr2(byte *base, byte *name) |
| { |
| byte *pe_header, *exports; |
| uint32 entries, *addr, *names, i; |
| uint16 *ordinals; |
| |
| pe_header = base+*(uint32*)(base+0x3c); |
| exports = base+*(uint32*)(pe_header+0x78); |
| entries = *(uint32*)(exports+0x18); |
| addr = (uint32*)(base+*(uint32*)(exports+0x1c)); |
| names = (uint32*)(base+*(uint32*)(exports+0x20)); |
| ordinals = (uint16*)(base+*(uint32*)(exports+0x24)); |
| for(i=0; i<entries; i++) { |
| byte *s = base+names[i]; |
| if(!strcmp(name, s)) |
| break; |
| } |
| if(i == entries) |
| return 0; |
| return base+addr[ordinals[i]]; |
| } |
| |
| void |
| osinit(void) |
| { |
| void *base; |
| |
| base = get_kernel_module(); |
| GetProcAddress = get_proc_addr2(base, (byte*)"GetProcAddress"); |
| LoadLibraryEx = get_proc_addr2(base, (byte*)"LoadLibraryExA"); |
| CloseHandle = get_proc_addr("kernel32.dll", "CloseHandle"); |
| CreateEvent = get_proc_addr("kernel32.dll", "CreateEventA"); |
| CreateThread = get_proc_addr("kernel32.dll", "CreateThread"); |
| ExitProcess = get_proc_addr("kernel32.dll", "ExitProcess"); |
| GetModuleHandle = get_proc_addr("kernel32.dll", "GetModuleHandleA"); |
| GetStdHandle = get_proc_addr("kernel32.dll", "GetStdHandle"); |
| SetEvent = get_proc_addr("kernel32.dll", "SetEvent"); |
| VirtualAlloc = get_proc_addr("kernel32.dll", "VirtualAlloc"); |
| WaitForSingleObject = get_proc_addr("kernel32.dll", "WaitForSingleObject"); |
| WriteFile = get_proc_addr("kernel32.dll", "WriteFile"); |
| GetLastError = get_proc_addr("kernel32.dll", "GetLastError"); |
| } |
| |
| // The arguments are strings. |
| void* |
| get_proc_addr(void *library, void *name) |
| { |
| void *base; |
| |
| base = stdcall(LoadLibraryEx, library, 0, 0); |
| return stdcall(GetProcAddress, base, name); |
| } |
| |
| void |
| mingw_goargs(void) |
| { |
| extern Slice os·Args; |
| extern Slice os·Envs; |
| |
| void *gcl, *clta, *ges; |
| uint16 *cmd, *env, **argv; |
| String *gargv; |
| String *genvv; |
| int32 i, argc, envc; |
| uint16 *envp; |
| |
| gcl = get_proc_addr("kernel32.dll", "GetCommandLineW"); |
| clta = get_proc_addr("shell32.dll", "CommandLineToArgvW"); |
| ges = get_proc_addr("kernel32.dll", "GetEnvironmentStringsW"); |
| |
| cmd = stdcall(gcl); |
| env = stdcall(ges); |
| argv = stdcall(clta, cmd, &argc); |
| |
| envc = 0; |
| for(envp=env; *envp; envc++) |
| envp += findnullw(envp)+1; |
| |
| gargv = malloc(argc*sizeof gargv[0]); |
| genvv = malloc(envc*sizeof genvv[0]); |
| |
| for(i=0; i<argc; i++) |
| gargv[i] = gostringw(argv[i]); |
| os·Args.array = (byte*)gargv; |
| os·Args.len = argc; |
| os·Args.cap = argc; |
| |
| envp = env; |
| for(i=0; i<envc; i++) { |
| genvv[i] = gostringw(envp); |
| envp += findnullw(envp)+1; |
| } |
| os·Envs.array = (byte*)genvv; |
| os·Envs.len = envc; |
| os·Envs.cap = envc; |
| } |
| |
| void |
| exit(int32 code) |
| { |
| stdcall(ExitProcess, code); |
| } |
| |
| int32 |
| write(int32 fd, void *buf, int32 n) |
| { |
| void *handle; |
| uint32 written; |
| |
| written = 0; |
| switch(fd) { |
| case 1: |
| handle = stdcall(GetStdHandle, -11); |
| break; |
| case 2: |
| handle = stdcall(GetStdHandle, -12); |
| break; |
| default: |
| return -1; |
| } |
| stdcall(WriteFile, handle, buf, n, &written, 0); |
| return written; |
| } |
| |
| void* |
| get_symdat_addr(void) |
| { |
| byte *mod, *p; |
| uint32 peh, add; |
| uint16 oph; |
| |
| mod = stdcall(GetModuleHandle, 0); |
| peh = *(uint32*)(mod+0x3c); |
| p = mod+peh+4; |
| oph = *(uint16*)(p+0x10); |
| p += 0x14+oph; |
| while(strcmp(p, (byte*)".symdat")) |
| p += 40; |
| add = *(uint32*)(p+0x0c); |
| return mod+add; |
| } |
| |
| // Thread-safe allocation of an event. |
| static void |
| initevent(void **pevent) |
| { |
| void *event; |
| |
| event = stdcall(CreateEvent, 0, 0, 0, 0); |
| if(!casp(pevent, 0, event)) { |
| // Someone else filled it in. Use theirs. |
| stdcall(CloseHandle, event); |
| } |
| } |
| |
| static void |
| eventlock(Lock *l) |
| { |
| // Allocate event if needed. |
| if(l->event == 0) |
| initevent(&l->event); |
| |
| if(xadd(&l->key, 1) > 1) // someone else has it; wait |
| stdcall(WaitForSingleObject, l->event, -1); |
| } |
| |
| static void |
| eventunlock(Lock *l) |
| { |
| if(xadd(&l->key, -1) > 0) // someone else is waiting |
| stdcall(SetEvent, l->event); |
| } |
| |
| void |
| lock(Lock *l) |
| { |
| if(m->locks < 0) |
| throw("lock count"); |
| m->locks++; |
| eventlock(l); |
| } |
| |
| void |
| unlock(Lock *l) |
| { |
| m->locks--; |
| if(m->locks < 0) |
| throw("lock count"); |
| eventunlock(l); |
| } |
| |
| void |
| destroylock(Lock *l) |
| { |
| } |
| |
| void |
| noteclear(Note *n) |
| { |
| eventlock(&n->lock); |
| } |
| |
| void |
| notewakeup(Note *n) |
| { |
| eventunlock(&n->lock); |
| } |
| |
| void |
| notesleep(Note *n) |
| { |
| eventlock(&n->lock); |
| eventunlock(&n->lock); // Let other sleepers find out too. |
| } |
| |
| void |
| newosproc(M *m, G *g, void *stk, void (*fn)(void)) |
| { |
| struct { |
| void *args; |
| void *event_handle; |
| } param = { &m }; |
| extern uint32 threadstart(void *p); |
| |
| USED(g, stk, fn); |
| param.event_handle = stdcall(CreateEvent, 0, 0, 0, 0); |
| stdcall(CreateThread, 0, 0, threadstart, ¶m, 0, 0); |
| stdcall(WaitForSingleObject, param.event_handle, -1); |
| stdcall(CloseHandle, param.event_handle); |
| } |
| |
| // Called to initialize a new m (including the bootstrap m). |
| void |
| minit(void) |
| { |
| } |