|  | @@ -51,7 +51,7 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/string_util.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/useful.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -typedef enum { PENDING_START, ALL_CALLS, CALL_LIST_COUNT } call_list;
 | 
	
		
			
				|  |  | +typedef enum { PENDING_START, CALL_LIST_COUNT } call_list;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct listener {
 | 
	
		
			
				|  |  |    void *arg;
 | 
	
	
		
			
				|  | @@ -114,7 +114,6 @@ typedef struct channel_registered_method {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  struct channel_data {
 | 
	
		
			
				|  |  |    grpc_server *server;
 | 
	
		
			
				|  |  | -  size_t num_calls;
 | 
	
		
			
				|  |  |    grpc_connectivity_state connectivity_state;
 | 
	
		
			
				|  |  |    grpc_channel *channel;
 | 
	
		
			
				|  |  |    grpc_mdstr *path_key;
 | 
	
	
		
			
				|  | @@ -204,9 +203,7 @@ struct call_data {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct {
 | 
	
		
			
				|  |  |    grpc_channel **channels;
 | 
	
		
			
				|  |  | -  grpc_channel **disconnects;
 | 
	
		
			
				|  |  |    size_t num_channels;
 | 
	
		
			
				|  |  | -  size_t num_disconnects;
 | 
	
		
			
				|  |  |  } channel_broadcaster;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #define SERVER_FROM_CALL_ELEM(elem) \
 | 
	
	
		
			
				|  | @@ -225,26 +222,15 @@ static void maybe_finish_shutdown(grpc_server *server);
 | 
	
		
			
				|  |  |  static void channel_broadcaster_init(grpc_server *s, channel_broadcaster *cb) {
 | 
	
		
			
				|  |  |    channel_data *c;
 | 
	
		
			
				|  |  |    size_t count = 0;
 | 
	
		
			
				|  |  | -  size_t dc_count = 0;
 | 
	
		
			
				|  |  |    for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
 | 
	
		
			
				|  |  |      count++;
 | 
	
		
			
				|  |  | -    if (c->num_calls == 0) {
 | 
	
		
			
				|  |  | -      dc_count++;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    cb->num_channels = count;
 | 
	
		
			
				|  |  | -  cb->num_disconnects = dc_count;
 | 
	
		
			
				|  |  |    cb->channels = gpr_malloc(sizeof(*cb->channels) * cb->num_channels);
 | 
	
		
			
				|  |  | -  cb->disconnects = gpr_malloc(sizeof(*cb->channels) * cb->num_disconnects);
 | 
	
		
			
				|  |  |    count = 0;
 | 
	
		
			
				|  |  | -  dc_count = 0;
 | 
	
		
			
				|  |  |    for (c = s->root_channel_data.next; c != &s->root_channel_data; c = c->next) {
 | 
	
		
			
				|  |  |      cb->channels[count++] = c->channel;
 | 
	
		
			
				|  |  |      GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast");
 | 
	
		
			
				|  |  | -    if (c->num_calls == 0) {
 | 
	
		
			
				|  |  | -      cb->disconnects[dc_count++] = c->channel;
 | 
	
		
			
				|  |  | -      GRPC_CHANNEL_INTERNAL_REF(c->channel, "broadcast-disconnect");
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -280,19 +266,14 @@ static void send_shutdown(grpc_channel *channel, int send_goaway,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void channel_broadcaster_shutdown(channel_broadcaster *cb,
 | 
	
		
			
				|  |  | -                                         int send_goaway, int send_disconnect) {
 | 
	
		
			
				|  |  | +                                         int send_goaway, int force_disconnect) {
 | 
	
		
			
				|  |  |    size_t i;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    for (i = 0; i < cb->num_channels; i++) {
 | 
	
		
			
				|  |  | -    send_shutdown(cb->channels[i], 1, 0);
 | 
	
		
			
				|  |  | +    send_shutdown(cb->channels[i], send_goaway, force_disconnect);
 | 
	
		
			
				|  |  |      GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  for (i = 0; i < cb->num_disconnects; i++) {
 | 
	
		
			
				|  |  | -    send_shutdown(cb->disconnects[i], 0, 1);
 | 
	
		
			
				|  |  | -    GRPC_CHANNEL_INTERNAL_UNREF(cb->channels[i], "broadcast-disconnect");
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |    gpr_free(cb->channels);
 | 
	
		
			
				|  |  | -  gpr_free(cb->disconnects);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* call list */
 | 
	
	
		
			
				|  | @@ -501,15 +482,6 @@ static void maybe_finish_shutdown(grpc_server *server) {
 | 
	
		
			
				|  |  |      return;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&server->mu_call);
 | 
	
		
			
				|  |  | -  if (server->lists[ALL_CALLS] != NULL) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_DEBUG,
 | 
	
		
			
				|  |  | -            "Waiting for all calls to finish before destroying server");
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&server->mu_call);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&server->mu_call);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    if (server->root_channel_data.next != &server->root_channel_data) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_DEBUG,
 | 
	
		
			
				|  |  |              "Waiting for all channels to close before destroying server");
 | 
	
	
		
			
				|  | @@ -541,22 +513,10 @@ static grpc_mdelem *server_filter(void *user_data, grpc_mdelem *md) {
 | 
	
		
			
				|  |  |    return md;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static int decrement_call_count(channel_data *chand) {
 | 
	
		
			
				|  |  | -  int disconnect = 0;
 | 
	
		
			
				|  |  | -  chand->num_calls--;
 | 
	
		
			
				|  |  | -  if (0 == chand->num_calls && chand->server->shutdown) {
 | 
	
		
			
				|  |  | -    disconnect = 1;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  maybe_finish_shutdown(chand->server);
 | 
	
		
			
				|  |  | -  return disconnect;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  static void server_on_recv(void *ptr, int success) {
 | 
	
		
			
				|  |  |    grpc_call_element *elem = ptr;
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  |    channel_data *chand = elem->channel_data;
 | 
	
		
			
				|  |  | -  int remove_res;
 | 
	
		
			
				|  |  | -  int disconnect = 0;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (success && !calld->got_initial_metadata) {
 | 
	
		
			
				|  |  |      size_t i;
 | 
	
	
		
			
				|  | @@ -601,20 +561,7 @@ static void server_on_recv(void *ptr, int success) {
 | 
	
		
			
				|  |  |          grpc_iomgr_closure_init(&calld->kill_zombie_closure, kill_zombie, elem);
 | 
	
		
			
				|  |  |          grpc_iomgr_add_callback(&calld->kill_zombie_closure);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      remove_res = call_list_remove(calld, ALL_CALLS);
 | 
	
		
			
				|  |  |        gpr_mu_unlock(&chand->server->mu_call);
 | 
	
		
			
				|  |  | -      gpr_mu_lock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -      if (remove_res) {
 | 
	
		
			
				|  |  | -        disconnect = decrement_call_count(chand);
 | 
	
		
			
				|  |  | -        if (disconnect) {
 | 
	
		
			
				|  |  | -          GRPC_CHANNEL_INTERNAL_REF(chand->channel, "send-disconnect");
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      gpr_mu_unlock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -      if (disconnect) {
 | 
	
		
			
				|  |  | -        send_shutdown(chand->channel, 0, 1);
 | 
	
		
			
				|  |  | -        GRPC_CHANNEL_INTERNAL_UNREF(chand->channel, "send-disconnect");
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -679,14 +626,6 @@ static void init_call_elem(grpc_call_element *elem,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_iomgr_closure_init(&calld->server_on_recv, server_on_recv, elem);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&chand->server->mu_call);
 | 
	
		
			
				|  |  | -  call_list_join(&chand->server->lists[ALL_CALLS], calld, ALL_CALLS);
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&chand->server->mu_call);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -  chand->num_calls++;
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    server_ref(chand->server);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (initial_op) server_mutate_op(elem, initial_op);
 | 
	
	
		
			
				|  | @@ -695,19 +634,13 @@ static void init_call_elem(grpc_call_element *elem,
 | 
	
		
			
				|  |  |  static void destroy_call_elem(grpc_call_element *elem) {
 | 
	
		
			
				|  |  |    channel_data *chand = elem->channel_data;
 | 
	
		
			
				|  |  |    call_data *calld = elem->call_data;
 | 
	
		
			
				|  |  | -  int removed[CALL_LIST_COUNT];
 | 
	
		
			
				|  |  |    size_t i;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    gpr_mu_lock(&chand->server->mu_call);
 | 
	
		
			
				|  |  |    for (i = 0; i < CALL_LIST_COUNT; i++) {
 | 
	
		
			
				|  |  | -    removed[i] = call_list_remove(elem->call_data, i);
 | 
	
		
			
				|  |  | +    call_list_remove(elem->call_data, i);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&chand->server->mu_call);
 | 
	
		
			
				|  |  | -  if (removed[ALL_CALLS]) {
 | 
	
		
			
				|  |  | -    gpr_mu_lock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -    decrement_call_count(chand);
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    if (calld->host) {
 | 
	
		
			
				|  |  |      grpc_mdstr_unref(calld->host);
 | 
	
	
		
			
				|  | @@ -727,7 +660,6 @@ static void init_channel_elem(grpc_channel_element *elem, grpc_channel *master,
 | 
	
		
			
				|  |  |    GPR_ASSERT(is_first);
 | 
	
		
			
				|  |  |    GPR_ASSERT(!is_last);
 | 
	
		
			
				|  |  |    chand->server = NULL;
 | 
	
		
			
				|  |  | -  chand->num_calls = 0;
 | 
	
		
			
				|  |  |    chand->channel = NULL;
 | 
	
		
			
				|  |  |    chand->path_key = grpc_mdstr_from_string(metadata_context, ":path");
 | 
	
		
			
				|  |  |    chand->authority_key = grpc_mdstr_from_string(metadata_context, ":authority");
 | 
	
	
		
			
				|  | @@ -1049,47 +981,13 @@ void grpc_server_listener_destroy_done(void *s) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_server_cancel_all_calls(grpc_server *server) {
 | 
	
		
			
				|  |  | -  call_data *calld;
 | 
	
		
			
				|  |  | -  grpc_call **calls;
 | 
	
		
			
				|  |  | -  size_t call_count;
 | 
	
		
			
				|  |  | -  size_t call_capacity;
 | 
	
		
			
				|  |  | -  int is_first = 1;
 | 
	
		
			
				|  |  | -  size_t i;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  gpr_mu_lock(&server->mu_call);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  GPR_ASSERT(server->shutdown);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  if (!server->lists[ALL_CALLS]) {
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(&server->mu_call);
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  call_capacity = 8;
 | 
	
		
			
				|  |  | -  call_count = 0;
 | 
	
		
			
				|  |  | -  calls = gpr_malloc(sizeof(grpc_call *) * call_capacity);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  for (calld = server->lists[ALL_CALLS];
 | 
	
		
			
				|  |  | -       calld != server->lists[ALL_CALLS] || is_first;
 | 
	
		
			
				|  |  | -       calld = calld->links[ALL_CALLS].next) {
 | 
	
		
			
				|  |  | -    if (call_count == call_capacity) {
 | 
	
		
			
				|  |  | -      call_capacity *= 2;
 | 
	
		
			
				|  |  | -      calls = gpr_realloc(calls, sizeof(grpc_call *) * call_capacity);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    calls[call_count++] = calld->call;
 | 
	
		
			
				|  |  | -    GRPC_CALL_INTERNAL_REF(calld->call, "cancel_all");
 | 
	
		
			
				|  |  | -    is_first = 0;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  gpr_mu_unlock(&server->mu_call);
 | 
	
		
			
				|  |  | +  channel_broadcaster broadcaster;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  for (i = 0; i < call_count; i++) {
 | 
	
		
			
				|  |  | -    grpc_call_cancel_with_status(calls[i], GRPC_STATUS_UNAVAILABLE,
 | 
	
		
			
				|  |  | -                                 "Unavailable");
 | 
	
		
			
				|  |  | -    GRPC_CALL_INTERNAL_UNREF(calls[i], "cancel_all", 1);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  gpr_mu_lock(&server->mu_global);
 | 
	
		
			
				|  |  | +  channel_broadcaster_init(server, &broadcaster);
 | 
	
		
			
				|  |  | +  gpr_mu_unlock(&server->mu_global);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_free(calls);
 | 
	
		
			
				|  |  | +  channel_broadcaster_shutdown(&broadcaster, 0, 1);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_server_destroy(grpc_server *server) {
 |