#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <Kerberos/KerberosDebug.h>
#include "com_err_threads.h"
static boolean_t g_com_err_thread_initialized = FALSE;
static errcode_t g_com_err_thread_init_error = 0;
static pthread_once_t g_com_err_thread_init_once = PTHREAD_ONCE_INIT;
static pthread_mutex_t g_bundle_lookup_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t g_error_tables_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct error_tables g_error_tables = {0, 0, NULL};
static pthread_key_t g_com_err_hook_key;
static pthread_key_t g_error_message_key;
static pthread_key_t g_error_manager_key;
static void com_err_thread_init_hook ()
{
errcode_t err = 0;
if (!err) {
err = pthread_key_create (&g_com_err_hook_key, NULL);
}
if (!err) {
err = pthread_key_create (&g_error_message_key, free);
}
if (!err) {
err = pthread_key_create (&g_error_manager_key, free);
}
if (err) {
g_com_err_thread_init_error = err; dprintf ("%s: Warning! Pthread initialization failed with error %ld (%s)",
__FUNCTION__, err, strerror (err));
} else {
g_com_err_thread_initialized = TRUE; }
}
static errcode_t com_err_thread_init ()
{
errcode_t err = 0;
if (!err) {
err = pthread_once (&g_com_err_thread_init_once, com_err_thread_init_hook);
}
return err ? err : g_com_err_thread_init_error;
}
static void com_err_thread_destroy () __attribute__((destructor));
static void com_err_thread_destroy ()
{
errcode_t err = 0;
if (!g_com_err_thread_initialized) {
return; }
if (!err) {
err = pthread_key_delete (g_com_err_hook_key);
}
#warning "Destructor doesn't free thread-specific data, only keys"
if (!err) {
err = pthread_key_delete (g_error_message_key);
}
if (!err) {
err = pthread_key_delete (g_error_manager_key);
}
if (err) {
dprintf ("%s: Warning! Pthread termination failed with error %ld (%s)",
__FUNCTION__, err, strerror (err));
}
}
#pragma mark -
errcode_t com_err_thread_lock_error_tables (error_table_array_t *error_tables)
{
errcode_t err = 0;
if (!err) {
err = pthread_mutex_lock (&g_error_tables_mutex);
}
if (!err) {
*error_tables = &g_error_tables;
}
return err;
}
errcode_t com_err_thread_unlock_error_tables (error_table_array_t *error_tables)
{
errcode_t err = 0;
if (!err) {
err = pthread_mutex_unlock (&g_error_tables_mutex);
}
if (!err) {
*error_tables = NULL;
}
return err;
}
#pragma mark -
errcode_t com_err_thread_lock_for_bundle_lookup ()
{
return pthread_mutex_lock (&g_bundle_lookup_mutex);
}
errcode_t com_err_thread_unlock_for_bundle_lookup ()
{
return pthread_mutex_unlock (&g_bundle_lookup_mutex);;
}
#pragma mark -
errcode_t com_err_thread_get_com_err_hook (com_err_handler_t *handler)
{
errcode_t err = com_err_thread_init ();
if (!err) {
*handler = pthread_getspecific (g_com_err_hook_key);
}
return err;
}
errcode_t com_err_thread_set_com_err_hook (com_err_handler_t handler)
{
errcode_t err = com_err_thread_init ();
if (!err) {
err = pthread_setspecific (g_com_err_hook_key, handler);
}
return err;
}
#pragma mark -
errcode_t com_err_thread_get_error_message (char **out_string)
{
errcode_t err = com_err_thread_init ();
if (!err) {
*out_string = pthread_getspecific (g_error_message_key);
}
return err;
}
errcode_t com_err_thread_set_error_message (const char *in_string)
{
errcode_t err = com_err_thread_init ();
char *old_string = NULL;
if (!err) {
err = com_err_thread_get_error_message (&old_string);
}
if (!err) {
if (old_string != NULL) { free (old_string); }
err = pthread_setspecific (g_error_message_key, in_string);
}
return err;
}
#pragma mark -
errcode_t com_err_thread_get_error_manager (char **out_string)
{
errcode_t err = com_err_thread_init ();
if (!err) {
*out_string = pthread_getspecific (g_error_manager_key);
}
return err;
}
errcode_t com_err_thread_set_error_manager (const char *in_string)
{
errcode_t err = com_err_thread_init ();
char *old_string = NULL;
if (!err) {
err = com_err_thread_get_error_manager (&old_string);
}
if (!err) {
if (old_string != NULL) { free (old_string); }
err = pthread_setspecific (g_error_manager_key, in_string);
}
return err;
}