diff --git a/src/core/iomgr/pollset.h b/src/core/iomgr/pollset.h
index 7472b6144fbbfb4cacbe1bca2fd34d207689c174..c40188b3c9e56b26fbca77181d527d29b2834122 100644
--- a/src/core/iomgr/pollset.h
+++ b/src/core/iomgr/pollset.h
@@ -62,7 +62,10 @@ void grpc_pollset_destroy(grpc_pollset *pollset);
    May involve invoking asynchronous callbacks, or actually polling file
    descriptors.
    Requires GRPC_POLLSET_MU(pollset) locked.
-   May unlock GRPC_POLLSET_MU(pollset) during its execution. */
+   May unlock GRPC_POLLSET_MU(pollset) during its execution.
+   
+   Returns true if some work has been done, and false if the deadline
+   got attained. */
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline);
 
 /* Break one polling thread out of polling work for this pollset.
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index 9deb0fa8faa845702924690aa2063420b09ff72d..d0507af9602287a26571454591582f9fa8adb66a 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -46,7 +46,10 @@
    set of features for the sake of the rest of grpc. But grpc_pollset_work
    won't actually do any polling, and return as quickly as possible. */
 
-void grpc_pollset_init(grpc_pollset *pollset) { gpr_mu_init(&pollset->mu); }
+void grpc_pollset_init(grpc_pollset *pollset) {
+  gpr_mu_init(&pollset->mu);
+  gpr_cv_init(&pollset->cv);
+}
 
 void grpc_pollset_shutdown(grpc_pollset *pollset,
                            void (*shutdown_done)(void *arg),
@@ -56,6 +59,7 @@ void grpc_pollset_shutdown(grpc_pollset *pollset,
 
 void grpc_pollset_destroy(grpc_pollset *pollset) {
   gpr_mu_destroy(&pollset->mu);
+  gpr_cv_destroy(&pollset->cv);
 }
 
 int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
@@ -70,9 +74,12 @@ int grpc_pollset_work(grpc_pollset *pollset, gpr_timespec deadline) {
   if (grpc_alarm_check(NULL, now, &deadline)) {
     return 1 /* GPR_TRUE */;
   }
-  return 0 /* GPR_FALSE */;
+  gpr_cv_wait(&pollset->cv, &pollset->mu, deadline);
+  return 1 /* GPR_TRUE */;
 }
 
-void grpc_pollset_kick(grpc_pollset *p) {}
+void grpc_pollset_kick(grpc_pollset *p) {
+  gpr_cv_signal(&p->cv);
+}
 
 #endif /* GPR_WINSOCK_SOCKET */
diff --git a/src/core/iomgr/pollset_windows.h b/src/core/iomgr/pollset_windows.h
index cbbd9efdd130631ec5c741763e3552f6e923914d..b4aec1b80983f79a44d7abf9180aebb3100ffdc7 100644
--- a/src/core/iomgr/pollset_windows.h
+++ b/src/core/iomgr/pollset_windows.h
@@ -41,10 +41,12 @@
 
 /* There isn't really any such thing as a pollset under Windows, due to the
    nature of the IO completion ports. A Windows "pollset" is merely a mutex
-   and a condition variable, as this is the minimal set of features we need
-   implemented for the rest of grpc. But we won't use them directly. */
+   and a condition variable, used to synchronize with the IOCP. */
 
-typedef struct grpc_pollset { gpr_mu mu; } grpc_pollset;
+typedef struct grpc_pollset {
+  gpr_mu mu;
+  gpr_cv cv;
+} grpc_pollset;
 
 #define GRPC_POLLSET_MU(pollset) (&(pollset)->mu)