Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
G
git2
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
git2
Commits
ae5838f1
Commit
ae5838f1
authored
Nov 18, 2016
by
Carlos Martín Nieto
Committed by
GitHub
Nov 18, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #4010 from libgit2/ethomson/clar_threads
Introduce some clar helpers for child threads
parents
6b0510e5
6367c58c
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
122 additions
and
12 deletions
+122
-12
src/global.h
+6
-0
src/unix/pthread.h
+2
-0
src/win32/thread.c
+18
-0
src/win32/thread.h
+2
-0
tests/clar_libgit2.h
+45
-0
tests/core/init.c
+2
-2
tests/threads/basic.c
+33
-0
tests/threads/refdb.c
+14
-10
No files found.
src/global.h
View file @
ae5838f1
...
...
@@ -16,6 +16,12 @@ typedef struct {
git_error
error_t
;
git_buf
error_buf
;
char
oid_fmt
[
GIT_OID_HEXSZ
+
1
];
/* On Windows, this is the current child thread that was started by
* `git_thread_create`. This is used to set the thread's exit code
* when terminated by `git_thread_exit`. It is unused on POSIX.
*/
git_thread
*
current_thread
;
}
git_global_st
;
#ifdef GIT_OPENSSL
...
...
src/unix/pthread.h
View file @
ae5838f1
...
...
@@ -17,6 +17,8 @@ typedef struct {
pthread_create(&(git_thread_ptr)->thread, NULL, start_routine, arg)
#define git_thread_join(git_thread_ptr, status) \
pthread_join((git_thread_ptr)->thread, status)
#define git_thread_currentid() ((size_t)(pthread_self()))
#define git_thread_exit(retval) pthread_exit(retval)
/* Git Mutex */
#define git_mutex pthread_mutex_t
...
...
src/win32/thread.c
View file @
ae5838f1
...
...
@@ -26,6 +26,9 @@ static DWORD WINAPI git_win32__threadproc(LPVOID lpParameter)
{
git_thread
*
thread
=
lpParameter
;
/* Set the current thread for `git_thread_exit` */
GIT_GLOBAL
->
current_thread
=
thread
;
thread
->
result
=
thread
->
proc
(
thread
->
param
);
git__free_tls_data
();
...
...
@@ -95,6 +98,21 @@ int git_thread_join(
return
0
;
}
void
git_thread_exit
(
void
*
value
)
{
assert
(
GIT_GLOBAL
->
current_thread
);
GIT_GLOBAL
->
current_thread
->
result
=
value
;
git__free_tls_data
();
ExitThread
(
CLEAN_THREAD_EXIT
);
}
size_t
git_thread_currentid
(
void
)
{
return
GetCurrentThreadId
();
}
int
git_mutex_init
(
git_mutex
*
GIT_RESTRICT
mutex
)
{
InitializeCriticalSection
(
mutex
);
...
...
src/win32/thread.h
View file @
ae5838f1
...
...
@@ -41,6 +41,8 @@ int git_thread_create(git_thread *GIT_RESTRICT,
void
*
(
*
)
(
void
*
),
void
*
GIT_RESTRICT
);
int
git_thread_join
(
git_thread
*
,
void
**
);
size_t
git_thread_currentid
(
void
);
void
git_thread_exit
(
void
*
);
int
git_mutex_init
(
git_mutex
*
GIT_RESTRICT
mutex
);
int
git_mutex_free
(
git_mutex
*
);
...
...
tests/clar_libgit2.h
View file @
ae5838f1
...
...
@@ -41,6 +41,51 @@
} \
} while(0)
/**
* Thread safe assertions; you cannot use `cl_git_report_failure` from a
* child thread since it will try to `longjmp` to abort and "the effect of
* a call to longjmp() where initialization of the jmp_buf structure was
* not performed in the calling thread is undefined."
*
* Instead, callers can provide a clar thread error context to a thread,
* which will populate and return it on failure. Callers can check the
* status with `cl_git_thread_check`.
*/
typedef
struct
{
int
error
;
const
char
*
file
;
int
line
;
const
char
*
expr
;
char
error_msg
[
4096
];
}
cl_git_thread_err
;
#ifdef GIT_THREADS
# define cl_git_thread_pass(threaderr, expr) cl_git_thread_pass_(threaderr, (expr), __FILE__, __LINE__)
#else
# define cl_git_thread_pass(threaderr, expr) cl_git_pass(expr)
#endif
#define cl_git_thread_pass_(__threaderr, __expr, __file, __line) do { \
giterr_clear(); \
if ((((cl_git_thread_err *)__threaderr)->error = (__expr)) != 0) { \
const git_error *_last = giterr_last(); \
((cl_git_thread_err *)__threaderr)->file = __file; \
((cl_git_thread_err *)__threaderr)->line = __line; \
((cl_git_thread_err *)__threaderr)->expr = "Function call failed: " #__expr; \
p_snprintf(((cl_git_thread_err *)__threaderr)->error_msg, 4096, "thread 0x%" PRIxZ " - error %d - %s", \
git_thread_currentid(), ((cl_git_thread_err *)__threaderr)->error, \
_last ? _last->message : "<no message>"); \
git_thread_exit(__threaderr); \
} \
} while (0)
static
void
cl_git_thread_check
(
void
*
data
)
{
cl_git_thread_err
*
threaderr
=
(
cl_git_thread_err
*
)
data
;
if
(
threaderr
->
error
!=
0
)
clar__assert
(
0
,
threaderr
->
file
,
threaderr
->
line
,
threaderr
->
expr
,
threaderr
->
error_msg
,
1
);
}
void
cl_git_report_failure
(
int
,
const
char
*
,
int
,
const
char
*
);
#define cl_assert_at_line(expr,file,line) \
...
...
tests/core/init.c
View file @
ae5838f1
...
...
@@ -39,14 +39,14 @@ void test_core_init__concurrent_init_succeeds(void)
git_thread
threads
[
10
];
unsigned
i
;
cl_assert_equal_i
(
0
,
git_libgit2_shutdown
());
cl_assert_equal_i
(
2
,
git_libgit2_init
());
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
threads
);
i
++
)
git_thread_create
(
&
threads
[
i
],
reinit
,
NULL
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
threads
);
i
++
)
git_thread_join
(
&
threads
[
i
],
NULL
);
cl_assert_equal_i
(
1
,
git_libgit2_
init
());
cl_assert_equal_i
(
1
,
git_libgit2_
shutdown
());
cl_sandbox_set_search_path_defaults
();
#else
cl_skip
();
...
...
tests/threads/basic.c
View file @
ae5838f1
...
...
@@ -48,3 +48,36 @@ void test_threads_basic__set_error(void)
{
run_in_parallel
(
1
,
4
,
set_error
,
NULL
,
NULL
);
}
#ifdef GIT_THREADS
static
void
*
return_normally
(
void
*
param
)
{
return
param
;
}
static
void
*
exit_abruptly
(
void
*
param
)
{
git_thread_exit
(
param
);
return
NULL
;
}
#endif
void
test_threads_basic__exit
(
void
)
{
#ifndef GIT_THREADS
clar__skip
();
#else
git_thread
thread
;
void
*
result
;
/* Ensure that the return value of the threadproc is returned. */
cl_git_pass
(
git_thread_create
(
&
thread
,
return_normally
,
(
void
*
)
424242
));
cl_git_pass
(
git_thread_join
(
&
thread
,
&
result
));
cl_assert_equal_sz
(
424242
,
(
size_t
)
result
);
/* Ensure that the return value of `git_thread_exit` is returned. */
cl_git_pass
(
git_thread_create
(
&
thread
,
return_normally
,
(
void
*
)
232323
));
cl_git_pass
(
git_thread_join
(
&
thread
,
&
result
));
cl_assert_equal_sz
(
232323
,
(
size_t
)
result
);
#endif
}
tests/threads/refdb.c
View file @
ae5838f1
...
...
@@ -22,6 +22,7 @@ void test_threads_refdb__cleanup(void)
#define NREFS 10
struct
th_data
{
cl_git_thread_err
error
;
int
id
;
const
char
*
path
;
};
...
...
@@ -34,11 +35,11 @@ static void *iterate_refs(void *arg)
int
count
=
0
,
error
;
git_repository
*
repo
;
cl_git_
pass
(
git_repository_open
(
&
repo
,
data
->
path
));
cl_git_
thread_pass
(
data
,
git_repository_open
(
&
repo
,
data
->
path
));
do
{
error
=
git_reference_iterator_new
(
&
i
,
repo
);
}
while
(
error
==
GIT_ELOCKED
);
cl_git_
pass
(
error
);
cl_git_
thread_pass
(
data
,
error
);
for
(
count
=
0
;
!
git_reference_next
(
&
ref
,
i
);
++
count
)
{
cl_assert
(
ref
!=
NULL
);
...
...
@@ -64,26 +65,27 @@ static void *create_refs(void *arg)
git_reference
*
ref
[
NREFS
];
git_repository
*
repo
;
cl_git_
pass
(
git_repository_open
(
&
repo
,
data
->
path
));
cl_git_
thread_pass
(
data
,
git_repository_open
(
&
repo
,
data
->
path
));
do
{
error
=
git_reference_name_to_id
(
&
head
,
repo
,
"HEAD"
);
}
while
(
error
==
GIT_ELOCKED
);
cl_git_
pass
(
error
);
cl_git_
thread_pass
(
data
,
error
);
for
(
i
=
0
;
i
<
NREFS
;
++
i
)
{
p_snprintf
(
name
,
sizeof
(
name
),
"refs/heads/thread-%03d-%02d"
,
data
->
id
,
i
);
do
{
error
=
git_reference_create
(
&
ref
[
i
],
repo
,
name
,
&
head
,
0
,
NULL
);
}
while
(
error
==
GIT_ELOCKED
);
cl_git_
pass
(
error
);
cl_git_
thread_pass
(
data
,
error
);
if
(
i
==
NREFS
/
2
)
{
git_refdb
*
refdb
;
cl_git_
pass
(
git_repository_refdb
(
&
refdb
,
repo
));
cl_git_
thread_pass
(
data
,
git_repository_refdb
(
&
refdb
,
repo
));
do
{
error
=
git_refdb_compress
(
refdb
);
}
while
(
error
==
GIT_ELOCKED
);
cl_git_thread_pass
(
data
,
error
);
git_refdb_free
(
refdb
);
}
}
...
...
@@ -105,7 +107,7 @@ static void *delete_refs(void *arg)
char
name
[
128
];
git_repository
*
repo
;
cl_git_
pass
(
git_repository_open
(
&
repo
,
data
->
path
));
cl_git_
thread_pass
(
data
,
git_repository_open
(
&
repo
,
data
->
path
));
for
(
i
=
0
;
i
<
NREFS
;
++
i
)
{
p_snprintf
(
...
...
@@ -119,17 +121,17 @@ static void *delete_refs(void *arg)
if
(
error
==
GIT_ENOTFOUND
)
error
=
0
;
cl_git_
pass
(
error
);
cl_git_
thread_pass
(
data
,
error
);
git_reference_free
(
ref
);
}
if
(
i
==
NREFS
/
2
)
{
git_refdb
*
refdb
;
cl_git_
pass
(
git_repository_refdb
(
&
refdb
,
repo
));
cl_git_
thread_pass
(
data
,
git_repository_refdb
(
&
refdb
,
repo
));
do
{
error
=
git_refdb_compress
(
refdb
);
}
while
(
error
==
GIT_ELOCKED
);
cl_git_
pass
(
error
);
cl_git_
thread_pass
(
data
,
error
);
git_refdb_free
(
refdb
);
}
}
...
...
@@ -194,6 +196,7 @@ void test_threads_refdb__edit_while_iterate(void)
#ifdef GIT_THREADS
for
(
t
=
0
;
t
<
THREADS
;
++
t
)
{
cl_git_pass
(
git_thread_join
(
&
th
[
t
],
NULL
));
cl_git_thread_check
(
&
th_data
[
t
]);
}
memset
(
th
,
0
,
sizeof
(
th
));
...
...
@@ -205,6 +208,7 @@ void test_threads_refdb__edit_while_iterate(void)
for
(
t
=
0
;
t
<
THREADS
;
++
t
)
{
cl_git_pass
(
git_thread_join
(
&
th
[
t
],
NULL
));
cl_git_thread_check
(
&
th_data
[
t
]);
}
#endif
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment