On Thursday, September 19, 2013 3:29:35 AM UTC-7, ZyX wrote:
> On Sep 19, 2013 2:01 PM, "kans" <[email protected]> wrote:
> 
> >
> 
> > On Friday, September 13, 2013 2:43:13 AM UTC-7, kans wrote:
> 
> > > On Thursday, September 12, 2013 1:59:51 AM UTC-7, ZyX wrote:
> 
> > >
> 
> > > > On Sep 12, 2013 3:28 AM, "kans" <[email protected]> wrote:
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > On Wednesday, September 11, 2013 7:46:06 AM UTC-7, ZyX wrote:
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > On Sep 11, 2013 1:27 PM, "Thomas" <[email protected]> wrote:
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > On 11 September 2013 00:18, Nikolay Pavlov <[email protected]> 
> > > > > > > wrote:
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > >>
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > >> Why do you keep calling it async?
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > Referring to the introduction to asynchronous programming linked 
> > > > > > > below, the patch is an almost asynchronous feature, or at least a 
> > > > > > > completition of the already existing asynchronous features of 
> > > > > > > vim. With all the "autocmd-events" we already have the 
> > > > > > > posibillity to run code asynchronous.
> 
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > Anyway asynchronous doesn't mean threaded, as far as I know and 
> > > > > > > referring again to the link. That a two different concepts (which 
> > > > > > > you can combine if you want).
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > http://cs.brown.edu/courses/cs168/f12/handouts/async.pdf
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > Now please show how you can run one sequence of commands 
> > > > > > interleaved with the other with this patch. Function that runs with 
> > > > > > given interval blocks everything until it completes, same for 
> > > > > > autocommands. You cannot say you implement preemptive multitasking 
> > > > > > if you have to wait for one task to complete before starting the 
> > > > > > other. It is not async feature.
> 
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > You can, of course, do some hacks with saving a state, exiting and 
> > > > > > resuming, but you will then be forced to *emulate* preemption 
> > > > > > without any support from vim. I used to have some simple emulation 
> > > > > > even without such patch.
> 
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > Note though that I would really like it merged. But not with the 
> > > > > > current name.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > --
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > --
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > You received this message from the "vim_dev" maillist.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > Do not top-post! Type your reply below the text you are replying 
> > > > > > > to.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > For more information, visit http://www.vim.org/maillist.php
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > >  
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > ---
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > You received this message because you are subscribed to the 
> > > > > > > Google Groups "vim_dev" group.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > To unsubscribe from this group and stop receiving emails from it, 
> > > > > > > send an email to [email protected].
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > > > For more options, visit https://groups.google.com/groups/opt_out.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > ZyX,
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > The new patch addresses your criticism apart from changing the name.  
> > > > > I believe we obey Vim code conventions everywhere.  We have also 
> > > > > implemented a monotonically increasing timer for unix and osx which 
> > > > > are the only two OSes we have on hand.  Otherwise, we fall back to 
> > > > > gettimeofday.  Async is only #defined if gettimeofday exists.
> 
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > You can take the code from python: since 3.3 it has monotonic() 
> > > > function defined in C code in time module: pymonotonic function in 
> > > > Modules/timemodule.c. It has implementation for windows as well. Linux 
> > > > implementation used CLOCK_MONOTONIC (or, with higher priority, 
> > > > CLOCK_HIRES which is not mentioned in my clock_gettime man page; I 
> > > > guess there is a reason for it) without _RAW, though I would write
> 
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > #ifdef CLOCK_MONOTONIC_RAW
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >                              CLOCK_MONOTONIC_RAW
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > #else
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >                              CLOCK_MONOTONIC
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > #endif
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > in function arguments. But it is not as severe as issue with 
> > > > gettimeofday: you cannot see 2 centuries hop with CLOCK_MONOTONIC, 
> > > > maximum slightly increased/decreased second duration when NTP daemon 
> > > > does his adjustments.
> 
> 
> > >
> 
> > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > By the way, two pairs of figure braces may be removed from 
> > > > insert_timeout. Not that it is required by coding style, but this makes 
> > > > code look better.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > Bram,
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > We now use long longs for keeping track of the timers.  We have also 
> > > > > documented the new functions and some of their limitations.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > Please let us know if you have further feedback.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > -Matt
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > --
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > --
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > You received this message from the "vim_dev" maillist.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > Do not top-post! Type your reply below the text you are replying to.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > For more information, visit http://www.vim.org/maillist.php
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > >
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > ---
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > You received this message because you are subscribed to the Google 
> > > > > Groups "vim_dev" group.
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > To unsubscribe from this group and stop receiving emails from it, 
> > > > > send an email to [email protected].
> 
> > >
> 
> > > >
> 
> > >
> 
> > > > > For more options, visit https://groups.google.com/groups/opt_out.
> 
> > >
> 
> > >
> 
> > >
> 
> > > ZyX,
> 
> > >
> 
> > >
> 
> > >
> 
> > > I added a monotonic timer for windows; I basically took the one from 
> > > python.  I also changed all the make files to include the new stuff as 
> > > well.  The patch is 1200 lines long now (37 files changed, 476 
> > > insertions, 24 deletions).  The current state includes monotonically 
> > > increasing timers for OsX, Win32, and *nix.  It really doesn't make sense 
> > > to add any more features, but I'm happy to do cleanup as needed.
> 
> 
> > >
> 
> > >
> 
> > >
> 
> > > -Matt
> 
> >
> 
> > I was doing some work cleaning up the patch.  It really does make sense to 
> > kill all intervals if one of them fails; its too annoying as an end user if 
> > a timeout fails every 50ms.  The docstring for do_cmdline_cmd implies it 
> > should return FAIL if it can't evaluate "cmdline", but in practice it 
> > returns OK most of the time.  For instance, evaluating a function that 
> > doesn't exist throws an error and returns OK.  Some invalid expressions 
> > return OK, some, like "if (" don't.  Does anyone know of an easy way to 
> > figure out of the expression could be evaluated and didn't throw?
> 
> 
> I can suggest looking at VimTry* functions in src/if_py_both.h: they are used 
> to transform all vim errors into python exceptions. Purge the python stuff 
> and you will get C functions for wrapping arbitrary code into try/catch.
> 
> 
> > -Matt
> 
> >
> 
> > --
> 
> > --
> 
> > You received this message from the "vim_dev" maillist.
> 
> > Do not top-post! Type your reply below the text you are replying to.
> 
> > For more information, visit http://www.vim.org/maillist.php
> 
> >
> 
> > ---
> 
> > You received this message because you are subscribed to the Google Groups 
> > "vim_dev" group.
> 
> > To unsubscribe from this group and stop receiving emails from it, send an 
> > email to [email protected].
> 
> > For more options, visit https://groups.google.com/groups/opt_out.

Zyx,

