|  | @@ -54,6 +54,7 @@ static zend_object_handlers channel_ce_handlers;
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  |  static gpr_mu global_persistent_list_mu;
 | 
	
		
			
				|  |  |  int le_plink;
 | 
	
		
			
				|  |  | +extern HashTable grpc_persistent_list;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* Frees and destroys an instance of wrapped_grpc_channel */
 | 
	
		
			
				|  |  |  PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
 | 
	
	
		
			
				|  | @@ -68,17 +69,21 @@ PHP_GRPC_FREE_WRAPPED_FUNC_START(wrapped_grpc_channel)
 | 
	
		
			
				|  |  |          php_grpc_int key_len = strlen(p->wrapper->key);
 | 
	
		
			
				|  |  |          // only destroy the channel here if not found in the persistent list
 | 
	
		
			
				|  |  |          gpr_mu_lock(&global_persistent_list_mu);
 | 
	
		
			
				|  |  | -        if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&EG(persistent_list), p->wrapper->key,
 | 
	
		
			
				|  |  | +        if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&grpc_persistent_list, p->wrapper->key,
 | 
	
		
			
				|  |  |                                              key_len, rsrc))) {
 | 
	
		
			
				|  |  |            in_persistent_list = false;
 | 
	
		
			
				|  |  |            grpc_channel_destroy(p->wrapper->wrapped);
 | 
	
		
			
				|  |  |            free(p->wrapper->target);
 | 
	
		
			
				|  |  |            free(p->wrapper->args_hashstr);
 | 
	
		
			
				|  |  | -          if(p->wrapper->creds_hashstr != NULL){
 | 
	
		
			
				|  |  | +          if (p->wrapper->creds_hashstr != NULL) {
 | 
	
		
			
				|  |  |              free(p->wrapper->creds_hashstr);
 | 
	
		
			
				|  |  |              p->wrapper->creds_hashstr = NULL;
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |            free(p->wrapper->key);
 | 
	
		
			
				|  |  | +          p->wrapper->wrapped = NULL;
 | 
	
		
			
				|  |  | +          p->wrapper->target = NULL;
 | 
	
		
			
				|  |  | +          p->wrapper->args_hashstr = NULL;
 | 
	
		
			
				|  |  | +          p->wrapper->key = NULL;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          gpr_mu_unlock(&global_persistent_list_mu);
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -188,9 +193,10 @@ void create_and_add_channel_to_persistent_list(
 | 
	
		
			
				|  |  |    create_channel(channel, target, args, creds);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    le->channel = channel->wrapper;
 | 
	
		
			
				|  |  | +  le->ref_count = 1;
 | 
	
		
			
				|  |  |    new_rsrc.ptr = le;
 | 
	
		
			
				|  |  |    gpr_mu_lock(&global_persistent_list_mu);
 | 
	
		
			
				|  |  | -  PHP_GRPC_PERSISTENT_LIST_UPDATE(&EG(persistent_list), key, key_len,
 | 
	
		
			
				|  |  | +  PHP_GRPC_PERSISTENT_LIST_UPDATE(&grpc_persistent_list, key, key_len,
 | 
	
		
			
				|  |  |                                    (void *)&new_rsrc);
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&global_persistent_list_mu);
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -311,7 +317,7 @@ PHP_METHOD(Channel, __construct) {
 | 
	
		
			
				|  |  |      // object, there is no way we can tell them apart. Do NOT persist
 | 
	
		
			
				|  |  |      // them. They should be individually destroyed.
 | 
	
		
			
				|  |  |      create_channel(channel, target, args, creds);
 | 
	
		
			
				|  |  | -  } else if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&EG(persistent_list), key,
 | 
	
		
			
				|  |  | +  } else if (!(PHP_GRPC_PERSISTENT_LIST_FIND(&grpc_persistent_list, key,
 | 
	
		
			
				|  |  |                                               key_len, rsrc))) {
 | 
	
		
			
				|  |  |      create_and_add_channel_to_persistent_list(
 | 
	
		
			
				|  |  |          channel, target, args, creds, key, key_len TSRMLS_CC);
 | 
	
	
		
			
				|  | @@ -327,7 +333,7 @@ PHP_METHOD(Channel, __construct) {
 | 
	
		
			
				|  |  |            channel, target, args, creds, key, key_len TSRMLS_CC);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        efree(args.args);
 | 
	
		
			
				|  |  | -      if (channel->wrapper->creds_hashstr != NULL){
 | 
	
		
			
				|  |  | +      if (channel->wrapper->creds_hashstr != NULL) {
 | 
	
		
			
				|  |  |          free(channel->wrapper->creds_hashstr);
 | 
	
		
			
				|  |  |          channel->wrapper->creds_hashstr = NULL;
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -336,6 +342,7 @@ PHP_METHOD(Channel, __construct) {
 | 
	
		
			
				|  |  |        free(channel->wrapper->target);
 | 
	
		
			
				|  |  |        free(channel->wrapper->args_hashstr);
 | 
	
		
			
				|  |  |        free(channel->wrapper);
 | 
	
		
			
				|  |  | +      le->ref_count += 1;
 | 
	
		
			
				|  |  |        channel->wrapper = le->channel;
 | 
	
		
			
				|  |  |        channel->wrapper->ref_count += 1;
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -456,10 +463,10 @@ PHP_METHOD(Channel, close) {
 | 
	
		
			
				|  |  |          grpc_channel_destroy(channel->wrapper->wrapped);
 | 
	
		
			
				|  |  |          free(channel->wrapper->target);
 | 
	
		
			
				|  |  |          free(channel->wrapper->args_hashstr);
 | 
	
		
			
				|  |  | -        if(channel->wrapper->creds_hashstr != NULL){
 | 
	
		
			
				|  |  | -          free(channel->wrapper->creds_hashstr);
 | 
	
		
			
				|  |  | -          channel->wrapper->creds_hashstr = NULL;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | +        free(channel->wrapper->creds_hashstr);
 | 
	
		
			
				|  |  | +        channel->wrapper->creds_hashstr = NULL;
 | 
	
		
			
				|  |  | +        channel->wrapper->target = NULL;
 | 
	
		
			
				|  |  | +        channel->wrapper->args_hashstr = NULL;
 | 
	
		
			
				|  |  |          channel->wrapper->wrapped = NULL;
 | 
	
		
			
				|  |  |          channel->wrapper->is_valid = false;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -469,7 +476,7 @@ PHP_METHOD(Channel, close) {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      channel->wrapper->ref_count -= 1;
 | 
	
		
			
				|  |  | -    if(channel->wrapper->ref_count == 0){
 | 
	
		
			
				|  |  | +    if (channel->wrapper->ref_count == 0) {
 | 
	
		
			
				|  |  |        // Mark that the wrapper can be freed because mu should be
 | 
	
		
			
				|  |  |        // destroyed outside the lock.
 | 
	
		
			
				|  |  |        is_last_wrapper = true;
 | 
	
	
		
			
				|  | @@ -494,12 +501,12 @@ void php_grpc_delete_persistent_list_entry(char *key, php_grpc_int key_len
 | 
	
		
			
				|  |  |                                             TSRMLS_DC) {
 | 
	
		
			
				|  |  |    php_grpc_zend_resource *rsrc;
 | 
	
		
			
				|  |  |    gpr_mu_lock(&global_persistent_list_mu);
 | 
	
		
			
				|  |  | -  if (PHP_GRPC_PERSISTENT_LIST_FIND(&EG(persistent_list), key,
 | 
	
		
			
				|  |  | +  if (PHP_GRPC_PERSISTENT_LIST_FIND(&grpc_persistent_list, key,
 | 
	
		
			
				|  |  |                                      key_len, rsrc)) {
 | 
	
		
			
				|  |  |      channel_persistent_le_t *le;
 | 
	
		
			
				|  |  |      le = (channel_persistent_le_t *)rsrc->ptr;
 | 
	
		
			
				|  |  |      le->channel = NULL;
 | 
	
		
			
				|  |  | -    php_grpc_zend_hash_del(&EG(persistent_list), key, key_len+1);
 | 
	
		
			
				|  |  | +    php_grpc_zend_hash_del(&grpc_persistent_list, key, key_len+1);
 | 
	
		
			
				|  |  |      free(le);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&global_persistent_list_mu);
 | 
	
	
		
			
				|  | @@ -509,27 +516,71 @@ void php_grpc_delete_persistent_list_entry(char *key, php_grpc_int key_len
 | 
	
		
			
				|  |  |  static void php_grpc_channel_plink_dtor(php_grpc_zend_resource *rsrc
 | 
	
		
			
				|  |  |                                          TSRMLS_DC) {
 | 
	
		
			
				|  |  |    channel_persistent_le_t *le = (channel_persistent_le_t *)rsrc->ptr;
 | 
	
		
			
				|  |  | +  if (le == NULL) {
 | 
	
		
			
				|  |  | +    return;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    if (le->channel != NULL) {
 | 
	
		
			
				|  |  |      gpr_mu_lock(&le->channel->mu);
 | 
	
		
			
				|  |  |      if (le->channel->wrapped != NULL) {
 | 
	
		
			
				|  |  |        grpc_channel_destroy(le->channel->wrapped);
 | 
	
		
			
				|  |  | -      free(le->channel->target);
 | 
	
		
			
				|  |  |        free(le->channel->args_hashstr);
 | 
	
		
			
				|  |  |        le->channel->wrapped = NULL;
 | 
	
		
			
				|  |  |        le->channel->target = NULL;
 | 
	
		
			
				|  |  |        le->channel->args_hashstr = NULL;
 | 
	
		
			
				|  |  | +      free(le->channel->key);
 | 
	
		
			
				|  |  | +      le->channel->key = NULL;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    free(le->channel->key);
 | 
	
		
			
				|  |  | -    le->channel->key = NULL;
 | 
	
		
			
				|  |  |      gpr_mu_unlock(&le->channel->mu);
 | 
	
		
			
				|  |  | -    gpr_mu_destroy(&le->channel->mu);
 | 
	
		
			
				|  |  | -    free(le->channel);
 | 
	
		
			
				|  |  | -    le->channel = NULL;
 | 
	
		
			
				|  |  | -    free(le);
 | 
	
		
			
				|  |  | -    le = NULL;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Clean all channels in the persistent.
 | 
	
		
			
				|  |  | + * @return void
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +PHP_METHOD(Channel, cleanPersistentList) {
 | 
	
		
			
				|  |  | +  zend_hash_clean(&grpc_persistent_list);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * Return an array of persistent list.
 | 
	
		
			
				|  |  | + * @return array
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +PHP_METHOD(Channel, getPersistentList) {
 | 
	
		
			
				|  |  | +  array_init(return_value);
 | 
	
		
			
				|  |  | +  zval *data;
 | 
	
		
			
				|  |  | +  PHP_GRPC_HASH_FOREACH_VAL_START(&grpc_persistent_list, data)
 | 
	
		
			
				|  |  | +    php_grpc_zend_resource *rsrc  =
 | 
	
		
			
				|  |  | +                (php_grpc_zend_resource*) PHP_GRPC_HASH_VALPTR_TO_VAL(data)
 | 
	
		
			
				|  |  | +    if (rsrc == NULL) {
 | 
	
		
			
				|  |  | +      break;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    channel_persistent_le_t* le = rsrc->ptr;
 | 
	
		
			
				|  |  | +    zval* ret_arr;
 | 
	
		
			
				|  |  | +    PHP_GRPC_MAKE_STD_ZVAL(ret_arr);
 | 
	
		
			
				|  |  | +    array_init(ret_arr);
 | 
	
		
			
				|  |  | +    // Info about the target
 | 
	
		
			
				|  |  | +    PHP_GRPC_ADD_STRING_TO_ARRAY(ret_arr, "target",
 | 
	
		
			
				|  |  | +                sizeof("target"), le->channel->target, true);
 | 
	
		
			
				|  |  | +    // Info about key
 | 
	
		
			
				|  |  | +    PHP_GRPC_ADD_STRING_TO_ARRAY(ret_arr, "key",
 | 
	
		
			
				|  |  | +                sizeof("key"), le->channel->key, true);
 | 
	
		
			
				|  |  | +    // Info about persistent channel ref_count
 | 
	
		
			
				|  |  | +    PHP_GRPC_ADD_LONG_TO_ARRAY(ret_arr, "ref_count",
 | 
	
		
			
				|  |  | +                sizeof("ref_count"), le->ref_count);
 | 
	
		
			
				|  |  | +    // Info about connectivity status
 | 
	
		
			
				|  |  | +    int state =
 | 
	
		
			
				|  |  | +        grpc_channel_check_connectivity_state(le->channel->wrapped, (int)0);
 | 
	
		
			
				|  |  | +    // It should be set to 'true' in PHP 5.6.33
 | 
	
		
			
				|  |  | +    PHP_GRPC_ADD_LONG_TO_ARRAY(ret_arr, "connectivity_status",
 | 
	
		
			
				|  |  | +                sizeof("connectivity_status"), state);
 | 
	
		
			
				|  |  | +    // Info about the channel is closed or not
 | 
	
		
			
				|  |  | +    PHP_GRPC_ADD_BOOL_TO_ARRAY(ret_arr, "is_valid",
 | 
	
		
			
				|  |  | +                sizeof("is_valid"), le->channel->is_valid);
 | 
	
		
			
				|  |  | +    add_assoc_zval(return_value, le->channel->target, ret_arr);
 | 
	
		
			
				|  |  | +  PHP_GRPC_HASH_FOREACH_END()
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  ZEND_BEGIN_ARG_INFO_EX(arginfo_construct, 0, 0, 2)
 | 
	
		
			
				|  |  |    ZEND_ARG_INFO(0, target)
 | 
	
		
			
				|  |  |    ZEND_ARG_INFO(0, args)
 | 
	
	
		
			
				|  | @@ -550,6 +601,12 @@ ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  |  ZEND_BEGIN_ARG_INFO_EX(arginfo_close, 0, 0, 0)
 | 
	
		
			
				|  |  |  ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +ZEND_BEGIN_ARG_INFO_EX(arginfo_cleanPersistentList, 0, 0, 0)
 | 
	
		
			
				|  |  | +ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +ZEND_BEGIN_ARG_INFO_EX(arginfo_getPersistentList, 0, 0, 0)
 | 
	
		
			
				|  |  | +ZEND_END_ARG_INFO()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static zend_function_entry channel_methods[] = {
 | 
	
		
			
				|  |  |    PHP_ME(Channel, __construct, arginfo_construct,
 | 
	
		
			
				|  |  |           ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
 | 
	
	
		
			
				|  | @@ -561,6 +618,10 @@ static zend_function_entry channel_methods[] = {
 | 
	
		
			
				|  |  |           ZEND_ACC_PUBLIC)
 | 
	
		
			
				|  |  |    PHP_ME(Channel, close, arginfo_close,
 | 
	
		
			
				|  |  |           ZEND_ACC_PUBLIC)
 | 
	
		
			
				|  |  | +  PHP_ME(Channel, cleanPersistentList, arginfo_cleanPersistentList,
 | 
	
		
			
				|  |  | +         ZEND_ACC_PUBLIC)
 | 
	
		
			
				|  |  | +  PHP_ME(Channel, getPersistentList, arginfo_getPersistentList,
 | 
	
		
			
				|  |  | +         ZEND_ACC_PUBLIC)
 | 
	
		
			
				|  |  |    PHP_FE_END
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -572,6 +633,8 @@ GRPC_STARTUP_FUNCTION(channel) {
 | 
	
		
			
				|  |  |    gpr_mu_init(&global_persistent_list_mu);
 | 
	
		
			
				|  |  |    le_plink = zend_register_list_destructors_ex(
 | 
	
		
			
				|  |  |        NULL, php_grpc_channel_plink_dtor, "Persistent Channel", module_number);
 | 
	
		
			
				|  |  | +  zend_hash_init_ex(&grpc_persistent_list, 20, NULL,
 | 
	
		
			
				|  |  | +                    EG(persistent_list).pDestructor, 1, 0);
 | 
	
		
			
				|  |  |    PHP_GRPC_INIT_HANDLER(wrapped_grpc_channel, channel_ce_handlers);
 | 
	
		
			
				|  |  |    return SUCCESS;
 | 
	
		
			
				|  |  |  }
 |