From 928500e00e0a73a11f5b2296d9baa82dafa7a1a8 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 15 Jan 2010 21:12:16 +0100 Subject: Windows: boost startup by avoiding a static dependency on shell32.dll This DLL is only needed to invoke the browser in a "git help" call. By looking up the only function that we need at runtime, we can avoid the startup costs of this DLL. DLL usage can be profiled with Microsoft's Dependency Walker. For example, a call to "git diff-files" loaded before: 19 DLLs after: 9 DLLs As a result, the runtime of 'make -j2 test' went down from 16:00min to 12:40min on one of my boxes. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'compat/mingw.c') diff --git a/compat/mingw.c b/compat/mingw.c index 0d73f15fa8..2afc978dfd 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,8 +3,6 @@ #include #include "../strbuf.h" -#include - static int err_win_to_posix(DWORD winerr) { int error = ENOSYS; @@ -1338,8 +1336,22 @@ static const char *make_backslash_path(const char *path) void mingw_open_html(const char *unixpath) { const char *htmlpath = make_backslash_path(unixpath); + typedef HINSTANCE (WINAPI *T)(HWND, const char *, + const char *, const char *, const char *, INT); + T ShellExecute; + HMODULE shell32; + + shell32 = LoadLibrary("shell32.dll"); + if (!shell32) + die("cannot load shell32.dll"); + ShellExecute = (T)GetProcAddress(shell32, "ShellExecuteA"); + if (!ShellExecute) + die("cannot run browser"); + printf("Launching default browser to display HTML ...\n"); ShellExecute(NULL, "open", htmlpath, NULL, "\\", 0); + + FreeLibrary(shell32); } int link(const char *oldpath, const char *newpath) -- cgit v1.2.3 From 3e34d6657733430164ef67ab2f000fa3d10d51b5 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 15 Jan 2010 21:12:17 +0100 Subject: Windows: simplify the pipe(2) implementation Our implementation of pipe() must create non-inheritable handles for the reason that when a child process is started, there is no opportunity to close the unneeded pipe ends in the child (on POSIX this is done between fork() and exec()). Previously, we used the _pipe() function provided by Microsoft's C runtime (which creates inheritable handles) and then turned the handles into non-inheritable handles using the DuplicateHandle() API. Simplify the procedure by using the CreatePipe() API, which can create non-inheritable handles right from the beginning. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.c | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) (limited to 'compat/mingw.c') diff --git a/compat/mingw.c b/compat/mingw.c index 2afc978dfd..162d1ff283 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -299,46 +299,25 @@ int gettimeofday(struct timeval *tv, void *tz) int pipe(int filedes[2]) { - int fd; - HANDLE h[2], parent; - - if (_pipe(filedes, 8192, 0) < 0) - return -1; + HANDLE h[2]; - parent = GetCurrentProcess(); - - if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[0]), - parent, &h[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) { - close(filedes[0]); - close(filedes[1]); - return -1; - } - if (!DuplicateHandle (parent, (HANDLE)_get_osfhandle(filedes[1]), - parent, &h[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) { - close(filedes[0]); - close(filedes[1]); - CloseHandle(h[0]); + /* this creates non-inheritable handles */ + if (!CreatePipe(&h[0], &h[1], NULL, 8192)) { + errno = err_win_to_posix(GetLastError()); return -1; } - fd = _open_osfhandle((int)h[0], O_NOINHERIT); - if (fd < 0) { - close(filedes[0]); - close(filedes[1]); + filedes[0] = _open_osfhandle((int)h[0], O_NOINHERIT); + if (filedes[0] < 0) { CloseHandle(h[0]); CloseHandle(h[1]); return -1; } - close(filedes[0]); - filedes[0] = fd; - fd = _open_osfhandle((int)h[1], O_NOINHERIT); - if (fd < 0) { + filedes[1] = _open_osfhandle((int)h[1], O_NOINHERIT); + if (filedes[0] < 0) { close(filedes[0]); - close(filedes[1]); CloseHandle(h[1]); return -1; } - close(filedes[1]); - filedes[1] = fd; return 0; } -- cgit v1.2.3 From 75301f90159a505f3683a5eba10174928dc30fb1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 15 Jan 2010 21:12:18 +0100 Subject: Windows: avoid the "dup dance" when spawning a child process When stdin, stdout, or stderr must be redirected for a child process that on Windows is spawned using one of the spawn() functions of Microsoft's C runtime, then there is no choice other than to 1. make a backup copy of fd 0,1,2 with dup 2. dup2 the redirection source fd into 0,1,2 3. spawn 4. dup2 the backup back into 0,1,2 5. close the backup copy and the redirection source We used this idiom as well -- but we are not using the spawn() functions anymore! Instead, we have our own implementation. We had hardcoded that stdin, stdout, and stderr of the child process were inherited from the parent's fds 0, 1, and 2. But we can actually specify any fd. With this patch, the fds to inherit are passed from start_command()'s WIN32 section to our spawn implementation. This way, we can avoid the backup copies of the fds. The backup copies were a bug waiting to surface: The OS handles underlying the dup()ed fds were inherited by the child process (but were not associated with a file descriptor in the child). Consequently, the file or pipe represented by the OS handle remained open even after the backup copy was closed in the parent process until the child exited. Since our implementation of pipe() creates non-inheritable OS handles, we still dup() file descriptors in start_command() because dup() happens to create inheritable duplicates. (A nice side effect is that the fd cleanup in start_command is the same for Windows and Unix and remains unchanged.) Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'compat/mingw.c') diff --git a/compat/mingw.c b/compat/mingw.c index 162d1ff283..73762473c5 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -615,8 +615,8 @@ static int env_compare(const void *a, const void *b) return strcasecmp(*ea, *eb); } -static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, - int prepend_cmd) +static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **env, + int prepend_cmd, int fhin, int fhout, int fherr) { STARTUPINFO si; PROCESS_INFORMATION pi; @@ -652,9 +652,9 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, memset(&si, 0, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; - si.hStdInput = (HANDLE) _get_osfhandle(0); - si.hStdOutput = (HANDLE) _get_osfhandle(1); - si.hStdError = (HANDLE) _get_osfhandle(2); + si.hStdInput = (HANDLE) _get_osfhandle(fhin); + si.hStdOutput = (HANDLE) _get_osfhandle(fhout); + si.hStdError = (HANDLE) _get_osfhandle(fherr); /* concatenate argv, quoting args as we go */ strbuf_init(&args, 0); @@ -709,7 +709,14 @@ static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, return (pid_t)pi.hProcess; } -pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) +static pid_t mingw_spawnve(const char *cmd, const char **argv, char **env, + int prepend_cmd) +{ + return mingw_spawnve_fd(cmd, argv, env, prepend_cmd, 0, 1, 2); +} + +pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env, + int fhin, int fhout, int fherr) { pid_t pid; char **path = get_path_split(); @@ -731,13 +738,15 @@ pid_t mingw_spawnvpe(const char *cmd, const char **argv, char **env) pid = -1; } else { - pid = mingw_spawnve(iprog, argv, env, 1); + pid = mingw_spawnve_fd(iprog, argv, env, 1, + fhin, fhout, fherr); free(iprog); } argv[0] = argv0; } else - pid = mingw_spawnve(prog, argv, env, 0); + pid = mingw_spawnve_fd(prog, argv, env, 0, + fhin, fhout, fherr); free(prog); } free_path_split(path); -- cgit v1.2.3 From 44626dc7d562d23b54d969bb73ddeda12d5602e9 Mon Sep 17 00:00:00 2001 From: "Andrzej K. Haczewski" Date: Fri, 15 Jan 2010 21:12:20 +0100 Subject: MSVC: Windows-native implementation for subset of Pthreads API This patch implements native to Windows subset of pthreads API used by Git. It allows to remove Pthreads for Win32 dependency for MSVC, msysgit and Cygwin. [J6t: If the MinGW build was built as part of the msysgit build environment, then threading was already enabled because the pthreads-win32 package is available in msysgit. With this patch, we can now enable threaded code unconditionally.] Signed-off-by: Andrzej K. Haczewski Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'compat/mingw.c') diff --git a/compat/mingw.c b/compat/mingw.c index 73762473c5..74ffc1834f 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -3,7 +3,7 @@ #include #include "../strbuf.h" -static int err_win_to_posix(DWORD winerr) +int err_win_to_posix(DWORD winerr) { int error = ENOSYS; switch(winerr) { -- cgit v1.2.3 From a6d15bc33529f923b205930d0a58fe6226570dc1 Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Fri, 15 Jan 2010 21:12:21 +0100 Subject: Do not use date.c:tm_to_time_t() from compat/mingw.c To implement gettimeofday(), a broken-down UTC time was requested from the system using GetSystemTime(), then tm_to_time_t() was used to convert it to a time_t because it does not look at the current timezone, which mktime() would do. Use GetSystemTimeAsFileTime() and a different conversion path to avoid this back-reference from the compatibility layer to the generic code. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'compat/mingw.c') diff --git a/compat/mingw.c b/compat/mingw.c index 74ffc1834f..ab65f77ab9 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -140,12 +140,20 @@ int mingw_open (const char *filename, int oflags, ...) return fd; } -static inline time_t filetime_to_time_t(const FILETIME *ft) +/* + * The unit of FILETIME is 100-nanoseconds since January 1, 1601, UTC. + * Returns the 100-nanoseconds ("hekto nanoseconds") since the epoch. + */ +static inline long long filetime_to_hnsec(const FILETIME *ft) { long long winTime = ((long long)ft->dwHighDateTime << 32) + ft->dwLowDateTime; - winTime -= 116444736000000000LL; /* Windows to Unix Epoch conversion */ - winTime /= 10000000; /* Nano to seconds resolution */ - return (time_t)winTime; + /* Windows to Unix Epoch conversion */ + return winTime - 116444736000000000LL; +} + +static inline time_t filetime_to_time_t(const FILETIME *ft) +{ + return (time_t)(filetime_to_hnsec(ft) / 10000000); } /* We keep the do_lstat code in a separate function to avoid recursion. @@ -281,19 +289,13 @@ int mkstemp(char *template) int gettimeofday(struct timeval *tv, void *tz) { - SYSTEMTIME st; - struct tm tm; - GetSystemTime(&st); - tm.tm_year = st.wYear-1900; - tm.tm_mon = st.wMonth-1; - tm.tm_mday = st.wDay; - tm.tm_hour = st.wHour; - tm.tm_min = st.wMinute; - tm.tm_sec = st.wSecond; - tv->tv_sec = tm_to_time_t(&tm); - if (tv->tv_sec < 0) - return -1; - tv->tv_usec = st.wMilliseconds*1000; + FILETIME ft; + long long hnsec; + + GetSystemTimeAsFileTime(&ft); + hnsec = filetime_to_hnsec(&ft); + tv->tv_sec = hnsec / 10000000; + tv->tv_usec = (hnsec % 10000000) / 10; return 0; } -- cgit v1.2.3