Thanks for the help.  Intervals are no longer run if they error of any sort 
(apart from a user interrupt which will likely happen accidentally).  I was 
also forced to change configure.in as the monotonic timer on Linux needs to 
sometimes link against rt.  I ran autoconf and also dumped those changes into 
auto/configure file.  They run in both Linux and OsX.


Originally, I had hopped that this patch will be 100 lines tops, but it is 
closer to 600.  A good chunk of that is documentation and touching the various 
make files.  I think we have addressed all the concerns (apart from changing 
the name).  What would it take to get this merged?

-Matt

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.
>From caa96d4f49a720bb81b291867b61d9ef2888cbf1 Mon Sep 17 00:00:00 2001
From: Geoff Greer <[email protected]>
Date: Tue, 10 Sep 2013 03:54:58 -0700
Subject: [PATCH] Add asynchronous functions to Vim: settimeout, setinterval,
 and canceltimeout.

---
 Filelist                |   2 +
 runtime/doc/eval.txt    |  45 ++++++++++++++++++++-
 runtime/doc/options.txt |  11 ++++++
 runtime/doc/tags        |   5 +++
 src/Make_bc3.mak        |   1 +
 src/Make_bc5.mak        |   1 +
 src/Make_cyg.mak        |   1 +
 src/Make_dice.mak       |   6 ++-
 src/Make_djg.mak        |   1 +
 src/Make_ivc.mak        |   5 +++
 src/Make_manx.mak       |  12 ++++--
 src/Make_ming.mak       |   1 +
 src/Make_morph.mak      |   3 +-
 src/Make_mvc.mak        |   3 ++
 src/Make_os2.mak        |   1 +
 src/Make_sas.mak        |   4 ++
 src/Make_vms.mms        |   4 +-
 src/Makefile            |   9 +++++
 src/async.c             |  89 ++++++++++++++++++++++++++++++++++++++++++
 src/auto/configure      |  51 ++++++++++++++++++++++++
 src/configure.in        |   7 ++++
 src/eval.c              | 102 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/feature.h           |   8 ++++
 src/globals.h           |   5 +++
 src/gui.c               |  31 +++++++++------
 src/main.aap            |   1 +
 src/option.c            |   8 ++++
 src/option.h            |   3 ++
 src/os_macosx.m         |  16 ++++++++
 src/os_unix.c           |  40 +++++++++++++++++--
 src/os_win32.c          |  47 ++++++++++++++++++++++
 src/os_win32.h          |   1 +
 src/proto.h             |   4 ++
 src/proto/async.pro     |   5 +++
 src/proto/os_unix.pro   |   1 +
 src/proto/os_win32.pro  |   1 +
 src/structs.h           |  14 +++++++
 src/version.c           |   5 +++
 38 files changed, 530 insertions(+), 24 deletions(-)
 create mode 100644 src/async.c
 create mode 100644 src/proto/async.pro

diff --git a/Filelist b/Filelist
index b324933..7f7d62e 100644
--- a/Filelist
+++ b/Filelist
@@ -7,6 +7,7 @@ SRC_ALL =	\
 		src/arabic.c \
 		src/arabic.h \
 		src/ascii.h \
+		src/async.c \
 		src/blowfish.c \
 		src/buffer.c \
 		src/charset.c \
