Commit 82f15896 by Edward Thomson

threads: introduce `git_thread_exit`

Introduce `git_thread_exit`, which will allow threads to terminate at an
arbitrary time, returning a `void *`.  On Windows, this means that we
need to store the current `git_thread` in TLS, so that we can set its
`return` value when terminating.

We cannot simply use `ExitThread`, since Win32 returns `DWORD`s from
threads; we return `void *`.
parent a6763ff9
......@@ -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
......
......@@ -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
......
......@@ -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);
......
......@@ -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 *);
......
......@@ -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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment