|  | @@ -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;
 | 
	
	
		
			
				|  | @@ -183,6 +183,10 @@ typedef enum {
 | 
	
		
			
				|  |  |  struct call_data {
 | 
	
		
			
				|  |  |    grpc_call *call;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /** is this call counted towards the channels total
 | 
	
		
			
				|  |  | +      number of calls? */
 | 
	
		
			
				|  |  | +  gpr_uint8 active;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    call_state state;
 | 
	
		
			
				|  |  |    grpc_mdstr *path;
 | 
	
		
			
				|  |  |    grpc_mdstr *host;
 | 
	
	
		
			
				|  | @@ -280,15 +284,27 @@ 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;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  if (send_goaway) {
 | 
	
		
			
				|  |  | +    for (i = 0; i < cb->num_channels; i++) {
 | 
	
		
			
				|  |  | +      send_shutdown(cb->channels[i], 1, 0);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (force_disconnect) {
 | 
	
		
			
				|  |  | +    for (i = 0; i < cb->num_channels; i++) {
 | 
	
		
			
				|  |  | +      send_shutdown(cb->channels[i], 0, 1);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    for (i = 0; i < cb->num_disconnects; i++) {
 | 
	
		
			
				|  |  | +      send_shutdown(cb->disconnects[i], 0, 1);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    for (i = 0; i < cb->num_channels; i++) {
 | 
	
		
			
				|  |  | -    send_shutdown(cb->channels[i], 1, 0);
 | 
	
		
			
				|  |  |      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);
 | 
	
	
		
			
				|  | @@ -501,15 +517,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");
 | 
	
	
		
			
				|  | @@ -601,7 +608,8 @@ 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);
 | 
	
		
			
				|  |  | +      remove_res = calld->active;
 | 
	
		
			
				|  |  | +      calld->active = 0;
 | 
	
		
			
				|  |  |        gpr_mu_unlock(&chand->server->mu_call);
 | 
	
		
			
				|  |  |        gpr_mu_lock(&chand->server->mu_global);
 | 
	
		
			
				|  |  |        if (remove_res) {
 | 
	
	
		
			
				|  | @@ -676,13 +684,10 @@ static void init_call_elem(grpc_call_element *elem,
 | 
	
		
			
				|  |  |    memset(calld, 0, sizeof(call_data));
 | 
	
		
			
				|  |  |    calld->deadline = gpr_inf_future;
 | 
	
		
			
				|  |  |    calld->call = grpc_call_from_top_element(elem);
 | 
	
		
			
				|  |  | +  calld->active = 1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    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);
 | 
	
	
		
			
				|  | @@ -695,20 +700,31 @@ 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];
 | 
	
		
			
				|  |  | +  int disconnect = 0;
 | 
	
		
			
				|  |  | +  int active;
 | 
	
		
			
				|  |  |    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);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  active = calld->active;
 | 
	
		
			
				|  |  | +  calld->active = 0;
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&chand->server->mu_call);
 | 
	
		
			
				|  |  | -  if (removed[ALL_CALLS]) {
 | 
	
		
			
				|  |  | +  if (active) {
 | 
	
		
			
				|  |  |      gpr_mu_lock(&chand->server->mu_global);
 | 
	
		
			
				|  |  | -    decrement_call_count(chand);
 | 
	
		
			
				|  |  | +    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");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    if (calld->host) {
 | 
	
		
			
				|  |  |      grpc_mdstr_unref(calld->host);
 | 
	
		
			
				|  |  |    }
 | 
	
	
		
			
				|  | @@ -1049,47 +1065,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) {
 |