@@ -94,6 +95,7 @@ SRC_ALL =	\
 		src/testdir/python_after/*.py \
 		src/testdir/python_before/*.py \
 		src/proto.h \
+		src/proto/async.pro \
 		src/proto/blowfish.pro \
 		src/proto/buffer.pro \
 		src/proto/charset.pro \
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 60b01a8..a0dd86a 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt*	For Vim version 7.4.  Last change: 2013 Aug 24
+*eval.txt*	For Vim version 7.4.  Last change: 2013 Sep 10
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -1926,6 +1926,7 @@ server2client( {clientid}, {string})
 serverlist()			String	get a list of available servers
 setbufvar( {expr}, {varname}, {val})	set {varname} in buffer {expr} to {val}
 setcmdpos( {pos})		Number	set cursor position in command-line
+setinterval( {nr},{string})   Number  evaluate the expression {string} every {nr} milliseconds
 setline( {lnum}, {line})	Number	set line {lnum} to {line}
 setloclist( {nr}, {list}[, {action}])
 				Number	modify location list using {list}
@@ -1936,6 +1937,7 @@ setreg( {n}, {v}[, {opt}])	Number	set register to value and type
 settabvar( {nr}, {varname}, {val})	set {varname} in tab page {nr} to {val}
 settabwinvar( {tabnr}, {winnr}, {varname}, {val})    set {varname} in window
 					{winnr} in tab page {tabnr} to {val}
+settimeout(	{nr}, {string})	Number  evaluate the expression {string} after {nr} milliseconds
 setwinvar( {nr}, {varname}, {val})	set {varname} in window {nr} to {val}
 sha256( {string})		String	SHA256 checksum of {string}
 shellescape( {string} [, {special}])
@@ -2281,6 +2283,15 @@ call({func}, {arglist} [, {dict}])			*call()* *E699*
 		{dict} is for functions with the "dict" attribute.  It will be
 		used to set the local variable "self". |Dictionary-function|
 
+canceltimeout({nr})					*canceltimeout()*
+		Cancel the timeout or interval with id, {nr}, preventing it 
+		from every firing.
+		Also see |settimeout()| and |setinterval()|.
+		{only available when compiled with the |+async| feature}
+		Examples: >
+			let timeout_id = settimeout(5000, 'echo(2)')
+			echo canceltimeout(timeout_id)
+
 ceil({expr})							*ceil()*
 		Return the smallest integral value greater than or equal to
 		{expr} as a |Float| (round up).
@@ -5187,6 +5198,23 @@ setcmdpos({pos})					*setcmdpos()*
 		Returns 0 when successful, 1 when not editing the command
 		line.
 
+setinterval({nr}, {string})				*setinterval()*
+		Immediately returns an interval id and evaluate the expression, 
+		{string}, every {nr} milliseconds. Intervals do not pile up.  
+		The timer's resolution defaults to 100ms and can be changed by 
+		setting |ticktime|.  Intervals can be canceled by calling 
+		|canceltimeout({interval_id})|.
+		NOTE: Vim is single-threaded and all expressions are run within 
+		the main thread.  Therefore, expressions should return control 
+		flow within	a short amount of time.
+		Also see |settimeout()| and |canceltimeout()|.
+		{only available when compiled with the |+async| feature}
+		Examples: >
+			:call setinterval(1000, "call echo(2)")
+<		2
+		2
+		2
+
 setline({lnum}, {text})					*setline()*
 		Set line {lnum} of the current buffer to {text}.  To insert
 		lines use |append()|.
@@ -5356,6 +5384,21 @@ settabwinvar({tabnr}, {winnr}, {varname}, {val})	*settabwinvar()*
 			:call settabwinvar(3, 2, "myvar", "foobar")
 <		This function is not available in the |sandbox|.
 
+settimeout({nr}, {string})				*settimeout()*
+		Immediately returns an interval id and evaluate the expression, 
+		{string}, once after {nr} milliseconds. The timer's
+		resolution defaults to 100ms and can be changed by setting 
+		|ticktime|.  Timeouts can be canceled by calling 
+		|canceltimeout({interval_id})|.
+		NOTE: Vim is single-threaded and all expressions are run within 
+		the main thread.  Therefore, expressions should return control 
+		flow within	a short amount of time.  
+		Also see |setinterval()| and |canceltimeout()|.
+		{only available when compiled with the |+async| feature}
+		Examples: >
+			:call settimeout(1000, "call echo(2)")
+<		2
+
 setwinvar({nr}, {varname}, {val})			*setwinvar()*
 		Like |settabwinvar()| for the current tab page.
 		Examples: >
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 0688fcc..e7174ff 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -7253,6 +7253,17 @@ A jump table for the options with a short description can be found at |Q_op|.
 	uses another default.
 	Backticks cannot be used in this option for security reasons.
 
+						*'ticktime'* *'tt'*
+'ticktime' 'tt'	number	(default 100)
+			global
+			{not in Vi}
+	This is the resolution for all timers set with |setinterval()| and 
+	|settimeout()|.  Decreasing this number will make the timers
+	more accurate but will also make Vim less efficient.  To globally
+	disable all timers for debugging, set |ticktime| to -1.
+	Also see |setinterval()|, |settimeout()|, and |canceltimeout()|.
+	{only available when compiled with the |+async| feature}
+
 			     *'tildeop'* *'top'* *'notildeop'* *'notop'*
 'tildeop' 'top'		boolean	(default off)
 			global
diff --git a/runtime/doc/tags b/runtime/doc/tags
index f32ea6f..3e8e0f7 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -1014,6 +1014,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 'tf'	options.txt	/*'tf'*
 'tgst'	options.txt	/*'tgst'*
 'thesaurus'	options.txt	/*'thesaurus'*
+'ticktime'	options.txt	/*'ticktime'*
 'tildeop'	options.txt	/*'tildeop'*
 'timeout'	options.txt	/*'timeout'*
 'timeoutlen'	options.txt	/*'timeoutlen'*
@@ -1032,6 +1033,7 @@ $VIMRUNTIME	starting.txt	/*$VIMRUNTIME*
 'ts'	options.txt	/*'ts'*
 'tsl'	options.txt	/*'tsl'*
 'tsr'	options.txt	/*'tsr'*
+'tt'	options.txt	/*'tt'*
 'ttimeout'	options.txt	/*'ttimeout'*
 'ttimeoutlen'	options.txt	/*'ttimeoutlen'*
 'ttm'	options.txt	/*'ttm'*
@@ -4987,6 +4989,7 @@ c_Up	cmdline.txt	/*c_Up*
 c_digraph	cmdline.txt	/*c_digraph*
 c_wildchar	cmdline.txt	/*c_wildchar*
 call()	eval.txt	/*call()*
+canceltimeout()	eval.txt	/*canceltimeout()*
 carriage-return	intro.txt	/*carriage-return*
 case	change.txt	/*case*
 catch-all	eval.txt	/*catch-all*
@@ -7653,6 +7656,7 @@ set-option	options.txt	/*set-option*
 set-spc-auto	spell.txt	/*set-spc-auto*
 setbufvar()	eval.txt	/*setbufvar()*
 setcmdpos()	eval.txt	/*setcmdpos()*
+setinterval()	eval.txt	/*setinterval()*
 setline()	eval.txt	/*setline()*
 setloclist()	eval.txt	/*setloclist()*
 setmatches()	eval.txt	/*setmatches()*
@@ -7661,6 +7665,7 @@ setqflist()	eval.txt	/*setqflist()*
 setreg()	eval.txt	/*setreg()*
 settabvar()	eval.txt	/*settabvar()*
 settabwinvar()	eval.txt	/*settabwinvar()*
+settimeout()	eval.txt	/*settimeout()*
 setting-guifont	gui.txt	/*setting-guifont*
 setting-guitablabel	tabpage.txt	/*setting-guitablabel*
 setting-tabline	tabpage.txt	/*setting-tabline*
diff --git a/src/Make_bc3.mak b/src/Make_bc3.mak
index 54c42ac..dbf653d 100644
--- a/src/Make_bc3.mak
+++ b/src/Make_bc3.mak
@@ -52,6 +52,7 @@ SPAWNL = spawnl.lib
 
 EXE_dependencies = \
 	blowfish.obj \
+	async.obj \
 	buffer.obj \
 	charset.obj \
 	diff.obj \
diff --git a/src/Make_bc5.mak b/src/Make_bc5.mak
index 8172c1f..d93cf47 100644
--- a/src/Make_bc5.mak
+++ b/src/Make_bc5.mak
@@ -577,6 +577,7 @@ vimwinmain = \
 !endif
 
 vimobj =  \
+	$(OBJDIR)\async.obj \
 	$(OBJDIR)\blowfish.obj \
 	$(OBJDIR)\buffer.obj \
 	$(OBJDIR)\charset.obj \
diff --git a/src/Make_cyg.mak b/src/Make_cyg.mak
index f955b4d..7daf32b 100644
--- a/src/Make_cyg.mak
+++ b/src/Make_cyg.mak
@@ -527,6 +527,7 @@ RCFLAGS = -O coff $(DEFINES)
 
 OBJ = \
 	$(OUTDIR)/blowfish.o \
+	$(OUTDIR)/async.o \
 	$(OUTDIR)/buffer.o \
 	$(OUTDIR)/charset.o \
 	$(OUTDIR)/diff.o \
diff --git a/src/Make_dice.mak b/src/Make_dice.mak
index e3a8b9e..056a280 100644
--- a/src/Make_dice.mak
+++ b/src/Make_dice.mak
@@ -26,6 +26,7 @@ LD = dcc
 	${CC} ${PRE} ${CFLAGS} $< -o $@
 
 SRC = \
+	async.c \
 	blowfish.c \
 	buffer.c \
 	charset.c \
@@ -72,7 +73,8 @@ SRC = \
 	window.c \
 	version.c
 
-OBJ =	o/blowfish.o \
+OBJ =	o/async.o \
+	o/blowfish.o \
 	o/buffer.o \
 	o/charset.o \
 	o/diff.o \
@@ -137,6 +139,8 @@ $(SYMS)  : vim.h globals.h keymap.h macros.h ascii.h term.h os_amiga.h structs.h
 
 ###########################################################################
 
+o/async.o:	async.c  $(SYMS)
+
 o/blowfish.o:	blowfish.c  $(SYMS)
 
 o/buffer.o:	buffer.c  $(SYMS)
diff --git a/src/Make_djg.mak b/src/Make_djg.mak
index f2e7c82..ce97da1 100644
--- a/src/Make_djg.mak
+++ b/src/Make_djg.mak
@@ -19,6 +19,7 @@ INCL = vim.h globals.h option.h keymap.h macros.h ascii.h term.h os_msdos.h stru
 CFLAGS = -O2 -DMSDOS -Iproto $(DEFINES) -Wall -Dinterrupt= -Dfar= -DMAXMEM=512 -D_NAIVE_DOS_REGS
 
 OBJ = \
+	obj/async.o \
 	obj/blowfish.o \
 	obj/buffer.o \
 	obj/charset.o \
diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak
index 16589ea..32c29b4 100644
--- a/src/Make_ivc.mak
+++ b/src/Make_ivc.mak
@@ -210,6 +210,7 @@ ALL : .\$(VIM).exe vimrun.exe install.exe uninstal.exe xxd/xxd.exe GvimExt/gvime
 
 LINK32_OBJS= \
 	$(EXTRAS) \
+	"$(INTDIR)/async.obj" \
 	"$(INTDIR)/blowfish.obj" \
 	"$(INTDIR)/buffer.obj" \
 	"$(INTDIR)/charset.obj" \
@@ -327,6 +328,10 @@ GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
 
 # Begin Source File
 
+SOURCE=.\async.c
+# End Source File
+# Begin Source File
+
 SOURCE=.\blowfish.c
 # End Source File
 # Begin Source File
diff --git a/src/Make_manx.mak b/src/Make_manx.mak
index 101c5c6..1a16a4c 100644
--- a/src/Make_manx.mak
+++ b/src/Make_manx.mak
@@ -34,7 +34,8 @@ SHELL = csh
 REN = $(SHELL) -c mv -f
 DEL = $(SHELL) -c rm -f
 
-SRC =	blowfish.c \
+SRC =	async.c \
+	blowfish.c \
 	buffer.c \
 	charset.c \
 	diff.c \
@@ -82,7 +83,8 @@ SRC =	blowfish.c \
 
 INCL = vim.h feature.h keymap.h macros.h ascii.h term.h structs.h os_amiga.h
 
-OBJ =	obj/blowfish.o \
+OBJ =	obj/async.o \
+	obj/blowfish.o \
 	obj/buffer.o \
 	obj/charset.o \
 	obj/diff.o \
@@ -128,7 +130,8 @@ OBJ =	obj/blowfish.o \
 	obj/window.o \
 	$(TERMLIB)
 
-PRO =	proto/blowfish.pro \
+PRO =	proto/async.pro \
+	proto/blowfish.pro \
 	proto/buffer.pro \
 	proto/charset.pro \
 	proto/diff.pro \
@@ -218,6 +221,9 @@ CCNOSYM = $(CC) $(CFLAGS) -o
 
 $(OBJ): $(SYMS)
 
+obj/async.o:	async.c
+	$(CCSYM) $@ async.c
+
 obj/blowfish.o:	blowfish.c
 	$(CCSYM) $@ blowfish.c
 
diff --git a/src/Make_ming.mak b/src/Make_ming.mak
index 7aa3994..46a7e14 100644
--- a/src/Make_ming.mak
+++ b/src/Make_ming.mak
@@ -502,6 +502,7 @@ endif
 LIB = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomdlg32 -lcomctl32 -lversion
 GUIOBJ =  $(OUTDIR)/gui.o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_beval.o $(OUTDIR)/os_w32exe.o
 OBJ = \
+	$(OUTDIR)/async.o \
 	$(OUTDIR)/blowfish.o \
 	$(OUTDIR)/buffer.o \
 	$(OUTDIR)/charset.o \
diff --git a/src/Make_morph.mak b/src/Make_morph.mak
index aa8fbd9..66b74d6 100644
--- a/src/Make_morph.mak
+++ b/src/Make_morph.mak
@@ -24,7 +24,8 @@ RM =		rm
 .c.o:
 	${CC} ${CFLAGS} $< -o $@
 
-SRC =	blowfish.c						\
+SRC =	async.c						\
+	blowfish.c						\
 	buffer.c						\
 	charset.c						\
 	diff.c							\
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index f23258b..7f90d65 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -525,6 +525,7 @@ INCL =	vim.h os_win32.h ascii.h feature.h globals.h keymap.h macros.h \
 	$(NBDEBUG_INCL)
 
 OBJ = \
+	$(OUTDIR)\async.obj \
 	$(OUTDIR)\blowfish.obj \
 	$(OUTDIR)\buffer.obj \
 	$(OUTDIR)\charset.obj \
@@ -1055,6 +1056,8 @@ testclean:
 !ENDIF
 	$(CC) $(CFLAGS) $<
 
+$(OUTDIR)/async.obj:	$(OUTDIR) async.c  $(INCL)
+
 $(OUTDIR)/blowfish.obj:	$(OUTDIR) blowfish.c  $(INCL)
 
 $(OUTDIR)/buffer.obj:	$(OUTDIR) buffer.c  $(INCL)
diff --git a/src/Make_os2.mak b/src/Make_os2.mak
index 42dbdb3..102a17a 100644
--- a/src/Make_os2.mak
+++ b/src/Make_os2.mak
@@ -39,6 +39,7 @@ INCL = vim.h globals.h option.h keymap.h macros.h ascii.h term.h os_unix.h struc
 CFLAGS = -O2 -fno-strength-reduce -DOS2 -Wall -Iproto $(DEFINES)
 
 OBJ = \
+	async.o \
 	blowfish.o \
 	buffer.o \
 	charset.o \
diff --git a/src/Make_sas.mak b/src/Make_sas.mak
index bf57c0d..2258165 100644
--- a/src/Make_sas.mak
+++ b/src/Make_sas.mak
@@ -136,6 +136,7 @@ SRC = \
 	version.c
 
 OBJ = \
+	async.o \
 	blowfish.o \
 	buffer.o \
 	charset.o \
@@ -183,6 +184,7 @@ OBJ = \
 	$(TERMLIB)
 
 PRO = \
+	proto/async.pro \
 	proto/blowfish.pro \
 	proto/buffer.pro \
 	proto/charset.pro \
@@ -284,6 +286,8 @@ $(PRO): $(GST) vim.h
 	$(CC) $(CFLAGS) GPFILE=proto/$*.pro $(PROPT) $*.c
 
 # dependencies
+async.o:		async.c
+proto/async.pro:	async.c
 blowfish.o:		blowfish.c
 proto/blowfish.pro:	blowfish.c
 buffer.o:		buffer.c
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index 86b61d6..3f61421 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -304,7 +304,7 @@ ALL_CFLAGS_VER = /def=($(MODEL_DEF)$(DEFS)$(VMS_DEF)$(DEBUG_DEF)$(PERL_DEF)$(PYT
 ALL_LIBS = $(LIBS) $(GUI_LIB_DIR) $(GUI_LIB) \
 	   $(PERL_LIB) $(PYTHON_LIB) $(TCL_LIB) $(SNIFF_LIB) $(RUBY_LIB)
 
-SRC =	blowfish.c buffer.c charset.c diff.c digraph.c edit.c eval.c ex_cmds.c ex_cmds2.c \
+SRC =	async.c blowfish.c buffer.c charset.c diff.c digraph.c edit.c eval.c ex_cmds.c ex_cmds2.c \
 	ex_docmd.c ex_eval.c ex_getln.c if_xcmdsrv.c fileio.c fold.c getchar.c \
 	hardcopy.c hashtab.c main.c mark.c menu.c mbyte.c memfile.c memline.c message.c misc1.c \
 	misc2.c move.c normal.c ops.c option.c popupmnu.c quickfix.c regexp.c search.c sha256.c\
@@ -313,7 +313,7 @@ SRC =	blowfish.c buffer.c charset.c diff.c digraph.c edit.c eval.c ex_cmds.c ex_
 	$(GUI_SRC) $(PERL_SRC) $(PYTHON_SRC) $(TCL_SRC) $(SNIFF_SRC) \
 	$(RUBY_SRC) $(HANGULIN_SRC) $(MZSCH_SRC)
 
-OBJ =	blowfish.obj buffer.obj charset.obj diff.obj digraph.obj edit.obj eval.obj \
+OBJ =	async.obj blowfish.obj buffer.obj charset.obj diff.obj digraph.obj edit.obj eval.obj \
 	ex_cmds.obj ex_cmds2.obj ex_docmd.obj ex_eval.obj ex_getln.obj \
 	if_xcmdsrv.obj fileio.obj fold.obj getchar.obj hardcopy.obj hashtab.obj main.obj mark.obj \
 	menu.obj memfile.obj memline.obj message.obj misc1.obj misc2.obj \
diff --git a/src/Makefile b/src/Makefile
index c830378..d6ee8c9 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1424,6 +1424,7 @@ DEST_MAN_RU_U = $(DEST_MAN_TOP)/ru.UTF-8$(MAN1DIR)
 TAGS_INCL = *.h
 
 BASIC_SRC = \
+	async.c \
 	blowfish.c \
 	buffer.c \
 	charset.c \
@@ -1513,6 +1514,7 @@ LINT_SRC = $(BASIC_SRC) $(GUI_SRC) $(HANGULIN_SRC) $(PYTHON_SRC) $(PYTHON3_SRC)
 #LINT_SRC = $(BASIC_SRC)
 
 OBJ_COMMON = \
+	objects/async.o \
 	objects/buffer.o \
 	objects/blowfish.o \
 	objects/charset.o \
@@ -1582,6 +1584,7 @@ MEMFILE_TEST_OBJ = $(OBJ_COMMON) \
         objects/memfile_test.o
 
 PRO_AUTO = \
+	async.pro \
 	blowfish.pro \
 	buffer.pro \
 	charset.pro \
@@ -2484,6 +2487,9 @@ auto/pathdef.c: Makefile auto/config.mk
 objects:
 	mkdir objects
 
+objects/async.o: async.c
+	$(CCC) -o $@ async.c
+
 objects/blowfish.o: blowfish.c
 	$(CCC) -o $@ blowfish.c
 
@@ -2830,6 +2836,9 @@ $(APPDIR)/Contents:
 ###############################################################################
 ### (automatically generated by 'make depend')
 ### Dependencies:
+objects/async.o: async.c vim.h auto/config.h feature.h os_unix.h os_mac.h ascii.h \
+  keymap.h term.h macros.h option.h structs.h regexp.h gui.h ex_cmds.h \
+  proto.h proto/async.pro globals.h farsi.h arabic.h auto/osdef.h
 objects/blowfish.o: blowfish.c vim.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \
  regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \
diff --git a/src/async.c b/src/async.c
new file mode 100644
index 0000000..1f76b92
--- /dev/null
+++ b/src/async.c
@@ -0,0 +1,89 @@
+#include "vim.h"
+
+#ifdef FEAT_ASYNC
+
+/*
+ * Return monotonic time, if available. Fall back to gettimeofday otherwise.
+ */
+	unsigned long long
+get_monotonic_time(void)
+{
+	unsigned long long tm;
+#ifdef MCH_MONOTONIC_TIME
+	tm = mch_monotonic_time();
+#else
+	struct timeval now;
+	gettimeofday(&now, NULL);
+	tm = now.tv_sec * 1000 + now.tv_usec/1000;
+#endif
+	return tm;
+}
+
+
+/*
+ * Insert a new timeout into the timeout linked list.
+ * This is called by set_timeout() in eval.c
+ */
+	void
+insert_timeout(to)
+	timeout_T *to;  /* timeout to insert */
+{
+	timeout_T *cur = timeouts;
+	timeout_T *prev = NULL;
+
+	if (timeouts == NULL) {
+		timeouts = to;
+		return;
+	}
+	while (cur != NULL) 
+	{
+		if (cur->tm > to->tm)
+		{
+			if (prev)
+			{
+				prev->next = to;
+			} 
+			else 
+			{
+				timeouts = to;
+			}
+			to->next = cur;
+			return;
+		}
+		prev = cur;
+		cur = cur->next;
+	}
+	prev->next = to;
+	to->next = NULL;
+}
+
+/*
+ * Execute timeouts that are due.
+ * This is called every ticktime milliseconds by low-level input functions.
+ */
+	void
+call_timeouts(void)
+{
+	unsigned long long tm = get_monotonic_time();
+	timeout_T *tmp;
+	int retval;
+
+	while (timeouts != NULL && timeouts->tm < tm)
+	{
+		retval = do_cmdline_cmd(timeouts->cmd);
+		tmp = timeouts;
+		timeouts = timeouts->next;
+		if (tmp->interval == -1 || retval == FAIL || (!got_int && (did_throw || did_emsg)))
+		{
+			free(tmp->cmd);
+			free(tmp);
+		} 
+		else
+		{
+			tmp->tm = tm + tmp->interval;
+			insert_timeout(tmp);
+		}
+	}
+}
+
+#endif
diff --git a/src/auto/configure b/src/auto/configure
index a9755a0..64ec51e 100755
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -11072,6 +11072,57 @@ if test "x$vim_cv_getcwd_broken" = "xyes" ; then
 
 fi
 
