All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Jeff Hostetler via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "Ævar Arnfjörð Bjarmason" <avarab@gmail.com>,
	"Jeff Hostetler" <git@jeffhostetler.com>,
	"Jeff King" <peff@peff.net>,
	"SZEDER Gábor" <szeder.dev@gmail.com>,
	"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
	"Chris Torek" <chris.torek@gmail.com>,
	"Jeff Hostetler" <jeffhost@microsoft.com>
Subject: [PATCH v5 00/12] Simple IPC Mechanism
Date: Tue, 09 Mar 2021 15:02:25 +0000	[thread overview]
Message-ID: <pull.766.v5.git.1615302157.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.766.v4.git.1613598529.gitgitgadget@gmail.com>

Here is V5 of my "Simple IPC" series. This version is a reiteration of the
series and combines the original "Simple IPC Mechanism V4" series [1] and
the "Simple IPC Cleanups V1" series [2]. It squashes them together and then
includes responses to last minute comments received on both.

These include: (a) Rename PACKET_READ_NEVER_DIE to
PACKET_READ_GENTLE_ON_READ_ERROR. (b) Accept zero length timeout in
unix_stream_socket__conect(). Only supply the default timeout when a
negative value is passed. Make the default timeout value private to the .c
file.

I apologize for rerolling something that is in "next". I think the combined
result is better long term than preserving them as two sequential series.
Given where we are in the release cycle, I thought it best to have a cleaned
up series for consideration post v2.31.

[1] Upstream in jh/simple-ipc via
https://github.com/gitgitgadget/git/pull/766 (and in "next" relative to
v2.30.1)
https://lore.kernel.org/git/pull.766.v4.git.1613598529.gitgitgadget@gmail.com/T/#mbd1da5ff93ef273049090f697aeab68c74f698f1

