1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-04-27 16:25:10 +02:00

sub-process: move sub-process functions into separate files

Move the sub-proces functions into sub-process.h/c.  Add documentation
for the new module in Documentation/technical/api-sub-process.txt

Signed-off-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ben Peart 2017-05-05 11:28:01 -04:00 committed by Junio C Hamano
parent f514d7d177
commit 99605d62e8
5 changed files with 212 additions and 103 deletions

View File

@ -0,0 +1,59 @@
sub-process API
===============
The sub-process API makes it possible to run background sub-processes
for the entire lifetime of a Git invocation. If Git needs to communicate
with an external process multiple times, then this can reduces the process
invocation overhead. Git and the sub-process communicate through stdin and
stdout.
The sub-processes are kept in a hashmap by command name and looked up
via the subprocess_find_entry function. If an existing instance can not
be found then a new process should be created and started. When the
parent git command terminates, all sub-processes are also terminated.
This API is based on the run-command API.
Data structures
---------------
* `struct subprocess_entry`
The sub-process structure. Members should not be accessed directly.
Types
-----
'int(*subprocess_start_fn)(struct subprocess_entry *entry)'::
User-supplied function to initialize the sub-process. This is
typically used to negotiate the interface version and capabilities.
Functions
---------
`cmd2process_cmp`::
Function to test two subprocess hashmap entries for equality.
`subprocess_start`::
Start a subprocess and add it to the subprocess hashmap.
`subprocess_stop`::
Kill a subprocess and remove it from the subprocess hashmap.
`subprocess_find_entry`::
Find a subprocess in the subprocess hashmap.
`subprocess_get_child_process`::
Get the underlying `struct child_process` from a subprocess.
`subprocess_read_status`::
Helper function to read packets looking for the last "status=<foo>"
key/value pair.

View File

@ -838,6 +838,7 @@ LIB_OBJS += streaming.o
LIB_OBJS += string-list.o
LIB_OBJS += submodule.o
LIB_OBJS += submodule-config.o
LIB_OBJS += sub-process.o
LIB_OBJS += symlinks.o
LIB_OBJS += tag.o
LIB_OBJS += tempfile.o

104
convert.c
View File