+
+for ac_func in clock_gettime
+do :
+  ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
+if test "x$ac_cv_func_clock_gettime" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_CLOCK_GETTIME 1
+_ACEOF
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if ${ac_cv_lib_rt_clock_gettime+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rt_clock_gettime=yes
+else
+  ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
+     LIBS="$LIBS -lrt"
+fi
+fi
+done
+
 for ac_func in bcmp fchdir fchown fsync getcwd getpseudotty \
 	getpwent getpwnam getpwuid getrlimit gettimeofday getwd lstat memcmp \
 	memset mkdtemp nanosleep opendir putenv qsort readlink select setenv \
diff --git a/src/configure.in b/src/configure.in
index ed30bed..5f47547 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -3240,6 +3240,13 @@ if test "x$vim_cv_getcwd_broken" = "xyes" ; then
   AC_DEFINE(BAD_GETCWD)
 fi
 
+AC_CHECK_FUNCS(clock_gettime, [], [
+  AC_CHECK_LIB(rt, clock_gettime, [
+     LIBS="$LIBS -lrt"
+   ])
+])
+
+
 dnl Check for functions in one big call, to reduce the size of configure.
 dnl Can only be used for functions that do not require any include.
 AC_CHECK_FUNCS(bcmp fchdir fchown fsync getcwd getpseudotty \
diff --git a/src/eval.c b/src/eval.c
index 807efe2..7259ba0 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -674,6 +674,11 @@ struct funccall_S
 static void f_setloclist __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_setmatches __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_setpos __ARGS((typval_T *argvars, typval_T *rettv));
+#ifdef FEAT_ASYNC
+static void f_canceltimeout __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_setinterval __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_settimeout __ARGS((typval_T *argvars, typval_T *rettv));
+#endif
 static void f_setqflist __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_setreg __ARGS((typval_T *argvars, typval_T *rettv));
 static void f_settabvar __ARGS((typval_T *argvars, typval_T *rettv));
@@ -7861,6 +7866,9 @@ struct funccall_S
     {"byte2line",	1, 1, f_byte2line},
     {"byteidx",		2, 2, f_byteidx},
     {"call",		2, 3, f_call},
+#ifdef FEAT_ASYNC
+    {"canceltimeout", 1, 1, f_canceltimeout},
+#endif
 #ifdef FEAT_FLOAT
     {"ceil",		1, 1, f_ceil},
 #endif
@@ -8059,6 +8067,9 @@ struct funccall_S
     {"serverlist",	0, 0, f_serverlist},
     {"setbufvar",	3, 3, f_setbufvar},
     {"setcmdpos",	1, 1, f_setcmdpos},
+#ifdef FEAT_ASYNC
+    {"setinterval",    2, 2, f_setinterval},
+#endif
     {"setline",		2, 2, f_setline},
     {"setloclist",	2, 3, f_setloclist},
     {"setmatches",	1, 1, f_setmatches},
@@ -8067,6 +8078,9 @@ struct funccall_S
     {"setreg",		2, 3, f_setreg},
     {"settabvar",	3, 3, f_settabvar},
     {"settabwinvar",	4, 4, f_settabwinvar},
+#ifdef FEAT_ASYNC
+    {"settimeout",    2, 2, f_settimeout},
+#endif
     {"setwinvar",	3, 3, f_setwinvar},
 #ifdef FEAT_CRYPT
     {"sha256",		1, 1, f_sha256},
@@ -12416,6 +12430,9 @@ struct funccall_S
 #ifdef FEAT_RELTIME
 	"reltime",
 #endif
+#ifdef FEAT_ASYNC
+    "async",
+#endif
 #ifdef FEAT_QUICKFIX
 	"quickfix",
 #endif
@@ -16589,6 +16606,91 @@ struct funccall_S
 #endif
 }
 
+#ifdef FEAT_ASYNC
+static int timeout_id = 0;
+
+    static void
+set_timeout(argvars, rettv, interval)
+    typval_T    *argvars;
+    typval_T    *rettv;
+    int interval;
+{
+    long i = get_tv_number(&argvars[0]);
+    char_u *cmd = get_tv_string(&argvars[1]);
+    rettv->v_type = VAR_NUMBER;
+
+    if (i < 0) {
+        rettv->vval.v_number = -1;
+        EMSG2(_(e_invarg2), "Interval cannot be negative.");
+        return;
+    }
+
+    timeout_T *to = malloc(sizeof(timeout_T));
+    to->id = timeout_id++;
+    to->tm = get_monotonic_time() + i;
+    rettv->vval.v_number = to->id;
+    to->cmd = (char_u*)strdup((char*)cmd);
+    to->interval = interval ? i : -1;
+    to->next = NULL;
+
+    insert_timeout(to);
+}
+
+    static void
+f_setinterval(argvars, rettv)
+    typval_T    *argvars;
+    typval_T    *rettv;
+{
+    set_timeout(argvars, rettv, TRUE);
+}
+
+    static void
+f_settimeout(argvars, rettv)
+    typval_T    *argvars;
+    typval_T    *rettv;
+{
+    set_timeout(argvars, rettv, FALSE);
+}
+
+    static void
+f_canceltimeout(argvars, rettv)
+    typval_T    *argvars;
+    typval_T    *rettv;
+{
+    long id = get_tv_number(&argvars[0]);
+    if (id < 0) {
+        rettv->vval.v_number = -1;
+        EMSG2(_(e_invarg2), "Timeout id cannot be negative.");
+        return;
+    }
+
+    timeout_T *tmp = timeouts;
+    timeout_T *prev = NULL;
+    timeout_T *next;
+    while (tmp != NULL) {
+        next = tmp->next;
+        if (tmp->id == id) {
+            if (prev) {
+                prev->next = next;
+            } else {
+                timeouts = next;
+            }
+            free(tmp->cmd);
+            free(tmp);
+            rettv->vval.v_number = 0;
+            rettv->v_type = VAR_NUMBER;
+            return;
+        } else {
+            prev = tmp;
+        }
+        tmp = next;
+    }
+    rettv->vval.v_number = 1;
+    rettv->v_type = VAR_NUMBER;
+    EMSG2(_(e_invarg2), "Timeout id not found.");
+}
+#endif
+
 /*
  * "setpos()" function
  */
diff --git a/src/feature.h b/src/feature.h
index d4b9aea..d12a3d2 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -467,6 +467,14 @@
 #endif
 
 /*
+ * +async		settimeout and setinterval functions.
+ */
+#if defined(FEAT_NORMAL) && defined(MSWIN) || defined(MACOS_X) || \
+	defined(HAVE_GETTIMEOFDAY) && defined(HAVE_SYS_TIME_H)
+# define FEAT_ASYNC
+#endif
+
+/*
  * +diff		Displaying diffs in a nice way.
  *			Requires +windows and +autocmd.
  */
diff --git a/src/globals.h b/src/globals.h
index feb1dd4..615cce9 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1626,3 +1626,8 @@
 #ifdef FEAT_ARABIC
 # include "arabic.h"
 #endif
+
+/*
+ * For keeping track of timeouts.
+ */
+EXTERN timeout_T *timeouts INIT(= NULL);
diff --git a/src/gui.c b/src/gui.c
index b667ba3..7387359 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -2863,6 +2863,7 @@ enum {
     long    wtime;
 {
     int	    retval;
+    int i = 0;
 
 #ifdef FEAT_MENU
     /*
@@ -2898,18 +2899,31 @@ enum {
     gui_mch_start_blink();
 
     retval = FAIL;
+
+    i = 0;
+    while (i < p_ut) {
+#ifdef FEAT_ASYNC
+		retval = gui_mch_wait_for_chars(p_tt);
+		call_timeouts();
+		i += p_tt;
+#else
+		retval = gui_mch_wait_for_chars(p_ut);
+		i += p_ut;
+#endif
+		if (retval == OK) {
+			break;
+		}
+    }
+
+#ifdef FEAT_AUTOCMD
     /*
      * We may want to trigger the CursorHold event.  First wait for
      * 'updatetime' and if nothing is typed within that time put the
      * K_CURSORHOLD key in the input buffer.
      */
-    if (gui_mch_wait_for_chars(p_ut) == OK)
-	retval = OK;
-#ifdef FEAT_AUTOCMD
-    else if (trigger_cursorhold())
+    if (retval == FAIL && trigger_cursorhold())
     {
 	char_u	buf[3];
-
 	/* Put K_CURSORHOLD in the input buffer. */
 	buf[0] = CSI;
 	buf[1] = KS_EXTRA;
@@ -2920,13 +2934,6 @@ enum {
     }
 #endif
 
-    if (retval == FAIL)
-    {
-	/* Blocking wait. */
-	before_blocking();
-	retval = gui_mch_wait_for_chars(-1L);
-    }
-
     gui_mch_stop_blink();
     return retval;
 }
diff --git a/src/main.aap b/src/main.aap
index 3c91d39..bd53ce0 100644
--- a/src/main.aap
+++ b/src/main.aap
@@ -290,6 +290,7 @@ testclean {virtual}:
 # Some are optional and depend on configure.
 # "version.c" is missing, it's always compiled (see below).
 Source =
+        async.c
         blowfish.c
         buffer.c
         charset.c
diff --git a/src/option.c b/src/option.c
index bf65556..b78809f 100644
--- a/src/option.c
+++ b/src/option.c
@@ -2590,6 +2590,14 @@ struct vimoption
 			    (char_u *)NULL, PV_NONE,
 #endif
 			    {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
+    {"ticktime",  "tt",   P_NUM|P_VI_DEF,
+#ifdef FEAT_ASYNC
+				(char_u *)&p_tt, PV_NONE,
+#else
+			    (char_u *)NULL, PV_NONE,
+#endif
+			    {(char_u *)100L, (char_u *)0L} SCRIPTID_INIT},
+
     {"tildeop",	    "top",  P_BOOL|P_VI_DEF|P_VIM,
 			    (char_u *)&p_to, PV_NONE,
 			    {(char_u *)FALSE, (char_u *)0L} SCRIPTID_INIT},
diff --git a/src/option.h b/src/option.h
index 167b562..ae2ba22 100644
--- a/src/option.h
+++ b/src/option.h
@@ -795,6 +795,9 @@
 #ifdef FEAT_INS_EXPAND
 EXTERN char_u	*p_tsr;		/* 'thesaurus' */
 #endif
+#ifdef FEAT_ASYNC
+EXTERN long	p_tt;		/* 'ticktime' */
+#endif
 EXTERN int	p_ttimeout;	/* 'ttimeout' */
 EXTERN long	p_ttm;		/* 'ttimeoutlen' */
 EXTERN int	p_tbi;		/* 'ttybuiltin' */
diff --git a/src/os_macosx.m b/src/os_macosx.m
index d919f63..1b8c5b5 100644
--- a/src/os_macosx.m
+++ b/src/os_macosx.m
@@ -23,6 +23,22 @@
 #include "vim.h"
 #import <Cocoa/Cocoa.h>
 
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+
+
+#define MCH_MONOTONIC_TIME
+	unsigned long long
+mch_monotonic_time(void)
+{
+	mach_timebase_info_data_t info;
+
+	if (mach_timebase_info(&info) != KERN_SUCCESS)
+		abort();
+
+	return (mach_absolute_time() * info.numer / info.denom) / 1000000;
+}
+
 
 /*
  * Clipboard support for the console.
diff --git a/src/os_unix.c b/src/os_unix.c
index cc02653..bd2d6dc 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -892,6 +892,17 @@ catch_sigpwr SIGDEFARG(sigarg)
 }
 #endif
 
+#if !defined(MACOS_X_UNIX)
+#define MCH_MONOTONIC_TIME
+	unsigned long long
+mch_monotonic_time(void)
+{
+	struct timespec ts;
+	clock_gettime(CLOCK_MONOTONIC, &ts);
+	return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
+}
+#endif
+
 #ifdef SET_SIG_ALARM
 /*
  * signal function for alarm().
@@ -5057,7 +5068,7 @@ sigcont_handler SIGDEFARG(sigarg)
 #ifdef FEAT_NETBEANS_INTG
     int		nb_fd = netbeans_filedesc();
 #endif
-#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME)
+#if defined(FEAT_XCLIPBOARD) || defined(USE_XSMP) || defined(FEAT_MZSCHEME) || defined(FEAT_ASYNC)
     static int	busy = FALSE;
 
     /* May retry getting characters after an event was handled. */
@@ -5072,18 +5083,24 @@ sigcont_handler SIGDEFARG(sigarg)
     if (msec > 0 && (
 #  ifdef FEAT_XCLIPBOARD
 	    xterm_Shell != (Widget)0
-#   if defined(USE_XSMP) || defined(FEAT_MZSCHEME)
+#   if defined(USE_XSMP) || defined(FEAT_MZSCHEME) || defined(FEAT_ASYNC)
 	    ||
 #   endif
 #  endif
 #  ifdef USE_XSMP
 	    xsmp_icefd != -1
-#   ifdef FEAT_MZSCHEME
+#   if defined(FEAT_MZSCHEME) || defined(FEAT_ASYNC)
 	    ||
 #   endif
 #  endif
 #  ifdef FEAT_MZSCHEME
 	(mzthreads_allowed() && p_mzq > 0)
+#   ifdef FEAT_ASYNC
+	    ||
+#   endif
+#  endif
+#  ifdef FEAT_ASYNC
+	TRUE
 #  endif
 	    ))
 	gettimeofday(&start_tv, NULL);
@@ -5130,6 +5147,12 @@ sigcont_handler SIGDEFARG(sigarg)
 	    mzquantum_used = TRUE;
 	}
 # endif
+# ifdef FEAT_ASYNC
+	call_timeouts();
+	if (p_tt > 0 && (msec < 0 || msec > p_tt)) {
+		towait = p_tt;
+	}
+# endif
 	fds[0].fd = fd;
 	fds[0].events = POLLIN;
 	nfd = 1;
@@ -5257,6 +5280,12 @@ sigcont_handler SIGDEFARG(sigarg)
 	    mzquantum_used = TRUE;
 	}
 # endif
+# ifdef FEAT_ASYNC
+	call_timeouts();
+	if (p_tt > 0 && (msec < 0 || msec > p_tt)) {
+		towait = p_tt;
+	}
+# endif
 # ifdef __EMX__
 	/* don't check for incoming chars if not in raw mode, because select()
 	 * always returns TRUE then (in some version of emx.dll) */
@@ -5369,6 +5398,10 @@ sigcont_handler SIGDEFARG(sigarg)
 	    /* loop if MzThreads must be scheduled and timeout occurred */
 	    finished = FALSE;
 # endif
+# ifdef FEAT_ASYNC
+	if (ret == 0 && msec > p_tt)
+	    finished = FALSE;
+# endif
 
 # ifdef FEAT_SNIFF
 	if (ret < 0 )
@@ -7367,5 +7400,4 @@ sig_sysmouse SIGDEFARG(sigarg)
       0,  0,229,  0,  0,  0,  0,196,  0,  0,  0,  0,227,228,  0,233,
 };
 
-
 #endif
diff --git a/src/os_win32.c b/src/os_win32.c
index f36dfb3..335bbc1 100644
--- a/src/os_win32.c
+++ b/src/os_win32.c
@@ -29,6 +29,7 @@
 #include <sys/types.h>
 #include <signal.h>
 #include <limits.h>
+#include <math.h>
 
 /* cproto fails on missing include files */
 #ifndef PROTO
@@ -634,6 +635,52 @@ typedef DWORD (WINAPI *PGNSECINFOW) (LPWSTR, SE_OBJECT_TYPE,
     }
 }
 
