Commit 9d7e3934 authored by Alex Brainman's avatar Alex Brainman

syscall: delay load of dll functions until they are called

Before this change, syscall package would load
all dlls used anywhere in the go tree on startup.
For example, this program:

package main

import "fmt"

func main() {
       fmt.Printf("Hello world\n")
}

would load these dlls

kernel32.dll
advapi32.dll
shell32.dll
wsock32.dll
ws2_32.dll
dnsapi.dll
iphlpapi.dll

Most of these dlls are network related and are not used
in this program. Now the same program loads only

kernel32.dll
shell32.dll

This decreases start times somewhat.

This also relaxes the rules of which dlls can be included
in the standard library. We could now include system calls
that are not available on all versions of Windows, because
we could decide if we should call them during runtime.

R=rsc, vcc.163
CC=golang-dev
https://golang.org/cl/4815046
parent be96fa5a
......@@ -23,6 +23,7 @@ zwinapi.go: winapi.go
| sed '/^import/a \
import "syscall"' \
| sed 's/Syscall/syscall.Syscall/' \
| sed 's/NewLazyDLL/syscall.NewLazyDLL/' \
| sed 's/EINVAL/syscall.EINVAL/' \
| gofmt \
> $@
......@@ -5,26 +5,9 @@
package main
import (
"syscall"
"unsafe"
)
func loadDll(fname string) syscall.Handle {
h, e := syscall.LoadLibrary(fname)
if e != 0 {
abortf("LoadLibrary(%s) failed with err=%d.\n", fname, e)
}
return h
}
func getSysProcAddr(m syscall.Handle, pname string) uintptr {
p, e := syscall.GetProcAddress(m, pname)
if e != 0 {
abortf("GetProcAddress(%s) failed with err=%d.\n", pname, e)
}
return uintptr(p)
}
type Wndclassex struct {
Size uint32
Style uint32
......
......@@ -7,29 +7,29 @@ import "unsafe"
import "syscall"
var (
modkernel32 = loadDll("kernel32.dll")
moduser32 = loadDll("user32.dll")
procGetModuleHandleW = getSysProcAddr(modkernel32, "GetModuleHandleW")
procRegisterClassExW = getSysProcAddr(moduser32, "RegisterClassExW")
procCreateWindowExW = getSysProcAddr(moduser32, "CreateWindowExW")
procDefWindowProcW = getSysProcAddr(moduser32, "DefWindowProcW")
procDestroyWindow = getSysProcAddr(moduser32, "DestroyWindow")
procPostQuitMessage = getSysProcAddr(moduser32, "PostQuitMessage")
procShowWindow = getSysProcAddr(moduser32, "ShowWindow")
procUpdateWindow = getSysProcAddr(moduser32, "UpdateWindow")
procGetMessageW = getSysProcAddr(moduser32, "GetMessageW")
procTranslateMessage = getSysProcAddr(moduser32, "TranslateMessage")
procDispatchMessageW = getSysProcAddr(moduser32, "DispatchMessageW")
procLoadIconW = getSysProcAddr(moduser32, "LoadIconW")
procLoadCursorW = getSysProcAddr(moduser32, "LoadCursorW")
procSetCursor = getSysProcAddr(moduser32, "SetCursor")
procSendMessageW = getSysProcAddr(moduser32, "SendMessageW")
procPostMessageW = getSysProcAddr(moduser32, "PostMessageW")
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
moduser32 = syscall.NewLazyDLL("user32.dll")
procGetModuleHandleW = modkernel32.NewProc("GetModuleHandleW")
procRegisterClassExW = moduser32.NewProc("RegisterClassExW")
procCreateWindowExW = moduser32.NewProc("CreateWindowExW")
procDefWindowProcW = moduser32.NewProc("DefWindowProcW")
procDestroyWindow = moduser32.NewProc("DestroyWindow")
procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
procShowWindow = moduser32.NewProc("ShowWindow")
procUpdateWindow = moduser32.NewProc("UpdateWindow")
procGetMessageW = moduser32.NewProc("GetMessageW")
procTranslateMessage = moduser32.NewProc("TranslateMessage")
procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
procLoadIconW = moduser32.NewProc("LoadIconW")
procLoadCursorW = moduser32.NewProc("LoadCursorW")
procSetCursor = moduser32.NewProc("SetCursor")
procSendMessageW = moduser32.NewProc("SendMessageW")
procPostMessageW = moduser32.NewProc("PostMessageW")
)
func GetModuleHandle(modname *uint16) (handle uint32, errno int) {
r0, _, e1 := syscall.Syscall(procGetModuleHandleW, 1, uintptr(unsafe.Pointer(modname)), 0, 0)
r0, _, e1 := syscall.Syscall(procGetModuleHandleW.Addr(), 1, uintptr(unsafe.Pointer(modname)), 0, 0)
handle = uint32(r0)
if handle == 0 {
if e1 != 0 {
......@@ -44,7 +44,7 @@ func GetModuleHandle(modname *uint16) (handle uint32, errno int) {
}
func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) {
r0, _, e1 := syscall.Syscall(procRegisterClassExW, 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
r0, _, e1 := syscall.Syscall(procRegisterClassExW.Addr(), 1, uintptr(unsafe.Pointer(wndclass)), 0, 0)
atom = uint16(r0)
if atom == 0 {
if e1 != 0 {
......@@ -59,7 +59,7 @@ func RegisterClassEx(wndclass *Wndclassex) (atom uint16, errno int) {
}
func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style uint32, x int32, y int32, width int32, height int32, wndparent uint32, menu uint32, instance uint32, param uintptr) (hwnd uint32, errno int) {
r0, _, e1 := syscall.Syscall12(procCreateWindowExW, 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(classname)), uintptr(unsafe.Pointer(windowname)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(wndparent), uintptr(menu), uintptr(instance), uintptr(param))
hwnd = uint32(r0)
if hwnd == 0 {
if e1 != 0 {
......@@ -74,13 +74,13 @@ func CreateWindowEx(exstyle uint32, classname *uint16, windowname *uint16, style
}
func DefWindowProc(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
r0, _, _ := syscall.Syscall6(procDefWindowProcW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
r0, _, _ := syscall.Syscall6(procDefWindowProcW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
lresult = int32(r0)
return
}
func DestroyWindow(hwnd uint32) (errno int) {
r1, _, e1 := syscall.Syscall(procDestroyWindow, 1, uintptr(hwnd), 0, 0)
r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
errno = int(e1)
......@@ -94,18 +94,18 @@ func DestroyWindow(hwnd uint32) (errno int) {
}
func PostQuitMessage(exitcode int32) {
syscall.Syscall(procPostQuitMessage, 1, uintptr(exitcode), 0, 0)
syscall.Syscall(procPostQuitMessage.Addr(), 1, uintptr(exitcode), 0, 0)
return
}
func ShowWindow(hwnd uint32, cmdshow int32) (wasvisible bool) {
r0, _, _ := syscall.Syscall(procShowWindow, 2, uintptr(hwnd), uintptr(cmdshow), 0)
r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
wasvisible = bool(r0 != 0)
return
}
func UpdateWindow(hwnd uint32) (errno int) {
r1, _, e1 := syscall.Syscall(procUpdateWindow, 1, uintptr(hwnd), 0, 0)
r1, _, e1 := syscall.Syscall(procUpdateWindow.Addr(), 1, uintptr(hwnd), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
errno = int(e1)
......@@ -119,7 +119,7 @@ func UpdateWindow(hwnd uint32) (errno int) {
}
func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, errno int) {
r0, _, e1 := syscall.Syscall6(procGetMessageW, 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax), 0, 0)
ret = int32(r0)
if ret == -1 {
if e1 != 0 {
......@@ -134,19 +134,19 @@ func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32)
}
func TranslateMessage(msg *Msg) (done bool) {
r0, _, _ := syscall.Syscall(procTranslateMessage, 1, uintptr(unsafe.Pointer(msg)), 0, 0)
r0, _, _ := syscall.Syscall(procTranslateMessage.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
done = bool(r0 != 0)
return
}
func DispatchMessage(msg *Msg) (ret int32) {
r0, _, _ := syscall.Syscall(procDispatchMessageW, 1, uintptr(unsafe.Pointer(msg)), 0, 0)
r0, _, _ := syscall.Syscall(procDispatchMessageW.Addr(), 1, uintptr(unsafe.Pointer(msg)), 0, 0)
ret = int32(r0)
return
}
func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) {
r0, _, e1 := syscall.Syscall(procLoadIconW, 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(iconname)), 0)
icon = uint32(r0)
if icon == 0 {
if e1 != 0 {
......@@ -161,7 +161,7 @@ func LoadIcon(instance uint32, iconname *uint16) (icon uint32, errno int) {
}
func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int) {
r0, _, e1 := syscall.Syscall(procLoadCursorW, 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(instance), uintptr(unsafe.Pointer(cursorname)), 0)
cursor = uint32(r0)
if cursor == 0 {
if e1 != 0 {
......@@ -176,7 +176,7 @@ func LoadCursor(instance uint32, cursorname *uint16) (cursor uint32, errno int)
}
func SetCursor(cursor uint32) (precursor uint32, errno int) {
r0, _, e1 := syscall.Syscall(procSetCursor, 1, uintptr(cursor), 0, 0)
r0, _, e1 := syscall.Syscall(procSetCursor.Addr(), 1, uintptr(cursor), 0, 0)
precursor = uint32(r0)
if precursor == 0 {
if e1 != 0 {
......@@ -191,13 +191,13 @@ func SetCursor(cursor uint32) (precursor uint32, errno int) {
}
func SendMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (lresult int32) {
r0, _, _ := syscall.Syscall6(procSendMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
lresult = int32(r0)
return
}
func PostMessage(hwnd uint32, msg uint32, wparam int32, lparam int32) (errno int) {
r1, _, e1 := syscall.Syscall6(procPostMessageW, 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
r1, _, e1 := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(msg), uintptr(wparam), uintptr(lparam), 0, 0)
if int(r1) == 0 {
if e1 != 0 {
errno = int(e1)
......
......@@ -96,7 +96,7 @@ while(<>) {
my $modvname = "mod$modname";
if($modnames !~ /$modname/) {
$modnames .= ".$modname";
$mods .= "\t$modvname = loadDll(\"$modname.dll\")\n";
$mods .= "\t$modvname = NewLazyDLL(\"$modname.dll\")\n";
}
# System call name.
......@@ -116,7 +116,7 @@ while(<>) {
my $strconvfunc = $sysname !~ /W$/ ? "StringBytePtr" : "StringToUTF16Ptr";
# Winapi proc address variable.
$vars .= sprintf "\t%s = getSysProcAddr(%s, \"%s\")\n", $sysvarname, $modvname, $sysname;
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
# Go function header.
$out = join(', ', @out);
......@@ -191,7 +191,7 @@ while(<>) {
# Actual call.
my $args = join(', ', @args);
my $call = "$asm($sysvarname, $nargs, $args)";
my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
# Assign return values.
my $body = "";
......
......@@ -7,6 +7,7 @@
package syscall
import (
"sync"
"unsafe"
"utf16"
)
......@@ -84,20 +85,64 @@ func Syscall12(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 ui
func loadlibraryex(filename uintptr) (handle uintptr)
func getprocaddress(handle uintptr, procname uintptr) (proc uintptr)
func loadDll(fname string) uintptr {
m := loadlibraryex(uintptr(unsafe.Pointer(StringBytePtr(fname))))
if m == 0 {
panic("syscall: could not LoadLibraryEx " + fname)
// A LazyDLL implements access to a single DLL.
// It will delay the load of the DLL until the first
// call to its Handle method or to one of its
// LazyProc's Addr method.
type LazyDLL struct {
sync.Mutex
Name string
h uintptr // module handle once dll is loaded
}
// Handle returns d's module handle.
func (d *LazyDLL) Handle() uintptr {
if d.h == 0 {
d.Lock()
defer d.Unlock()
if d.h == 0 {
d.h = loadlibraryex(uintptr(unsafe.Pointer(StringBytePtr(d.Name))))
if d.h == 0 {
panic("syscall: could not LoadLibraryEx " + d.Name)
}
}
}
return m
return d.h
}
// NewProc returns a LazyProc for accessing the named procedure in the DLL d.
func (d *LazyDLL) NewProc(name string) *LazyProc {
return &LazyProc{dll: d, Name: name}
}
func getSysProcAddr(m uintptr, pname string) uintptr {
p := getprocaddress(m, uintptr(unsafe.Pointer(StringBytePtr(pname))))
if p == 0 {
panic("syscall: could not GetProcAddress for " + pname)
// NewLazyDLL creates new LazyDLL associated with dll file.
func NewLazyDLL(name string) *LazyDLL {
return &LazyDLL{Name: name}
}
// A LazyProc implements access to a procedure inside a LazyDLL.
// It delays the lookup until the Addr method is called.
type LazyProc struct {
sync.Mutex
Name string
dll *LazyDLL
addr uintptr
}
// Addr returns the address of the procedure represented by s.
// The return value can be passed to Syscall to run the procedure.
func (s *LazyProc) Addr() uintptr {
if s.addr == 0 {
s.Lock()
defer s.Unlock()
if s.addr == 0 {
s.addr = getprocaddress(s.dll.Handle(), uintptr(unsafe.Pointer(StringBytePtr(s.Name))))
if s.addr == 0 {
panic("syscall: could not GetProcAddress for " + s.Name)
}
}
}
return p
return s.addr
}
func Getpagesize() int { return 4096 }
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment