Skip to content

Commit 99605d6

Browse files
benpeartgitster
authored andcommitted
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>
1 parent f514d7d commit 99605d6

5 files changed

Lines changed: 212 additions & 103 deletions

File tree

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
sub-process API
2+
===============
3+
4+
The sub-process API makes it possible to run background sub-processes
5+
for the entire lifetime of a Git invocation. If Git needs to communicate
6+
with an external process multiple times, then this can reduces the process
7+
invocation overhead. Git and the sub-process communicate through stdin and
8+
stdout.
9+
10+
The sub-processes are kept in a hashmap by command name and looked up
11+
via the subprocess_find_entry function. If an existing instance can not
12+
be found then a new process should be created and started. When the
13+
parent git command terminates, all sub-processes are also terminated.
14+
15+
This API is based on the run-command API.
16+
17+
Data structures
18+
---------------
19+
20+
* `struct subprocess_entry`
21+
22+
The sub-process structure. Members should not be accessed directly.
23+
24+
Types
25+
-----
26+
27+
'int(*subprocess_start_fn)(struct subprocess_entry *entry)'::
28+
29+
User-supplied function to initialize the sub-process. This is
30+
typically used to negotiate the interface version and capabilities.
31+
32+
33+
Functions
34+
---------
35+
36+
`cmd2process_cmp`::
37+
38+
Function to test two subprocess hashmap entries for equality.
39+
40+
`subprocess_start`::
41+
42+
Start a subprocess and add it to the subprocess hashmap.
43+
44+
`subprocess_stop`::
45+
46+
Kill a subprocess and remove it from the subprocess hashmap.
47+
48+
`subprocess_find_entry`::
49+
50+
Find a subprocess in the subprocess hashmap.
51+
52+
`subprocess_get_child_process`::
53+
54+
Get the underlying `struct child_process` from a subprocess.
55+
56+
`subprocess_read_status`::
57+
58+
Helper function to read packets looking for the last "status=<foo>"
59+
key/value pair.

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,7 @@ LIB_OBJS += streaming.o
838838
LIB_OBJS += string-list.o
839839
LIB_OBJS += submodule.o
840840
LIB_OBJS += submodule-config.o
841+
LIB_OBJS += sub-process.o
841842
LIB_OBJS += symlinks.o
842843
LIB_OBJS += tag.o
843844
LIB_OBJS += tempfile.o

convert.c

Lines changed: 1 addition & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "quote.h"
55
#include "sigchain.h"
66
#include "pkt-line.h"
7+
#include "sub-process.h"
78

