/**********************************************************************/ /* Howard Eng 2/94 */ /* Unixpros, Inc */ /* */ /* This module implements thread keys. A separate list is maintained */ /* for each task and a global, master key list is maintained. This */ /* master key list contains all valid keys known to the application. */ /* The master key list is created during execution of the once block */ /* When a thread does a set/getspecfic() call, the master list is */ /* checked to see if the key is valid. If it is, then the next check */ /* sees if the key is known to the thread. If it is then the desired */ /* operation is performed. Otherwise, the key is added to the thread */ /**********************************************************************/ #include #include #include "tree.h" #include "ada_ptd_exc.h" typedef struct { pthread_key_t key; char *data; void (*destructor)(); } item_t; static tree *master_key_list = (item_t *) NULL; /**********************************************************************/ /* Used to compare two thread key values. */ /**********************************************************************/ static int compare_keys ( node, data ) tree *node; void *data; { item_t *this_node; int answer; this_node = (item_t *) node->data; if( this_node->key == ((item_t *) data)->key ) answer = 0; else if ( ((item_t *) data)->key < this_node->key ) answer = -1; else answer = 1; return ( answer ); } /**********************************************************************/ /* Sets the data associated with "key". */ /**********************************************************************/ item_t *ada_thd_set_key_value ( list_root, key, value ) tree *list_root; pthread_key_t key; char *value; { item_t *item; item_t find; find.key = key; item = (item_t *) ada_thd_get_from_tree( list_root, &find, compare_keys ); if ( item != (item_t *) NULL ) item->data = value; return ( item ); } /**********************************************************************/ /* Gets the data associated with "key". */ /**********************************************************************/ char *ada_thd_get_key_value ( list_root, key ) tree *list_root; pthread_key_t key; { item_t *item; char *data; item_t find; find.key = key; item = (item_t *) ada_thd_get_from_tree( list_root, &find, compare_keys ); if ( item != (item_t *) NULL ) data = item->data; else data = (char *) NULL; return ( data ); } /**********************************************************************/ /* Checks to see if "key" is known to this thread. Returns 0 if it */ /* is invalid. */ /**********************************************************************/ int ada_thd_check_key ( list_root, key ) tree *list_root; pthread_key_t key; { item_t *item; item_t find; find.key = key; item = (item_t *) ada_thd_get_from_tree( list_root, &find, compare_keys ); return ( item == (item_t *) NULL ? 0 : -1 ); } /**********************************************************************/ /* Add a new key to a task. */ /**********************************************************************/ void ada_thd_create_key ( list_root, key, destructor ) tree **list_root; pthread_key_t key; char *destructor; { item_t *new_node; new_node = (item_t *) malloc( sizeof( item_t ) ); if ( new_node == (item_t *) NULL ) ada_thd_raise_exception( ADA_NO_MEMORY_E ); new_node->key = key; new_node->data = (char *) NULL; new_node->destructor = destructor; ada_thd_add_to_tree( list_root, (char *) new_node, (int (*)( tree *, void *)) compare_keys ); } /**********************************************************************/ /* Add a new key to the master key list. A new key value is created */ /* by incrementing a counter. */ /**********************************************************************/ void ada_thd_create_master_key ( key, destructor ) pthread_key_t *key; char *destructor; { static unsigned long master_key = 0; pthread_lock_global_np(); *key = (pthread_key_t) ++master_key; if ( master_key == 0 ) ada_thd_raise_exception( ADA_NO_RESOURCES_E ); pthread_unlock_global_np(); ada_thd_create_key( &master_key_list, *key, destructor ); } /**********************************************************************/ /* Checks the key to see if it is in the current master list */ /**********************************************************************/ int ada_ptd_check_master_key_list ( key ) pthread_key_t key; { return ( ada_thd_check_key( master_key_list, key ) ); } pthread_destructor_t ada_thd_get_master_key_destructor ( key ) pthread_key_t key; { item_t *item; pthread_destructor_t data; item_t find; find.key = key; item = (item_t *) ada_thd_get_from_tree( master_key_list, &find, (int (*)( tree *, void *)) compare_keys ); if ( item != (item_t *) NULL ) data = item->destructor; else data = (pthread_destructor_t *) NULL; return ( data ); } /**********************************************************************/ /* Runs a task's key destructor, if there is one present. The node */ /* is also destroyed. */ /**********************************************************************/ static void run_one_destructor ( node, data ) tree *node; char *data; { item_t *item; item = (item_t *) node->data; if( item->destructor != ( void (*)() ) NULL && item->data != (char *) NULL ) (*item->destructor)( item->data ); free( node ); } /**********************************************************************/ /* Run's through a task's entire list of destructors, executing them */ /* as they are found. The task's original list root is freed and set */ /* back to NULL. */ /**********************************************************************/ void ada_thd_run_key_destructors ( list_root ) tree **list_root; { ada_thd_walk_tree( *list_root, run_one_destructor, (char *) NULL ); free( *list_root ); list_root = (tree *) NULL; }