@ -4,6 +4,7 @@
#include "quote.h"
#include "sigchain.h"
#include "pkt-line.h"
#include "sub-process.h"
/*
* convert.c - convert a file when checking it out and checking it in.
@ -496,12 +497,6 @@ static int apply_single_file_filter(const char *path, const char *src, size_t le
#define CAP_CLEAN (1u<<0)
#define CAP_SMUDGE (1u<<1)
struct subprocess_entry {
struct hashmap_entry ent; /* must be the first member! */
const char *cmd;
struct child_process process;
};
struct cmd2process {
struct subprocess_entry subprocess; /* must be the first member! */
unsigned int supported_capabilities;
@ -510,65 +505,6 @@ struct cmd2process {
static int subprocess_map_initialized;
static struct hashmap subprocess_map;
static int cmd2process_cmp(const struct subprocess_entry *e1,
const struct subprocess_entry *e2,
const void *unused)
{
return strcmp(e1->cmd, e2->cmd);
}
static struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
{
struct subprocess_entry key;
hashmap_entry_init(&key, strhash(cmd));
key.cmd = cmd;
return hashmap_get(hashmap, &key, NULL);
}
static void subprocess_read_status(int fd, struct strbuf *status)
{
struct strbuf **pair;
char *line;
for (;;) {
line = packet_read_line(fd, NULL);
if (!line)
break;
pair = strbuf_split_str(line, '=', 2);
if (pair[0] && pair[0]->len && pair[1]) {
/* the last "status=<foo>" line wins */
if (!strcmp(pair[0]->buf, "status=")) {
strbuf_reset(status);
strbuf_addbuf(status, pair[1]);
}
}
strbuf_list_free(pair);
}
}
static void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
{
if (!entry)
return;
entry->process.clean_on_exit = 0;
kill(entry->process.pid, SIGTERM);
finish_command(&entry->process);
hashmap_remove(hashmap, entry, NULL);
}
static void subprocess_exit_handler(struct child_process *process)
{
sigchain_push(SIGPIPE, SIG_IGN);
/* Closing the pipe signals the subprocess to initiate a shutdown. */
close(process->in);
close(process->out);
sigchain_pop(SIGPIPE);
/* Finish command will wait until the shutdown is complete. */
finish_command(process);
}
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
{
int err;
@ -629,44 +565,6 @@ static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
return err;
}
typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
subprocess_start_fn startfn)
{
int err;
struct child_process *process;
const char *argv[] = { cmd, NULL };
entry->cmd = cmd;
process = &entry->process;
child_process_init(process);
process->argv = argv;
process->use_shell = 1;
process->in = -1;
process->out = -1;
process->clean_on_exit = 1;
process->clean_on_exit_handler = subprocess_exit_handler;
err = start_command(process);
if (err) {
error("cannot fork to run subprocess '%s'", cmd);
return err;
}
hashmap_entry_init(entry, strhash(cmd));
err = startfn(entry);
if (err) {
error("initialization for subprocess '%s' failed", cmd);
subprocess_stop(hashmap, entry);
return err;
}
hashmap_add(hashmap, entry);
return 0;
}
static int apply_multi_file_filter(const char *path, const char *src, size_t len,
int fd, struct strbuf *dst, const char *cmd,
const unsigned int wanted_capability)

102
sub-process.c Normal file
View File

@ -0,0 +1,102 @@
/*
* Generic implementation of background process infrastructure.
*/
#include "sub-process.h"
#include "sigchain.h"
#include "pkt-line.h"
int cmd2process_cmp(const struct subprocess_entry *e1,
const struct subprocess_entry *e2,
const void *unused)
{
return strcmp(e1->cmd, e2->cmd);
}
struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
{
struct subprocess_entry key;
hashmap_entry_init(&key, strhash(cmd));
key.cmd = cmd;
return hashmap_get(hashmap, &key, NULL);
}
void subprocess_read_status(int fd, struct strbuf *status)
{
struct strbuf **pair;
char *line;
for (;;) {
line = packet_read_line(fd, NULL);
if (!line)
break;
pair = strbuf_split_str(line, '=', 2);
if (pair[0] && pair[0]->len && pair[1]) {
/* the last "status=<foo>" line wins */
if (!strcmp(pair[0]->buf, "status=")) {
strbuf_reset(status);
strbuf_addbuf(status, pair[1]);
}
}
strbuf_list_free(pair);
}
}
void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
{
if (!entry)
return;
entry->process.clean_on_exit = 0;
kill(entry->process.pid, SIGTERM);
finish_command(&entry->process);
hashmap_remove(hashmap, entry, NULL);
}
static void subprocess_exit_handler(struct child_process *process)
{
sigchain_push(SIGPIPE, SIG_IGN);
/* Closing the pipe signals the subprocess to initiate a shutdown. */
close(process->in);
close(process->out);
sigchain_pop(SIGPIPE);
/* Finish command will wait until the shutdown is complete. */
finish_command(process);
}
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
subprocess_start_fn startfn)
{
int err;
struct child_process *process;
const char *argv[] = { cmd, NULL };
entry->cmd = cmd;
process = &entry->process;
child_process_init(process);
process->argv = argv;
process->use_shell = 1;
process->in = -1;
process->out = -1;
process->clean_on_exit = 1;
process->clean_on_exit_handler = subprocess_exit_handler;
err = start_command(process);
if (err) {
error("cannot fork to run subprocess '%s'", cmd);
return err;
}
hashmap_entry_init(entry, strhash(cmd));
err = startfn(entry);
if (err) {
error("initialization for subprocess '%s' failed", cmd);
subprocess_stop(hashmap, entry);
return err;
}
hashmap_add(hashmap, entry);
return 0;
}

49
sub-process.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef SUBPROCESS_H
#define SUBPROCESS_H
#include "git-compat-util.h"
#include "hashmap.h"
#include "run-command.h"
/*
* Generic implementation of background process infrastructure.
* See Documentation/technical/api-background-process.txt.
*/
/* data structures */
struct subprocess_entry {
struct hashmap_entry ent; /* must be the first member! */
const char *cmd;
struct child_process process;
};
/* subprocess functions */
int cmd2process_cmp(const struct subprocess_entry *e1,
const struct subprocess_entry *e2, const void *unused);
typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
subprocess_start_fn startfn);
void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry);
struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd);
/* subprocess helper functions */
static inline struct child_process *subprocess_get_child_process(
struct subprocess_entry *entry)
{
return &entry->process;
}
/*
* Helper function that will read packets looking for "status=<foo>"
* key/value pairs and return the value from the last "status" packet
*/
void subprocess_read_status(int fd, struct strbuf *status);
#endif