89
/*
910
* 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
496497
#define CAP_CLEAN (1u<<0)
497498
#define CAP_SMUDGE (1u<<1)
498499

499-
struct subprocess_entry {
500-
struct hashmap_entry ent; /* must be the first member! */
501-
const char *cmd;
502-
struct child_process process;
503-
};
504-
505500
struct cmd2process {
506501
struct subprocess_entry subprocess; /* must be the first member! */
507502
unsigned int supported_capabilities;
@@ -510,65 +505,6 @@ struct cmd2process {
510505
static int subprocess_map_initialized;
511506
static struct hashmap subprocess_map;
512507

513-
static int cmd2process_cmp(const struct subprocess_entry *e1,
514-
const struct subprocess_entry *e2,
515-
const void *unused)
516-
{
517-
return strcmp(e1->cmd, e2->cmd);
518-
}
519-
520-
static struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
521-
{
522-
struct subprocess_entry key;
523-
524-
hashmap_entry_init(&key, strhash(cmd));
525-
key.cmd = cmd;
526-
return hashmap_get(hashmap, &key, NULL);
527-
}
528-
529-
static void subprocess_read_status(int fd, struct strbuf *status)
530-
{
531-
struct strbuf **pair;
532-
char *line;
533-
for (;;) {
534-
line = packet_read_line(fd, NULL);
535-
if (!line)
536-
break;
537-
pair = strbuf_split_str(line, '=', 2);
538-
if (pair[0] && pair[0]->len && pair[1]) {
539-
/* the last "status=<foo>" line wins */
540-
if (!strcmp(pair[0]->buf, "status=")) {
541-
strbuf_reset(status);
542-
strbuf_addbuf(status, pair[1]);
543-
}
544-
}
545-
strbuf_list_free(pair);
546-
}
547-
}
548-
549-
static void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
550-
{
551-
if (!entry)
552-
return;
553-
554-
entry->process.clean_on_exit = 0;
555-
kill(entry->process.pid, SIGTERM);
556-
finish_command(&entry->process);
557-
558-
hashmap_remove(hashmap, entry, NULL);
559-
}
560-
561-
static void subprocess_exit_handler(struct child_process *process)
562-
{
563-
sigchain_push(SIGPIPE, SIG_IGN);
564-
/* Closing the pipe signals the subprocess to initiate a shutdown. */
565-
close(process->in);
566-
close(process->out);
567-
sigchain_pop(SIGPIPE);
568-
/* Finish command will wait until the shutdown is complete. */
569-
finish_command(process);
570-
}
571-
572508
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
573509
{
574510
int err;
@@ -629,44 +565,6 @@ static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
629565
return err;
630566
}
631567

632-
typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
633-
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
634-
subprocess_start_fn startfn)
635-
{
636-
int err;
637-
struct child_process *process;
638-
const char *argv[] = { cmd, NULL };
639-
640-
entry->cmd = cmd;
641-
process = &entry->process;
642-
643-
child_process_init(process);
644-
process->argv = argv;
645-
process->use_shell = 1;
646-
process->in = -1;
647-
process->out = -1;
648-
process->clean_on_exit = 1;
649-
process->clean_on_exit_handler = subprocess_exit_handler;
650-
651-
err = start_command(process);
652-
if (err) {
653-
error("cannot fork to run subprocess '%s'", cmd);
654-
return err;
655-
}
656-
657-
hashmap_entry_init(entry, strhash(cmd));
658-
659-
err = startfn(entry);
660-
if (err) {
661-
error("initialization for subprocess '%s' failed", cmd);
662-
subprocess_stop(hashmap, entry);
663-
return err;
664-
}
665-
666-
hashmap_add(hashmap, entry);
667-
return 0;
668-
}
669-
670568
static int apply_multi_file_filter(const char *path, const char *src, size_t len,
671569
int fd, struct strbuf *dst, const char *cmd,
672570
const unsigned int wanted_capability)

sub-process.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Generic implementation of background process infrastructure.
3+
*/
4+
#include "sub-process.h"
5+
#include "sigchain.h"
6+
#include "pkt-line.h"
7+
8+
int cmd2process_cmp(const struct subprocess_entry *e1,
9+
const struct subprocess_entry *e2,
10+
const void *unused)
11+
{
12+
return strcmp(e1->cmd, e2->cmd);
13+
}
14+
15+
struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
16+
{
17+
struct subprocess_entry key;
18+
19+
hashmap_entry_init(&key, strhash(cmd));
20+
key.cmd = cmd;
21+
return hashmap_get(hashmap, &key, NULL);
22+
}
23+
24+
void subprocess_read_status(int fd, struct strbuf *status)
25+
{
26+
struct strbuf **pair;
27+
char *line;
28+
for (;;) {
29+
line = packet_read_line(fd, NULL);
30+
if (!line)
31+
break;
32+
pair = strbuf_split_str(line, '=', 2);
33+
if (pair[0] && pair[0]->len && pair[1]) {
34+
/* the last "status=<foo>" line wins */
35+
if (!strcmp(pair[0]->buf, "status=")) {
36+
strbuf_reset(status);
37+
strbuf_addbuf(status, pair[1]);
38+
}
39+
}
40+
strbuf_list_free(pair);
41+
}
42+
}
43+
44+
void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
45+
{
46+
if (!entry)
47+
return;
48+
49+
entry->process.clean_on_exit = 0;
50+
kill(entry->process.pid, SIGTERM);
51+
finish_command(&entry->process);
52+
53+
hashmap_remove(hashmap, entry, NULL);
54+
}
55+
56+
static void subprocess_exit_handler(struct child_process *process)
57+
{
58+
sigchain_push(SIGPIPE, SIG_IGN);
59+
/* Closing the pipe signals the subprocess to initiate a shutdown. */
60+
close(process->in);
61+
close(process->out);
62+
sigchain_pop(SIGPIPE);
63+
/* Finish command will wait until the shutdown is complete. */
64+
finish_command(process);
65+
}
66+
67+
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
68+
subprocess_start_fn startfn)
69+
{
70+
int err;
71+
struct child_process *process;
72+
const char *argv[] = { cmd, NULL };
73+
74+
entry->cmd = cmd;
75+
process = &entry->process;
76+
77+
child_process_init(process);
78+
process->argv = argv;
79+
process->use_shell = 1;
80+
process->in = -1;
81+
process->out = -1;
82+
process->clean_on_exit = 1;
83+
process->clean_on_exit_handler = subprocess_exit_handler;
84+
85+
err = start_command(process);
86+
if (err) {
87+
error("cannot fork to run subprocess '%s'", cmd);
88+
return err;
89+
}
90+
91+
hashmap_entry_init(entry, strhash(cmd));
92+
93+
err = startfn(entry);
94+
if (err) {
95+
error("initialization for subprocess '%s' failed", cmd);
96+
subprocess_stop(hashmap, entry);
97+
return err;
98+
}
99+
100+
hashmap_add(hashmap, entry);
101+
return 0;
102+
}

sub-process.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef SUBPROCESS_H
2+
#define SUBPROCESS_H
3+
4+
#include "git-compat-util.h"
5+
#include "hashmap.h"
6+
#include "run-command.h"
7+
8+
/*
9+
* Generic implementation of background process infrastructure.
10+
* See Documentation/technical/api-background-process.txt.
11+
*/
12+
13+
/* data structures */
14+
15+
struct subprocess_entry {
16+
struct hashmap_entry ent; /* must be the first member! */
17+
const char *cmd;
18+
struct child_process process;
19+
};
20+
21+
/* subprocess functions */
22+
23+
int cmd2process_cmp(const struct subprocess_entry *e1,
24+
const struct subprocess_entry *e2, const void *unused);
25+
26+
typedef int(*subprocess_start_fn)(struct subprocess_entry *entry);
27+
int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
28+
subprocess_start_fn startfn);
29+
30+
void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry);
31+
32+
struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd);
33+
34+
/* subprocess helper functions */
35+
36+
static inline struct child_process *subprocess_get_child_process(
37+
struct subprocess_entry *entry)
38+
{
39+
return &entry->process;
40+
}
41+
42+
/*
43+
* Helper function that will read packets looking for "status=<foo>"
44+
* key/value pairs and return the value from the last "status" packet
45+
*/
46+
47+
void subprocess_read_status(int fd, struct strbuf *status);
48+
49+
#endif

0 commit comments

Comments
 (0)