[2] Upstream in `jh/simple-ipc-cleanups via
https://github.com/gitgitgadget/git/pull/893
https://lore.kernel.org/git/8ea6401c-6ee6-94cb-4e33-9dfffaf466e8@jeffhostetler.com/T/#t

Jeff Hostetler (9):
  pkt-line: eliminate the need for static buffer in
    packet_write_gently()
  simple-ipc: design documentation for new IPC mechanism
  simple-ipc: add win32 implementation
  unix-socket: eliminate static unix_stream_socket() helper function
  unix-socket: add backlog size option to unix_stream_listen()
  unix-socket: disallow chdir() when creating unix domain sockets
  unix-stream-server: create unix domain socket under lock
  simple-ipc: add Unix domain socket implementation
  t0052: add simple-ipc tests and t/helper/test-simple-ipc tool

Johannes Schindelin (3):
  pkt-line: do not issue flush packets in write_packetized_*()
  pkt-line: add PACKET_READ_GENTLE_ON_READ_ERROR option
  pkt-line: add options argument to read_packetized_to_strbuf()

 Documentation/technical/api-simple-ipc.txt | 105 +++
 Makefile                                   |   9 +
 builtin/credential-cache--daemon.c         |   3 +-
 builtin/credential-cache.c                 |   2 +-
 compat/simple-ipc/ipc-shared.c             |  28 +
 compat/simple-ipc/ipc-unix-socket.c        | 986 +++++++++++++++++++++
 compat/simple-ipc/ipc-win32.c              | 751 ++++++++++++++++
 config.mak.uname                           |   2 +
 contrib/buildsystems/CMakeLists.txt        |   8 +-
 convert.c                                  |  11 +-
 pkt-line.c                                 |  58 +-
 pkt-line.h                                 |  17 +-
 simple-ipc.h                               | 239 +++++
 t/helper/test-simple-ipc.c                 | 787 ++++++++++++++++
 t/helper/test-tool.c                       |   1 +
 t/helper/test-tool.h                       |   1 +
 t/t0052-simple-ipc.sh                      | 122 +++
 unix-socket.c                              |  53 +-
 unix-socket.h                              |  12 +-
 unix-stream-server.c                       | 128 +++
 unix-stream-server.h                       |  36 +
 21 files changed, 3307 insertions(+), 52 deletions(-)
 create mode 100644 Documentation/technical/api-simple-ipc.txt
 create mode 100644 compat/simple-ipc/ipc-shared.c
 create mode 100644 compat/simple-ipc/ipc-unix-socket.c
 create mode 100644 compat/simple-ipc/ipc-win32.c
 create mode 100644 simple-ipc.h
 create mode 100644 t/helper/test-simple-ipc.c
 create mode 100755 t/t0052-simple-ipc.sh
 create mode 100644 unix-stream-server.c
 create mode 100644 unix-stream-server.h


base-commit: f01623b2c9d14207e497b21ebc6b3ec4afaf4b46
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-766%2Fjeffhostetler%2Fsimple-ipc-v5
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-766/jeffhostetler/simple-ipc-v5
Pull-Request: https://github.com/gitgitgadget/git/pull/766

Range-diff vs v4:

  1:  2d6858b1625a !  1:  311ea4a5cd71 pkt-line: eliminate the need for static buffer in packet_write_gently()
     @@ Commit message
          static buffer, thread-safe scratch space, or an excessively large stack
          buffer.
      
     -    Change the API of `write_packetized_from_fd()` to accept a scratch space
     -    argument from its caller to avoid similar issues here.
     +    Change `write_packetized_from_fd()` to allocate a temporary buffer rather
     +    than using a static buffer to avoid similar issues here.
      
          These changes are intended to make it easier to use pkt-line routines in
          a multi-threaded context with multiple concurrent writers writing to
     @@ Commit message
      
          Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
      
     - ## convert.c ##
     -@@ convert.c: static int apply_multi_file_filter(const char *path, const char *src, size_t len
     - 	if (err)
     - 		goto done;
     - 
     --	if (fd >= 0)
     --		err = write_packetized_from_fd(fd, process->in);
     --	else
     -+	if (fd >= 0) {
     -+		struct packet_scratch_space scratch;
     -+		err = write_packetized_from_fd(fd, process->in, &scratch);
     -+	} else
     - 		err = write_packetized_from_buf(src, len, process->in);
     - 	if (err)
     - 		goto done;
     -
       ## pkt-line.c ##
      @@ pkt-line.c: int packet_write_fmt_gently(int fd, const char *fmt, ...)
       
     @@ pkt-line.c: int packet_write_fmt_gently(int fd, const char *fmt, ...)
       	return 0;
       }
      @@ pkt-line.c: void packet_buf_write_len(struct strbuf *buf, const char *data, size_t len)
     - 	packet_trace(data, len, 1);
     - }
       
     --int write_packetized_from_fd(int fd_in, int fd_out)
     -+int write_packetized_from_fd(int fd_in, int fd_out,
     -+			     struct packet_scratch_space *scratch)
     + int write_packetized_from_fd(int fd_in, int fd_out)
       {
      -	static char buf[LARGE_PACKET_DATA_MAX];
     ++	char *buf = xmalloc(LARGE_PACKET_DATA_MAX);
       	int err = 0;
       	ssize_t bytes_to_write;
       
       	while (!err) {
      -		bytes_to_write = xread(fd_in, buf, sizeof(buf));
     -+		bytes_to_write = xread(fd_in, scratch->buffer,
     -+				       sizeof(scratch->buffer));
     - 		if (bytes_to_write < 0)
     +-		if (bytes_to_write < 0)
     ++		bytes_to_write = xread(fd_in, buf, LARGE_PACKET_DATA_MAX);
     ++		if (bytes_to_write < 0) {
     ++			free(buf);
       			return COPY_READ_ERROR;
     ++		}
       		if (bytes_to_write == 0)
       			break;
     --		err = packet_write_gently(fd_out, buf, bytes_to_write);
     -+		err = packet_write_gently(fd_out, scratch->buffer,
     -+					  bytes_to_write);
     + 		err = packet_write_gently(fd_out, buf, bytes_to_write);
       	}
       	if (!err)
       		err = packet_flush_gently(fd_out);
     -
     - ## pkt-line.h ##
     -@@
     - #include "strbuf.h"
     - #include "sideband.h"
     - 
     -+#define LARGE_PACKET_MAX 65520
     -+#define LARGE_PACKET_DATA_MAX (LARGE_PACKET_MAX - 4)
     -+
     -+struct packet_scratch_space {
     -+	char buffer[LARGE_PACKET_DATA_MAX]; /* does not include header bytes */
     -+};
     -+
     - /*
     -  * Write a packetized stream, where each line is preceded by
     -  * its length (including the header) as a 4-byte hex number.
     -@@ pkt-line.h: void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __attribute__((f
     - void packet_buf_write_len(struct strbuf *buf, const char *data, size_t len);
     - int packet_flush_gently(int fd);
     - int packet_write_fmt_gently(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
     --int write_packetized_from_fd(int fd_in, int fd_out);
     -+int write_packetized_from_fd(int fd_in, int fd_out, struct packet_scratch_space *scratch);
     - int write_packetized_from_buf(const char *src_in, size_t len, int fd_out);
     - 
     - /*
     -@@ pkt-line.h: enum packet_read_status packet_reader_read(struct packet_reader *reader);
     - enum packet_read_status packet_reader_peek(struct packet_reader *reader);
     - 
     - #define DEFAULT_PACKET_MAX 1000
     --#define LARGE_PACKET_MAX 65520
     --#define LARGE_PACKET_DATA_MAX (LARGE_PACKET_MAX - 4)
     -+
     - extern char packet_buffer[LARGE_PACKET_MAX];
     ++	free(buf);
     + 	return err;
     + }
       
     - struct packet_writer {
  2:  91a9f63d6692 !  2:  25157c1f4873 pkt-line: do not issue flush packets in write_packetized_*()
     @@ Commit message
      
       ## convert.c ##
      @@ convert.c: static int apply_multi_file_filter(const char *path, const char *src, size_t len
     + 		goto done;
       
     - 	if (fd >= 0) {
     - 		struct packet_scratch_space scratch;
     --		err = write_packetized_from_fd(fd, process->in, &scratch);
     -+		err = write_packetized_from_fd_no_flush(fd, process->in, &scratch);
     - 	} else
     + 	if (fd >= 0)
     +-		err = write_packetized_from_fd(fd, process->in);
     ++		err = write_packetized_from_fd_no_flush(fd, process->in);
     + 	else
      -		err = write_packetized_from_buf(src, len, process->in);
      +		err = write_packetized_from_buf_no_flush(src, len, process->in);
      +	if (err)
     @@ pkt-line.c: void packet_buf_write_len(struct strbuf *buf, const char *data, size
       	packet_trace(data, len, 1);
       }
       
     --int write_packetized_from_fd(int fd_in, int fd_out,
     --			     struct packet_scratch_space *scratch)
     -+int write_packetized_from_fd_no_flush(int fd_in, int fd_out,
     -+				      struct packet_scratch_space *scratch)
     +-int write_packetized_from_fd(int fd_in, int fd_out)
     ++int write_packetized_from_fd_no_flush(int fd_in, int fd_out)
       {
     + 	char *buf = xmalloc(LARGE_PACKET_DATA_MAX);
       	int err = 0;
     - 	ssize_t bytes_to_write;
     -@@ pkt-line.c: int write_packetized_from_fd(int fd_in, int fd_out,
     - 		err = packet_write_gently(fd_out, scratch->buffer,
     - 					  bytes_to_write);
     +@@ pkt-line.c: int write_packetized_from_fd(int fd_in, int fd_out)
     + 			break;
     + 		err = packet_write_gently(fd_out, buf, bytes_to_write);
       	}
      -	if (!err)
      -		err = packet_flush_gently(fd_out);
     + 	free(buf);
       	return err;
       }
       
     @@ pkt-line.h: void packet_buf_write(struct strbuf *buf, const char *fmt, ...) __at
       void packet_buf_write_len(struct strbuf *buf, const char *data, size_t len);
       int packet_flush_gently(int fd);
       int packet_write_fmt_gently(int fd, const char *fmt, ...) __attribute__((format (printf, 2, 3)));
     --int write_packetized_from_fd(int fd_in, int fd_out, struct packet_scratch_space *scratch);
     +-int write_packetized_from_fd(int fd_in, int fd_out);
      -int write_packetized_from_buf(const char *src_in, size_t len, int fd_out);
     -+int write_packetized_from_fd_no_flush(int fd_in, int fd_out, struct packet_scratch_space *scratch);
     ++int write_packetized_from_fd_no_flush(int fd_in, int fd_out);
      +int write_packetized_from_buf_no_flush(const char *src_in, size_t len, int fd_out);
       
       /*
  3:  e05467def4e1 !  3:  af3d13113bc9 pkt-line: (optionally) libify the packet readers
     @@ Metadata
      Author: Johannes Schindelin <Johannes.Schindelin@gmx.de>
      
       ## Commit message ##
     -    pkt-line: (optionally) libify the packet readers
     +    pkt-line: add PACKET_READ_GENTLE_ON_READ_ERROR option
     +
     +    Introduce PACKET_READ_GENTLE_ON_READ_ERROR option to help libify the
     +    packet readers.
      
          So far, the (possibly indirect) callers of `get_packet_data()` can ask
          that function to return an error instead of `die()`ing upon end-of-file.
          However, random read errors will still cause the process to die.
      
          So let's introduce an explicit option to tell the packet reader
     -    machinery to please be nice and only return an error.
     +    machinery to please be nice and only return an error on read errors.
      
          This change prepares pkt-line for use by long-running daemon processes.
          Such processes should be able to serve multiple concurrent clients and
     @@ Commit message
          a daemon should be able to drop that connection and continue serving
          existing and future connections.
      
     -    This ability will be used by a Git-aware "Internal FSMonitor" feature
     +    This ability will be used by a Git-aware "Builtin FSMonitor" feature
          in a later patch series.
      
          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
     +    Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
      
       ## pkt-line.c ##
      @@ pkt-line.c: static int get_packet_data(int fd, char **src_buf, size_t *src_size,
     @@ pkt-line.c: static int get_packet_data(int fd, char **src_buf, size_t *src_size,
       		ret = read_in_full(fd, dst, size);
      -		if (ret < 0)
      +		if (ret < 0) {
     -+			if (options & PACKET_READ_NEVER_DIE)
     ++			if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
      +				return error_errno(_("read error"));
       			die_errno(_("read error"));
      +		}
     @@ pkt-line.c: static int get_packet_data(int fd, char **src_buf, size_t *src_size,
       		if (options & PACKET_READ_GENTLE_ON_EOF)
       			return -1;
       
     -+		if (options & PACKET_READ_NEVER_DIE)
     ++		if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
      +			return error(_("the remote end hung up unexpectedly"));
       		die(_("the remote end hung up unexpectedly"));
       	}
     @@ pkt-line.c: enum packet_read_status packet_read_with_status(int fd, char **src_b
       	len = packet_length(linelen);
       
       	if (len < 0) {
     -+		if (options & PACKET_READ_NEVER_DIE)
     ++		if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
      +			return error(_("protocol error: bad line length "
      +				       "character: %.4s"), linelen);
       		die(_("protocol error: bad line length character: %.4s"), linelen);
     @@ pkt-line.c: enum packet_read_status packet_read_with_status(int fd, char **src_b
       		*pktlen = 0;
       		return PACKET_READ_RESPONSE_END;
       	} else if (len < 4) {
     -+		if (options & PACKET_READ_NEVER_DIE)
     ++		if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
      +			return error(_("protocol error: bad line length %d"),
      +				     len);
       		die(_("protocol error: bad line length %d"), len);
     @@ pkt-line.c: enum packet_read_status packet_read_with_status(int fd, char **src_b
       	len -= 4;
      -	if ((unsigned)len >= size)
      +	if ((unsigned)len >= size) {
     -+		if (options & PACKET_READ_NEVER_DIE)
     ++		if (options & PACKET_READ_GENTLE_ON_READ_ERROR)
      +			return error(_("protocol error: bad line length %d"),
      +				     len);
       		die(_("protocol error: bad line length %d"), len);
     @@ pkt-line.h: int write_packetized_from_buf_no_flush(const char *src_in, size_t le
        * If options contains PACKET_READ_DIE_ON_ERR_PACKET, it dies when it sees an
        * ERR packet.
      + *
     -+ * With `PACKET_READ_NEVER_DIE`, no errors are allowed to trigger die() (except
     -+ * an ERR packet, when `PACKET_READ_DIE_ON_ERR_PACKET` is in effect).
     ++ * If options contains PACKET_READ_GENTLE_ON_READ_ERROR, we will not die
     ++ * on read errors, but instead return -1.  However, we may still die on an
     ++ * ERR packet (if requested).
        */
     - #define PACKET_READ_GENTLE_ON_EOF     (1u<<0)
     - #define PACKET_READ_CHOMP_NEWLINE     (1u<<1)
     - #define PACKET_READ_DIE_ON_ERR_PACKET (1u<<2)
     -+#define PACKET_READ_NEVER_DIE         (1u<<3)
     +-#define PACKET_READ_GENTLE_ON_EOF     (1u<<0)
     +-#define PACKET_READ_CHOMP_NEWLINE     (1u<<1)
     +-#define PACKET_READ_DIE_ON_ERR_PACKET (1u<<2)
     ++#define PACKET_READ_GENTLE_ON_EOF        (1u<<0)
     ++#define PACKET_READ_CHOMP_NEWLINE        (1u<<1)
     ++#define PACKET_READ_DIE_ON_ERR_PACKET    (1u<<2)
     ++#define PACKET_READ_GENTLE_ON_READ_ERROR (1u<<3)
       int packet_read(int fd, char **src_buffer, size_t *src_len, char
       		*buffer, unsigned size, int options);
       
  4:  81e14bed955c =  4:  b73e66a69b61 pkt-line: add options argument to read_packetized_to_strbuf()
  5:  22eec60761a8 <  -:  ------------ simple-ipc: design documentation for new IPC mechanism
  -:  ------------ >  5:  1ae99d824a21 simple-ipc: design documentation for new IPC mechanism
  6:  171ec43ecfa4 !  6:  8b3ce40e4538 simple-ipc: add win32 implementation
     @@ compat/simple-ipc/ipc-win32.c (new)
      +
      +	if (read_packetized_to_strbuf(
      +		    connection->fd, answer,
     -+		    PACKET_READ_GENTLE_ON_EOF | PACKET_READ_NEVER_DIE) < 0) {
     ++		    PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR) < 0) {
      +		ret = error(_("could not read IPC response"));
      +		goto done;
      +	}
     @@ compat/simple-ipc/ipc-win32.c (new)
      +
      +	ret = read_packetized_to_strbuf(
      +		reply_data.fd, &buf,
     -+		PACKET_READ_GENTLE_ON_EOF | PACKET_READ_NEVER_DIE);
     ++		PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR);
      +	if (ret >= 0) {
      +		ret = server_thread_data->server_data->application_cb(
      +			server_thread_data->server_data->application_data,
     @@ compat/simple-ipc/ipc-win32.c (new)
      +	*returned_server_data = NULL;
      +
      +	ret = initialize_pipe_name(path, wpath, ARRAY_SIZE(wpath));
     -+	if (ret < 0)
     -+		return error(
     -+			_("could not create normalized wchar_t path for '%s'"),
     -+			path);
     ++	if (ret < 0) {
     ++		errno = EINVAL;
     ++		return -1;
     ++	}
      +
      +	hPipeFirst = create_new_pipe(wpath, 1);
     -+	if (hPipeFirst == INVALID_HANDLE_VALUE)
     -+		return error(_("IPC server already running on '%s'"), path);
     ++	if (hPipeFirst == INVALID_HANDLE_VALUE) {
     ++		errno = EADDRINUSE;
     ++		return -2;
     ++	}
      +
      +	server_data = xcalloc(1, sizeof(*server_data));
      +	server_data->magic = MAGIC_SERVER_DATA;
     @@ simple-ipc.h (new)
      + *
      + * Returns 0 if the asynchronous server pool was started successfully.
      + * Returns -1 if not.
     ++ * Returns -2 if we could not startup because another server is using
     ++ * the socket or named pipe.
      + *
      + * When a client IPC message is received, the `application_cb` will be
      + * called (possibly on a random thread) to handle the message and
     @@ simple-ipc.h (new)
      + *
      + * Returns 0 after the server has completed successfully.
      + * Returns -1 if the server cannot be started.
     ++ * Returns -2 if we could not startup because another server is using
     ++ * the socket or named pipe.
      + *
      + * When a client IPC message is received, the `application_cb` will be
      + * called (possibly on a random thread) to handle the message and
  7:  b368318e6a23 !  7:  34df1af98e5b unix-socket: elimiate static unix_stream_socket() helper function
     @@ Metadata
      Author: Jeff Hostetler <jeffhost@microsoft.com>
      
       ## Commit message ##
     -    unix-socket: elimiate static unix_stream_socket() helper function
     +    unix-socket: eliminate static unix_stream_socket() helper function
      
          The static helper function `unix_stream_socket()` calls `die()`.  This
          is not appropriate for all callers.  Eliminate the wrapper function
  8:  985b2e02b2df !  8:  d6ff6e0e050a unix-socket: add backlog size option to unix_stream_listen()
     @@ builtin/credential-cache--daemon.c: static int serve_cache_loop(int fd)
       
      
       ## unix-socket.c ##
     +@@
     + #include "cache.h"
     + #include "unix-socket.h"
     + 
     ++#define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5)
     ++
     + static int chdir_len(const char *orig, int len)
     + {
     + 	char *path = xmemdupz(orig, len);
      @@ unix-socket.c: int unix_stream_connect(const char *path)
       	return -1;
       }
     @@ unix-socket.h
      +	int listen_backlog_size;
      +};
      +
     -+#define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5)
     -+
     -+#define UNIX_STREAM_LISTEN_OPTS_INIT \
     -+{ \
     -+	.listen_backlog_size = DEFAULT_UNIX_STREAM_LISTEN_BACKLOG, \
     -+}
     ++#define UNIX_STREAM_LISTEN_OPTS_INIT { 0 }
      +
       int unix_stream_connect(const char *path);
      -int unix_stream_listen(const char *path);
  9:  1bfa36409d07 !  9:  21b8d3c63dbf unix-socket: disallow chdir() when creating unix domain sockets
     @@ unix-socket.h
      +	unsigned int disallow_chdir:1;
       };
       
     - #define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5)
     -@@ unix-socket.h: struct unix_stream_listen_opts {
     - #define UNIX_STREAM_LISTEN_OPTS_INIT \
     - { \
     - 	.listen_backlog_size = DEFAULT_UNIX_STREAM_LISTEN_BACKLOG, \
     -+	.disallow_chdir = 0, \
     - }
     + #define UNIX_STREAM_LISTEN_OPTS_INIT { 0 }
       
      -int unix_stream_connect(const char *path);
      +int unix_stream_connect(const char *path, int disallow_chdir);
 10:  b443e11ac32f ! 10:  1ee9de55a106 unix-socket: create `unix_stream_server__listen_with_lock()`
     @@ Metadata
      Author: Jeff Hostetler <jeffhost@microsoft.com>
      
       ## Commit message ##
     -    unix-socket: create `unix_stream_server__listen_with_lock()`
     +    unix-stream-server: create unix domain socket under lock
      
     -    Create a version of `unix_stream_listen()` that uses a ".lock" lockfile
     -    to create the unix domain socket in a race-free manner.
     +    Create a wrapper class for `unix_stream_listen()` that uses a ".lock"
     +    lockfile to create the unix domain socket in a race-free manner.
      
          Unix domain sockets have a fundamental problem on Unix systems because
          they persist in the filesystem until they are deleted.  This is
     @@ Commit message
      
          As an alternative, we hold a plain lockfile ("<path>.lock") as a
          mutual exclusion device.  Under the lock, we test if an existing
     -    socket ("<path>") is has an active server.  If not, create a new
     -    socket and begin listening.  Then we rollback the lockfile in all
     -    cases.
     +    socket ("<path>") is has an active server.  If not, we create a new
     +    socket and begin listening.  Then we use "rollback" to delete the
     +    lockfile in all cases.
     +
     +    This wrapper code conceptually exists at a higher-level than the core
     +    unix_stream_connect() and unix_stream_listen() routines that it
     +    consumes.  It is isolated in a wrapper class for clarity.
      
          Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
      
     - ## unix-socket.c ##
     + ## Makefile ##
     +@@ Makefile: ifdef NO_UNIX_SOCKETS
     + 	BASIC_CFLAGS += -DNO_UNIX_SOCKETS
     + else
     + 	LIB_OBJS += unix-socket.o
     ++	LIB_OBJS += unix-stream-server.o
     + endif
     + 
     + ifdef USE_WIN32_IPC
     +
     + ## contrib/buildsystems/CMakeLists.txt ##
     +@@ contrib/buildsystems/CMakeLists.txt: if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
     + 
     + elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
     + 	add_compile_definitions(PROCFS_EXECUTABLE_PATH="/proc/self/exe" HAVE_DEV_TTY )
     +-	list(APPEND compat_SOURCES unix-socket.c)
     ++	list(APPEND compat_SOURCES unix-socket.c unix-stream-server.c)
     + endif()
     + 
     + if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
     +
     + ## unix-stream-server.c (new) ##
      @@
     - #include "cache.h"
     ++#include "cache.h"
      +#include "lockfile.h"
     - #include "unix-socket.h"
     - 
     - static int chdir_len(const char *orig, int len)
     -@@ unix-socket.c: int unix_stream_listen(const char *path,
     - 	errno = saved_errno;
     - 	return -1;
     - }
     ++#include "unix-socket.h"
     ++#include "unix-stream-server.h"
      +
     ++#define DEFAULT_LOCK_TIMEOUT (100)
     ++
     ++/*
     ++ * Try to connect to a unix domain socket at `path` (if it exists) and
     ++ * see if there is a server listening.
     ++ *
     ++ * We don't know if the socket exists, whether a server died and
     ++ * failed to cleanup, or whether we have a live server listening, so
     ++ * we "poke" it.
     ++ *
     ++ * We immediately hangup without sending/receiving any data because we
     ++ * don't know anything about the protocol spoken and don't want to
     ++ * block while writing/reading data.  It is sufficient to just know
     ++ * that someone is listening.
     ++ */
      +static int is_another_server_alive(const char *path,
      +				   const struct unix_stream_listen_opts *opts)
      +{
     -+	struct stat st;
     -+	int fd;
     -+
     -+	if (!lstat(path, &st) && S_ISSOCK(st.st_mode)) {
     -+		/*
     -+		 * A socket-inode exists on disk at `path`, but we
     -+		 * don't know whether it belongs to an active server
     -+		 * or whether the last server died without cleaning
     -+		 * up.
     -+		 *
     -+		 * Poke it with a trivial connection to try to find
     -+		 * out.
     -+		 */
     -+		fd = unix_stream_connect(path, opts->disallow_chdir);
     -+		if (fd >= 0) {
     -+			close(fd);
     -+			return 1;
     -+		}
     ++	int fd = unix_stream_connect(path, opts->disallow_chdir);
     ++	if (fd >= 0) {
     ++		close(fd);
     ++		return 1;
      +	}
      +
      +	return 0;
      +}
      +
     -+struct unix_stream_server_socket *unix_stream_server__listen_with_lock(
     ++int unix_stream_server__create(
      +	const char *path,
     -+	const struct unix_stream_listen_opts *opts)
     ++	const struct unix_stream_listen_opts *opts,
     ++	long timeout_ms,
     ++	struct unix_stream_server_socket **new_server_socket)
      +{
      +	struct lock_file lock = LOCK_INIT;
      +	int fd_socket;
      +	struct unix_stream_server_socket *server_socket;
      +
     ++	*new_server_socket = NULL;
     ++
     ++	if (timeout_ms < 0)
     ++		timeout_ms = DEFAULT_LOCK_TIMEOUT;
     ++
      +	/*
      +	 * Create a lock at "<path>.lock" if we can.
      +	 */
     -+	if (hold_lock_file_for_update_timeout(&lock, path, 0,
     -+					      opts->timeout_ms) < 0) {
     -+		error_errno(_("could not lock listener socket '%s'"), path);
     -+		return NULL;
     -+	}
     ++	if (hold_lock_file_for_update_timeout(&lock, path, 0, timeout_ms) < 0)
     ++		return -1;
      +
      +	/*
      +	 * If another server is listening on "<path>" give up.  We do not
      +	 * want to create a socket and steal future connections from them.
      +	 */
      +	if (is_another_server_alive(path, opts)) {
     -+		errno = EADDRINUSE;
     -+		error_errno(_("listener socket already in use '%s'"), path);
      +		rollback_lock_file(&lock);
     -+		return NULL;
     ++		errno = EADDRINUSE;
     ++		return -2;
      +	}
      +
      +	/*
     @@ unix-socket.c: int unix_stream_listen(const char *path,
      +	 */
      +	fd_socket = unix_stream_listen(path, opts);
      +	if (fd_socket < 0) {
     -+		error_errno(_("could not create listener socket '%s'"), path);
     ++		int saved_errno = errno;
      +		rollback_lock_file(&lock);
     -+		return NULL;
     ++		errno = saved_errno;
     ++		return -1;
      +	}
      +
      +	server_socket = xcalloc(1, sizeof(*server_socket));
     @@ unix-socket.c: int unix_stream_listen(const char *path,
      +	server_socket->fd_socket = fd_socket;
      +	lstat(path, &server_socket->st_socket);
      +
     ++	*new_server_socket = server_socket;
     ++
      +	/*
      +	 * Always rollback (just delete) "<path>.lock" because we already created
      +	 * "<path>" as a socket and do not want to commit_lock to do the atomic
     @@ unix-socket.c: int unix_stream_listen(const char *path,
      +	 */
      +	rollback_lock_file(&lock);
      +
     -+	return server_socket;
     ++	return 0;
      +}
      +
      +void unix_stream_server__free(
     @@ unix-socket.c: int unix_stream_listen(const char *path,
      +
      +	if (st_now.st_ino != server_socket->st_socket.st_ino)
      +		return 1;
     ++	if (st_now.st_dev != server_socket->st_socket.st_dev)
     ++		return 1;
      +
     -+	/* We might also consider the ctime on some platforms. */
     ++	if (!S_ISSOCK(st_now.st_mode))
     ++		return 1;
      +
      +	return 0;
      +}
      
     - ## unix-socket.h ##
     + ## unix-stream-server.h (new) ##
      @@
     - #define UNIX_SOCKET_H
     - 
     - struct unix_stream_listen_opts {
     -+	long timeout_ms;
     - 	int listen_backlog_size;
     - 	unsigned int disallow_chdir:1;
     - };
     - 
     -+#define DEFAULT_UNIX_STREAM_LISTEN_TIMEOUT (100)
     - #define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5)
     - 
     - #define UNIX_STREAM_LISTEN_OPTS_INIT \
     - { \
     -+	.timeout_ms = DEFAULT_UNIX_STREAM_LISTEN_TIMEOUT, \
     - 	.listen_backlog_size = DEFAULT_UNIX_STREAM_LISTEN_BACKLOG, \
     - 	.disallow_chdir = 0, \
     - }
     -@@ unix-socket.h: int unix_stream_connect(const char *path, int disallow_chdir);
     - int unix_stream_listen(const char *path,
     - 		       const struct unix_stream_listen_opts *opts);
     - 
     ++#ifndef UNIX_STREAM_SERVER_H
     ++#define UNIX_STREAM_SERVER_H
     ++
     ++#include "unix-socket.h"
     ++
      +struct unix_stream_server_socket {
      +	char *path_socket;
      +	struct stat st_socket;
     @@ unix-socket.h: int unix_stream_connect(const char *path, int disallow_chdir);
      +/*
      + * Create a Unix Domain Socket at the given path under the protection
      + * of a '.lock' lockfile.
     ++ *
     ++ * Returns 0 on success, -1 on error, -2 if socket is in use.
      + */
     -+struct unix_stream_server_socket *unix_stream_server__listen_with_lock(
     ++int unix_stream_server__create(
      +	const char *path,
     -+	const struct unix_stream_listen_opts *opts);
     ++	const struct unix_stream_listen_opts *opts,
     ++	long timeout_ms,
     ++	struct unix_stream_server_socket **server_socket);
      +
      +/*
      + * Close and delete the socket.
     @@ unix-socket.h: int unix_stream_connect(const char *path, int disallow_chdir);
      +int unix_stream_server__was_stolen(
      +	struct unix_stream_server_socket *server_socket);
      +
     - #endif /* UNIX_SOCKET_H */
     ++#endif /* UNIX_STREAM_SERVER_H */
 11:  43c8db9a4468 ! 11:  f2e3b046cc8f simple-ipc: add Unix domain socket implementation
     @@ Commit message
      
       ## Makefile ##
      @@ Makefile: ifdef NO_UNIX_SOCKETS
     - 	BASIC_CFLAGS += -DNO_UNIX_SOCKETS
       else
       	LIB_OBJS += unix-socket.o
     + 	LIB_OBJS += unix-stream-server.o
      +	LIB_OBJS += compat/simple-ipc/ipc-shared.o
      +	LIB_OBJS += compat/simple-ipc/ipc-unix-socket.o
       endif
     @@ compat/simple-ipc/ipc-unix-socket.c (new)
      +#include "pkt-line.h"
      +#include "thread-utils.h"
      +#include "unix-socket.h"
     ++#include "unix-stream-server.h"
      +
      +#ifdef NO_UNIX_SOCKETS
      +#error compat/simple-ipc/ipc-unix-socket.c requires Unix sockets
     @@ compat/simple-ipc/ipc-unix-socket.c (new)
      +
      +	if (read_packetized_to_strbuf(
      +		    connection->fd, answer,
     -+		    PACKET_READ_GENTLE_ON_EOF | PACKET_READ_NEVER_DIE) < 0) {
     ++		    PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR) < 0) {
      +		ret = error(_("could not read IPC response"));
      +		goto done;
      +	}
     @@ compat/simple-ipc/ipc-unix-socket.c (new)
      +
      +	ret = read_packetized_to_strbuf(
      +		reply_data.fd, &buf,
     -+		PACKET_READ_GENTLE_ON_EOF | PACKET_READ_NEVER_DIE);
     ++		PACKET_READ_GENTLE_ON_EOF | PACKET_READ_GENTLE_ON_READ_ERROR);
      +	if (ret >= 0) {
      +		ret = worker_thread_data->server_data->application_cb(
      +			worker_thread_data->server_data->application_data,
     @@ compat/simple-ipc/ipc-unix-socket.c (new)
      + */
      +#define LISTEN_BACKLOG (50)
      +
     -+static struct unix_stream_server_socket *create_listener_socket(
     ++static int create_listener_socket(
      +	const char *path,
     -+	const struct ipc_server_opts *ipc_opts)
     ++	const struct ipc_server_opts *ipc_opts,
     ++	struct unix_stream_server_socket **new_server_socket)
      +{
      +	struct unix_stream_server_socket *server_socket = NULL;
      +	struct unix_stream_listen_opts uslg_opts = UNIX_STREAM_LISTEN_OPTS_INIT;
     ++	int ret;
      +
      +	uslg_opts.listen_backlog_size = LISTEN_BACKLOG;
      +	uslg_opts.disallow_chdir = ipc_opts->uds_disallow_chdir;
      +
     -+	server_socket = unix_stream_server__listen_with_lock(path, &uslg_opts);
     -+	if (!server_socket)
     -+		return NULL;
     ++	ret = unix_stream_server__create(path, &uslg_opts, -1, &server_socket);
     ++	if (ret)
     ++		return ret;
      +
      +	if (set_socket_blocking_flag(server_socket->fd_socket, 1)) {
      +		int saved_errno = errno;
     -+		error_errno(_("could not set listener socket nonblocking '%s'"),
     -+			    path);
      +		unix_stream_server__free(server_socket);
      +		errno = saved_errno;
     -+		return NULL;
     ++		return -1;
      +	}
      +
     ++	*new_server_socket = server_socket;
     ++
      +	trace2_data_string("ipc-server", NULL, "listen-with-lock", path);
     -+	return server_socket;
     ++	return 0;
      +}
      +
     -+static struct unix_stream_server_socket *setup_listener_socket(
     ++static int setup_listener_socket(
      +	const char *path,
     -+	const struct ipc_server_opts *ipc_opts)
     ++	const struct ipc_server_opts *ipc_opts,
     ++	struct unix_stream_server_socket **new_server_socket)
      +{
     -+	struct unix_stream_server_socket *server_socket;
     ++	int ret, saved_errno;
      +
      +	trace2_region_enter("ipc-server", "create-listener_socket", NULL);
     -+	server_socket = create_listener_socket(path, ipc_opts);
     ++
     ++	ret = create_listener_socket(path, ipc_opts, new_server_socket);
     ++
     ++	saved_errno = errno;
      +	trace2_region_leave("ipc-server", "create-listener_socket", NULL);
     ++	errno = saved_errno;
      +
     -+	return server_socket;
     ++	return ret;
      +}
      +
      +/*
     @@ compat/simple-ipc/ipc-unix-socket.c (new)
      +	struct ipc_server_data *server_data;
      +	int sv[2];
      +	int k;
     ++	int ret;
      +	int nr_threads = opts->nr_threads;
      +
      +	*returned_server_data = NULL;
     @@ compat/simple-ipc/ipc-unix-socket.c (new)
      +	 * connection or a shutdown request without spinning.
      +	 */
      +	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0)
     -+		return error_errno(_("could not create socketpair for '%s'"),
     -+				   path);
     ++		return -1;
      +
      +	if (set_socket_blocking_flag(sv[1], 1)) {
      +		int saved_errno = errno;
      +		close(sv[0]);
      +		close(sv[1]);
      +		errno = saved_errno;
     -+		return error_errno(_("making socketpair nonblocking '%s'"),
     -+				   path);
     ++		return -1;
      +	}
      +
     -+	server_socket = setup_listener_socket(path, opts);
     -+	if (!server_socket) {
     ++	ret = setup_listener_socket(path, opts, &server_socket);
     ++	if (ret) {
      +		int saved_errno = errno;
      +		close(sv[0]);
      +		close(sv[1]);
      +		errno = saved_errno;
     -+		return -1;
     ++		return ret;
      +	}
      +
      +	server_data = xcalloc(1, sizeof(*server_data));
 12:  09568a6500dd ! 12:  6ccc7472096f t0052: add simple-ipc tests and t/helper/test-simple-ipc tool
     @@ t/helper/test-simple-ipc.c (new)
      +	return app__unhandled_command(command, reply_cb, reply_data);
      +}
      +
     ++struct cl_args
     ++{
     ++	const char *subcommand;
     ++	const char *path;
     ++	const char *token;
     ++
     ++	int nr_threads;
     ++	int max_wait_sec;
     ++	int bytecount;
     ++	int batchsize;
     ++
     ++	char bytevalue;
     ++};
     ++
     ++static struct cl_args cl_args = {
     ++	.subcommand = NULL,
     ++	.path = "ipc-test",
     ++	.token = NULL,
     ++
     ++	.nr_threads = 5,
     ++	.max_wait_sec = 60,
     ++	.bytecount = 1024,
     ++	.batchsize = 10,
     ++
     ++	.bytevalue = 'x',
     ++};
     ++
      +/*
      + * This process will run as a simple-ipc server and listen for IPC commands
      + * from client processes.
      + */
     -+static int daemon__run_server(const char *path, int argc, const char **argv)
     ++static int daemon__run_server(void)
      +{
     -+	struct ipc_server_opts opts = {
     -+		.nr_threads = 5
     -+	};
     ++	int ret;
      +
     -+	const char * const daemon_usage[] = {
     -+		N_("test-helper simple-ipc run-daemon [<options>"),
     -+		NULL
     -+	};
     -+	struct option daemon_options[] = {
     -+		OPT_INTEGER(0, "threads", &opts.nr_threads,
     -+			    N_("number of threads in server thread pool")),
     -+		OPT_END()
     ++	struct ipc_server_opts opts = {
     ++		.nr_threads = cl_args.nr_threads,
      +	};
      +
     -+	argc = parse_options(argc, argv, NULL, daemon_options, daemon_usage, 0);
     -+
     -+	if (opts.nr_threads < 1)
     -+		opts.nr_threads = 1;
     -+
      +	/*
      +	 * Synchronously run the ipc-server.  We don't need any application
      +	 * instance data, so pass an arbitrary pointer (that we'll later
      +	 * verify made the round trip).
      +	 */
     -+	return ipc_server_run(path, &opts, test_app_cb, (void*)&my_app_data);
     ++	ret = ipc_server_run(cl_args.path, &opts, test_app_cb, (void*)&my_app_data);
     ++	if (ret == -2)
     ++		error(_("socket/pipe already in use: '%s'"), cl_args.path);
     ++	else if (ret == -1)
     ++		error_errno(_("could not start server on: '%s'"), cl_args.path);
     ++
     ++	return ret;
      +}
      +
      +#ifndef GIT_WINDOWS_NATIVE
     @@ t/helper/test-simple-ipc.c (new)
      + * This is adapted from `daemonize()`.  Use `fork()` to directly create and
      + * run the daemon in a child process.
      + */
     -+static int spawn_server(const char *path,
     -+			const struct ipc_server_opts *opts,
     -+			pid_t *pid)
     ++static int spawn_server(pid_t *pid)
      +{
     ++	struct ipc_server_opts opts = {
     ++		.nr_threads = cl_args.nr_threads,
     ++	};
     ++
      +	*pid = fork();
      +
      +	switch (*pid) {
     @@ t/helper/test-simple-ipc.c (new)
      +		close(2);
      +		sanitize_stdfds();
      +
     -+		return ipc_server_run(path, opts, test_app_cb, (void*)&my_app_data);
     ++		return ipc_server_run(cl_args.path, &opts, test_app_cb,
     ++				      (void*)&my_app_data);
      +
      +	case -1:
      +		return error_errno(_("could not spawn daemon in the background"));
     @@ t/helper/test-simple-ipc.c (new)
      + * have `fork(2)`.  Spawn a normal Windows child process but without the
      + * limitations of `start_command()` and `finish_command()`.
      + */
     -+static int spawn_server(const char *path,
     -+			const struct ipc_server_opts *opts,
     -+			pid_t *pid)
     ++static int spawn_server(pid_t *pid)
      +{
      +	char test_tool_exe[MAX_PATH];
      +	struct strvec args = STRVEC_INIT;
     @@ t/helper/test-simple-ipc.c (new)
      +	strvec_push(&args, test_tool_exe);
      +	strvec_push(&args, "simple-ipc");
      +	strvec_push(&args, "run-daemon");
     -+	strvec_pushf(&args, "--threads=%d", opts->nr_threads);
     ++	strvec_pushf(&args, "--name=%s", cl_args.path);
     ++	strvec_pushf(&args, "--threads=%d", cl_args.nr_threads);
      +
      +	*pid = mingw_spawnvpe(args.v[0], args.v, NULL, NULL, in, out, out);
      +	close(in);
     @@ t/helper/test-simple-ipc.c (new)
      + * let it get started and begin listening for requests on the socket
      + * before reporting our success.
      + */
     -+static int wait_for_server_startup(const char * path, pid_t pid_child,
     -+				   int max_wait_sec)
     ++static int wait_for_server_startup(pid_t pid_child)
      +{
      +	int status;
      +	pid_t pid_seen;
     @@ t/helper/test-simple-ipc.c (new)
      +	time_t time_limit, now;
      +
      +	time(&time_limit);
     -+	time_limit += max_wait_sec;
     ++	time_limit += cl_args.max_wait_sec;
      +
      +	for (;;) {
      +		pid_seen = waitpid(pid_child, &status, WNOHANG);
     @@ t/helper/test-simple-ipc.c (new)
      +			 * after a timeout on the lock), but we don't
      +			 * care (who responds) if the socket is live.
      +			 */
     -+			s = ipc_get_active_state(path);
     ++			s = ipc_get_active_state(cl_args.path);
      +			if (s == IPC_STATE__LISTENING)
      +				return 0;
      +
     @@ t/helper/test-simple-ipc.c (new)
      +			 *
      +			 * Again, we don't care who services the socket.
      +			 */
     -+			s = ipc_get_active_state(path);
     ++			s = ipc_get_active_state(cl_args.path);
      +			if (s == IPC_STATE__LISTENING)
      +				return 0;
      +
     @@ t/helper/test-simple-ipc.c (new)
      + * more control and better error reporting (and makes it easier to write
      + * unit tests).
      + */
     -+static int daemon__start_server(const char *path, int argc, const char **argv)
     ++static int daemon__start_server(void)
      +{
      +	pid_t pid_child;
      +	int ret;
     -+	int max_wait_sec = 60;
     -+	struct ipc_server_opts opts = {
     -+		.nr_threads = 5
     -+	};
     -+
     -+	const char * const daemon_usage[] = {
     -+		N_("test-helper simple-ipc start-daemon [<options>"),
     -+		NULL
     -+	};
     -+
     -+	struct option daemon_options[] = {
     -+		OPT_INTEGER(0, "max-wait", &max_wait_sec,
     -+			    N_("seconds to wait for daemon to startup")),
     -+		OPT_INTEGER(0, "threads", &opts.nr_threads,
     -+			    N_("number of threads in server thread pool")),
     -+		OPT_END()
     -+	};
     -+
     -+	argc = parse_options(argc, argv, NULL, daemon_options, daemon_usage, 0);
     -+
     -+	if (max_wait_sec < 0)
     -+		max_wait_sec = 0;
     -+	if (opts.nr_threads < 1)
     -+		opts.nr_threads = 1;
      +
      +	/*
      +	 * Run the actual daemon in a background process.
      +	 */
     -+	ret = spawn_server(path, &opts, &pid_child);
     ++	ret = spawn_server(&pid_child);
      +	if (pid_child <= 0)
      +		return ret;
      +
     @@ t/helper/test-simple-ipc.c (new)
      +	 * Let the parent wait for the child process to get started
      +	 * and begin listening for requests on the socket.
      +	 */
     -+	ret = wait_for_server_startup(path, pid_child, max_wait_sec);
     ++	ret = wait_for_server_startup(pid_child);
      +
      +	return ret;
      +}
     @@ t/helper/test-simple-ipc.c (new)
      + *
      + * Returns 0 if the server is alive.
      + */
     -+static int client__probe_server(const char *path)
     ++static int client__probe_server(void)
      +{
      +	enum ipc_active_state s;
      +
     -+	s = ipc_get_active_state(path);
     ++	s = ipc_get_active_state(cl_args.path);
      +	switch (s) {
      +	case IPC_STATE__LISTENING:
      +		return 0;
      +
      +	case IPC_STATE__NOT_LISTENING:
     -+		return error("no server listening at '%s'", path);
     ++		return error("no server listening at '%s'", cl_args.path);
      +
      +	case IPC_STATE__PATH_NOT_FOUND:
     -+		return error("path not found '%s'", path);
     ++		return error("path not found '%s'", cl_args.path);
      +
      +	case IPC_STATE__INVALID_PATH:
     -+		return error("invalid pipe/socket name '%s'", path);
     ++		return error("invalid pipe/socket name '%s'", cl_args.path);
      +
      +	case IPC_STATE__OTHER_ERROR:
      +	default:
     -+		return error("other error for '%s'", path);
     ++		return error("other error for '%s'", cl_args.path);
      +	}
      +}
      +
      +/*
     -+ * Send an IPC command to an already-running server daemon and print the
     -+ * response.
     ++ * Send an IPC command token to an already-running server daemon and
     ++ * print the response.
      + *
     -+ * argv[2] contains a simple (1 word) command that `test_app_cb()` (in
     -+ * the daemon process) will understand.
     ++ * This is a simple 1 word command/token that `test_app_cb()` (in the
     ++ * daemon process) will understand.
      + */
     -+static int client__send_ipc(int argc, const char **argv, const char *path)
     ++static int client__send_ipc(void)
      +{
     -+	const char *command = argc > 2 ? argv[2] : "(no command)";
     ++	const char *command = "(no-command)";
      +	struct strbuf buf = STRBUF_INIT;
      +	struct ipc_client_connect_options options
      +		= IPC_CLIENT_CONNECT_OPTIONS_INIT;
      +
     ++	if (cl_args.token && *cl_args.token)
     ++		command = cl_args.token;
     ++
      +	options.wait_if_busy = 1;
      +	options.wait_if_not_found = 0;
      +
     -+	if (!ipc_client_send_command(path, &options, command, &buf)) {
     ++	if (!ipc_client_send_command(cl_args.path, &options, command, &buf)) {
      +		if (buf.len) {
      +			printf("%s\n", buf.buf);
      +			fflush(stdout);
     @@ t/helper/test-simple-ipc.c (new)
      +		return 0;
      +	}
      +
     -+	return error("failed to send '%s' to '%s'", command, path);
     ++	return error("failed to send '%s' to '%s'", command, cl_args.path);
      +}
      +
      +/*
     @@ t/helper/test-simple-ipc.c (new)
      + * event in the server, so we spin and wait here for it to actually
      + * shutdown to make the unit tests a little easier to write.
      + */
     -+static int client__stop_server(int argc, const char **argv, const char *path)
     ++static int client__stop_server(void)
      +{
     -+	const char *send_quit[] = { argv[0], "send", "quit", NULL };
     -+	int max_wait_sec = 60;
      +	int ret;
      +	time_t time_limit, now;
      +	enum ipc_active_state s;
      +
     -+	const char * const stop_usage[] = {
     -+		N_("test-helper simple-ipc stop-daemon [<options>]"),
     -+		NULL
     -+	};
     -+
     -+	struct option stop_options[] = {
     -+		OPT_INTEGER(0, "max-wait", &max_wait_sec,
     -+			    N_("seconds to wait for daemon to stop")),
     -+		OPT_END()
     -+	};
     -+
     -+	argc = parse_options(argc, argv, NULL, stop_options, stop_usage, 0);
     -+
     -+	if (max_wait_sec < 0)
     -+		max_wait_sec = 0;
     -+
      +	time(&time_limit);
     -+	time_limit += max_wait_sec;
     ++	time_limit += cl_args.max_wait_sec;
     ++
     ++	cl_args.token = "quit";
      +
     -+	ret = client__send_ipc(3, send_quit, path);
     ++	ret = client__send_ipc();
      +	if (ret)
      +		return ret;
      +
      +	for (;;) {
      +		sleep_millisec(100);
      +
     -+		s = ipc_get_active_state(path);
     ++		s = ipc_get_active_state(cl_args.path);
      +
      +		if (s != IPC_STATE__LISTENING) {
      +			/*
     @@ t/helper/test-simple-ipc.c (new)
      +/*
      + * Send an IPC command with ballast to an already-running server daemon.
      + */
     -+static int client__sendbytes(int argc, const char **argv, const char *path)
     ++static int client__sendbytes(void)
      +{
     -+	int bytecount = 1024;
     -+	char *string = "x";
     -+	const char * const sendbytes_usage[] = {
     -+		N_("test-helper simple-ipc sendbytes [<options>]"),
     -+		NULL
     -+	};
     -+	struct option sendbytes_options[] = {
     -+		OPT_INTEGER(0, "bytecount", &bytecount, N_("number of bytes")),
     -+		OPT_STRING(0, "byte", &string, N_("byte"), N_("ballast")),
     -+		OPT_END()
     -+	};
      +	struct ipc_client_connect_options options
      +		= IPC_CLIENT_CONNECT_OPTIONS_INIT;
      +
     @@ t/helper/test-simple-ipc.c (new)
      +	options.wait_if_not_found = 0;
      +	options.uds_disallow_chdir = 0;
      +
     -+	argc = parse_options(argc, argv, NULL, sendbytes_options, sendbytes_usage, 0);
     -+
     -+	return do_sendbytes(bytecount, string[0], path, &options);
     ++	return do_sendbytes(cl_args.bytecount, cl_args.bytevalue, cl_args.path,
     ++			    &options);
      +}
      +
      +struct multiple_thread_data {
     @@ t/helper/test-simple-ipc.c (new)
      + * Start a client-side thread pool.  Each thread sends a series of
      + * IPC requests.  Each request is on a new connection to the server.
      + */
     -+static int client__multiple(int argc, const char **argv, const char *path)
     ++static int client__multiple(void)
      +{
      +	struct multiple_thread_data *list = NULL;
      +	int k;
     -+	int nr_threads = 5;
     -+	int bytecount = 1;
     -+	int batchsize = 10;
      +	int sum_join_errors = 0;
      +	int sum_thread_errors = 0;
      +	int sum_good = 0;
      +
     -+	const char * const multiple_usage[] = {
     -+		N_("test-helper simple-ipc multiple [<options>]"),
     -+		NULL
     -+	};
     -+	struct option multiple_options[] = {
     -+		OPT_INTEGER(0, "bytecount", &bytecount, N_("number of bytes")),
     -+		OPT_INTEGER(0, "threads", &nr_threads, N_("number of threads")),
     -+		OPT_INTEGER(0, "batchsize", &batchsize, N_("number of requests per thread")),
     -+		OPT_END()
     -+	};
     -+
     -+	argc = parse_options(argc, argv, NULL, multiple_options, multiple_usage, 0);
     -+
     -+	if (bytecount < 1)
     -+		bytecount = 1;
     -+	if (nr_threads < 1)
     -+		nr_threads = 1;
     -+	if (batchsize < 1)
     -+		batchsize = 1;
     -+
     -+	for (k = 0; k < nr_threads; k++) {
     ++	for (k = 0; k < cl_args.nr_threads; k++) {
      +		struct multiple_thread_data *d = xcalloc(1, sizeof(*d));
      +		d->next = list;
     -+		d->path = path;
     -+		d->bytecount = bytecount + batchsize*(k/26);
     -+		d->batchsize = batchsize;
     ++		d->path = cl_args.path;
     ++		d->bytecount = cl_args.bytecount + cl_args.batchsize*(k/26);
     ++		d->batchsize = cl_args.batchsize;
      +		d->sum_errors = 0;
      +		d->sum_good = 0;
      +		d->letter = 'A' + (k % 26);
     @@ t/helper/test-simple-ipc.c (new)
      +
      +int cmd__simple_ipc(int argc, const char **argv)
      +{
     -+	const char *path = "ipc-test";
     ++	const char * const simple_ipc_usage[] = {
     ++		N_("test-helper simple-ipc is-active    [<name>] [<options>]"),
     ++		N_("test-helper simple-ipc run-daemon   [<name>] [<threads>]"),
     ++		N_("test-helper simple-ipc start-daemon [<name>] [<threads>] [<max-wait>]"),
     ++		N_("test-helper simple-ipc stop-daemon  [<name>] [<max-wait>]"),
     ++		N_("test-helper simple-ipc send         [<name>] [<token>]"),
     ++		N_("test-helper simple-ipc sendbytes    [<name>] [<bytecount>] [<byte>]"),
     ++		N_("test-helper simple-ipc multiple     [<name>] [<threads>] [<bytecount>] [<batchsize>]"),
     ++		NULL
     ++	};
     ++
     ++	const char *bytevalue = NULL;
     ++
     ++	struct option options[] = {
     ++#ifndef GIT_WINDOWS_NATIVE
     ++		OPT_STRING(0, "name", &cl_args.path, N_("name"), N_("name or pathname of unix domain socket")),
     ++#else
     ++		OPT_STRING(0, "name", &cl_args.path, N_("name"), N_("named-pipe name")),
     ++#endif
     ++		OPT_INTEGER(0, "threads", &cl_args.nr_threads, N_("number of threads in server thread pool")),
     ++		OPT_INTEGER(0, "max-wait", &cl_args.max_wait_sec, N_("seconds to wait for daemon to start or stop")),
     ++
     ++		OPT_INTEGER(0, "bytecount", &cl_args.bytecount, N_("number of bytes")),
     ++		OPT_INTEGER(0, "batchsize", &cl_args.batchsize, N_("number of requests per thread")),
     ++
     ++		OPT_STRING(0, "byte", &bytevalue, N_("byte"), N_("ballast character")),
     ++		OPT_STRING(0, "token", &cl_args.token, N_("token"), N_("command token to send to the server")),
     ++
     ++		OPT_END()
     ++	};
     ++
     ++	if (argc < 2)
     ++		usage_with_options(simple_ipc_usage, options);
     ++
     ++	if (argc == 2 && !strcmp(argv[1], "-h"))
     ++		usage_with_options(simple_ipc_usage, options);
      +
      +	if (argc == 2 && !strcmp(argv[1], "SUPPORTS_SIMPLE_IPC"))
      +		return 0;
      +
     ++	cl_args.subcommand = argv[1];
     ++
     ++	argc--;
     ++	argv++;
     ++
     ++	argc = parse_options(argc, argv, NULL, options, simple_ipc_usage, 0);
     ++
     ++	if (cl_args.nr_threads < 1)
     ++		cl_args.nr_threads = 1;
     ++	if (cl_args.max_wait_sec < 0)
     ++		cl_args.max_wait_sec = 0;
     ++	if (cl_args.bytecount < 1)
     ++		cl_args.bytecount = 1;
     ++	if (cl_args.batchsize < 1)
     ++		cl_args.batchsize = 1;
     ++
     ++	if (bytevalue && *bytevalue)
     ++		cl_args.bytevalue = bytevalue[0];
     ++
      +	/*
      +	 * Use '!!' on all dispatch functions to map from `error()` style
      +	 * (returns -1) style to `test_must_fail` style (expects 1).  This
      +	 * makes shell error messages less confusing.
      +	 */
      +
     -+	if (argc == 2 && !strcmp(argv[1], "is-active"))
     -+		return !!client__probe_server(path);
     ++	if (!strcmp(cl_args.subcommand, "is-active"))
     ++		return !!client__probe_server();
      +
     -+	if (argc >= 2 && !strcmp(argv[1], "run-daemon"))
     -+		return !!daemon__run_server(path, argc, argv);
     ++	if (!strcmp(cl_args.subcommand, "run-daemon"))
     ++		return !!daemon__run_server();
      +
     -+	if (argc >= 2 && !strcmp(argv[1], "start-daemon"))
     -+		return !!daemon__start_server(path, argc, argv);
     ++	if (!strcmp(cl_args.subcommand, "start-daemon"))
     ++		return !!daemon__start_server();
      +
      +	/*
      +	 * Client commands follow.  Ensure a server is running before
     -+	 * going any further.
     ++	 * sending any data.  This might be overkill, but then again
     ++	 * this is a test harness.
      +	 */
     -+	if (client__probe_server(path))
     -+		return 1;
      +
     -+	if (argc >= 2 && !strcmp(argv[1], "stop-daemon"))
     -+		return !!client__stop_server(argc, argv, path);
     ++	if (!strcmp(cl_args.subcommand, "stop-daemon")) {
     ++		if (client__probe_server())
     ++			return 1;
     ++		return !!client__stop_server();
     ++	}
      +
     -+	if ((argc == 2 || argc == 3) && !strcmp(argv[1], "send"))
     -+		return !!client__send_ipc(argc, argv, path);
     ++	if (!strcmp(cl_args.subcommand, "send")) {
     ++		if (client__probe_server())
     ++			return 1;
     ++		return !!client__send_ipc();
     ++	}
      +
     -+	if (argc >= 2 && !strcmp(argv[1], "sendbytes"))
     -+		return !!client__sendbytes(argc, argv, path);
     ++	if (!strcmp(cl_args.subcommand, "sendbytes")) {
     ++		if (client__probe_server())
     ++			return 1;
     ++		return !!client__sendbytes();
     ++	}
      +
     -+	if (argc >= 2 && !strcmp(argv[1], "multiple"))
     -+		return !!client__multiple(argc, argv, path);
     ++	if (!strcmp(cl_args.subcommand, "multiple")) {
     ++		if (client__probe_server())
     ++			return 1;
     ++		return !!client__multiple();
     ++	}
      +
     -+	die("Unhandled argv[1]: '%s'", argv[1]);
     ++	die("Unhandled subcommand: '%s'", cl_args.subcommand);
      +}
      +#endif
      
     @@ t/t0052-simple-ipc.sh (new)
      +'
      +
      +test_expect_success 'simple command server' '
     -+	test-tool simple-ipc send ping >actual &&
     ++	test-tool simple-ipc send --token=ping >actual &&
      +	echo pong >expect &&
      +	test_cmp expect actual
      +'
     @@ t/t0052-simple-ipc.sh (new)
      +'
      +
      +test_expect_success 'big response' '
     -+	test-tool simple-ipc send big >actual &&
     ++	test-tool simple-ipc send --token=big >actual &&
      +	test_line_count -ge 10000 actual &&
      +	grep -q "big: [0]*9999\$" actual
      +'
      +
      +test_expect_success 'chunk response' '
     -+	test-tool simple-ipc send chunk >actual &&
     ++	test-tool simple-ipc send --token=chunk >actual &&
      +	test_line_count -ge 10000 actual &&
      +	grep -q "big: [0]*9999\$" actual
      +'
      +
      +test_expect_success 'slow response' '
     -+	test-tool simple-ipc send slow >actual &&
     ++	test-tool simple-ipc send --token=slow >actual &&
      +	test_line_count -ge 100 actual &&
      +	grep -q "big: [0]*99\$" actual
      +'
     @@ t/t0052-simple-ipc.sh (new)
      +test_expect_success 'stop-daemon works' '
      +	test-tool simple-ipc stop-daemon &&
      +	test_must_fail test-tool simple-ipc is-active &&
     -+	test_must_fail test-tool simple-ipc send ping
     ++	test_must_fail test-tool simple-ipc send --token=ping
      +'
      +
      +test_done

-- 
gitgitgadget

  parent reply	other threads:[~2021-03-09 15:03 UTC|newest]

Thread overview: 178+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-12 15:31 [PATCH 00/10] [RFC] Simple IPC Mechanism Jeff Hostetler via GitGitGadget
2021-01-12 15:31 ` [PATCH 01/10] pkt-line: use stack rather than static buffer in packet_write_gently() Jeff Hostetler via GitGitGadget
2021-01-13 13:29   ` Jeff King
2021-01-25 19:34     ` Jeff Hostetler
2021-01-12 15:31 ` [PATCH 02/10] pkt-line: (optionally) libify the packet readers Johannes Schindelin via GitGitGadget
2021-01-12 15:31 ` [PATCH 03/10] pkt-line: optionally skip the flush packet in write_packetized_from_buf() Johannes Schindelin via GitGitGadget
2021-01-12 15:31 ` [PATCH 04/10] pkt-line: accept additional options in read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-01-12 15:31 ` [PATCH 05/10] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-01-12 16:40   ` Ævar Arnfjörð Bjarmason
2021-01-12 15:31 ` [PATCH 06/10] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-01-12 15:31 ` [PATCH 07/10] unix-socket: create gentle version of unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-01-13 14:06   ` Jeff King
2021-01-14  1:19     ` Chris Torek
2021-01-12 15:31 ` [PATCH 08/10] unix-socket: add no-chdir option to unix_stream_listen_gently() Jeff Hostetler via GitGitGadget
2021-01-12 15:31 ` [PATCH 09/10] simple-ipc: add t/helper/test-simple-ipc and t0052 Jeff Hostetler via GitGitGadget
2021-01-12 15:31 ` [PATCH 10/10] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-01-12 16:50 ` [PATCH 00/10] [RFC] Simple IPC Mechanism Ævar Arnfjörð Bjarmason
2021-01-12 18:25   ` Jeff Hostetler
2021-01-12 20:01 ` Junio C Hamano
2021-01-12 23:25   ` Jeff Hostetler
2021-01-13  0:13     ` Junio C Hamano
2021-01-13  0:32       ` Jeff Hostetler
2021-01-13 13:46     ` Jeff King
2021-01-13 15:48       ` Ævar Arnfjörð Bjarmason
2021-02-01 19:45 ` [PATCH v2 00/14] " Jeff Hostetler via GitGitGadget
2021-02-01 19:45   ` [PATCH v2 01/14] ci/install-depends: attempt to fix "brew cask" stuff Junio C Hamano via GitGitGadget
2021-02-01 19:45   ` [PATCH v2 02/14] pkt-line: promote static buffer in packet_write_gently() to callers Jeff Hostetler via GitGitGadget
2021-02-02  9:41     ` Jeff King
2021-02-02 20:33       ` Jeff Hostetler
2021-02-02 22:54       ` Johannes Schindelin
2021-02-03  4:52         ` Jeff King
2021-02-01 19:45   ` [PATCH v2 03/14] pkt-line: add write_packetized_from_buf2() that takes scratch buffer Jeff Hostetler via GitGitGadget
2021-02-02  9:44     ` Jeff King
2021-02-01 19:45   ` [PATCH v2 04/14] pkt-line: optionally skip the flush packet in write_packetized_from_buf() Johannes Schindelin via GitGitGadget
2021-02-02  9:48     ` Jeff King
2021-02-02 22:56       ` Johannes Schindelin
2021-02-05 18:30       ` Jeff Hostetler
2021-02-01 19:45   ` [PATCH v2 05/14] pkt-line: (optionally) libify the packet readers Johannes Schindelin via GitGitGadget
2021-02-01 19:45   ` [PATCH v2 06/14] pkt-line: accept additional options in read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-02-11  1:52     ` Taylor Blau
2021-02-01 19:45   ` [PATCH v2 07/14] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-02-01 19:45   ` [PATCH v2 08/14] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-02-01 19:45   ` [PATCH v2 09/14] simple-ipc: add t/helper/test-simple-ipc and t0052 Jeff Hostetler via GitGitGadget
2021-02-02 21:35     ` SZEDER Gábor
2021-02-03  4:36       ` Jeff King
2021-02-09 15:45       ` Jeff Hostetler
2021-02-05 19:38     ` SZEDER Gábor
2021-02-01 19:45   ` [PATCH v2 10/14] unix-socket: elimiate static unix_stream_socket() helper function Jeff Hostetler via GitGitGadget
2021-02-02  9:54     ` Jeff King
2021-02-02  9:58     ` Jeff King
2021-02-01 19:45   ` [PATCH v2 11/14] unix-socket: add options to unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-02-02 10:14     ` Jeff King
2021-02-05 23:28       ` Jeff Hostetler
2021-02-09 16:32         ` Jeff King
2021-02-09 17:39           ` Jeff Hostetler
2021-02-10 15:55             ` Jeff King
2021-02-10 21:31               ` Jeff Hostetler
2021-02-01 19:45   ` [PATCH v2 12/14] unix-socket: add no-chdir option " Jeff Hostetler via GitGitGadget
2021-02-02 10:26     ` Jeff King
2021-02-01 19:45   ` [PATCH v2 13/14] unix-socket: do not call die in unix_stream_connect() Jeff Hostetler via GitGitGadget
2021-02-01 19:45   ` [PATCH v2 14/14] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-02-01 22:20   ` [PATCH v2 00/14] Simple IPC Mechanism Junio C Hamano
2021-02-01 23:26     ` Jeff Hostetler
2021-02-02 23:07       ` Johannes Schindelin
2021-02-04 19:08         ` Junio C Hamano
2021-02-05 13:19           ` candidate branches for `maint`, was " Johannes Schindelin
2021-02-05 19:55             ` Junio C Hamano
2021-02-13  0:09   ` [PATCH v3 00/12] " Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 01/12] pkt-line: eliminate the need for static buffer in packet_write_gently() Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 02/12] pkt-line: do not issue flush packets in write_packetized_*() Johannes Schindelin via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 03/12] pkt-line: (optionally) libify the packet readers Johannes Schindelin via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 04/12] pkt-line: add options argument to read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 05/12] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 06/12] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 07/12] unix-socket: elimiate static unix_stream_socket() helper function Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 08/12] unix-socket: add backlog size option to unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 09/12] unix-socket: disallow chdir() when creating unix domain sockets Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 10/12] unix-socket: create `unix_stream_server__listen_with_lock()` Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 11/12] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-02-13  0:09     ` [PATCH v3 12/12] t0052: add simple-ipc tests and t/helper/test-simple-ipc tool Jeff Hostetler via GitGitGadget
2021-02-13  9:30       ` SZEDER Gábor
2021-02-16 15:53         ` Jeff Hostetler
2021-02-17 21:48     ` [PATCH v4 00/12] Simple IPC Mechanism Jeff Hostetler via GitGitGadget
2021-02-17 21:48       ` [PATCH v4 01/12] pkt-line: eliminate the need for static buffer in packet_write_gently() Jeff Hostetler via GitGitGadget
2021-02-26  7:21         ` Jeff King
2021-02-26 19:52           ` Jeff Hostetler
2021-02-26 20:43             ` Jeff King
2021-03-03 19:38             ` Junio C Hamano
2021-03-04 13:29               ` Jeff Hostetler
2021-03-04 20:26                 ` Junio C Hamano
2021-02-17 21:48       ` [PATCH v4 02/12] pkt-line: do not issue flush packets in write_packetized_*() Johannes Schindelin via GitGitGadget
2021-02-17 21:48       ` [PATCH v4 03/12] pkt-line: (optionally) libify the packet readers Johannes Schindelin via GitGitGadget
2021-03-03 19:53         ` Junio C Hamano
2021-03-04 14:17           ` Jeff Hostetler
2021-03-04 14:40             ` Jeff King
2021-03-04 20:28               ` Junio C Hamano
2021-02-17 21:48       ` [PATCH v4 04/12] pkt-line: add options argument to read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-02-17 21:48       ` [PATCH v4 05/12] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-03-03 20:19         ` Junio C Hamano
2021-02-17 21:48       ` [PATCH v4 06/12] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-02-17 21:48       ` [PATCH v4 07/12] unix-socket: elimiate static unix_stream_socket() helper function Jeff Hostetler via GitGitGadget
2021-02-26  7:25         ` Jeff King
2021-03-03 20:41         ` Junio C Hamano
2021-02-17 21:48       ` [PATCH v4 08/12] unix-socket: add backlog size option to unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-02-26  7:30         ` Jeff King
2021-03-03 20:54           ` Junio C Hamano
2021-02-17 21:48       ` [PATCH v4 09/12] unix-socket: disallow chdir() when creating unix domain sockets Jeff Hostetler via GitGitGadget
2021-03-03 22:53         ` Junio C Hamano
2021-03-04 14:56           ` Jeff King
2021-03-04 20:34             ` Junio C Hamano
2021-03-04 23:34               ` Junio C Hamano
2021-03-05  9:02                 ` Jeff King
2021-03-05  9:25                   ` Jeff King
2021-03-05 11:59                     ` Chris Torek
2021-03-05 17:33                       ` Jeff Hostetler
2021-03-05 17:53                         ` Junio C Hamano
2021-03-05 21:30               ` Jeff Hostetler
2021-03-05 21:52                 ` Junio C Hamano
2021-02-17 21:48       ` [PATCH v4 10/12] unix-socket: create `unix_stream_server__listen_with_lock()` Jeff Hostetler via GitGitGadget
2021-02-26  7:56         ` Jeff King
2021-03-02 23:50           ` Jeff Hostetler
2021-03-04 15:13             ` Jeff King
2021-02-17 21:48       ` [PATCH v4 11/12] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-02-17 21:48       ` [PATCH v4 12/12] t0052: add simple-ipc tests and t/helper/test-simple-ipc tool Jeff Hostetler via GitGitGadget
2021-03-02  9:44         ` Jeff King
2021-03-03 15:25           ` Jeff Hostetler
2021-02-25 19:39       ` [PATCH v4 00/12] Simple IPC Mechanism Junio C Hamano
2021-02-26  7:59         ` Jeff King
2021-02-26 20:18           ` Jeff Hostetler
2021-02-26 20:50             ` Jeff King
2021-03-03 19:29               ` Junio C Hamano
2021-03-09 15:02       ` Jeff Hostetler via GitGitGadget [this message]
2021-03-09 15:02         ` [PATCH v5 01/12] pkt-line: eliminate the need for static buffer in packet_write_gently() Jeff Hostetler via GitGitGadget
2021-03-09 23:48           ` Junio C Hamano
2021-03-11 19:29             ` Jeff King
2021-03-11 20:32               ` Junio C Hamano
2021-03-11 20:53                 ` Jeff King
2021-03-09 15:02         ` [PATCH v5 02/12] pkt-line: do not issue flush packets in write_packetized_*() Johannes Schindelin via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 03/12] pkt-line: add PACKET_READ_GENTLE_ON_READ_ERROR option Johannes Schindelin via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 04/12] pkt-line: add options argument to read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 05/12] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 06/12] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 07/12] unix-socket: eliminate static unix_stream_socket() helper function Jeff Hostetler via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 08/12] unix-socket: add backlog size option to unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 09/12] unix-socket: disallow chdir() when creating unix domain sockets Jeff Hostetler via GitGitGadget
2021-03-09 15:02         ` [PATCH v5 10/12] unix-stream-server: create unix domain socket under lock Jeff Hostetler via GitGitGadget
2021-03-10  0:18           ` Junio C Hamano
2021-03-09 15:02         ` [PATCH v5 11/12] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-03-10  0:08           ` Junio C Hamano
2021-03-15 19:56             ` Jeff Hostetler
2021-03-09 15:02         ` [PATCH v5 12/12] t0052: add simple-ipc tests and t/helper/test-simple-ipc tool Jeff Hostetler via GitGitGadget
2021-03-09 23:28         ` [PATCH v5 00/12] Simple IPC Mechanism Junio C Hamano
2021-03-15 21:08         ` [PATCH v6 " Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 01/12] pkt-line: eliminate the need for static buffer in packet_write_gently() Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 02/12] pkt-line: do not issue flush packets in write_packetized_*() Johannes Schindelin via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 03/12] pkt-line: add PACKET_READ_GENTLE_ON_READ_ERROR option Johannes Schindelin via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 04/12] pkt-line: add options argument to read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 05/12] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 06/12] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 07/12] unix-socket: eliminate static unix_stream_socket() helper function Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 08/12] unix-socket: add backlog size option to unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 09/12] unix-socket: disallow chdir() when creating unix domain sockets Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 10/12] unix-stream-server: create unix domain socket under lock Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 11/12] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-03-15 21:08           ` [PATCH v6 12/12] t0052: add simple-ipc tests and t/helper/test-simple-ipc tool Jeff Hostetler via GitGitGadget
2021-03-22 10:29           ` [PATCH v7 00/12] Simple IPC Mechanism Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 01/12] pkt-line: eliminate the need for static buffer in packet_write_gently() Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 02/12] pkt-line: do not issue flush packets in write_packetized_*() Johannes Schindelin via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 03/12] pkt-line: add PACKET_READ_GENTLE_ON_READ_ERROR option Johannes Schindelin via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 04/12] pkt-line: add options argument to read_packetized_to_strbuf() Johannes Schindelin via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 05/12] simple-ipc: design documentation for new IPC mechanism Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 06/12] simple-ipc: add win32 implementation Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 07/12] unix-socket: eliminate static unix_stream_socket() helper function Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 08/12] unix-socket: add backlog size option to unix_stream_listen() Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 09/12] unix-socket: disallow chdir() when creating unix domain sockets Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 10/12] unix-stream-server: create unix domain socket under lock Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 11/12] simple-ipc: add Unix domain socket implementation Jeff Hostetler via GitGitGadget
2021-03-22 10:29             ` [PATCH v7 12/12] t0052: add simple-ipc tests and t/helper/test-simple-ipc tool Jeff Hostetler via GitGitGadget

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=pull.766.v5.git.1615302157.gitgitgadget@gmail.com \
    --to=gitgitgadget@gmail.com \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=avarab@gmail.com \
    --cc=chris.torek@gmail.com \
    --cc=git@jeffhostetler.com \
    --cc=git@vger.kernel.org \
    --cc=jeffhost@microsoft.com \
    --cc=peff@peff.net \
    --cc=szeder.dev@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.