1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** ctxeecli.c 82** 83** FACILITY: 84** 85** IDL Stub Runtime Support 86** 87** ABSTRACT: 88** 89** Maintain callee stub's table of clients 90** 91** 92*/ 93#if HAVE_CONFIG_H 94#include <config.h> 95#endif 96 97/* The ordering of the following 3 includes should NOT be changed! */ 98#include <dce/rpc.h> 99#include <dce/stubbase.h> 100#include <lsysdep.h> 101 102#include <ctxeertl.h> 103 104# include <stdio.h> 105 106#ifdef PERFMON 107#include <dce/idl_log.h> 108#endif 109 110#ifndef DEBUG_VERBOSE 111# define NDEBUG 112#endif 113#include <assert.h> 114 115#ifdef CTXEETEST 116# define DPRINT(ARGS) printf ARGS 117#else 118# define DPRINT(ARGS) /* ARGS */ 119#endif 120 121#include <rpcsvc.h> 122 123/* 124 * Data structure for element of list of rundown actions 125 */ 126typedef struct rpc_ss_rundown_list_elt { 127 ctx_rundown_fn_p_t rundown; /* Pointer to rundown routine for context */ 128 rpc_ss_context_t user_context; 129 struct rpc_ss_rundown_list_elt *next; 130} rpc_ss_rundown_list_elt; 131 132/* Number of client slots in hash table. 133*/ 134#define CALLEE_CLIENT_TABLE_SIZE 256 135 136/* Macro to hash client IDs. ID is actually a pointer to memory, 137** probably allocated by malloc and 16-byte aligned. 138*/ 139#define HASH_CLIENT_ID(ID) (((unsigned long)(ID) >> 4) % CALLEE_CLIENT_TABLE_SIZE) 140 141static callee_client_entry_t *client_table = NULL; 142 143/* Allocate callee client lookup table and initialize pointers to NULL. 144*/ 145void rpc_ss_init_callee_client_table( 146 void 147) 148{ 149#ifdef PERFMON 150 RPC_SS_INIT_CALLEE_CLNT_TABLE_N; 151#endif 152 153 assert(!client_table); /* Must not be called more than once. */ 154 155 client_table = (callee_client_entry_t *)malloc( 156 CALLEE_CLIENT_TABLE_SIZE * sizeof(callee_client_entry_t) 157 ); 158 159 if (!client_table) 160 DCETHREAD_RAISE(rpc_x_no_memory); 161 162 memset(client_table, 0, CALLEE_CLIENT_TABLE_SIZE * sizeof(callee_client_entry_t)); 163 164#ifdef PERFMON 165 RPC_SS_INIT_CALLEE_CLNT_TABLE_X; 166#endif 167 168} 169 170/******************************************************************************/ 171/* */ 172/* Add a context to the list being maintained for a client */ 173/* or create a client table entry for a client which it is expected */ 174/* a context will be created */ 175/* */ 176/* Assumes that the context table mutex is locked */ 177/* */ 178/******************************************************************************/ 179void rpc_ss_add_to_callee_client 180( 181 /* [in] */ rpc_client_handle_t ctx_client, 182 /* Client for whom there is or will be a context */ 183 /* [in] */ callee_context_entry_t *p_context, /* Pointer to the context, 184 NULL if we are creating a client table entry to which 185 we expect a context to be attached later */ 186 /* [out] */ndr_boolean *p_is_new_client, 187 /* TRUE => first context for client */ 188 error_status_t *result /* Function result */ 189) 190{ 191 int slot; /* Index of the slot in the lookup table the client 192 should be in */ 193 ndr_boolean creating_at_home; /* TRUE if new client being created in slot 194 in lookup table */ 195 callee_client_entry_t *this_client, *next_client, *new_client; 196 197#ifdef PERFMON 198 RPC_SS_ADD_TO_CALLEE_CLIENT_N; 199#endif 200 /* Now find which chain */ 201 slot = HASH_CLIENT_ID(ctx_client); 202 203 /* Look for the client in a chain based on the slot. 204 Note the following possibilities exist for the slot: 205 1) Unoccupied. No chain. 206 2) Occupied. No chain. 207 3) Occupied. Chain exists. 208 4) Unoccupied. Chain exists. 209 This is because once a client record is 210 created it is constrained by the presence of threads machinery 211 not to be moved */ 212 this_client = &client_table[slot]; 213 while (ndr_true) 214 { 215 if ( ctx_client == this_client->client ) 216 { 217 ++this_client->count; 218 *p_is_new_client = (this_client->count == 1); 219 /* Linkage of contexts within client */ 220 p_context->p_client_entry = this_client; 221 p_context->prev_in_client = this_client->last_context; 222 p_context->next_in_client = NULL; 223 if (this_client->first_context == NULL) 224 { 225 /* Client table entry created before manager was entered */ 226 this_client->first_context = p_context; 227 } 228 else 229 { 230 (this_client->last_context)->next_in_client = p_context; 231 } 232 this_client->last_context = p_context; 233 *result = error_status_ok; 234#ifdef PERFMON 235 RPC_SS_ADD_TO_CALLEE_CLIENT_X; 236#endif 237 return; 238 } 239 next_client = this_client->next_h_client; 240 if (next_client == NULL) break; 241 this_client = next_client; 242 } 243 244 /* Get here only if this is the first context for the client */ 245 creating_at_home = (client_table[slot].client == NULL); 246 if (creating_at_home) 247 { 248 /* The slot in the table is unoccupied */ 249 new_client = &client_table[slot]; 250 } 251 else 252 { 253 new_client = (callee_client_entry_t *) 254 malloc(sizeof(callee_client_entry_t)); 255 if (new_client == NULL) 256 { 257 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 258 DPRINT(("Released context tables\n")); 259 DCETHREAD_RAISE( rpc_x_no_memory ); 260 } 261 this_client->next_h_client = new_client; 262 new_client->prev_h_client = this_client; 263 new_client->next_h_client = NULL; 264 } 265 new_client->client = ctx_client; 266 new_client->rundown_pending = idl_false; 267 RPC_SS_THREADS_CONDITION_CREATE(&(new_client->cond_var)); 268 if (p_context == NULL) 269 { 270 /* New (locking) code. Client table entry created before manager 271 entered */ 272 new_client->count = 0; 273 new_client->first_context = NULL; 274 new_client->last_context = NULL; 275 new_client->ref_count = 1; 276 *p_is_new_client = ndr_false; 277 } 278 else 279 { 280 /* Old (non-locking) code. Client table entry created when non-null 281 context marshalled after return from manager */ 282 new_client->count = 1; 283 new_client->first_context = p_context; 284 new_client->last_context = p_context; 285 new_client->ref_count = 0; 286 p_context->p_client_entry = new_client; 287 p_context->prev_in_client = NULL; 288 p_context->next_in_client = NULL; 289 *p_is_new_client = ndr_true; 290 } 291 *result = error_status_ok; 292 293#ifdef PERFMON 294 RPC_SS_ADD_TO_CALLEE_CLIENT_X; 295#endif 296} 297 298/******************************************************************************/ 299/* */ 300/* Remove a client entry from the client hash table */ 301/* */ 302/* Assumes that the context table mutex is locked */ 303/* */ 304/******************************************************************************/ 305static void rpc_ss_ctx_remove_client_entry 306( 307 /* [in] */callee_client_entry_t *this_client 308) 309{ 310 callee_client_entry_t *next_client, *prev_client; 311 312 RPC_SS_THREADS_CONDITION_DELETE(&(this_client->cond_var)); 313 prev_client = this_client->prev_h_client; 314 next_client = this_client->next_h_client; 315 316 if (prev_client != NULL) 317 { 318 /* Not at head of chain, cut this client out */ 319 prev_client->next_h_client = next_client; 320 if (next_client != NULL) 321 { 322 next_client->prev_h_client = prev_client; 323 } 324 free((char_p_t)this_client); 325 } 326 else /* Head of chain */ 327 { 328 this_client->client = NULL; 329 /* Hash link fields left intact. Other fields will be initialized 330 next time a context is created in this slot */ 331 } 332} 333 334/******************************************************************************/ 335/* */ 336/* Remove a context from the list being maintained for a client */ 337/* */ 338/* Assumes that the context table mutex is locked */ 339/* */ 340/******************************************************************************/ 341void rpc_ss_take_from_callee_client 342( 343 /* [in] */ callee_context_entry_t *p_context, /* Pointer to the context */ 344 /* [out] */ rpc_client_handle_t *p_close_client, 345 /* Ptr to NULL or client to stop monitoring */ 346 /* [out] */ error_status_t *result /* Function result */ 347) 348{ 349 callee_client_entry_t *this_client; 350 351#ifdef PERFMON 352 RPC_SS_TAKE_FROM_CALLEE_CLNT_N; 353#endif 354 355 *result = error_status_ok; 356 *p_close_client = NULL; 357 this_client = p_context->p_client_entry; 358 --this_client->count; 359 if ( (this_client->count != 0) || (this_client->rundown_pending) ) 360 { 361 /* We will not be destroying the client entry */ 362 /* Remove this context from the chain */ 363 if (this_client->first_context == p_context) 364 { 365 /* Context to be removed is first in client chain */ 366 this_client->first_context = p_context->next_in_client; 367 } 368 else 369 { 370 (p_context->prev_in_client)->next_in_client 371 = p_context->next_in_client; 372 } 373 if (this_client->last_context == p_context) 374 { 375 /* Context to be removed is last in client chain */ 376 this_client->last_context = p_context->prev_in_client; 377 } 378 else 379 { 380 (p_context->next_in_client)->prev_in_client 381 = p_context->prev_in_client; 382 } 383 if (this_client->count != 0) 384 { 385#ifdef PERFMON 386 RPC_SS_TAKE_FROM_CALLEE_CLNT_X; 387#endif 388 return; 389 } 390 } 391 392 /* Was last context for client */ 393 *p_close_client = this_client->client; 394 if ( ! this_client->rundown_pending ) 395 { 396 rpc_ss_ctx_remove_client_entry(this_client); 397 } 398 399#ifdef PERFMON 400 RPC_SS_TAKE_FROM_CALLEE_CLNT_X; 401#endif 402 403} 404 405/******************************************************************************/ 406/* */ 407/* Run down all the contexts a client owns */ 408/* */ 409/******************************************************************************/ 410void rpc_ss_rundown_client 411( 412 /* [in] */ rpc_client_handle_t failed_client 413) 414{ 415 error_status_t result; 416 callee_client_entry_t *this_client; 417 callee_context_entry_t *this_context; 418 rpc_client_handle_t close_client = NULL; 419 /* NULL or client to stop monitoring */ 420 /* FIXME: is the volatility set correctly here? */ 421 rpc_ss_rundown_list_elt * volatile rundown_list; 422 rpc_ss_rundown_list_elt * volatile rundown_elt; 423 424 rundown_list = NULL; 425 426#ifdef PERFMON 427 RPC_SS_RUNDOWN_CLIENT_N; 428#endif 429 430 RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); 431 DPRINT(("Seized context tables\n")); 432 for( this_client = &client_table[HASH_CLIENT_ID(failed_client)]; 433 (this_client != NULL) && (close_client == NULL); 434 this_client = this_client->next_h_client ) 435 { 436 if (this_client->client == failed_client) 437 { 438 while (this_client->ref_count != 0) 439 { 440 this_client->rundown_pending = idl_true; 441 RPC_SS_THREADS_CONDITION_WAIT(&this_client->cond_var, 442 &rpc_ss_context_table_mutex); 443 /* Mutex has been released */ 444 RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); 445 } 446 if (this_client->count == 0) 447 { 448 /* The manager closed the contexts while a rundown was 449 pending */ 450 rpc_ss_ctx_remove_client_entry(this_client); 451 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 452 DPRINT(("Released context tables\n")); 453#ifdef PERFMON 454 RPC_SS_RUNDOWN_CLIENT_X; 455#endif 456 return; 457 } 458 /* Need to clear the rundown pending flag so that the client 459 entry can be deleted */ 460 this_client->rundown_pending = idl_false; 461 while (close_client == NULL) 462 { 463 /* Loop until all contexts for this client have been removed 464 from the context table. Note that each iteration brings 465 a different context to first_context position */ 466 this_context = this_client->first_context; 467 rundown_elt = (rpc_ss_rundown_list_elt *) 468 malloc(sizeof(rpc_ss_rundown_list_elt)); 469 if (rundown_elt == NULL) 470 { 471 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 472 DPRINT(("Released context tables\n")); 473 /* 474 * rpc_m_ctxrundown_nomem 475 * "Out of memory while trying to run down contexts of client %x" 476 */ 477#if 0 478 rpc_dce_svc_printf ( 479 __FILE__, __LINE__, 480 "%x", 481 rpc_svc_libidl, 482 svc_c_sev_error, 483 rpc_m_ctxrundown_nomem, 484 this_client ); 485#endif 486 return; 487 } 488 rundown_elt->rundown = this_context->rundown; 489 rundown_elt->user_context = this_context->user_context; 490 rundown_elt->next = rundown_list; 491 rundown_list = rundown_elt; 492 rpc_ss_lkddest_callee_context 493 (&this_context->uuid,&close_client,&result); 494 } 495 } 496 } 497 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 498 DPRINT(("Released context tables\n")); 499 while (rundown_list != NULL) 500 { 501 if (rundown_list->rundown != NULL) 502 { 503 DCETHREAD_TRY 504 (*(rundown_list->rundown))(rundown_list->user_context); 505 DCETHREAD_CATCH_ALL(caught) 506 /* 507 * rpc_m_ctxrundown_exc 508 * "Exception in routine at %x, running down context %x of client %x" 509 */ 510#if 0 511 rpc_dce_svc_printf ( 512 __FILE__, __LINE__, 513 %x %x %x", 514 rpc_svc_libidl, 515 svc_c_sev_error, 516 rpc_m_ctxrundown_exc, 517 rundown_list->rundown, 518 rundown_list->user_context, 519 this_client ); 520#endif 521 DCETHREAD_ENDTRY 522 } 523 rundown_elt = rundown_list; 524 rundown_list = rundown_list->next; 525 free(rundown_elt); 526 } 527 528#ifdef PERFMON 529 RPC_SS_RUNDOWN_CLIENT_X; 530#endif 531 532 return; 533} 534 535/******************************************************************************/ 536/* */ 537/* Increment the count of managers currently using contexts of a client */ 538/* */ 539/* ENTRY POINT INTO LIBIDL FROM STUB */ 540/* */ 541/******************************************************************************/ 542void rpc_ss_ctx_client_ref_count_inc 543( 544 handle_t h, 545 error_status_t *p_st 546) 547{ 548 rpc_client_handle_t client_id; /* ID of client */ 549 callee_client_entry_t *this_client; 550 ndr_boolean is_new_client; /* Dummy procedure parameter */ 551 552 /* This could be the first access to the context tables */ 553 RPC_SS_INIT_CONTEXT 554 555 rpc_binding_inq_client(h, &client_id, p_st); 556 if (*p_st != error_status_ok) 557 return; 558 RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); 559 this_client = &client_table[HASH_CLIENT_ID(client_id)]; 560 while (this_client != NULL) 561 { 562 if (this_client->client == client_id) 563 { 564 (this_client->ref_count)++; 565 break; 566 } 567 this_client = this_client->next_h_client; 568 } 569 if (this_client == NULL) 570 { 571 /* Client does not yet have any active contexts. 572 Current manager is expected to create one */ 573 rpc_ss_add_to_callee_client(client_id, NULL, &is_new_client, p_st); 574 } 575 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 576} 577 578/******************************************************************************/ 579/* */ 580/* Decrement the count of managers currently using contexts of a client */ 581/* */ 582/* ENTRY POINT INTO LIBIDL FROM STUB */ 583/* */ 584/******************************************************************************/ 585void rpc_ss_ctx_client_ref_count_dec 586( 587 handle_t h, 588 error_status_t *p_st 589) 590{ 591 rpc_client_handle_t client_id; /* ID of client */ 592 callee_client_entry_t *this_client; 593 594 rpc_binding_inq_client(h, &client_id, p_st); 595 if (*p_st != error_status_ok) 596 return; 597 RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); 598 this_client = &client_table[HASH_CLIENT_ID(client_id)]; 599 while (this_client != NULL) 600 { 601 if (this_client->client == client_id) 602 { 603 (this_client->ref_count)--; 604 if (this_client->rundown_pending) 605 { 606 RPC_SS_THREADS_CONDITION_SIGNAL(&this_client->cond_var); 607 } 608 else if ((this_client->count == 0) && (this_client->ref_count == 0)) 609 { 610 /* This thread expected to create a context for the client, 611 but didn't */ 612 rpc_ss_ctx_remove_client_entry(this_client); 613 } 614 break; 615 } 616 this_client = this_client->next_h_client; 617 } 618 /* Can reach here with this_client == NULL if last context of client 619 was destroyed by manager */ 620 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 621} 622 623/* 624 * OT_8069 - context reference counts incorrectly maintained 625 * Duplicate routines so existing stubs still work 626 */ 627 628/******************************************************************************/ 629/* */ 630/* Increment the count of managers currently using contexts of a client */ 631/* */ 632/* ENTRY POINT INTO LIBIDL FROM STUB */ 633/* */ 634/******************************************************************************/ 635void rpc_ss_ctx_client_ref_count_i_2 636( 637 handle_t h, 638 rpc_client_handle_t *p_client_id, /* [out] ID of client, or NULL */ 639 error_status_t *p_st 640) 641{ 642 rpc_client_handle_t client_id; /* ID of client */ 643 callee_client_entry_t *this_client; 644 ndr_boolean is_new_client; /* Dummy procedure parameter */ 645 646 /* This could be the first access to the context tables */ 647 RPC_SS_INIT_CONTEXT 648 649 rpc_binding_inq_client(h, p_client_id, p_st); 650 if (*p_st != error_status_ok) 651 { 652 *p_client_id = NULL; 653 return; 654 } 655 client_id = *p_client_id; 656 RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); 657 this_client = &client_table[HASH_CLIENT_ID(client_id)]; 658 while (this_client != NULL) 659 { 660 if (this_client->client == client_id) 661 { 662 (this_client->ref_count)++; 663 break; 664 } 665 this_client = this_client->next_h_client; 666 } 667 if (this_client == NULL) 668 { 669 /* Client does not yet have any active contexts. 670 Current manager is expected to create one */ 671 rpc_ss_add_to_callee_client(client_id, NULL, &is_new_client, p_st); 672 } 673 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 674} 675 676/******************************************************************************/ 677/* */ 678/* Decrement the count of managers currently using contexts of a client */ 679/* */ 680/* ENTRY POINT INTO LIBIDL FROM STUB */ 681/* */ 682/******************************************************************************/ 683void rpc_ss_ctx_client_ref_count_d_2 684( 685 handle_t h ATTRIBUTE_UNUSED, 686 rpc_client_handle_t client_id /* [in] ID of client, or NULL */ 687) 688{ 689 callee_client_entry_t *this_client; 690 691 if (client_id == NULL) 692 return; 693 RPC_SS_THREADS_MUTEX_LOCK(&rpc_ss_context_table_mutex); 694 this_client = &client_table[HASH_CLIENT_ID(client_id)]; 695 while (this_client != NULL) 696 { 697 if (this_client->client == client_id) 698 { 699 (this_client->ref_count)--; 700 if (this_client->rundown_pending) 701 { 702 RPC_SS_THREADS_CONDITION_SIGNAL(&this_client->cond_var); 703 } 704 else if ((this_client->count == 0) && (this_client->ref_count == 0)) 705 { 706 /* This thread expected to create a context for the client, 707 but didn't */ 708 rpc_ss_ctx_remove_client_entry(this_client); 709 } 710 break; 711 } 712 this_client = this_client->next_h_client; 713 } 714 /* Can reach here with this_client == NULL if last context of client 715 was destroyed by manager */ 716 RPC_SS_THREADS_MUTEX_UNLOCK(&rpc_ss_context_table_mutex); 717} 718 719#ifdef CTXEETEST 720void show_client_context_chain 721( 722 callee_client_entry_t *p_client_entry 723) 724{ 725 callee_context_entry_t *this_context; 726 727 this_context = p_client_entry->first_context; 728 printf("\t\tForward context chain\n"); 729 while (this_context != NULL) 730 { 731 printf("\t\t\t %s %lx\n", 732 &this_context->uuid, 733 this_context->user_context); 734 this_context = this_context->next_in_client; 735 } 736 737 this_context = p_client_entry->last_context; 738 printf("\t\tBackward context chain\n"); 739 while (this_context != NULL) 740 { 741 printf("\t\t\t %s %lx\n", 742 &this_context->uuid, 743 this_context->user_context); 744 this_context = this_context->prev_in_client; 745 } 746 747} 748 749void dump_client_table( 750 void 751) 752{ 753 int i; 754 callee_client_entry_t *this_client; 755 756 for (i=0; i<CALLEE_CLIENT_TABLE_SIZE; i++) 757 { 758 if ( (client_table[i].client != NULL) 759 || (client_table[i].next_h_client != NULL) ) 760 { 761 printf("Forward client chain for client slot %d\n",i); 762 this_client = &client_table[i]; 763 while (ndr_true) 764 { 765 if (this_client->client != NULL) 766 { 767 printf("\t %lx %d\n",this_client->client,this_client->count); 768 show_client_context_chain(this_client); 769 } 770 if (this_client->next_h_client == NULL) break; 771 this_client = this_client->next_h_client; 772 } 773 printf("Backward chain to same slot\n"); 774 while (ndr_true) 775 { 776 if (this_client->client != NULL) 777 { 778 printf("\t %lx %d\n",this_client->client,this_client->count); 779 show_client_context_chain(this_client); 780 } 781 if (this_client->prev_h_client == NULL) break; 782 this_client = this_client->prev_h_client; 783 } 784 } 785 } 786} 787#endif 788