void rpc_ss_destroy_callee_context ( dce_uuid_t *p_uuid, /* Pointer to UUID of context to be destroyed */ handle_t h, /* Binding handle */ error_status_t *result /* Function result */ ) /* Returns error_status_ok unless the UUID is not in the lookup table */ { rpc_client_handle_t close_client; /* NULL or client to stop monitoring */ #ifdef PERFMON RPC_SS_DESTROY_CALLEE_CONTEXT_N; #endif RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); DPRINT(("Seized context tables\n")); rpc_ss_lkddest_callee_context(p_uuid,&close_client,result); RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); if ((*result == error_status_ok) && (close_client != NULL)) { rpc_network_stop_monitoring(h, close_client, (error_status_t *) result); } #ifdef PERFMON RPC_SS_DESTROY_CALLEE_CONTEXT_X; #endif }
void rpc_ss_update_callee_context ( rpc_ss_context_t callee_context, /* The user's local form of the context */ dce_uuid_t *p_uuid, /* Pointer to the equivalent UUID */ error_status_t *result /* Function result */ ) { callee_context_entry_t *this_link; #ifdef PERFMON RPC_SS_UPDATE_CALLEE_CONTEXT_N; #endif RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); DPRINT(("Seized context tables\n")); this_link = &context_table[dce_uuid_hash(p_uuid,result) % CALLEE_CONTEXT_TABLE_SIZE]; while ( ! dce_uuid_equal(p_uuid,&this_link->uuid,result) ) { this_link = this_link->next_context; if (this_link == NULL) { RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); DCETHREAD_RAISE( rpc_x_ss_context_mismatch); } } this_link->user_context = callee_context; RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); *result = error_status_ok; #ifdef PERFMON RPC_SS_UPDATE_CALLEE_CONTEXT_X; #endif }
void rpc_ss_lkddest_callee_context ( dce_uuid_t *p_uuid, /* Pointer to UUID of context to be destroyed */ rpc_client_handle_t *p_close_client, /* Ptr to NULL or client to stop monitoring */ error_status_t *result /* Function result */ ) /* Returns error_status_ok unless the UUID is not in the lookup table */ { callee_context_entry_t *this_link, *next_link, *last_link; #ifdef PERFMON RPC_SS_LKDDEST_CALLEE_CONTEXT_N; #endif this_link = &context_table[dce_uuid_hash(p_uuid,(error_status_t *) result) % CALLEE_CONTEXT_TABLE_SIZE]; next_link = this_link->next_context; if ( dce_uuid_equal(p_uuid,&this_link->uuid, (error_status_t *) result) ) { /* Context to be destroyed is in home slot */ rpc_ss_take_from_callee_client(this_link,p_close_client,result); if (next_link == NULL) { /* There is no chain from the home slot */ dce_uuid_create_nil(&this_link->uuid, (error_status_t *) result); } else { /* Move the second item in the chain to the home slot */ memcpy( (char *)&this_link->uuid, (char *)&next_link->uuid, sizeof(dce_uuid_t) ); this_link->user_context = next_link->user_context; this_link->rundown = next_link->rundown; this_link->p_client_entry = next_link->p_client_entry; this_link->prev_in_client = next_link->prev_in_client; if (this_link->prev_in_client == NULL) { (this_link->p_client_entry)->first_context = this_link; } else { (this_link->prev_in_client)->next_in_client = this_link; } this_link->next_in_client = next_link->next_in_client; if (this_link->next_in_client == NULL) { (this_link->p_client_entry)->last_context = this_link; } else { (this_link->next_in_client)->prev_in_client = this_link; } this_link->next_context = next_link->next_context; /* And release the memory it was in */ free((char_p_t)next_link); } #ifdef PERFMON RPC_SS_LKDDEST_CALLEE_CONTEXT_X; #endif return; } else /* Context is further down chain */ { while (next_link != NULL) { last_link = this_link; this_link = next_link; next_link = this_link->next_context; if ( dce_uuid_equal(p_uuid,&this_link->uuid,(error_status_t *)result) ) { rpc_ss_take_from_callee_client(this_link,p_close_client,result); /* Relink chain to omit found entry */ last_link->next_context = next_link; /* And free the memory it occupied */ free((char_p_t)this_link); #ifdef PERFMON RPC_SS_LKDDEST_CALLEE_CONTEXT_X; #endif return; } } RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); DCETHREAD_RAISE( rpc_x_ss_context_mismatch); } }
void rpc_ss_ee_ctx_from_wire ( ndr_context_handle *p_wire_context, rpc_ss_context_t *p_context, /* The application context */ volatile error_status_t *p_st ) { dce_uuid_t *p_uuid; /* Pointer to the UUID that has come off the wire */ callee_context_entry_t *this_link; #ifdef PERFMON RPC_SS_EE_CTX_FROM_WIRE_N; #endif p_uuid = &p_wire_context->context_handle_uuid; #ifdef DEBUGCTX debug_context_lookup(p_uuid); debug_context_table(); #endif *p_st = error_status_ok; if ( dce_uuid_is_nil(p_uuid, (error_status_t *)p_st) ) { *p_context = NULL; #ifdef PERFMON RPC_SS_EE_CTX_FROM_WIRE_X; #endif return; } RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); DPRINT(("Seized context tables\n")); this_link = &context_table[dce_uuid_hash(p_uuid, (error_status_t *)p_st) % CALLEE_CONTEXT_TABLE_SIZE]; while ( ! dce_uuid_equal(p_uuid,&this_link->uuid, (error_status_t *)p_st) ) { this_link = this_link->next_context; if (this_link == NULL) { RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); #ifdef PERFMON RPC_SS_EE_CTX_FROM_WIRE_X; #endif DCETHREAD_RAISE( rpc_x_ss_context_mismatch ); return; } } *p_context = this_link->user_context; RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); #ifdef PERFMON RPC_SS_EE_CTX_FROM_WIRE_X; #endif return; }
void rpc_ss_create_callee_context ( rpc_ss_context_t callee_context,/* The user's local form of the context */ dce_uuid_t *p_uuid, /* Pointer to the equivalent UUID */ handle_t h, /* Binding handle */ ctx_rundown_fn_p_t ctx_rundown, /* Pointer to context rundown routine */ error_status_t *result /* Function result */ ) { rpc_client_handle_t ctx_client; /* ID of client owning context */ callee_context_entry_t *this_link, *next_link, * volatile new_link; ndr_boolean is_new_client; //DO_NOT_CLOBBER(new_link); #ifdef PERFMON RPC_SS_CREATE_CALLEE_CONTEXT_N; #endif /* If this is the first context to be created, initialization is needed */ RPC_SS_INIT_CONTEXT rpc_binding_inq_client(h, &ctx_client, (error_status_t *) result); if (*result != error_status_ok) return; RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); DPRINT(("Seized context tables\n")); this_link = &context_table[dce_uuid_hash(p_uuid,(error_status_t *)result) % CALLEE_CONTEXT_TABLE_SIZE]; if ( dce_uuid_is_nil(&this_link->uuid, (error_status_t *)result) ) { /* Home slot in the hash table is empty */ new_link = this_link; next_link = NULL; } else { /* Put the new item at the head of the overflow chain */ new_link = (callee_context_entry_t *) malloc(sizeof(callee_context_entry_t)); if (new_link == NULL) { RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); DCETHREAD_RAISE( rpc_x_no_memory ); } next_link = this_link->next_context; this_link->next_context = new_link; } /* Fill in fields of context entry */ memcpy( (char *)&new_link->uuid, (char *)p_uuid, sizeof(dce_uuid_t) ); new_link->user_context = callee_context; new_link->rundown = ctx_rundown; new_link->next_context = next_link; DCETHREAD_TRY rpc_ss_add_to_callee_client(ctx_client,new_link,&is_new_client, result); DCETHREAD_FINALLY RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); DCETHREAD_ENDTRY if ((*result == error_status_ok) && is_new_client) { rpc_network_monitor_liveness( h, ctx_client, rpc_ss_rundown_client, (error_status_t *) result ); #ifdef PERFMON RPC_SS_CREATE_CALLEE_CONTEXT_X; #endif } }
void rpc_ss_rundown_client ( /* [in] */ rpc_client_handle_t failed_client ) { error_status_t result; callee_client_entry_t *this_client; callee_context_entry_t *this_context; rpc_client_handle_t close_client = NULL; /* NULL or client to stop monitoring */ /* FIXME: is the volatility set correctly here? */ rpc_ss_rundown_list_elt * volatile rundown_list; rpc_ss_rundown_list_elt * volatile rundown_elt; rundown_list = NULL; #ifdef PERFMON RPC_SS_RUNDOWN_CLIENT_N; #endif RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); DPRINT(("Seized context tables\n")); for( this_client = &client_table[HASH_CLIENT_ID(failed_client)]; (this_client != NULL) && (close_client == NULL); this_client = this_client->next_h_client ) { if (this_client->client == failed_client) { while (this_client->ref_count != 0) { this_client->rundown_pending = idl_true; RPC_SS_THREADS_CONDITION_WAIT(&this_client->cond_var, &rpc_ss_context_table_mutex); /* Mutex has been released */ RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); } if (this_client->count == 0) { /* The manager closed the contexts while a rundown was pending */ rpc_ss_ctx_remove_client_entry(this_client); RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); #ifdef PERFMON RPC_SS_RUNDOWN_CLIENT_X; #endif return; } /* Need to clear the rundown pending flag so that the client entry can be deleted */ this_client->rundown_pending = idl_false; while (close_client == NULL) { /* Loop until all contexts for this client have been removed from the context table. Note that each iteration brings a different context to first_context position */ this_context = this_client->first_context; rundown_elt = (rpc_ss_rundown_list_elt *) malloc(sizeof(rpc_ss_rundown_list_elt)); if (rundown_elt == NULL) { RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); /* * rpc_m_ctxrundown_nomem * "Out of memory while trying to run down contexts of client %x" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%x"), rpc_svc_libidl, svc_c_sev_error, rpc_m_ctxrundown_nomem, this_client )); return; } rundown_elt->rundown = this_context->rundown; rundown_elt->user_context = this_context->user_context; rundown_elt->next = rundown_list; rundown_list = rundown_elt; rpc_ss_lkddest_callee_context (&this_context->uuid,&close_client,&result); } } } RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); while (rundown_list != NULL) { if (rundown_list->rundown != NULL) { DCETHREAD_TRY (*(rundown_list->rundown))(rundown_list->user_context); DCETHREAD_CATCH_ALL(caught) /* * rpc_m_ctxrundown_exc * "Exception in routine at %x, running down context %x of client %x" */ RPC_DCE_SVC_PRINTF (( DCE_SVC(RPC__SVC_HANDLE, "%x%x%x"), rpc_svc_libidl, svc_c_sev_error, rpc_m_ctxrundown_exc, rundown_list->rundown, rundown_list->user_context, this_client )); DCETHREAD_ENDTRY } rundown_elt = rundown_list; rundown_list = rundown_list->next; free(rundown_elt); }
void rpc_ss_add_to_callee_client ( /* [in] */ rpc_client_handle_t ctx_client, /* Client for whom there is or will be a context */ /* [in] */ callee_context_entry_t *p_context, /* Pointer to the context, NULL if we are creating a client table entry to which we expect a context to be attached later */ /* [out] */ndr_boolean *p_is_new_client, /* TRUE => first context for client */ error_status_t *result /* Function result */ ) { int slot; /* Index of the slot in the lookup table the client should be in */ ndr_boolean creating_at_home; /* TRUE if new client being created in slot in lookup table */ callee_client_entry_t *this_client, *next_client, *new_client; #ifdef PERFMON RPC_SS_ADD_TO_CALLEE_CLIENT_N; #endif /* Now find which chain */ slot = HASH_CLIENT_ID(ctx_client); /* Look for the client in a chain based on the slot. Note the following possibilities exist for the slot: 1) Unoccupied. No chain. 2) Occupied. No chain. 3) Occupied. Chain exists. 4) Unoccupied. Chain exists. This is because once a client record is created it is constrained by the presence of threads machinery not to be moved */ this_client = &client_table[slot]; while (ndr_true) { if ( ctx_client == this_client->client ) { ++this_client->count; *p_is_new_client = (this_client->count == 1); /* Linkage of contexts within client */ p_context->p_client_entry = this_client; p_context->prev_in_client = this_client->last_context; p_context->next_in_client = NULL; if (this_client->first_context == NULL) { /* Client table entry created before manager was entered */ this_client->first_context = p_context; } else { (this_client->last_context)->next_in_client = p_context; } this_client->last_context = p_context; *result = error_status_ok; #ifdef PERFMON RPC_SS_ADD_TO_CALLEE_CLIENT_X; #endif return; } next_client = this_client->next_h_client; if (next_client == NULL) break; this_client = next_client; } /* Get here only if this is the first context for the client */ creating_at_home = (client_table[slot].client == NULL); if (creating_at_home) { /* The slot in the table is unoccupied */ new_client = &client_table[slot]; } else { new_client = (callee_client_entry_t *) malloc(sizeof(callee_client_entry_t)); if (new_client == NULL) { RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); DPRINT(("Released context tables\n")); DCETHREAD_RAISE( rpc_x_no_memory ); } this_client->next_h_client = new_client; new_client->prev_h_client = this_client; new_client->next_h_client = NULL; } new_client->client = ctx_client; new_client->rundown_pending = idl_false; RPC_SS_THREADS_CONDITION_CREATE(&(new_client->cond_var)); if (p_context == NULL) { /* New (locking) code. Client table entry created before manager entered */ new_client->count = 0; new_client->first_context = NULL; new_client->last_context = NULL; new_client->ref_count = 1; *p_is_new_client = ndr_false; } else { /* Old (non-locking) code. Client table entry created when non-null context marshalled after return from manager */ new_client->count = 1; new_client->first_context = p_context; new_client->last_context = p_context; new_client->ref_count = 0; p_context->p_client_entry = new_client; p_context->prev_in_client = NULL; p_context->next_in_client = NULL; *p_is_new_client = ndr_true; } *result = error_status_ok; #ifdef PERFMON RPC_SS_ADD_TO_CALLEE_CLIENT_X; #endif }