git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Michael Lukashov <michael.lukashov@gmail.com>
Date
Jan 28, 2010, 08:15 UTC
Message-ID
<1264666525-4956-1-git-send-email-michael.lukashov@gmail.com>

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@gmail.com>
---
 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
Next: Johannes Sixt
Message 1 of 6 in “Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dll”
  1. Windows: improve performance by avoiding a static dependency on ws2_32.dll and advapi32.dllMichael Lukashov, Jan 28, 2010
  2. Johannes SixtJan 28, 2010
  3. Michael LukashovJan 28, 2010
  4. Johannes SchindelinJan 28, 2010
  5. Michael LukashovJan 28, 2010
  6. Johannes SixtJan 29, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.