16
#include "quote.h"
17
#include "dir.h"
18
19
+#ifndef NO_PTHREADS
20
+#include "thread-utils.h"
21
+#include <pthread.h>
22
+#endif
23
+
24
static char const * const grep_usage[] = {
25
"git grep [options] [-e] <pattern> [<rev>...] [[--] path...]",
26
NULL
27
};
28
29
+static int use_threads = 1;
30
+
31
+#ifndef NO_PTHREADS
32
+#define THREADS 8
33
+static pthread_t threads[THREADS];
34
+
35
+static void *load_sha1(const unsigned char *sha1, unsigned long *size,
36
+ const char *name);
37
+static void *load_file(const char *filename, size_t *sz);
38
+
39
+enum work_type {WORK_SHA1, WORK_FILE};
40
+
41
+/* We use one producer thread and THREADS consumer
42
+ * threads. The producer adds struct work_items to 'todo' and the
43
+ * consumers pick work items from the same array.
44
+ */
45
+struct work_item
46
+{
47
+ enum work_type type;
48
+ char *name;
49
+
50
+ /* if type == WORK_SHA1, then 'identifier' is a SHA1,
51
+ * otherwise type == WORK_FILE, and 'identifier' is a NUL
52
+ * terminated filename.
53
+ */
54
+ void *identifier;
55
+ char done;
56
+ struct strbuf out;
57
+};
58
+
59
+/* In the range [todo_done, todo_start) in 'todo' we have work_items
60
+ * that have been or are processed by a consumer thread. We haven't
61
+ * written the result for these to stdout yet.
62
+ *
63
+ * The work_items in [todo_start, todo_end) are waiting to be picked
64
+ * up by a consumer thread.
65
+ *
66
+ * The ranges are modulo TODO_SIZE.
67
+ */
68
+#define TODO_SIZE 128
69
+static struct work_item todo[TODO_SIZE];
70
+static int todo_start;
71
+static int todo_end;
72
+static int todo_done;
73
+
74
+/* Has all work items been added? */
75
+static int all_work_added;
76
+
77
+/* This lock protects all the variables above. */
78
+static pthread_mutex_t grep_mutex;
79
+
80
+/* Used to serialize calls to read_sha1_file. */
81
+static pthread_mutex_t read_sha1_mutex;
82
+
83
+#define grep_lock() pthread_mutex_lock(&grep_mutex)
84
+#define grep_unlock() pthread_mutex_unlock(&grep_mutex)
85
+#define read_sha1_lock() pthread_mutex_lock(&read_sha1_mutex)
86
+#define read_sha1_unlock() pthread_mutex_unlock(&read_sha1_mutex)
87
+
88
+/* Signalled when a new work_item is added to todo. */
89
+static pthread_cond_t cond_add;
90
+
91
+/* Signalled when the result from one work_item is written to
92
+ * stdout.
93
+ */
94
+static pthread_cond_t cond_write;
95
+
96
+/* Signalled when we are finished with everything. */
97
+static pthread_cond_t cond_result;
98
+
99
+static void add_work(enum work_type type, char *name, void *id)
100
+{
101
+ grep_lock();
102
+
103
+ while ((todo_end+1) % ARRAY_SIZE(todo) == todo_done) {
104
+ pthread_cond_wait(&cond_write, &grep_mutex);
105
+ }
106
+
107
+ todo[todo_end].type = type;
108
+ todo[todo_end].name = name;
109
+ todo[todo_end].identifier = id;
110
+ todo[todo_end].done = 0;
111
+ strbuf_reset(&todo[todo_end].out);
112
+ todo_end = (todo_end + 1) % ARRAY_SIZE(todo);
113
+
114
+ pthread_cond_signal(&cond_add);
115
+ grep_unlock();
116
+}
117
+
118
+static struct work_item *get_work(void)
119
+{
120
+ struct work_item *ret;
121
+
122
+ grep_lock();
123
+ while (todo_start == todo_end && !all_work_added) {
124
+ pthread_cond_wait(&cond_add, &grep_mutex);
125
+ }
126
+
127
+ if (todo_start == todo_end && all_work_added) {
128
+ ret = NULL;
129
+ } else {
130
+ ret = &todo[todo_start];
131
+ todo_start = (todo_start + 1) % ARRAY_SIZE(todo);
132
+ }
133
+ grep_unlock();
134
+ return ret;
135
+}
136
+
137
+static void grep_sha1_async(struct grep_opt *opt, char *name,
138
+ const unsigned char *sha1)
139
+{
140
+ unsigned char *s;
141
+ s = xmalloc(20);
142
+ memcpy(s, sha1, 20);
143
+ add_work(WORK_SHA1, name, s);
144
+}
145
+
146
+static void grep_file_async(struct grep_opt *opt, char *name,
147
+ const char *filename)
148
+{
149
+ add_work(WORK_FILE, name, xstrdup(filename));
150
+}
151
+
152
+static void work_done(struct work_item *w)
153
+{
154
+ int old_done;
155
+
156
+ grep_lock();
157
+ w->done = 1;
158
+ old_done = todo_done;
159
+ for(; todo[todo_done].done && todo_done != todo_start;
160
+ todo_done = (todo_done+1) % ARRAY_SIZE(todo)) {
161
+ w = &todo[todo_done];
162
+ write_or_die(1, w->out.buf, w->out.len);
163
+ free(w->name);
164
+ free(w->identifier);
165
+ }
166
+
167
+ if (old_done != todo_done)
168
+ pthread_cond_signal(&cond_write);
169
+
170
+ if (all_work_added && todo_done == todo_end)
171
+ pthread_cond_signal(&cond_result);
172
+
173
+ grep_unlock();
174
+}
175
+
176
+static void *run(void *arg)
177
+{
178
+ int hit = 0;
179
+ struct grep_opt *opt = arg;
180
+
181
+ while (1) {
182
+ struct work_item *w = get_work();
183
+ if (!w)
184
+ break;
185
+
186
+ opt->output_priv = w;
187
+ if (w->type == WORK_SHA1) {
188
+ unsigned long sz;
189
+ void* data = load_sha1(w->identifier, &sz, w->name);
190
+
191
+ if (data) {
192
+ hit |= grep_buffer(opt, w->name, data, sz);
193
+ free(data);
194
+ }
195
+ } else if (w->type == WORK_FILE) {
196
+ size_t sz;
197
+ void* data = load_file(w->identifier, &sz);
198
+ if (data) {
199
+ hit |= grep_buffer(opt, w->name, data, sz);
200
+ free(data);
201
+ }
202
+ } else {
203
+ assert(0);
204
+ }
205
+
206
+ work_done(w);
207
+ }
208
+
209
+ return (void*) (intptr_t) hit;
210
+}
211
+
212
+static void strbuf_out(struct grep_opt *opt, const void *buf, size_t size)
213
+{
214
+ struct work_item *w = opt->output_priv;
215
+ strbuf_add(&w->out, buf, size);
216
+}
217
+
218
+static void start_threads(struct grep_opt *opt)
219
+{
220
+ int i;
221
+
222
+ pthread_mutex_init(&grep_mutex, NULL);
223
+ pthread_mutex_init(&read_sha1_mutex, NULL);
224
+ pthread_cond_init(&cond_add, NULL);
225
+ pthread_cond_init(&cond_write, NULL);
226
+ pthread_cond_init(&cond_result, NULL);
227
+
228
+ for (i = 0; i < ARRAY_SIZE(todo); i++) {
229
+ strbuf_init(&todo[i].out, 0);
230
+ }
231
+
232
+ for (i = 0; i < ARRAY_SIZE(threads); i++) {
233
+ int err;
234
+ struct grep_opt *o = grep_opt_dup(opt);
235
+ o->output = strbuf_out;
236
+ compile_grep_patterns(o);
237
+ err = pthread_create(&threads[i], NULL, run, o);
238
+
239
+ if (err)
240
+ die("grep: failed to create thread: %s",
241
+ strerror(err));
242
+ }
243
+}
244
+
245
+static int wait_all(void)
246
+{
247
+ int hit = 0;
248
+ int i;
249
+
250
+ grep_lock();
251
+ all_work_added = 1;
252
+
253
+ /* Wait until all work is done. */
254
+ while (todo_done != todo_end)
255
+ pthread_cond_wait(&cond_result, &grep_mutex);
256
+
257
+ /* Wake up all the consumer threads so they can see that there
258
+ * is no more work to do.
259
+ */
260
+ pthread_cond_broadcast(&cond_add);
261
+ grep_unlock();
262
+
263
+ for (i = 0; i < ARRAY_SIZE(threads); i++) {
264
+ void *h;
265
+ pthread_join(threads[i], &h);
266
+ hit |= (int) (intptr_t) h;
267
+ }
268
+
269
+ pthread_mutex_destroy(&grep_mutex);
270
+ pthread_mutex_destroy(&read_sha1_mutex);
271
+ pthread_cond_destroy(&cond_add);
272
+ pthread_cond_destroy(&cond_write);
273
+ pthread_cond_destroy(&cond_result);
274
+
275
+ return hit;
276
+}
277
+#else /* !NO_PTHREADS */
278
+#define read_sha1_lock()
279
+#define read_sha1_unlock()
280
+
281
+static int wait_all(void)
282
+{
283
+ return 0;
284
+}
285
+#endif
286
+
287
static int grep_config(const char *var, const char *value, void *cb)
288
{
289
struct grep_opt *opt = cb;
407
return 0;
408
}
409
147
-static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1, const char *name, int tree_name_len)
410
+static void *load_sha1(const unsigned char *sha1, unsigned long *size,
411
+ const char *name)
412
{
149
- unsigned long size;
150
- char *data;
413
enum object_type type;
152
- int hit;
153
- struct strbuf pathbuf = STRBUF_INIT;
414
+ char *data;
415
155
- data = read_sha1_file(sha1, &type, &size);
156
- if (!data) {
416
+ read_sha1_lock();
417
+ data = read_sha1_file(sha1, &type, size);
418
+ read_sha1_unlock();
419
+
420
+ if (!data)
421
error("'%s': unable to read %s", name, sha1_to_hex(sha1));
158
- return 0;
159
- }
422
+
423
+ return data;
424
+}
425
+
426
+static int grep_sha1(struct grep_opt *opt, const unsigned char *sha1,
427
+ const char *filename, int tree_name_len)
428
+{
429
+ struct strbuf pathbuf = STRBUF_INIT;
430
+ char *name;
431
+
432
if (opt->relative && opt->prefix_length) {
161
- quote_path_relative(name + tree_name_len, -1, &pathbuf, opt->prefix);
162
- strbuf_insert(&pathbuf, 0, name, tree_name_len);
163
- name = pathbuf.buf;
433
+ quote_path_relative(filename + tree_name_len, -1, &pathbuf,
434
+ opt->prefix);
435
+ strbuf_insert(&pathbuf, 0, filename, tree_name_len);
436
+ } else {
437
+ strbuf_addstr(&pathbuf, filename);
438
+ }
439
+
440
+ name = strbuf_detach(&pathbuf, NULL);
441
+
442
+#ifndef NO_PTHREADS
443
+ if (use_threads) {
444
+ grep_sha1_async(opt, name, sha1);
445
+ return 0;
446
+ } else
447
+#endif
448
+ {
449
+ int hit;
450
+ unsigned long sz;
451
+ void *data = load_sha1(sha1, &sz, name);
452
+ if (!data)
453
+ hit = 0;
454
+ else
455
+ hit = grep_buffer(opt, name, data, sz);
456
+
457
+ free(data);
458
+ free(name);
459
+ return hit;
460
}
165
- hit = grep_buffer(opt, name, data, size);
166
- strbuf_release(&pathbuf);
167
- free(data);
168
- return hit;
461
}
462
171
-static int grep_file(struct grep_opt *opt, const char *filename)
463
+static void *load_file(const char *filename, size_t *sz)
464
{
465
struct stat st;
174
- int i;
466
char *data;
176
- size_t sz;
177
- struct strbuf buf = STRBUF_INIT;
467
+ int i;
468
469
if (lstat(filename, &st) < 0) {
470
err_ret:
474
}
475
if (!S_ISREG(st.st_mode))
476
return 0;
187
- sz = xsize_t(st.st_size);
477
+ *sz = xsize_t(st.st_size);
478
i = open(filename, O_RDONLY);
479
if (i < 0)
480
goto err_ret;
191
- data = xmalloc(sz + 1);
192
- if (st.st_size != read_in_full(i, data, sz)) {
481
+ data = xmalloc(*sz + 1);
482
+ if (st.st_size != read_in_full(i, data, *sz)) {
483
error("'%s': short read %s", filename, strerror(errno));
484
close(i);
485
free(data);
486
return 0;
487
}
488
close(i);
199
- data[sz] = 0;
489
+ data[*sz] = 0;
490
+ return data;
491
+}
492
+
493
+static int grep_file(struct grep_opt *opt, const char *filename)
494
+{
495
+ struct strbuf buf = STRBUF_INIT;
496
+ char *name;
497
+
498
if (opt->relative && opt->prefix_length)
201
- filename = quote_path_relative(filename, -1, &buf, opt->prefix);
202
- i = grep_buffer(opt, filename, data, sz);
203
- strbuf_release(&buf);
204
- free(data);
205
- return i;
499
+ quote_path_relative(filename, -1, &buf, opt->prefix);
500
+ else
501
+ strbuf_addstr(&buf, filename);
502
+ name = strbuf_detach(&buf, NULL);
503
+
504
+#ifndef NO_PTHREADS
505
+ if (use_threads) {
506
+ grep_file_async(opt, name, filename);
507
+ return 0;
508
+ } else
509
+#endif
510
+ {
511
+ int hit;
512
+ size_t sz;
513
+ void *data = load_file(filename, &sz);
514
+ if (!data)
515
+ hit = 0;
516
+ else
517
+ hit = grep_buffer(opt, name, data, sz);
518
+
519
+ free(data);
520
+ free(name);
521
+ return hit;
522
+ }
523
}
524
525
static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
604
void *data;
605
unsigned long size;
606
607
+ read_sha1_lock();
608
data = read_sha1_file(entry.sha1, &type, &size);
609
+ read_sha1_unlock();
610
+
611
if (!data)
612
die("unable to read tree (%s)",
613
sha1_to_hex(entry.sha1));
901
opt.regflags |= REG_ICASE;
902
if ((opt.regflags != REG_NEWLINE) && opt.fixed)
903
die("cannot mix --fixed-strings and regexp");
904
+
905
+#ifndef NO_PTHREADS
906
+ if (online_cpus() == 1 || !grep_threads_ok(&opt))
907
+ use_threads = 0;
908
+
909
+ if (use_threads)
910
+ start_threads(&opt);
911
+#else
912
+ use_threads = 0;
913
+#endif
914
+
915
compile_grep_patterns(&opt);
916
917
/* Check revs and then paths */
949
}
950
951
if (!use_index) {
952
+ int hit;
953
if (cached)
954
die("--cached cannot be used with --no-index.");
955
if (list.nr)
956
die("--no-index cannot be used with revs.");
625
- return !grep_directory(&opt, paths);
957
+ hit = grep_directory(&opt, paths);
958
+ if (use_threads)
959
+ hit |= wait_all();
960
+ return !hit;
961
}
962
963
if (!list.nr) {
964
+ int hit;
965
if (!cached)
966
setup_work_tree();
631
- return !grep_cache(&opt, paths, cached);
967
+
968
+ hit = grep_cache(&opt, paths, cached);
969
+ if (use_threads)
970
+ hit |= wait_all();
971
+ return !hit;
972
}
973
974
if (cached)
983
break;
984
}
985
}
986
+
987
+ if (use_threads)
988
+ hit |= wait_all();
989
free_grep_patterns(&opt);
990
return !hit;
991
}