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>
Ben Peart committed
May 5, 2017 at 11:28 UTC
99605d62e8e7e568035dc953b24b79b3d52f0522
5 files changed
+212
-103
Documentation/technical/api-sub-process.txt
new
+59
@@ -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
+1
@@ -838,6 +838,7 @@ LIB_OBJS += streaming.o
838
LIB_OBJS += string-list.o
839
LIB_OBJS += submodule.o
840
LIB_OBJS += submodule-config.o
841
+LIB_OBJS += sub-process.o
842
LIB_OBJS += symlinks.o
843
LIB_OBJS += tag.o
844
LIB_OBJS += tempfile.o
convert.c
+1
-103
@@ -4,6 +4,7 @@
4
#include "quote.h"
5
#include "sigchain.h"
6
#include "pkt-line.h"
7
+#include "sub-process.h"
8
9
/*
10
* 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
497
#define CAP_CLEAN (1u<<0)
498
#define CAP_SMUDGE (1u<<1)
499
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
-
500
struct cmd2process {
501
struct subprocess_entry subprocess; /* must be the first member! */
502
unsigned int supported_capabilities;
@@ -510,65 +505,6 @@ struct cmd2process {
505
static int subprocess_map_initialized;
506
static struct hashmap subprocess_map;
507
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
-
508
static int start_multi_file_filter_fn(struct subprocess_entry *subprocess)
509
{
510
int err;
@@ -629,44 +565,6 @@ done:
565
return err;
566
}
567
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
-
568
static int apply_multi_file_filter(const char *path, const char *src, size_t len,
569
int fd, struct strbuf *dst, const char *cmd,
570
const unsigned int wanted_capability)
sub-process.c
new
+102
@@ -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
new
+49
@@ -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