+	unsigned long long
+mch_monotonic_time(void)
+{	
+	static ULONGLONG (*GetTickCount64) (void) = NULL;
+	static ULONGLONG (CALLBACK *_GetTickCount64)(void);
+	static int has_getickcount64 = -1;
+	ULONGLONG result;
+	OSVERSIONINFO ovi;
+
+	ovi.dwOSVersionInfoSize = sizeof(ovi);
+	GetVersionEx(&ovi);
+
+	if (has_getickcount64 == -1)
+	{
+	    /* GetTickCount64() was added to Windows Vista */
+	    if (ovi.dwMajorVersion >= 6)
+	    {
+	        HINSTANCE hKernel32 = GetModuleHandleW(L"KERNEL32");
+	        *(FARPROC*)&_GetTickCount64 = GetProcAddress(hKernel32,
+	                                                       "GetTickCount64");
+	        has_getickcount64 = (_GetTickCount64 != NULL);
+	    }
+	    else
+	        has_getickcount64 = 0;
+	}
+
+	if (has_getickcount64)
+	{
+	    result = _GetTickCount64();
+	}
+	else
+	{
+	    static DWORD last_ticks = 0;
+	    static DWORD n_overflow = 0;
+	    DWORD ticks;
+
+	    ticks = GetTickCount();
+	    if (ticks < last_ticks)
+	        n_overflow++;
+	    last_ticks = ticks;
+
+	    result = (unsigned long long)ldexp(n_overflow, 32);
+	    result += ticks;
+	}
+    return result;
+}
 /*
  * Return TRUE when running on Windows 95 (or 98 or ME).
  * Only to be used after mch_init().
diff --git a/src/os_win32.h b/src/os_win32.h
index 58b179f..9145527 100644
--- a/src/os_win32.h
+++ b/src/os_win32.h
@@ -56,6 +56,7 @@
 #define HAVE_ST_MODE		/* have stat.st_mode */
 
 #define FEAT_SHORTCUT		/* resolve shortcuts */
