threadstate.c 2.11 KB
Newer Older
1 2 3 4 5 6 7 8
/*
 * Copyright (C) the libgit2 contributors. All rights reserved.
 *
 * This file is part of libgit2, distributed under the GNU GPL v2 with
 * a Linking Exception. For full terms see the included COPYING file.
 */

#include "threadstate.h"
9
#include "runtime.h"
10 11 12 13 14 15 16 17

/**
 * Handle the thread-local state
 *
 * `git_threadstate_global_init` will be called as part
 * of `git_libgit2_init` (which itself must be called
 * before calling any other function in the library).
 *
18
 * This function allocates a TLS index to store the per-
19 20 21 22 23 24 25 26 27 28 29 30 31
 * thread state.
 *
 * Any internal method that requires thread-local state
 * will then call `git_threadstate_get()` which returns a
 * pointer to the thread-local state structure; this
 * structure is lazily allocated on each thread.
 *
 * This mechanism will register a shutdown handler
 * (`git_threadstate_global_shutdown`) which will free the
 * TLS index.  This shutdown handler will be called by
 * `git_libgit2_shutdown`.
 */

32
static git_tlsdata_key tls_key;
33

34
static void threadstate_dispose(git_threadstate *threadstate)
35
{
36 37 38
	if (!threadstate)
		return;

39 40
    if (threadstate->error_t.message != git_buf__initbuf)
        git__free(threadstate->error_t.message);
41
	threadstate->error_t.message = NULL;
42 43
}

44
static void GIT_SYSTEM_CALL threadstate_free(void *threadstate)
45 46 47 48 49 50 51 52 53
{
	threadstate_dispose(threadstate);
	git__free(threadstate);
}

static void git_threadstate_global_shutdown(void)
{
	git_threadstate *threadstate;

54 55
	threadstate = git_tlsdata_get(tls_key);
	git_tlsdata_set(tls_key, NULL);
56 57 58 59

	threadstate_dispose(threadstate);
	git__free(threadstate);

60
	git_tlsdata_dispose(tls_key);
61 62 63 64
}

int git_threadstate_global_init(void)
{
65
	if (git_tlsdata_init(&tls_key, &threadstate_free) != 0)
66 67
		return -1;

68
	return git_runtime_shutdown_register(git_threadstate_global_shutdown);
69 70 71 72 73 74
}

git_threadstate *git_threadstate_get(void)
{
	git_threadstate *threadstate;

75
	if ((threadstate = git_tlsdata_get(tls_key)) != NULL)
76 77 78 79 80 81
		return threadstate;

	if ((threadstate = git__calloc(1, sizeof(git_threadstate))) == NULL ||
	    git_buf_init(&threadstate->error_buf, 0) < 0)
		return NULL;

82
	git_tlsdata_set(tls_key, threadstate);
83 84
	return threadstate;
}