II_EXTERN IIAPI_ENVHNDL * IIapi_initAPI( II_LONG version, II_LONG timeout ) { IIAPI_ENVHNDL *envHndl; IIAPI_ENVHNDL *defEnvHndl; II_BOOL first_init = FALSE; STATUS status; char *env; if ( ! IIapi_static ) { /* ** Perform global initializations which are ** environment independent. */ first_init = TRUE; if ( ! ( IIapi_static = (IIAPI_STATIC *) MEreqmem( 0, sizeof( IIAPI_STATIC ), TRUE, &status ) ) ) return( NULL ); QUinit( &IIapi_static->api_env_q ); if ( MUi_semaphore( &IIapi_static->api_semaphore ) != OK ) goto muiFail; if ( MEtls_create( &IIapi_static->api_thread ) != OK ) goto metFail; /* ** Initialize sub-systems. */ IIAPI_INITTRACE(); IIAPI_TRACE( IIAPI_TR_TRACE )( "IIapi_initAPI: initializing API.\n" ); /* ** Make sure II_SYSTEM or similar is set to provide useful feedback ** rather than just failing in one of following subsystems. */ NMgtAt( SYSTEM_LOCATION_VARIABLE, &env ); if ( env == NULL || *env == EOS ) { IIAPI_TRACE( IIAPI_TR_FATAL ) ( "IIapi_initAPI: error - %s not set.\n", SYSTEM_LOCATION_VARIABLE ); goto adfFail; } IIapi_init_mib(); if ( ! IIapi_initADF() ) goto adfFail; if ( ! IIapi_initGCA(timeout) ) goto gcaFail; /* Initialize the unicode collation values */ IIapi_static->api_unicol_init = FALSE; IIapi_static->api_ucode_ctbl = NULL; IIapi_static->api_ucode_cvtbl = NULL; /* ** Create the default environment. */ if ( ! (IIapi_static->api_env_default = (PTR)IIapi_createEnvHndl( IIAPI_VERSION_1 )) ) goto defFail; /* Spoken Language to use */ if( ( status = ERlangcode( (char *)NULL, &IIapi_static->api_slang ) != OK) ) { IIAPI_TRACE( IIAPI_TR_ERROR ) ( "IIapi_initAPI: error initializing lang 0x%x\n", status ); return( NULL ); } /* ** The SQL state machines are used by default prior to ** IIapi_connect() being called, so make sure they are ** initialized. */ if ( IIapi_sm_init( IIAPI_SMT_SQL ) != IIAPI_ST_SUCCESS ) goto envFail; } /* ** Now do environment specific initialization. */ defEnvHndl = IIapi_defaultEnvHndl(); if ( version == IIAPI_VERSION_1 ) { /* ** Version 1 initializers share the default ** environment. Keep track of the number of ** initializers so that IIapi_termAPI() can ** determine when to do global shutdown. */ envHndl = defEnvHndl; MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount++; MUv_semaphore( &defEnvHndl->en_semaphore ); } else { /* ** Create a new environment for the initializer. ** These environments are saved on the global ** environment queue. The caller may also make ** API calls using the default environment handle, ** so increment the default environment handle ** initialization count. */ if ( (envHndl = IIapi_createEnvHndl( version )) ) { MUp_semaphore( &IIapi_static->api_semaphore ); QUinsert( (QUEUE *)envHndl, &IIapi_static->api_env_q ); MUv_semaphore( &IIapi_static->api_semaphore ); MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount++; MUv_semaphore( &defEnvHndl->en_semaphore ); } else { /* ** We may need to undo the global initialization. ** If not, the NULL environment handle will simply ** be returned. */ if ( first_init ) goto envFail; } } return( envHndl ); envFail: IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default ); defFail: IIapi_termGCA(); gcaFail: IIapi_termADF(); adfFail: IIAPI_TERMTRACE(); MEtls_destroy( &IIapi_static->api_thread, NULL ); metFail: MUr_semaphore( &IIapi_static->api_semaphore ); muiFail: MEfree( (PTR)IIapi_static ); IIapi_static = NULL; return( NULL ); }
II_EXTERN II_BOOL IIapi_termAPI( IIAPI_ENVHNDL *envHndl ) { IIAPI_ENVHNDL *defEnvHndl; II_BOOL last_term = FALSE; if ( ! IIapi_static ) return( TRUE ); defEnvHndl = IIapi_defaultEnvHndl(); if ( envHndl ) { /* ** Free the environment handle. */ MUp_semaphore( &IIapi_static->api_semaphore ); QUremove( (QUEUE *)envHndl ); MUv_semaphore( &IIapi_static->api_semaphore ); IIapi_deleteEnvHndl( envHndl ); } else { /* ** Decrement the usage counter in ** the default environment handle. */ MUp_semaphore( &defEnvHndl->en_semaphore ); defEnvHndl->en_initCount = max( 0, defEnvHndl->en_initCount - 1 ); MUv_semaphore( &defEnvHndl->en_semaphore ); } /* ** Shutdown API when all version 1 initializers have terminated ** and there are no active version 2 environments. */ if ( ! defEnvHndl->en_initCount && IIapi_isQueEmpty( &IIapi_static->api_env_q ) ) { QUEUE *q; IIAPI_TRACE( IIAPI_TR_TRACE ) ( "IIapi_termAPI: shutting down API completely.\n" ); /* ** Free the default environment. */ IIapi_deleteEnvHndl( (IIAPI_ENVHNDL *)IIapi_static->api_env_default ); IIapi_static->api_env_default = NULL; /* ** Shutdown sub-systems. */ IIapi_termGCA(); IIapi_termADF(); IIAPI_TRACE( IIAPI_TR_INFO )( "IIapi_termAPI: API shutdown.\n" ); IIAPI_TERMTRACE(); /* ** Free the remaining global resources. */ if (IIapi_static->api_ucode_ctbl) MEfree (IIapi_static->api_ucode_ctbl); if (IIapi_static->api_ucode_cvtbl) MEfree (IIapi_static->api_ucode_cvtbl); MEtls_destroy( &IIapi_static->api_thread, MEfree ); MUr_semaphore( &IIapi_static->api_semaphore ); MEfree( (PTR)IIapi_static ); IIapi_static = NULL; last_term = TRUE; } return( last_term ); }
VOID gca_terminate( GCA_SVC_PARMS *svc_parms ) { GCA_CB *gca_cb = (GCA_CB *)svc_parms->gca_cb; char id_buff[16]; /* ** Increment the term counter and perform global ** shutdown if all initializers have terminated. ** ** The current request must be completed during ** global shutdown so that ACB resources can be ** freed. If global shutdown is not being done, ** the request must still be completed to ensure ** a consistent state. */ if ( IIGCa_global.gca_initiate > ++IIGCa_global.gca_terminate ) gca_complete( svc_parms ); else { i4 assoc_id; /* ** Shutdown any remaining associations. */ for( assoc_id = gca_next_acb( -1 ); assoc_id >= 0; assoc_id = gca_next_acb( assoc_id ) ) { /* ** Skip ACB flagged for deletion since it has ** already been shutdown. */ GCA_ACB *acb = gca_find_acb( assoc_id ); if ( acb && ! acb->flags.delete_acb ) { GCA_DA_PARMS da_parms; STATUS status; /* ** TODO: Fix GC CL interface for register/llsten. ** ** If this association is an active listen, this ** call will fail. With the current interface ** there is nothing we can do. A GC control ** block is needed for registration, created ** by GCregister() and used in GClisten(), which ** can then be passed to a deregister routine ** capable of aborting a listen and cleaning up ** the register resources. ** ** Currently, the CL must do register/listen ** cleanup during GCterminate(), which can't be ** called prior to these calls here. */ da_parms.gca_association_id = assoc_id; IIGCa_cb_call( (PTR *)&gca_cb, GCA_DISASSOC, (GCA_PARMLIST *)&da_parms, GCA_SYNC_FLAG, NULL, -1L, &status ); } } /* ** Call GCterminate to perform system-dependent cleanup */ GCterminate( &svc_parms->gc_parms ); /* ** Cleanup ACB global resources. ** ** There may be an ACB associated with the current ** request. If so, it is the registration ACB and ** should be shutdown and flagged for deletion. We ** need to perform request completion at this point ** so that the ACB resources can be freed. */ gca_complete( svc_parms ); /* ** Release any remaining ACB. Normally, there should ** only be an active listen ACB at this point. */ for( assoc_id = gca_next_acb( -1 ); assoc_id >= 0; assoc_id = gca_next_acb( assoc_id ) ) { GCA_ACB *acb = gca_find_acb( assoc_id ); if ( acb ) gca_del_acb( acb->assoc_id ); } /* ** Now, release the remaining ACB resources. */ gca_free_acbs(); MUr_semaphore( &IIGCa_global.gca_acb_semaphore ); #ifdef GCF_EMBEDDED_GCN /* ** Shutdown the embedded Name Server interface */ if ( IIGCa_global.gca_embedded_gcn ) gca_ns_term(); #endif /* GCF_EMBEDDED_GCN */ /* ** Shutdown security. */ IIgcs_call( GCS_OP_TERM, GCS_NO_MECH, NULL ); IIGCa_global.gca_initialized = FALSE; } /* ** Tell MO that the control block is no longer active. */ STprintf( id_buff, "%d", gca_cb->gca_cb_id ); MOdetach( GCA_MIB_CLIENT, id_buff ); /* ** Free resources. */ MUr_semaphore( &gca_cb->gca_reg_semaphore ); /* ** Clear the initialization flag so the ** control block will be freed in gca_call(). */ gca_cb->gca_initialized = FALSE; return; }