+#define MCH_MONOTONIC_TIME	/* for async */
 
 #if (!defined(__BORLANDC__) || __BORLANDC__ >= 0x550) \
 	&& (!defined(_MSC_VER) || _MSC_VER > 1020)
diff --git a/src/proto.h b/src/proto.h
index 191ecd8..135aff9 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -293,3 +293,7 @@
 # define _PROTO_H
 #endif
 #endif /* !PROTO && !NOPROTO */
+
+#ifdef FEAT_ASYNC
+# include "async.pro"
+#endif
\ No newline at end of file
diff --git a/src/proto/async.pro b/src/proto/async.pro
new file mode 100644
index 0000000..006475f
--- /dev/null
+++ b/src/proto/async.pro
@@ -0,0 +1,5 @@
+/* async.c */
+unsigned long long get_monotonic_time __ARGS((void));
+void insert_timeout __ARGS((timeout_T *to));
+void call_timeouts __ARGS((void));
+/* vim: set ft=c : */
diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro
index e4cad51..632179e 100644
--- a/src/proto/os_unix.pro
+++ b/src/proto/os_unix.pro
@@ -6,6 +6,7 @@ int mch_char_avail __ARGS((void));
 long_u mch_total_mem __ARGS((int special));
 void mch_delay __ARGS((long msec, int ignoreinput));
 int mch_stackcheck __ARGS((char *p));
