long
thread_id_get()
{
    long				thread_id;

    thread_id = (long) globus_thread_getspecific(thread_ids);

    return thread_id;
}
int
globus_extension_register_builtin(
    const char *                        extension_name,
    globus_module_descriptor_t *        module_descriptor)
{
    globus_l_extension_builtin_t *      builtin;
    GlobusFuncName(globus_extension_register_builtin);
    
    GlobusExtensionDebugEnterSymbol(extension_name);
    
    builtin = (globus_l_extension_builtin_t *)
        globus_malloc(sizeof(globus_l_extension_builtin_t));
    if(!builtin)
    {
        goto error_alloc;
    }
    
    builtin->owner = (globus_l_extension_module_t *)
        globus_thread_getspecific(globus_l_extension_owner_key);
    builtin->module = module_descriptor;
    builtin->extension_name = globus_libc_strdup(extension_name);
    if(!builtin->extension_name)
    {
        goto error_strdup;
    }
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        int                             rc;
        
        rc = globus_hashtable_insert(
            &globus_l_extension_builtins, builtin->extension_name, builtin);
        if(rc != 0)
        {
            goto error_insert;
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return GLOBUS_SUCCESS;

error_insert:
    globus_rmutex_unlock(&globus_l_extension_mutex);
    globus_free(builtin->extension_name);
error_strdup:
    globus_free(builtin);
error_alloc:
    GlobusExtensionDebugExitWithError();
    return GLOBUS_FAILURE;
}
void *
globus_extension_reference(
    globus_extension_handle_t           handle)
{
    globus_l_extension_handle_t *       entry;
    void *                              datum = NULL;
    GlobusFuncName(globus_extension_reference);
    
    GlobusExtensionDebugEnter();
    
    if(!handle)
    {
        goto error_param;
    }
    
    entry = handle;
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        datum = entry->datum;
        entry->ref++;
        if(entry->owner)
        {
            entry->owner->ref++;
            
            globus_assert(
                (entry->owner != (globus_l_extension_module_t *)
                    globus_thread_getspecific(
                        globus_l_extension_owner_key)) &&
           "You can not reference something owned by the calling module");
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return datum;

error_param:
    GlobusExtensionDebugExitWithError();
    return NULL;
}
static int s_error_cache_destroy (void)
{
  globus_object_t *                   cached;
    
  cached = (globus_object_t *) globus_thread_getspecific(s_peek_key);
  if(cached)
  {
      globus_object_free(cached);
  }
    
  globus_thread_key_delete(s_peek_key);
  globus_thread_key_delete(globus_i_error_verbose_key);
  
  globus_object_cache_destroy (&s_result_to_object_mapper);
  local_mutex_destroy (&s_result_to_object_mutex);
  s_error_cache_initialized = 0;
  
  globus_module_deactivate(GLOBUS_OBJECT_MODULE);
  
  return GLOBUS_SUCCESS;
}
globus_object_t *
globus_error_peek(
    globus_result_t                     result)
{
  globus_object_t * error;
  int err;

  if (! s_error_cache_initialized ) return NULL;

  if ( result == GLOBUS_SUCCESS ) return NULL;

  err = local_mutex_lock (&s_result_to_object_mutex);
  if (err) return NULL;

  error = globus_object_cache_lookup (&s_result_to_object_mapper,
				      (void *) (intptr_t) result);
  
  if (error!=NULL) 
  {
    globus_object_t *                   cached;
    
    globus_object_reference(error);
    cached = (globus_object_t *) globus_thread_getspecific(s_peek_key);
    if(cached)
    {
        globus_object_free(cached);
    }
    
    globus_thread_setspecific(s_peek_key, error);
  }
  
  local_mutex_unlock (&s_result_to_object_mutex);
  
  if (error!=NULL) 
    return error;
  else
    return GLOBUS_ERROR_NO_INFO;
}
/*
 * globus_module_deactivate()
 */
int
globus_module_deactivate(
    globus_module_descriptor_t *	module_descriptor)
{
    globus_l_module_key_t               parent_key;
    int					ret_val;
    globus_l_module_key_t		parent_key_save;


    /*
     * If module activation hasn't been initialized then return an error
     */
    if (!globus_i_module_initialized)
    {
	return GLOBUS_FAILURE;
    }
    
    parent_key = (globus_l_module_key_t)
        globus_thread_getspecific(globus_l_deactivate_parent_key);
    /*
     * Once the recursive mutex has been acquired, decrement the reference
     * counter for this module, and call it's deactivation function if it is
     * no longer being used.
     */
    ret_val = GLOBUS_SUCCESS;
    if (module_descriptor->activation_func != GLOBUS_NULL)
    {
        globus_l_module_entry_t *       entry;
        
        globus_l_module_mutex_lock(&globus_l_module_mutex);
        
        entry = globus_l_module_decrement(module_descriptor, parent_key);
        if (entry && entry->reference_count == 0)
        {
            globus_l_module_mutex_unlock(&globus_l_module_mutex);
            
            parent_key_save = parent_key;
            globus_thread_setspecific(
                globus_l_deactivate_parent_key,
                module_descriptor->activation_func);
            
            if(entry->deactivate_cb)
            {
                ret_val = entry->deactivate_cb(
                    module_descriptor, entry->user_arg);
            }
            else if(module_descriptor->deactivation_func != NULL)
            {
                ret_val = module_descriptor->deactivation_func();
            }
            
            globus_thread_setspecific(
                globus_l_deactivate_parent_key, parent_key_save);
        }
        else
        {
            if(globus_l_module_reference_count(module_descriptor) == 0)
            {
                ret_val = GLOBUS_FAILURE;
            }
            globus_l_module_mutex_unlock(&globus_l_module_mutex);
        }
    }

    return ret_val;
}
/*
 * globus_module_activate()
 */
int
globus_module_activate_proxy(
    globus_module_descriptor_t *	module_descriptor,
    globus_module_deactivate_proxy_cb_t deactivate_cb,
    void *                              user_arg)
{
    globus_l_module_key_t               parent_key;
    int                                 ret_val;
    globus_l_module_key_t               parent_key_save;
    
    /*
     * If this is the first time this routine has been called, then we need to
     * initialize the internal data structures and activate the threads
     * packages if the system has been configured to use threads.
     */
    if (globus_i_module_initialized == GLOBUS_FALSE)
    {
	globus_i_module_initialized = GLOBUS_TRUE;
	globus_l_module_initialize();
    }
    
    parent_key = (globus_l_module_key_t)
        globus_thread_getspecific(globus_l_activate_parent_key);
    /*
     * Once the recursive mutex has been acquired, increment the reference
     * counter for this module, and call it's activation function if it is not
     * currently active.
     */
    globus_l_module_mutex_lock(&globus_l_module_mutex);
    {
	ret_val = GLOBUS_SUCCESS;

	if (module_descriptor->activation_func != GLOBUS_NULL)
	{
	    if (globus_l_module_increment(module_descriptor,
					  parent_key,
					  deactivate_cb,
					  user_arg) == GLOBUS_TRUE)
	    {
		parent_key_save = parent_key;
		globus_thread_setspecific(
		    globus_l_activate_parent_key,
		    module_descriptor->activation_func);
		
		ret_val = module_descriptor->activation_func();
                
                if(ret_val != GLOBUS_SUCCESS)
                {
                    globus_l_module_decrement(
                        module_descriptor, parent_key_save);
                }
                else
                {
		/*
		 * Set up the exit handler
		 */
#                   if defined(HAVE_ATEXIT) || defined(HAVE_ONEXIT)
                    {
                        if(module_descriptor->atexit_func != GLOBUS_NULL)
                        {
                            /* only call the atexit function once */
                            if(!globus_list_search(
                                globus_l_module_atexit_funcs,
                                (void *) module_descriptor->atexit_func))
                            {
                                globus_list_insert(
                                    &globus_l_module_atexit_funcs,
                                    (void *) module_descriptor->atexit_func);
    
                                atexit(module_descriptor->atexit_func);
                            }
                        }
                    }
#                   endif
                }
                
                globus_thread_setspecific(
		    globus_l_activate_parent_key, parent_key_save);
	    }
	}
    }
    globus_l_module_mutex_unlock(&globus_l_module_mutex);

    return ret_val;
}
void *
globus_extension_lookup(
    globus_extension_handle_t *         handle,
    globus_extension_registry_t *       registry,
    void *                              symbol)
{
    globus_l_extension_handle_t *       entry;
    void *                              datum = NULL;
    GlobusFuncName(globus_extension_lookup);
    
    GlobusExtensionDebugEnterSymbol(registry->user_hashing ? "" : symbol);
    
    if(!handle)
    {
        goto error_param;
    }
    
    *handle = NULL;
    if(!registry || !symbol)
    {
        goto error_param;
    }
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        if(registry->initialized)
        {
            entry = (globus_l_extension_handle_t *)
                globus_hashtable_lookup(&registry->table, (void *) symbol);
            if(entry && (!entry->owner || entry->owner->module_ref > 0))
            {
                datum = entry->datum;
                entry->ref++;
                if(entry->owner)
                {
                    entry->owner->ref++;
                    
                    globus_assert(
                        (entry->owner != (globus_l_extension_module_t *)
                            globus_thread_getspecific(
                                globus_l_extension_owner_key)) &&
                   "You can not lookup something owned by the calling module");
                        
                    GlobusExtensionDebugPrintf(
                        GLOBUS_L_EXTENSION_DEBUG_VERBOSE,
                        (_GCSL("[%s] Accessing entry %s within %s\n"),
                            _globus_func_name,
                            registry->user_hashing ? "" : symbol,
                            entry->owner->name));
                }
                
                *handle = entry;
            }
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return datum;

error_param:
    GlobusExtensionDebugExitWithError();
    return NULL;
}
int
globus_extension_registry_add(
    globus_extension_registry_t *       registry,
    void *                              symbol,
    globus_module_descriptor_t *        module,
    void *                              data)
{
    globus_l_extension_handle_t *       entry;
    GlobusFuncName(globus_extension_registry_add);
    
    GlobusExtensionDebugEnterSymbol(registry->user_hashing ? "" : symbol);
    
    if(!data || !symbol || !registry)
    {
        goto error_params;
    }
    
    entry = (globus_l_extension_handle_t *)
        globus_malloc(sizeof(globus_l_extension_handle_t));
    if(!entry)
    {
        goto error_malloc;
    }
    
    entry->owner = (globus_l_extension_module_t *)
        globus_thread_getspecific(globus_l_extension_owner_key);
    entry->module = module;
    entry->datum = data;
    entry->ref = 1;
    entry->symbol = symbol;
    entry->user_hashing = registry->user_hashing;
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        if(!registry->initialized)
        {
            if(globus_hashtable_init(
                &registry->table,
                20,
                globus_hashtable_string_hash,
                globus_hashtable_string_keyeq) != GLOBUS_SUCCESS)
            {
                goto error_init;
            }
            
            registry->initialized = GLOBUS_TRUE;
        }
        
        if(globus_hashtable_insert(
            &registry->table, entry->symbol, entry) != GLOBUS_SUCCESS)
        {
            goto error_insert;
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return GLOBUS_SUCCESS;

error_insert:
error_init:
    globus_rmutex_unlock(&globus_l_extension_mutex);
    globus_free(entry);
error_malloc:
error_params:
    GlobusExtensionDebugExitWithError();
    return GLOBUS_FAILURE;
}
int
globus_extension_activate(
    const char *                        extension_name)
{
    globus_l_extension_module_t *       extension;
    globus_l_extension_module_t *       last_extension;
    globus_l_extension_builtin_t *      builtin;
    int                                 rc;
    globus_result_t                     result = GLOBUS_FAILURE;
    GlobusFuncName(globus_extension_activate);
    
    GlobusExtensionDebugEnterSymbol(extension_name);
    
    if(!extension_name)
    {
        goto error_param;
    }
    
    globus_rmutex_lock(&globus_l_extension_mutex);
    {
        extension = (globus_l_extension_module_t *)
            globus_hashtable_lookup(
                &globus_l_extension_loaded, (void *) extension_name);
        if(!extension)
        {
            extension = (globus_l_extension_module_t *)
                globus_malloc(sizeof(globus_l_extension_module_t));
            if(!extension)
            {
                goto error_alloc;
            }
            
            extension->module_ref = 1;
            extension->ref = 1;
            extension->name = globus_libc_strdup(extension_name);
            if(!extension->name)
            {
                goto error_strdup;
            }
            
            builtin = (globus_l_extension_builtin_t *)
                globus_hashtable_lookup(
                    &globus_l_extension_builtins, (void *) extension_name);
            if(builtin && (!builtin->owner || builtin->owner->module_ref > 0))
            {
#               if !defined(BUILD_STATIC_ONLY)
                {

                    extension->dlhandle = NULL;
                }
#               endif
                extension->module = builtin->module;
                extension->owner = builtin->owner;
                if(extension->owner)
                {
                    extension->owner->ref++;
                }
            }
            else
            {
                extension->owner = NULL;

#               if !defined(BUILD_STATIC_ONLY)
                {

                    result =   
                        globus_l_extension_dlopen(
                            extension->name,
                            &extension->dlhandle);
                    if(result != GLOBUS_SUCCESS)
                    {
                        goto error_dll;
                    }
                    
                    result =
                       globus_l_extension_get_module(
                           extension->dlhandle,
                           extension_name,
                           &extension->module);

                }
#               else
                {
                    globus_assert(BUILD_STATIC_ONLY == 0);
                    result = globus_error_put(
                        globus_error_construct_error(
                            GLOBUS_EXTENSION_MODULE,
                            NULL,
                            GLOBUS_EXTENSION_ERROR_OPEN_FAILED,
                            __FILE__,
                            _globus_func_name,
                            __LINE__,
                            "No support for dynamically loading %s\n",
                            extension->name));
                }
#               endif /* !defined(BUILD_STATIC_ONLY) */

                if(result != GLOBUS_SUCCESS)
                {
                    goto error_module;
                }
            }
            
            globus_hashtable_insert(
                &globus_l_extension_loaded,
                extension->name,
                extension);
                
            last_extension = (globus_l_extension_module_t *)
                globus_thread_getspecific(globus_l_extension_owner_key);
            globus_thread_setspecific(globus_l_extension_owner_key, extension);
            
#if USE_SYMBOL_LABELS
            {
                int pre_warned = WARNING_USING_MIXED_THREAD_MODELS;
#endif
            rc = globus_module_activate_proxy(
                extension->module,
                globus_l_extension_deactivate_proxy,
                extension);
#if USE_SYMBOL_LABELS
                if ((!pre_warned) && WARNING_USING_MIXED_THREAD_MODELS)
                {
                    GlobusExtensionDebugPrintf(
                        GLOBUS_L_EXTENSION_DEBUG_VERBOSE,
                        (_GCSL("[%s] Warning: extension %s was compiled with pthreads for GT 5.0.x and may not work correctly\n"),
                            _globus_func_name,
                            extension->name));

                }
            }
#endif
            
            globus_thread_setspecific(
                globus_l_extension_owner_key, last_extension);
            if(rc != GLOBUS_SUCCESS)
            {
                goto error_activate;
            }
        }
        else
        {
            extension->module_ref++;
            extension->ref++;
        }
    }
    globus_rmutex_unlock(&globus_l_extension_mutex);
    
    GlobusExtensionDebugExit();
    return GLOBUS_SUCCESS;

error_activate:
    globus_hashtable_remove(
        &globus_l_extension_loaded, extension->name);
    if(builtin && builtin->owner)
    {
        builtin->owner->ref--;
    }
error_module:
#ifndef BUILD_STATIC_ONLY
    if(extension->dlhandle)
    {
        lt_dlclose(extension->dlhandle);
    }
error_dll:
#endif /* !BUILD_STATIC_ONLY */
    globus_free(extension->name);
error_strdup:
    globus_free(extension);
error_alloc:
    globus_rmutex_unlock(&globus_l_extension_mutex);
error_param:
    GlobusExtensionDebugExitWithError();
    return result;
}
static
const char *
globus_l_libtool_get_error(void)
{
    return (char *) globus_thread_getspecific(globus_l_libtool_key);
}