1 #include "clar_libgit2.h"
2 #include "thread_helpers.h"
6 # if defined(GIT_WIN32)
7 # define git_thread_yield() Sleep(0)
8 # elif defined(__FreeBSD__) || defined(__MidnightBSD__) || defined(__DragonFly__)
9 # define git_thread_yield() pthread_yield()
11 # define git_thread_yield() sched_yield()
15 # define git_thread_yield() (void)0
18 static git_repository
*_repo
;
19 static git_tree
*_a
, *_b
;
20 static git_atomic32 _counts
[4];
21 static int _check_counts
;
28 void test_threads_diff__initialize(void)
31 _retries
= git_win32__retries
;
32 git_win32__retries
= 1;
36 void test_threads_diff__cleanup(void)
38 cl_git_sandbox_cleanup();
41 git_win32__retries
= _retries
;
45 static void setup_trees(void)
49 _repo
= cl_git_sandbox_reopen(); /* reopen sandbox to flush caches */
51 /* avoid competing to load initial index */
52 cl_git_pass(git_repository_index(&idx
, _repo
));
55 cl_git_pass(git_revparse_single(
56 (git_object
**)&_a
, _repo
, "0017bd4ab1^{tree}"));
57 cl_git_pass(git_revparse_single(
58 (git_object
**)&_b
, _repo
, "26a125ee1b^{tree}"));
60 memset(_counts
, 0, sizeof(_counts
));
63 static void free_trees(void)
65 git_tree_free(_a
); _a
= NULL
;
66 git_tree_free(_b
); _b
= NULL
;
69 cl_assert_equal_i(288, git_atomic32_get(&_counts
[0]));
70 cl_assert_equal_i(112, git_atomic32_get(&_counts
[1]));
71 cl_assert_equal_i( 80, git_atomic32_get(&_counts
[2]));
72 cl_assert_equal_i( 96, git_atomic32_get(&_counts
[3]));
76 static void *run_index_diffs(void *arg
)
78 int thread
= *(int *)arg
;
80 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
81 git_diff
*diff
= NULL
;
83 int exp
[4] = { 0, 0, 0, 0 };
85 cl_git_pass(git_repository_open(&repo
, git_repository_path(_repo
)));
87 switch (thread
& 0x03) {
88 case 0: /* diff index to workdir */;
89 cl_git_pass(git_diff_index_to_workdir(&diff
, repo
, NULL
, &opts
));
91 case 1: /* diff tree 'a' to index */;
92 cl_git_pass(git_diff_tree_to_index(&diff
, repo
, _a
, NULL
, &opts
));
94 case 2: /* diff tree 'b' to index */;
95 cl_git_pass(git_diff_tree_to_index(&diff
, repo
, _b
, NULL
, &opts
));
97 case 3: /* diff index to workdir (explicit index) */;
100 cl_git_pass(git_repository_index(&idx
, repo
));
101 cl_git_pass(git_diff_index_to_workdir(&diff
, repo
, idx
, &opts
));
107 /* keep some diff stats to make sure results are as expected */
109 i
= git_diff_num_deltas(diff
);
110 git_atomic32_add(&_counts
[0], (int32_t)i
);
114 switch (git_diff_get_delta(diff
, --i
)->status
) {
115 case GIT_DELTA_MODIFIED
: exp
[1]++; git_atomic32_inc(&_counts
[1]); break;
116 case GIT_DELTA_ADDED
: exp
[2]++; git_atomic32_inc(&_counts
[2]); break;
117 case GIT_DELTA_DELETED
: exp
[3]++; git_atomic32_inc(&_counts
[3]); break;
122 switch (thread
& 0x03) {
124 cl_assert_equal_i(8, exp
[0]); cl_assert_equal_i(4, exp
[1]);
125 cl_assert_equal_i(0, exp
[2]); cl_assert_equal_i(4, exp
[3]);
128 cl_assert_equal_i(12, exp
[0]); cl_assert_equal_i(3, exp
[1]);
129 cl_assert_equal_i(7, exp
[2]); cl_assert_equal_i(2, exp
[3]);
132 cl_assert_equal_i(8, exp
[0]); cl_assert_equal_i(3, exp
[1]);
133 cl_assert_equal_i(3, exp
[2]); cl_assert_equal_i(2, exp
[3]);
138 git_repository_free(repo
);
144 void test_threads_diff__concurrent_diffs(void)
146 _repo
= cl_git_sandbox_init("status");
150 5, 32, run_index_diffs
, setup_trees
, free_trees
);
153 static void *run_index_diffs_with_modifier(void *arg
)
155 int thread
= *(int *)arg
;
156 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
157 git_diff
*diff
= NULL
;
158 git_index
*idx
= NULL
;
159 git_repository
*repo
;
161 cl_git_pass(git_repository_open(&repo
, git_repository_path(_repo
)));
162 cl_git_pass(git_repository_index(&idx
, repo
));
164 /* have first thread altering the index as we go */
168 for (i
= 0; i
< 300; ++i
) {
170 case 0: (void)git_index_add_bypath(idx
, "new_file"); break;
171 case 1: (void)git_index_remove_bypath(idx
, "modified_file"); break;
172 case 2: (void)git_index_remove_bypath(idx
, "new_file"); break;
173 case 3: (void)git_index_add_bypath(idx
, "modified_file"); break;
181 /* only use explicit index in this test to prevent reloading */
183 switch (thread
& 0x03) {
184 case 0: /* diff index to workdir */;
185 cl_git_pass(git_diff_index_to_workdir(&diff
, repo
, idx
, &opts
));
187 case 1: /* diff tree 'a' to index */;
188 cl_git_pass(git_diff_tree_to_index(&diff
, repo
, _a
, idx
, &opts
));
190 case 2: /* diff tree 'b' to index */;
191 cl_git_pass(git_diff_tree_to_index(&diff
, repo
, _b
, idx
, &opts
));
193 case 3: /* diff index to workdir reversed */;
194 opts
.flags
|= GIT_DIFF_REVERSE
;
195 cl_git_pass(git_diff_index_to_workdir(&diff
, repo
, idx
, &opts
));
199 /* results will be unpredictable with index modifier thread running */
205 git_repository_free(repo
);
211 void test_threads_diff__with_concurrent_index_modified(void)
213 _repo
= cl_git_sandbox_init("status");
217 5, 16, run_index_diffs_with_modifier
, setup_trees
, free_trees
);