+unsigned long long mch_monotonic_time __ARGS((void));
 void mch_startjmp __ARGS((void));
 void mch_endjmp __ARGS((void));
 void mch_didjmp __ARGS((void));
diff --git a/src/proto/os_win32.pro b/src/proto/os_win32.pro
index a4c590f..5db7ba2 100644
--- a/src/proto/os_win32.pro
+++ b/src/proto/os_win32.pro
@@ -55,4 +55,5 @@ void free_cmd_argsW __ARGS((void));
 void used_file_arg __ARGS((char *name, int literal, int full_path, int diff_mode));
 void set_alist_count __ARGS((void));
 void fix_arg_enc __ARGS((void));
+unsigned long long mch_monotonic_time __ARGS((void));
 /* vim: set ft=c : */
diff --git a/src/structs.h b/src/structs.h
index f74d218..8a0fb2d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -2540,3 +2540,17 @@ struct VimMenu
   UINT32_T state[8];
   char_u   buffer[64];
 } context_sha256_T;
+
+#ifdef FEAT_ASYNC
+/*
+ * Used for async settimeout/interval.
+ */
+struct timeout_T {
+    int id;                     /* timeout/interval id */
+    int interval;               /* interval period if interval, otherwise -1 */
+    unsigned long long tm;           /* time to fire (epoch milliseconds) */
+    char_u *cmd;                /* vim command to run */
+    struct timeout_T *next;     /* pointer to next timeout in linked list */
+};
+typedef struct timeout_T timeout_T;
+#endif
diff --git a/src/version.c b/src/version.c
index ef3f9b1..f98a1b5 100644
--- a/src/version.c
+++ b/src/version.c
@@ -77,6 +77,11 @@
 #else
 	"-arabic",
 #endif
+#ifdef FEAT_ASYNC
+	"+async",
+#else
+	"-async",
+#endif
 #ifdef FEAT_AUTOCMD
 	"+autocmd",
 #else
-- 
1.8.4


Raspunde prin e-mail lui