From 114c696fd4b89e50c353bc0b4315925efcb17e18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5ivo=20Leedj=C3=A4rv?= Date: Wed, 2 Nov 2022 15:52:54 +0100 Subject: [PATCH 1/6] Differentiate Lwt_unix platform at run time Lwt_unix does not implement all functions on Win32. Make it possible to differentiate the Lwt_unix implementation at run time to avoid calling unimplemented functions. Previously this differentiation was done by probing the compiler OS platform (Win32? with Cygwin?) but this is not reliable because it does not indicate the actual Lwt_unix implementation that's linked in. --- src/external.ml | 2 +- src/lwt/generic/lwt_unix_impl.ml | 2 ++ src/lwt/lwt_unix.mli | 6 ++++++ src/lwt/win/lwt_unix_impl.ml | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/external.ml b/src/external.ml index cefb9ea98..863ad8ede 100644 --- a/src/external.ml +++ b/src/external.ml @@ -81,7 +81,7 @@ let readChannelsTillEof l = l let runExternalProgram cmd = - if Util.osType = `Win32 && not Util.isCygwin then begin + if Lwt_unix.impl_platform = `Win32 then begin debug (fun()-> Util.msg "Executing external program windows-style\n"); let c = openProcessIn ("\"" ^ cmd ^ "\"") in let log = Util.trimWhitespace (readChannelTillEof c) in diff --git a/src/lwt/generic/lwt_unix_impl.ml b/src/lwt/generic/lwt_unix_impl.ml index 2bf98e99c..90f0648b9 100644 --- a/src/lwt/generic/lwt_unix_impl.ml +++ b/src/lwt/generic/lwt_unix_impl.ml @@ -13,6 +13,8 @@ therefore have the following limitations: time, this could result in a dead-lock. - [connect] is blocking *) +let impl_platform = `Generic + let windows_hack = Sys.os_type <> "Unix" let recent_ocaml = Scanf.sscanf Sys.ocaml_version "%d.%d" diff --git a/src/lwt/lwt_unix.mli b/src/lwt/lwt_unix.mli index 61860e0d2..8d87cd228 100644 --- a/src/lwt/lwt_unix.mli +++ b/src/lwt/lwt_unix.mli @@ -55,3 +55,9 @@ type lwt_in_channel val intern_in_channel : in_channel -> lwt_in_channel val input_line : lwt_in_channel -> string Lwt.t + +(* Not all functions are implemented on Win32. [impl_platform] indicates + which implementation has been built. This value must not be used to + detect the OS platform; it's intendend to be used for guarding code + which uses functions that are not implemented on Win32. *) +val impl_platform : [ `Generic | `Win32 ] diff --git a/src/lwt/win/lwt_unix_impl.ml b/src/lwt/win/lwt_unix_impl.ml index 779687476..7d3987632 100644 --- a/src/lwt/win/lwt_unix_impl.ml +++ b/src/lwt/win/lwt_unix_impl.ml @@ -3,6 +3,7 @@ conditions... (we have the first, scan the subsequent ones) *) +let impl_platform = `Win32 let no_overlapped_io = false let d = ref false From a1bc7be8c6bf2bbb6b35fbff5066eb2dc555b0c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5ivo=20Leedj=C3=A4rv?= Date: Fri, 28 Oct 2022 13:54:48 +0200 Subject: [PATCH 2/6] Add graceful stop in repeat mode - stdin Add a new stop request method to terminate repeat mode. See commit e72c1c5838ba6e85bcfba690a5a8fb228633a83a. Monitor stdin to read any of the several stop conditions. Using stdin for checking the repeat mode stop request opens up a wide range of possibilities for the user, including manual and automated, local and remote. This method is usable only if stdin is an interactive terminal or is redirected from a readable source that is not a regular file. --- doc/unison-manual.tex | 15 +++++- man/unison.1.in | 16 +++++- src/lwt/generic/lwt_unix_impl.ml | 2 + src/lwt/lwt_unix.mli | 1 + src/lwt/win/lwt_unix_impl.ml | 1 + src/pty.c | 24 +++++++++ src/uitext.ml | 89 +++++++++++++++++++++++++++++++- 7 files changed, 145 insertions(+), 3 deletions(-) diff --git a/doc/unison-manual.tex b/doc/unison-manual.tex index 6ed8d5973..50b6db341 100644 --- a/doc/unison-manual.tex +++ b/doc/unison-manual.tex @@ -1995,7 +1995,20 @@ monitoring), interrupting with ``Ctrl-C'' or with signal \verb|SIGINT| or \verb|SIGTERM| works the same way as described above and will additionally stop the continuous process. To stop only the continuous process and let the last -synchronization complete normally, send signal \verb|SIGUSR2| instead. +synchronization complete normally, press ``Ctrl-D'' or send signal +\verb|SIGUSR2| instead. +Closing the input, receiving an EOF, or receiving a \verb|^D| (0x04) from the +input terminal or a redirected standard input all have the same effect. If the +standard input is redirected from a regular file, is not open or is not open +for reading already at Unison startup then it is ignored and only signals can +be used to send the stop request. + +\begin{quote} + {\em Tips:} For continuous synchronization the input should not be redirected + from any source providing a lot of input (such as a device or a pipe that + produces large quantities of data). In such cases, Unison would keep reading + all the input looking for the stop condition. +\end{quote} \end{textui} \SUBSECTION{Exit Code}{exit} diff --git a/man/unison.1.in b/man/unison.1.in index e2397e5bc..76a80ba1e 100644 --- a/man/unison.1.in +++ b/man/unison.1.in @@ -310,9 +310,23 @@ or .Sy SIGTERM works the same way as described above and will additionally stop the continuous process. To stop only the continuous process and let the last synchronization -complete normally, send signal +complete normally, press +.Sy Ctrl-D +or send signal .Sy SIGUSR2 instead. +Closing the input, receiving an EOF, or receiving a +.Sy ^D +(0x04) from the input terminal or a redirected standard input all have the same +effect. If the standard input is redirected from a regular file, is not open or +is not open for reading already at Unison startup then it is ignored and only +signals can be used to send the stop request. +.Bd -ragged -offset indent +Tips: For continuous synchronization the input should not be redirected from +any source providing a lot of input (such as a device or a pipe that produces +large quantities of data). In such cases, Unison would keep reading all the +input looking for the stop condition. +.Ed .Sh ENVIRONMENT .Bl -tag .It Ev UNISON diff --git a/src/lwt/generic/lwt_unix_impl.ml b/src/lwt/generic/lwt_unix_impl.ml index 90f0648b9..298a03835 100644 --- a/src/lwt/generic/lwt_unix_impl.ml +++ b/src/lwt/generic/lwt_unix_impl.ml @@ -206,6 +206,8 @@ let wait_read ch = inputs := (ch, `Wait res) :: !inputs; res +let wait_read' = wait_read + let wait_write ch = let res = Lwt.wait () in outputs := (ch, `Wait res) :: !outputs; diff --git a/src/lwt/lwt_unix.mli b/src/lwt/lwt_unix.mli index 8d87cd228..a6fa9b712 100644 --- a/src/lwt/lwt_unix.mli +++ b/src/lwt/lwt_unix.mli @@ -38,6 +38,7 @@ val read : file_descr -> bytes -> int -> int -> int Lwt.t val write : file_descr -> bytes -> int -> int -> int Lwt.t val write_substring : file_descr -> string -> int -> int -> int Lwt.t val wait_read : file_descr -> unit Lwt.t +val wait_read' : Unix.file_descr -> unit Lwt.t val wait_write : file_descr -> unit Lwt.t val pipe_in : ?cloexec:bool -> unit -> file_descr * Unix.file_descr val pipe_out : ?cloexec:bool -> unit -> Unix.file_descr * file_descr diff --git a/src/lwt/win/lwt_unix_impl.ml b/src/lwt/win/lwt_unix_impl.ml index 7d3987632..050e65664 100644 --- a/src/lwt/win/lwt_unix_impl.ml +++ b/src/lwt/win/lwt_unix_impl.ml @@ -336,6 +336,7 @@ if !d then prerr_endline "ACCEPT"; (****) let wait_read ch = assert false +let wait_read' = wait_read let wait_write ch = assert false diff --git a/src/pty.c b/src/pty.c index a14d1b7d2..753c2e143 100644 --- a/src/pty.c +++ b/src/pty.c @@ -85,6 +85,30 @@ CAMLprim value c_openpty(value unit) { #endif +#ifndef _WIN32 + +#include + +CAMLprim value unsn_fd_readable(value fd) +{ + CAMLparam1(fd); + int fl = fcntl(Int_val(fd), F_GETFL); + if (fl == -1) { + caml_uerror("fcntl", Nothing); + } + CAMLreturn(Val_bool(!(fl & O_WRONLY))); +} + +#else // _WIN32 + +CAMLprim value unsn_fd_readable(value fd) +{ + CAMLparam0(); + CAMLreturn(Val_bool(1)); +} + +#endif + #ifdef _WIN32 #include diff --git a/src/uitext.ml b/src/uitext.ml index d6812b16e..8e538a626 100644 --- a/src/uitext.ml +++ b/src/uitext.ml @@ -1248,7 +1248,89 @@ let setupSafeStop () = if ok then stopPipe := Some (Lwt_unix.pipe_in ~cloexec:true ())) end +(*** Requesting safe termination via stdin ***) + +let nonEofStopCond s = + String.contains s '\004' (* ^D *) + +let selectStdin () = + match Unix.select [Unix.stdin] [] [] 0. with + | ([r1], _, _) when r1 ==(*phys*) Unix.stdin -> true + | _ -> false + +let rec readStdinNoIntr b l = + try Unix.read Unix.stdin b 0 l + with Unix.Unix_error (EINTR, _, _) -> readStdinNoIntr b l + +external fdIsReadable : Unix.file_descr -> bool = "unsn_fd_readable" + +let stdinIsatty = Unix.isatty Unix.stdin + +let stdinOkForStopReq = + let rec notEOF st = + if stdinIsatty then true else + match selectStdin () with + | true -> + let l = 32 in + let b = Bytes.create l in + begin match readStdinNoIntr b l with + | 0 -> false + | n -> + if nonEofStopCond (Bytes.sub_string b 0 n) then requestSafeStop (); + true + | exception Unix.Unix_error _ -> true + end + | false -> true + | exception Unix.Unix_error (EINTR, _, _) -> notEOF st + | exception Unix.Unix_error (EBADF, _, _) -> true + in + match Unix.LargeFile.fstat Unix.stdin with + | { st_kind = S_REG; _ } -> false + | st -> begin try fdIsReadable Unix.stdin with Unix.Unix_error _ -> true end && notEOF st + | exception Unix.Unix_error _ -> false + +let ignoreSignal signa f = + let prev = + try Some (Sys.signal signa Signal_ignore) + with Invalid_argument _ | Sys_error _ -> None in + let restoreSig () = + match prev with + | None -> () + | Some prev -> try Sys.set_signal signa prev with Sys_error _ -> () + in + try let r = f () in restoreSig (); r + with e -> + let origbt = Printexc.get_raw_backtrace () in + restoreSig (); + Printexc.raise_with_backtrace e origbt + +let isStdinStopCond n s = + n = 0 (* Assuming terminal_io.c_vmin > 0, this is true EOF *) + || nonEofStopCond s + +let readStopFromStdin () = + let l = 32 in + let b = Bytes.create l in + let ignoreTtin f = if stdinIsatty then ignoreSignal Sys.sigttin f else f () in + try + let n = ignoreTtin (fun () -> readStdinNoIntr b l) in + isStdinStopCond n (Bytes.sub_string b 0 n) + with + | Unix.Unix_error ((EAGAIN | EWOULDBLOCK), _, _) -> false + | Unix.Unix_error (EIO, _, _) -> false + | Unix.Unix_error (EBADF, _, _) -> true + +let rec checkStdinStopReq () = + if not stdinOkForStopReq then () else + match selectStdin () with + | true -> + if readStopFromStdin () then requestSafeStop () else checkStdinStopReq () + | false -> () + | exception Unix.Unix_error (EINTR, _, _) -> checkStdinStopReq () + | exception Unix.Unix_error (EBADF, _, _) -> () + let safeStopRequested () = + if not (safeStopReqd ()) then checkStdinStopReq (); safeStopReqd () (*** Sleep interruptible by a termination request ***) @@ -1265,8 +1347,13 @@ let safeStopWait = | e -> Lwt.fail e in let rec loop () = + let waitStdin () = + if not stdinOkForStopReq then Lwt.wait () + else if Lwt_unix.impl_platform = `Win32 then Lwt.wait () + else Lwt_unix.wait_read' Unix.stdin + in Lwt.catch - (fun () -> readStop) readFail >>= fun () -> + (fun () -> Lwt.choose [waitStdin (); readStop]) readFail >>= fun () -> if not (safeStopRequested ()) then Lwt_unix.sleep 0.15 >>= loop else From 1ae3db4c2c3a774f88b276b394a8a309581211d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5ivo=20Leedj=C3=A4rv?= Date: Sat, 29 Oct 2022 21:06:21 +0200 Subject: [PATCH 3/6] Add graceful stop in repeat mode - Windows stdin Add a new stop request method to terminate repeat mode. See commit e72c1c5838ba6e85bcfba690a5a8fb228633a83a. Enable the method from commit a1bc7be8c6bf2bbb6b35fbff5066eb2dc555b0c5 to work in Windows. --- src/uitext.ml | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/uitext.ml b/src/uitext.ml index 8e538a626..2ee432cd5 100644 --- a/src/uitext.ml +++ b/src/uitext.ml @@ -1253,8 +1253,12 @@ let setupSafeStop () = let nonEofStopCond s = String.contains s '\004' (* ^D *) +(* [Unix.select] emulation in Windows does not manage to capture all + events (for fds other than sockets/files) if timeout is zero. *) +let selectTimeout = if Sys.win32 then 0.01 else 0. + let selectStdin () = - match Unix.select [Unix.stdin] [] [] 0. with + match Unix.select [Unix.stdin] [] [] selectTimeout with | ([r1], _, _) when r1 ==(*phys*) Unix.stdin -> true | _ -> false @@ -1342,6 +1346,16 @@ let safeStopWait = | None -> Lwt.wait () | Some (i, _) -> Lwt_unix.wait_read i in + let winFd = ref None in + let winReadStdin () = + let (b, fd) = match !winFd with Some x -> x | None -> + let x = (Bytes.create 32, Lwt_unix.of_unix_file_descr Unix.stdin) in + winFd := Some x; x in + Lwt_unix.read fd b 0 (Bytes.length b) >>= fun n -> + if (isStdinStopCond n (Bytes.sub_string b 0 n)) then + requestSafeStop (); + Lwt.return () + in let readFail = function | Unix.Unix_error (EBADF, _, _) -> Lwt.return (requestSafeStop ()) | e -> Lwt.fail e @@ -1349,7 +1363,7 @@ let safeStopWait = let rec loop () = let waitStdin () = if not stdinOkForStopReq then Lwt.wait () - else if Lwt_unix.impl_platform = `Win32 then Lwt.wait () + else if Lwt_unix.impl_platform = `Win32 then winReadStdin () else Lwt_unix.wait_read' Unix.stdin in Lwt.catch From 95bc9f583dde5c051a9739c8723a09bad6eb1430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5ivo=20Leedj=C3=A4rv?= Date: Fri, 28 Oct 2022 12:56:04 +0200 Subject: [PATCH 4/6] Add graceful stop in repeat mode - background job Improve the method from commit a1bc7be8c6bf2bbb6b35fbff5066eb2dc555b0c5 to allow Unison run as a background job in an interactive terminal. Reading from stdin while not a foreground process will normally result in the process being stopped (or receiving EIO if ignoring the stop signal). Do not attempt to read from stdin while not in foreground. Guard the process against being stopped when trying to read from stdin at the wrong moment. --- src/pty.c | 29 +++++++++++++++++++++++++++++ src/uitext.ml | 12 ++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/pty.c b/src/pty.c index 753c2e143..727ebffa3 100644 --- a/src/pty.c +++ b/src/pty.c @@ -87,8 +87,25 @@ CAMLprim value c_openpty(value unit) { #ifndef _WIN32 +#include // pgrp #include +CAMLprim value unsn_getpgrp(value unit) +{ + CAMLparam0(); + CAMLreturn(Val_int(getpgrp())); +} + +CAMLprim value unsn_tcgetpgrp(value fd) +{ + CAMLparam1(fd); + pid_t pgrp = tcgetpgrp(Int_val(fd)); + if (pgrp == -1) { + caml_uerror("tcgetpgrp", Nothing); + } + CAMLreturn(Val_int(pgrp)); +} + CAMLprim value unsn_fd_readable(value fd) { CAMLparam1(fd); @@ -101,6 +118,18 @@ CAMLprim value unsn_fd_readable(value fd) #else // _WIN32 +CAMLprim value unsn_getpgrp(value unit) +{ + CAMLparam0(); + CAMLreturn(Val_int(-1)); +} + +CAMLprim value unsn_tcgetpgrp(value fd) +{ + CAMLparam0(); + CAMLreturn(Val_int(-1)); +} + CAMLprim value unsn_fd_readable(value fd) { CAMLparam0(); diff --git a/src/uitext.ml b/src/uitext.ml index 2ee432cd5..f40ef6c49 100644 --- a/src/uitext.ml +++ b/src/uitext.ml @@ -1293,6 +1293,14 @@ let stdinOkForStopReq = | st -> begin try fdIsReadable Unix.stdin with Unix.Unix_error _ -> true end && notEOF st | exception Unix.Unix_error _ -> false +external getpgrp : unit -> int = "unsn_getpgrp" +external tcgetpgrp : Unix.file_descr -> int = "unsn_tcgetpgrp" + +let isBackgroundProcess () = + try + stdinIsatty && (getpgrp () <> tcgetpgrp Unix.stdin) + with Unix.Unix_error ((EBADF | ENOTTY), _, _) -> false + let ignoreSignal signa f = let prev = try Some (Sys.signal signa Signal_ignore) @@ -1325,7 +1333,7 @@ let readStopFromStdin () = | Unix.Unix_error (EBADF, _, _) -> true let rec checkStdinStopReq () = - if not stdinOkForStopReq then () else + if not stdinOkForStopReq || isBackgroundProcess () then () else match selectStdin () with | true -> if readStopFromStdin () then requestSafeStop () else checkStdinStopReq () @@ -1369,7 +1377,7 @@ let safeStopWait = Lwt.catch (fun () -> Lwt.choose [waitStdin (); readStop]) readFail >>= fun () -> if not (safeStopRequested ()) then - Lwt_unix.sleep 0.15 >>= loop + Lwt_unix.sleep (if isBackgroundProcess () then 1. else 0.15) >>= loop else Lwt.return () in From 7a966413916bebfa7fa563963d8bbf777b4b3109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5ivo=20Leedj=C3=A4rv?= Date: Tue, 15 Nov 2022 13:28:29 +0100 Subject: [PATCH 5/6] Add graceful stop in repeat mode - regular file Add a new stop request method to terminate repeat mode. See commit e72c1c5838ba6e85bcfba690a5a8fb228633a83a. Enable the method from commit a1bc7be8c6bf2bbb6b35fbff5066eb2dc555b0c5 to work with stdin redirected from a regular file. Regular files differ from other sources: - Since a regular file is always ready for reading, limit the reads to once a second. - Reaching EOF in a regular file is not considered a stop request. This enables the process to be started with input redirected from an empty file and then waiting for data to be written into the file. - To prevent reading massive amounts of data, only enable the regular file method if the file is initially empty or at most 32 bytes in size. --- doc/unison-manual.tex | 16 +++++++++------- man/unison.1.in | 14 ++++++++------ src/uitext.ml | 20 +++++++++++++------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/doc/unison-manual.tex b/doc/unison-manual.tex index 50b6db341..b66d7130e 100644 --- a/doc/unison-manual.tex +++ b/doc/unison-manual.tex @@ -1998,16 +1998,18 @@ synchronization complete normally, press ``Ctrl-D'' or send signal \verb|SIGUSR2| instead. Closing the input, receiving an EOF, or receiving a \verb|^D| (0x04) from the -input terminal or a redirected standard input all have the same effect. If the -standard input is redirected from a regular file, is not open or is not open -for reading already at Unison startup then it is ignored and only signals can -be used to send the stop request. +input terminal or a redirected standard input all have the same effect. EOF is +not interpreted as a stop request when standard input is redirected from a +regular file. If the standard input is not open or is not open for reading +already at Unison startup then it is ignored and only signals can be used to +send the stop request. \begin{quote} {\em Tips:} For continuous synchronization the input should not be redirected - from any source providing a lot of input (such as a device or a pipe that - produces large quantities of data). In such cases, Unison would keep reading - all the input looking for the stop condition. + from any source providing a lot of input (such as an existing regular file + larger than a few tens of bytes or a device or a pipe that produces large + quantities of data). In such cases, Unison would keep reading all the input + looking for the stop condition. \end{quote} \end{textui} diff --git a/man/unison.1.in b/man/unison.1.in index 76a80ba1e..a4dea3681 100644 --- a/man/unison.1.in +++ b/man/unison.1.in @@ -318,14 +318,16 @@ instead. Closing the input, receiving an EOF, or receiving a .Sy ^D (0x04) from the input terminal or a redirected standard input all have the same -effect. If the standard input is redirected from a regular file, is not open or -is not open for reading already at Unison startup then it is ignored and only -signals can be used to send the stop request. +effect. EOF is not interpreted as a stop request when standard input is +redirected from a regular file. If the standard input is not open or is not +open for reading already at Unison startup then it is ignored and only signals +can be used to send the stop request. .Bd -ragged -offset indent Tips: For continuous synchronization the input should not be redirected from -any source providing a lot of input (such as a device or a pipe that produces -large quantities of data). In such cases, Unison would keep reading all the -input looking for the stop condition. +any source providing a lot of input (such as an existing regular file larger +than a few tens of bytes or a device or a pipe that produces large quantities +of data). In such cases, Unison would keep reading all the input looking for +the stop condition. .Ed .Sh ENVIRONMENT .Bl -tag diff --git a/src/uitext.ml b/src/uitext.ml index f40ef6c49..4067d0708 100644 --- a/src/uitext.ml +++ b/src/uitext.ml @@ -1270,7 +1270,11 @@ external fdIsReadable : Unix.file_descr -> bool = "unsn_fd_readable" let stdinIsatty = Unix.isatty Unix.stdin -let stdinOkForStopReq = +let stdinIsRegfile, stdinOkForStopReq = + let readingOk = function + | { Unix.LargeFile.st_kind = S_REG; st_size; _ } when st_size > 32L -> false + | _ -> begin try fdIsReadable Unix.stdin with Unix.Unix_error _ -> true end + in let rec notEOF st = if stdinIsatty then true else match selectStdin () with @@ -1289,9 +1293,9 @@ let stdinOkForStopReq = | exception Unix.Unix_error (EBADF, _, _) -> true in match Unix.LargeFile.fstat Unix.stdin with - | { st_kind = S_REG; _ } -> false - | st -> begin try fdIsReadable Unix.stdin with Unix.Unix_error _ -> true end && notEOF st - | exception Unix.Unix_error _ -> false + | { st_kind = S_REG; _ } as st -> true, readingOk st + | st -> false, readingOk st && notEOF st + | exception Unix.Unix_error _ -> false, false external getpgrp : unit -> int = "unsn_getpgrp" external tcgetpgrp : Unix.file_descr -> int = "unsn_tcgetpgrp" @@ -1317,7 +1321,7 @@ let ignoreSignal signa f = Printexc.raise_with_backtrace e origbt let isStdinStopCond n s = - n = 0 (* Assuming terminal_io.c_vmin > 0, this is true EOF *) + (n = 0 && not stdinIsRegfile) (* Assuming terminal_io.c_vmin > 0, this is true EOF *) || nonEofStopCond s let readStopFromStdin () = @@ -1336,7 +1340,8 @@ let rec checkStdinStopReq () = if not stdinOkForStopReq || isBackgroundProcess () then () else match selectStdin () with | true -> - if readStopFromStdin () then requestSafeStop () else checkStdinStopReq () + if readStopFromStdin () then requestSafeStop () + else if not stdinIsRegfile then checkStdinStopReq () | false -> () | exception Unix.Unix_error (EINTR, _, _) -> checkStdinStopReq () | exception Unix.Unix_error (EBADF, _, _) -> () @@ -1377,7 +1382,8 @@ let safeStopWait = Lwt.catch (fun () -> Lwt.choose [waitStdin (); readStop]) readFail >>= fun () -> if not (safeStopRequested ()) then - Lwt_unix.sleep (if isBackgroundProcess () then 1. else 0.15) >>= loop + (if stdinIsRegfile || isBackgroundProcess () then 1. else 0.15) + |> Lwt_unix.sleep >>= loop else Lwt.return () in From 7ff6fa4031543ece19aa2270a04d892957f7758a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?T=C3=B5ivo=20Leedj=C3=A4rv?= Date: Tue, 25 Oct 2022 16:26:08 +0200 Subject: [PATCH 6/6] Regen strings.ml --- src/strings.ml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/strings.ml b/src/strings.ml index b8787e203..664ae95d3 100644 --- a/src/strings.ml +++ b/src/strings.ml @@ -2785,6 +2785,26 @@ let docs = \032 cleanup procedures and terminates the process forcibly (similar to\n\ \032 SIGKILL). Doing so may leave the archives or replicas in an\n\ \032 inconsistent state or locked.\n\ + \032 When synchronizing continuously (time interval repeat or with\n\ + \032 filesystem monitoring), interrupting with \226\128\156Ctrl-C\226\128\157 or with signal\n\ + \032 SIGINT or SIGTERM works the same way as described above and will\n\ + \032 additionally stop the continuous process. To stop only the\n\ + \032 continuous process and let the last synchronization complete\n\ + \032 normally, press \226\128\156Ctrl-D\226\128\157 or send signal SIGUSR2 instead. Closing\n\ + \032 the input, receiving an EOF, or receiving a ^D (0x04) from the\n\ + \032 input terminal or a redirected standard input all have the same\n\ + \032 effect. EOF is not interpreted as a stop request when standard\n\ + \032 input is redirected from a regular file. If the standard input is\n\ + \032 not open or is not open for reading already at Unison startup then\n\ + \032 it is ignored and only signals can be used to send the stop\n\ + \032 request.\n\ + \n\ + \032 Tips: For continuous synchronization the input should not be\n\ + \032 redirected from any source providing a lot of input (such as an\n\ + \032 existing regular file larger than a few tens of bytes or a device or\n\ + \032 a pipe that produces large quantities of data). In such cases,\n\ + \032 Unison would keep reading all the input looking for the stop\n\ + \032 condition.\n\ \n\ Exit Code\n\ \n\