|  | @@ -39,38 +39,66 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  #include "src/core/iomgr/alarm_internal.h"
 | 
	
		
			
				|  |  |  #include "src/core/iomgr/iomgr_internal.h"
 | 
	
		
			
				|  |  | +#include "src/core/iomgr/iocp_windows.h"
 | 
	
		
			
				|  |  |  #include "src/core/iomgr/pollset.h"
 | 
	
		
			
				|  |  |  #include "src/core/iomgr/pollset_windows.h"
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void remove_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
 | 
	
		
			
				|  |  | -  worker->prev->next = worker->next;
 | 
	
		
			
				|  |  | -  worker->next->prev = worker->prev;
 | 
	
		
			
				|  |  | +static gpr_mu g_polling_mu;
 | 
	
		
			
				|  |  | +static grpc_pollset_worker *g_active_poller;
 | 
	
		
			
				|  |  | +static grpc_pollset_worker g_global_root_worker;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void grpc_pollset_global_init() {
 | 
	
		
			
				|  |  | +  gpr_mu_init(&g_polling_mu);
 | 
	
		
			
				|  |  | +  g_active_poller = NULL;
 | 
	
		
			
				|  |  | +  g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].next =
 | 
	
		
			
				|  |  | +    g_global_root_worker.links[GRPC_POLLSET_WORKER_LINK_GLOBAL].prev =
 | 
	
		
			
				|  |  | +    &g_global_root_worker;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +void grpc_pollset_global_shutdown() {
 | 
	
		
			
				|  |  | +  gpr_mu_destroy(&g_polling_mu);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static int has_workers(grpc_pollset *p) {
 | 
	
		
			
				|  |  | -  return p->root_worker.next != &p->root_worker;
 | 
	
		
			
				|  |  | +static void remove_worker(grpc_pollset_worker *worker, 
 | 
	
		
			
				|  |  | +                          grpc_pollset_worker_link_type type) {
 | 
	
		
			
				|  |  | +  worker->links[type].prev->links[type].next = worker->links[type].next;
 | 
	
		
			
				|  |  | +  worker->links[type].next->links[type].prev = worker->links[type].prev;
 | 
	
		
			
				|  |  | +  worker->links[type].next = worker->links[type].prev = worker;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static grpc_pollset_worker *pop_front_worker(grpc_pollset *p) {
 | 
	
		
			
				|  |  | -  if (has_workers(p)) {
 | 
	
		
			
				|  |  | -    grpc_pollset_worker *w = p->root_worker.next;
 | 
	
		
			
				|  |  | -    remove_worker(p, w);
 | 
	
		
			
				|  |  | +static int has_workers(grpc_pollset_worker *root, grpc_pollset_worker_link_type type) {
 | 
	
		
			
				|  |  | +  return root->links[type].next != root;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static grpc_pollset_worker *pop_front_worker(
 | 
	
		
			
				|  |  | +    grpc_pollset_worker *root, grpc_pollset_worker_link_type type) {
 | 
	
		
			
				|  |  | +  if (has_workers(root, type)) {
 | 
	
		
			
				|  |  | +    grpc_pollset_worker *w = root->links[type].next;
 | 
	
		
			
				|  |  | +    remove_worker(w, type);
 | 
	
		
			
				|  |  |      return w;
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      return NULL;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void push_back_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
 | 
	
		
			
				|  |  | -  worker->next = &p->root_worker;
 | 
	
		
			
				|  |  | -  worker->prev = worker->next->prev;
 | 
	
		
			
				|  |  | -  worker->prev->next = worker->next->prev = worker;
 | 
	
		
			
				|  |  | +static void push_back_worker(grpc_pollset_worker *root, 
 | 
	
		
			
				|  |  | +                             grpc_pollset_worker_link_type type, 
 | 
	
		
			
				|  |  | +                             grpc_pollset_worker *worker) {
 | 
	
		
			
				|  |  | +  worker->links[type].next = root;
 | 
	
		
			
				|  |  | +  worker->links[type].prev = worker->links[type].next->links[type].prev;
 | 
	
		
			
				|  |  | +  worker->links[type].prev->links[type].next = 
 | 
	
		
			
				|  |  | +    worker->links[type].next->links[type].prev = 
 | 
	
		
			
				|  |  | +    worker;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
 | 
	
		
			
				|  |  | -  worker->prev = &p->root_worker;
 | 
	
		
			
				|  |  | -  worker->next = worker->prev->next;
 | 
	
		
			
				|  |  | -  worker->prev->next = worker->next->prev = worker;
 | 
	
		
			
				|  |  | +static void push_front_worker(grpc_pollset_worker *root, 
 | 
	
		
			
				|  |  | +                              grpc_pollset_worker_link_type type, 
 | 
	
		
			
				|  |  | +                              grpc_pollset_worker *worker) {
 | 
	
		
			
				|  |  | +  worker->links[type].prev = root;
 | 
	
		
			
				|  |  | +  worker->links[type].next = worker->links[type].prev->links[type].next;
 | 
	
		
			
				|  |  | +  worker->links[type].prev->links[type].next = 
 | 
	
		
			
				|  |  | +    worker->links[type].next->links[type].prev = 
 | 
	
		
			
				|  |  | +    worker;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /* There isn't really any such thing as a pollset under Windows, due to the
 | 
	
	
		
			
				|  | @@ -81,8 +109,9 @@ static void push_front_worker(grpc_pollset *p, grpc_pollset_worker *worker) {
 | 
	
		
			
				|  |  |  void grpc_pollset_init(grpc_pollset *pollset) {
 | 
	
		
			
				|  |  |    memset(pollset, 0, sizeof(*pollset));
 | 
	
		
			
				|  |  |    gpr_mu_init(&pollset->mu);
 | 
	
		
			
				|  |  | -  pollset->root_worker.next = pollset->root_worker.prev = &pollset->root_worker;
 | 
	
		
			
				|  |  | -  pollset->kicked_without_pollers = 0;
 | 
	
		
			
				|  |  | +  pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = 
 | 
	
		
			
				|  |  | +    pollset->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = 
 | 
	
		
			
				|  |  | +    &pollset->root_worker;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
	
		
			
				|  | @@ -90,8 +119,12 @@ void grpc_pollset_shutdown(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |    gpr_mu_lock(&pollset->mu);
 | 
	
		
			
				|  |  |    pollset->shutting_down = 1;
 | 
	
		
			
				|  |  |    grpc_pollset_kick(pollset, GRPC_POLLSET_KICK_BROADCAST);
 | 
	
		
			
				|  |  | +  if (!pollset->is_iocp_worker) {
 | 
	
		
			
				|  |  | +    grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    pollset->on_shutdown = closure;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    gpr_mu_unlock(&pollset->mu);
 | 
	
		
			
				|  |  | -  grpc_exec_ctx_enqueue(exec_ctx, closure, 1);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_pollset_destroy(grpc_pollset *pollset) {
 | 
	
	
		
			
				|  | @@ -102,13 +135,42 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
 | 
	
		
			
				|  |  |                         grpc_pollset_worker *worker, gpr_timespec now,
 | 
	
		
			
				|  |  |                         gpr_timespec deadline) {
 | 
	
		
			
				|  |  |    int added_worker = 0;
 | 
	
		
			
				|  |  | -  worker->next = worker->prev = NULL;
 | 
	
		
			
				|  |  | +  worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next = 
 | 
	
		
			
				|  |  | +    worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].prev = 
 | 
	
		
			
				|  |  | +    NULL;
 | 
	
		
			
				|  |  |    gpr_cv_init(&worker->cv);
 | 
	
		
			
				|  |  |    if (grpc_alarm_check(exec_ctx, now, &deadline)) {
 | 
	
		
			
				|  |  |      goto done;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (!pollset->kicked_without_pollers && !pollset->shutting_down) {
 | 
	
		
			
				|  |  | -    push_front_worker(pollset, worker);
 | 
	
		
			
				|  |  | +    gpr_mu_lock(&g_polling_mu);
 | 
	
		
			
				|  |  | +    if (g_active_poller == NULL) {
 | 
	
		
			
				|  |  | +      grpc_pollset_worker *next_worker;
 | 
	
		
			
				|  |  | +      /* become poller */
 | 
	
		
			
				|  |  | +      pollset->is_iocp_worker = 1;
 | 
	
		
			
				|  |  | +      g_active_poller = worker;
 | 
	
		
			
				|  |  | +      gpr_mu_unlock(&g_polling_mu);
 | 
	
		
			
				|  |  | +      gpr_mu_unlock(&pollset->mu);
 | 
	
		
			
				|  |  | +      grpc_iocp_work(exec_ctx, deadline);
 | 
	
		
			
				|  |  | +      gpr_mu_lock(&pollset->mu);
 | 
	
		
			
				|  |  | +      gpr_mu_lock(&g_polling_mu);
 | 
	
		
			
				|  |  | +      pollset->is_iocp_worker = 0;
 | 
	
		
			
				|  |  | +      g_active_poller = NULL;
 | 
	
		
			
				|  |  | +      next_worker = pop_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL);
 | 
	
		
			
				|  |  | +      if (next_worker != NULL) {
 | 
	
		
			
				|  |  | +        gpr_cv_signal(&next_worker->cv);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      gpr_mu_unlock(&g_polling_mu);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (pollset->shutting_down && pollset->on_shutdown != NULL) {
 | 
	
		
			
				|  |  | +        grpc_exec_ctx_enqueue(exec_ctx, pollset->on_shutdown, 1);
 | 
	
		
			
				|  |  | +        pollset->on_shutdown = NULL;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      goto done;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    push_front_worker(&g_global_root_worker, GRPC_POLLSET_WORKER_LINK_GLOBAL, worker);
 | 
	
		
			
				|  |  | +    gpr_mu_unlock(&g_polling_mu);
 | 
	
		
			
				|  |  | +    push_front_worker(&pollset->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET, worker);
 | 
	
		
			
				|  |  |      added_worker = 1;
 | 
	
		
			
				|  |  |      gpr_cv_wait(&worker->cv, &pollset->mu, deadline);
 | 
	
		
			
				|  |  |    } else {
 | 
	
	
		
			
				|  | @@ -122,27 +184,40 @@ done:
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_cv_destroy(&worker->cv);
 | 
	
		
			
				|  |  |    if (added_worker) {
 | 
	
		
			
				|  |  | -    remove_worker(pollset, worker);
 | 
	
		
			
				|  |  | +    remove_worker(worker, GRPC_POLLSET_WORKER_LINK_GLOBAL);
 | 
	
		
			
				|  |  | +    remove_worker(worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void grpc_pollset_kick(grpc_pollset *p, grpc_pollset_worker *specific_worker) {
 | 
	
		
			
				|  |  |    if (specific_worker != NULL) {
 | 
	
		
			
				|  |  |      if (specific_worker == GRPC_POLLSET_KICK_BROADCAST) {
 | 
	
		
			
				|  |  | -      for (specific_worker = p->root_worker.next;
 | 
	
		
			
				|  |  | +      for (specific_worker = p->root_worker.links[GRPC_POLLSET_WORKER_LINK_POLLSET].next;
 | 
	
		
			
				|  |  |             specific_worker != &p->root_worker;
 | 
	
		
			
				|  |  | -           specific_worker = specific_worker->next) {
 | 
	
		
			
				|  |  | +           specific_worker = specific_worker->links[GRPC_POLLSET_WORKER_LINK_POLLSET].next) {
 | 
	
		
			
				|  |  |          gpr_cv_signal(&specific_worker->cv);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        p->kicked_without_pollers = 1;
 | 
	
		
			
				|  |  | +      if (p->is_iocp_worker) {
 | 
	
		
			
				|  |  | +        grpc_iocp_kick();
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -      gpr_cv_signal(&specific_worker->cv);
 | 
	
		
			
				|  |  | +      if (p->is_iocp_worker) {
 | 
	
		
			
				|  |  | +        gpr_mu_lock(&g_polling_mu);
 | 
	
		
			
				|  |  | +        if (g_active_poller == specific_worker) {
 | 
	
		
			
				|  |  | +          grpc_iocp_kick();
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        gpr_mu_unlock(&g_polling_mu);
 | 
	
		
			
				|  |  | +      } else {
 | 
	
		
			
				|  |  | +        gpr_cv_signal(&specific_worker->cv);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  | -    specific_worker = pop_front_worker(p);
 | 
	
		
			
				|  |  | +    specific_worker = pop_front_worker(&p->root_worker, GRPC_POLLSET_WORKER_LINK_POLLSET);
 | 
	
		
			
				|  |  |      if (specific_worker != NULL) {
 | 
	
		
			
				|  |  | -      push_back_worker(p, specific_worker);
 | 
	
		
			
				|  |  | -      gpr_cv_signal(&specific_worker->cv);
 | 
	
		
			
				|  |  | +      grpc_pollset_kick(p, specific_worker);
 | 
	
		
			
				|  |  | +    } else if (p->is_iocp_worker) {
 | 
	
		
			
				|  |  | +      grpc_iocp_kick();
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        p->kicked_without_pollers = 1;
 | 
	
		
			
				|  |  |      }
 |