summaryrefslogtreecommitdiff
path: root/src/os_win32.c
diff options
context:
space:
mode:
authorPaul Ollis <paul@cleversheep.org>2022-06-05 16:55:54 +0100
committerBram Moolenaar <Bram@vim.org>2022-06-05 16:55:54 +0100
commit6574577cacd393ab7591fc776ea060eebc939e55 (patch)
treef583ca9957280e7086b8d14ef44127302829fd40 /src/os_win32.c
parent1d97db3d987c05af88c30ad20f537bcf3024f9c1 (diff)
downloadvim-git-6574577cacd393ab7591fc776ea060eebc939e55.tar.gz
patch 8.2.5057: using gettimeofday() for timeout is very inefficientv8.2.5057
Problem: Using gettimeofday() for timeout is very inefficient. Solution: Set a platform dependent timer. (Paul Ollis, closes #10505)
Diffstat (limited to 'src/os_win32.c')
-rw-r--r--src/os_win32.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/os_win32.c b/src/os_win32.c
index 59072c49b..6a02fe283 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -100,6 +100,8 @@ typedef char * LPCSTR;
typedef char * LPWSTR;
typedef int ACCESS_MASK;
typedef int BOOL;
+typedef int BOOLEAN;
+typedef int CALLBACK;
typedef int COLORREF;
typedef int CONSOLE_CURSOR_INFO;
typedef int COORD;
@@ -7327,6 +7329,7 @@ typedef struct _FILE_EA_INFORMATION_ {
ULONG EaSize;
} FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_;
+#ifndef PROTO
typedef NTSTATUS (NTAPI *PfnNtOpenFile)(
PHANDLE FileHandle,
ACCESS_MASK DesiredAccess,
@@ -7367,6 +7370,7 @@ PfnNtSetEaFile pNtSetEaFile = NULL;
PfnNtQueryEaFile pNtQueryEaFile = NULL;
PfnNtQueryInformationFile pNtQueryInformationFile = NULL;
PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL;
+#endif
/*
* Load ntdll.dll functions.
@@ -8315,3 +8319,85 @@ GetWin32Error(void)
}
return msg;
}
+
+#if defined(FEAT_RELTIME) || defined(PROTO)
+static HANDLE timer_handle;
+static int timer_active = FALSE;
+
+/*
+ * Calls to start_timeout alternate the return value pointer between the two
+ * entries in timeout_flags. If the previously active timeout is very close to
+ * expiring when start_timeout() is called then a race condition means that the
+ * set_flag() function may still be invoked after the previous timer is
+ * deleted. Ping-ponging between the two flags prevents this causing 'fake'
+ * timeouts.
+ */
+static int timeout_flags[2];
+static int flag_idx = 0;
+static int *timeout_flag = &timeout_flags[0];
+
+
+ static void CALLBACK
+set_flag(void *param, BOOLEAN unused2)
+{
+ int *timeout_flag = (int *)param;
+
+ *timeout_flag = TRUE;
+}
+
+/*
+ * Stop any active timeout.
+ */
+ void
+stop_timeout(void)
+{
+ if (timer_active)
+ {
+ BOOL ret = DeleteTimerQueueTimer(NULL, timer_handle, NULL);
+ timer_active = FALSE;
+ if (!ret && GetLastError() != ERROR_IO_PENDING)
+ {
+ semsg(_(e_could_not_clear_timeout_str), GetWin32Error());
+ }
+ }
+ *timeout_flag = FALSE;
+}
+
+/*
+ * Start the timeout timer.
+ *
+ * The period is defined in milliseconds.
+ *
+ * The return value is a pointer to a flag that is initialised to 0. If the
+ * timeout expires, the flag is set to 1. This will only return pointers to
+ * static memory; i.e. any pointer returned by this function may always be
+ * safely dereferenced.
+ *
+ * This function is not expected to fail, but if it does it still returns a
+ * valid flag pointer; the flag will remain stuck at zero.
+ */
+ const int *
+start_timeout(long msec)
+{
+ UINT interval = (UINT)msec;
+ BOOL ret;
+
+ timeout_flag = &timeout_flags[flag_idx];
+
+ stop_timeout();
+ ret = CreateTimerQueueTimer(
+ &timer_handle, NULL, set_flag, timeout_flag,
+ (DWORD)msec, 0, WT_EXECUTEDEFAULT);
+ if (!ret)
+ {
+ semsg(_(e_could_not_set_timeout_str), GetWin32Error());
+ }
+ else
+ {
+ flag_idx = (flag_idx + 1) % 2;
+ timer_active = TRUE;
+ *timeout_flag = FALSE;
+ }
+ return timeout_flag;
+}
+#endif