[PATCH v2] Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ws2_32.dll is used by limited subset of git commands, such as pull,
push, fetch, send-email, ... By looking up functions that we need
at runtime, we can avoid the startup costs of this DLL.
As a result, we can remove static dependency on advapi32.dll too.

A call to "git status" loaded

before:  8 DLL
after:   4 DLL

Signed-off-by: Michael Lukashov <michael.lukashov@xxxxxxxxx>
---
 Makefile       |    1 -
 compat/bswap.h |   30 +++++++++
 compat/mingw.c |  193 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 compat/mingw.h |   49 +++++++++++++-
 4 files changed, 265 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index af08c8f..4a79eaa 100644
--- a/Makefile
+++ b/Makefile
@@ -1041,7 +1041,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\"
 	COMPAT_OBJS += compat/mingw.o compat/fnmatch/fnmatch.o compat/winansi.o \
 		compat/win32/pthread.o
-	EXTLIBS += -lws2_32
 	PTHREAD_LIBS =
 	X = .exe
 ifneq (,$(wildcard ../THIS_IS_MSYSGIT))
diff --git a/compat/bswap.h b/compat/bswap.h
index f3b8c44..08aea39 100644
--- a/compat/bswap.h
+++ b/compat/bswap.h
@@ -1,3 +1,6 @@
+#ifndef BSWAP_H
+#define BSWAP_H
+
 /*
  * Let's make sure we always have a sane definition for ntohl()/htonl().
  * Some libraries define those as a function call, just to perform byte
@@ -17,6 +20,12 @@ static inline uint32_t default_swab32(uint32_t val)
 		((val & 0x000000ff) << 24));
 }
 
+static inline uint16_t default_swab16(uint16_t val)
+{
+	return (((val & 0xff00) >>  8) |
+		((val & 0x00ff) << 8));
+}
+
 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
 
 #define bswap32(x) ({ \
@@ -28,11 +37,21 @@ static inline uint32_t default_swab32(uint32_t val)
 	} \
 	__res; })
 
+#define bswap16(x) ({ \
+	uint16_t __res; \
+	if (__builtin_constant_p(x)) { \
+		__res = default_swab16(x); \
+	} else { \
+		__asm__("xchgb %b0, %h0" : "=q" (__res) : "0" ((uint16_t)(x))); \
+	} \
+	__res; })
+
 #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
 
 #include <stdlib.h>
 
 #define bswap32(x) _byteswap_ulong(x)
+#define bswap16(x) _byteswap_ushort(x)
 
 #endif
 
@@ -44,3 +63,14 @@ static inline uint32_t default_swab32(uint32_t val)
 #define htonl(x) bswap32(x)
 
 #endif
+
+#ifdef bswap16
+
+#undef ntohs
+#undef htons
+#define ntohs(x) bswap16(x)
+#define htons(x) bswap16(x)
+
+#endif
+
+#endif
diff --git a/compat/mingw.c b/compat/mingw.c
index ab65f77..484cf7c 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -891,6 +891,172 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+static HMODULE ws2_32_dll = NULL;
+static LPFN_INET_NTOA ws2_32_inet_ntoa;
+static LPFN_CONNECT ws2_32_connect;
+static LPFN_SELECT ws2_32_select;
+static LPFN_CLOSESOCKET ws2_32_closesocket;
+static LPFN_GETSERVBYPORT ws2_32_getservbyport;
+static LPFN_GETSERVBYNAME ws2_32_getservbyname;
+static LPFN_GETHOSTBYADDR ws2_32_gethostbyaddr;
+static LPFN_GETHOSTNAME ws2_32_gethostname;
+static LPFN_GETHOSTBYNAME ws2_32_gethostbyname;
+static LPFN_WSASTARTUP ws2_32_WSAStartup;
+static LPFN_WSACLEANUP ws2_32_WSACleanup;
+static LPFN_WSAGETLASTERROR ws2_32_WSAGetLastError;
+static LPFN_WSASOCKETA ws2_32_WSASocketA;
+
+static void ws2_32_cleanup(void)
+{
+	if (ws2_32_dll)
+		FreeLibrary(ws2_32_dll);
+	ws2_32_dll = NULL;
+	ws2_32_inet_ntoa = NULL;
+	ws2_32_connect = NULL;
+	ws2_32_select = NULL;
+	ws2_32_closesocket = NULL;
+	ws2_32_getservbyport = NULL;
+	ws2_32_getservbyname = NULL;
+	ws2_32_gethostbyaddr = NULL;
+	ws2_32_gethostname = NULL;
+	ws2_32_gethostbyname = NULL;
+	ws2_32_WSAStartup = NULL;
+	ws2_32_WSACleanup = NULL;
+	ws2_32_WSAGetLastError = NULL;
+	ws2_32_WSASocketA = NULL;
+}
+
+static void ensure_ws2_32_initialization(void)
+{
+	static int ws2_32_initialized = 0;
+
+	if (ws2_32_initialized)
+		return;
+
+	ws2_32_dll = LoadLibrary("ws2_32.dll");
+	if (!ws2_32_dll)
+		die("cannot load ws2_32.dll");
+
+	ws2_32_inet_ntoa = (LPFN_INET_NTOA)
+		GetProcAddress(ws2_32_dll, "inet_ntoa");
+	ws2_32_connect = (LPFN_CONNECT)
+		GetProcAddress(ws2_32_dll, "connect");
+	ws2_32_select = (LPFN_SELECT)
+		GetProcAddress(ws2_32_dll, "select");
+	ws2_32_closesocket = (LPFN_CLOSESOCKET)
+		GetProcAddress(ws2_32_dll, "closesocket");
+	ws2_32_getservbyport = (LPFN_GETSERVBYPORT)
+		GetProcAddress(ws2_32_dll, "getservbyport");
+	ws2_32_getservbyname = (LPFN_GETSERVBYNAME)
+		GetProcAddress(ws2_32_dll, "getservbyname");
+	ws2_32_gethostbyaddr = (LPFN_GETHOSTBYADDR)
+		GetProcAddress(ws2_32_dll, "gethostbyaddr");
+	ws2_32_gethostname = (LPFN_GETHOSTNAME)
+		GetProcAddress(ws2_32_dll, "gethostname");
+	ws2_32_gethostbyname = (LPFN_GETHOSTBYNAME)
+		GetProcAddress(ws2_32_dll, "gethostbyname");
+	ws2_32_WSAStartup = (LPFN_WSASTARTUP)
+		GetProcAddress(ws2_32_dll, "WSAStartup");
+	ws2_32_WSACleanup = (LPFN_WSACLEANUP)
+		GetProcAddress(ws2_32_dll, "WSACleanup");
+	ws2_32_WSAGetLastError = (LPFN_WSAGETLASTERROR)
+		GetProcAddress(ws2_32_dll, "WSAGetLastError");
+	ws2_32_WSASocketA = (LPFN_WSASOCKETA)
+		GetProcAddress(ws2_32_dll, "WSASocketA");
+
+	if (!ws2_32_inet_ntoa || !ws2_32_connect || !ws2_32_select ||
+		!ws2_32_closesocket || !ws2_32_getservbyport || !ws2_32_getservbyname ||
+		!ws2_32_gethostbyaddr || !ws2_32_gethostname || !ws2_32_gethostbyname ||
+		!ws2_32_WSAStartup || !ws2_32_WSACleanup ||
+		!ws2_32_WSAGetLastError || !ws2_32_WSASocketA) {
+		FreeLibrary(ws2_32_dll);
+		ws2_32_dll = NULL;
+		die("cannot initialize ws2_32.dll");
+	}
+	atexit(ws2_32_cleanup);
+	ws2_32_initialized = 1;
+}
+
+char *mingw_inet_ntoa(struct in_addr in)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_inet_ntoa(in);
+}
+
+int mingw_closesocket(SOCKET s)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_closesocket(s);
+}
+
+int mingw_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+			const struct timeval *timeout)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+struct servent *mingw_getservbyport(int port, const char *proto)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_getservbyport(port, proto);
+}
+
+struct hostent *mingw_gethostbyaddr(const char *addr, int len, int type)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_gethostbyaddr(addr, len, type);
+}
+
+int mingw_gethostname(char *name, int namelen)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_gethostname(name, namelen);
+}
+
+struct servent *mingw_getservbyname(const char *name, const char *proto)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_getservbyname(name, proto);
+}
+
+int mingw_WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSAStartup(wVersionRequested, lpWSAData);
+}
+
+int mingw_WSACleanup(void)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSACleanup();
+}
+
+int mingw_WSAGetLastError(void)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSAGetLastError();
+}
+
+SOCKET mingw_WSASocketA(int af, int type, int protocol,
+			LPWSAPROTOCOL_INFOA lpProtocolInfo,
+			GROUP g, DWORD dwFlags)
+{
+	ensure_ws2_32_initialization();
+	return ws2_32_WSASocketA(af, type, protocol, lpProtocolInfo, g, dwFlags);
+}
+
+static HMODULE advapi32_dll = NULL;
+static BOOL (WINAPI *advapi32_get_user_name)(char *, DWORD *);
+
+static void advapi32_cleanup(void)
+{
+	if (advapi32_dll)
+		FreeLibrary(advapi32_dll);
+	advapi32_dll = NULL;
+	advapi32_get_user_name = NULL;
+}
+
 /*
  * Note, this isn't a complete replacement for getaddrinfo. It assumes
  * that service contains a numerical port, or that it it is null. It
@@ -1057,11 +1223,13 @@ static void ensure_socket_initialization(void)
 struct hostent *mingw_gethostbyname(const char *host)
 {
 	ensure_socket_initialization();
-	return gethostbyname(host);
+	ensure_ws2_32_initialization();
+	return ws2_32_gethostbyname(host);
 }
 
 void mingw_freeaddrinfo(struct addrinfo *res)
 {
+	ensure_socket_initialization();
 	ipv6_freeaddrinfo(res);
 }
 
@@ -1110,7 +1278,8 @@ int mingw_socket(int domain, int type, int protocol)
 int mingw_connect(int sockfd, struct sockaddr *sa, size_t sz)
 {
 	SOCKET s = (SOCKET)_get_osfhandle(sockfd);
-	return connect(s, sa, sz);
+	ensure_ws2_32_initialization();
+	return ws2_32_connect(s, sa, sz);
 }
 
 #undef rename
@@ -1180,9 +1349,27 @@ struct passwd *getpwuid(int uid)
 {
 	static char user_name[100];
 	static struct passwd p;
+	static int advapi32_initialized = 0;
 
 	DWORD len = sizeof(user_name);
-	if (!GetUserName(user_name, &len))
+
+	if (!advapi32_initialized)
+	{
+		advapi32_dll = LoadLibrary("advapi32.dll");
+		if (!advapi32_dll)
+			die("cannot load advapi32.dll");
+		advapi32_get_user_name = (BOOL (WINAPI *)(char *, DWORD *))
+			GetProcAddress(advapi32_dll, "GetUserNameA");
+		if (!advapi32_get_user_name) {
+			FreeLibrary(advapi32_dll);
+			advapi32_dll = NULL;
+			die("cannot find GetUserNameA");
+		}
+		atexit(advapi32_cleanup);
+		advapi32_initialized = 1;
+	}
+
+	if (!advapi32_get_user_name(user_name, &len))
 		return NULL;
 	p.pw_name = user_name;
 	p.pw_gecos = "unknown";
diff --git a/compat/mingw.h b/compat/mingw.h
index e254fb4..466c473 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,5 +1,6 @@
 #include <winsock2.h>
 #include <ws2tcpip.h>
+#include "bswap.h"
 
 /*
  * things that are not available in header files
@@ -176,9 +177,53 @@ char *mingw_getcwd(char *pointer, int len);
 char *mingw_getenv(const char *name);
 #define getenv mingw_getenv
 
+/*
+ * wrappers for functions dynamically loaded from ws2_32.dll
+ */
+
+char *mingw_inet_ntoa(struct in_addr in);
+#define inet_ntoa mingw_inet_ntoa
+
+int mingw_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+			const struct timeval *timeout);
+#define select mingw_select
+
+int mingw_closesocket(SOCKET s);
+#define closesocket mingw_closesocket
+
+struct servent *mingw_getservbyport(int port, const char *proto);
+#define getservbyport mingw_getservbyport
+
+struct servent *mingw_getservbyname(const char *name, const char *proto);
+#define getservbyname mingw_getservbyname
+
+struct hostent *mingw_gethostbyaddr(const char *addr, int len, int type);
+#define gethostbyaddr mingw_gethostbyaddr
+
+int mingw_gethostname(char *name, int namelen);
+#define gethostname mingw_gethostname
+
 struct hostent *mingw_gethostbyname(const char *host);
 #define gethostbyname mingw_gethostbyname
 
+int mingw_WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);
+#define WSAStartup mingw_WSAStartup
+
+int mingw_WSACleanup(void);
+#define WSACleanup mingw_WSACleanup
+
+int mingw_WSAGetLastError(void);
+#define WSAGetLastError mingw_WSAGetLastError
+
+SOCKET mingw_WSASocketA(int af, int type, int protocol,
+			LPWSAPROTOCOL_INFOA lpProtocolInfo,
+			GROUP g, DWORD dwFlags);
+#define WSASocketA mingw_WSASocketA
+
+/*
+ * support for IPv6 on MinGW
+ */
+
 void mingw_freeaddrinfo(struct addrinfo *res);
 #define freeaddrinfo mingw_freeaddrinfo
 
@@ -227,10 +272,6 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env,
 void mingw_execvp(const char *cmd, char *const *argv);
 #define execvp mingw_execvp
 
-static inline unsigned int git_ntohl(unsigned int x)
-{ return (unsigned int)ntohl(x); }
-#define ntohl git_ntohl
-
 sig_handler_t mingw_signal(int sig, sig_handler_t handler);
 #define signal mingw_signal
 
-- 
1.7.0.rc0.1466.g79f2.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]