diff --git a/src/global.h b/src/global.h index 219951525..88f40aad1 100644 --- a/src/global.h +++ b/src/global.h @@ -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 diff --git a/src/unix/pthread.h b/src/unix/pthread.h index 0f3f17927..3f23d10d5 100644 --- a/src/unix/pthread.h +++ b/src/unix/pthread.h @@ -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 diff --git a/src/win32/thread.c b/src/win32/thread.c index 80d56ce5d..87318c9d3 100644 --- a/src/win32/thread.c +++ b/src/win32/thread.c @@ -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); diff --git a/src/win32/thread.h b/src/win32/thread.h index 0d01822a6..7f4a2170f 100644 --- a/src/win32/thread.h +++ b/src/win32/thread.h @@ -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 *); diff --git a/tests/threads/basic.c b/tests/threads/basic.c index 9c342bc42..685452d44 100644 --- a/tests/threads/basic.c +++ b/tests/threads/basic.c @@ -48,3 +48,30 @@ void test_threads_basic__set_error(void) { run_in_parallel(1, 4, set_error, NULL, NULL); } + +static void *return_normally(void *param) +{ + return param; +} + +static void *exit_abruptly(void *param) +{ + git_thread_exit(param); + return NULL; +} + +void test_threads_basic__exit(void) +{ + 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); +} \ No newline at end of file