From ccdea1900fdad3d507617c8b1b639c7f5914d06b Mon Sep 17 00:00:00 2001
From: Craig Tiller <ctiller@google.com>
Date: Tue, 16 Feb 2016 08:06:46 -0800
Subject: [PATCH] Separate timer checking from pollsets

---
 BUILD                                         |  3 -
 build.yaml                                    |  1 -
 gRPC.podspec                                  |  2 -
 grpc.gemspec                                  |  1 -
 package.json                                  |  1 -
 src/core/iomgr/iocp_windows.c                 |  2 +-
 src/core/iomgr/iomgr.c                        |  2 +-
 src/core/iomgr/pollset_posix.c                | 11 ----
 src/core/iomgr/pollset_windows.c              |  4 --
 src/core/iomgr/timer.c                        |  1 -
 src/core/iomgr/timer.h                        | 20 ++++++
 src/core/iomgr/timer_internal.h               | 61 -------------------
 src/core/surface/completion_queue.c           | 28 ++++++++-
 test/core/iomgr/timer_list_test.c             |  1 -
 tools/doxygen/Doxyfile.core.internal          |  1 -
 tools/run_tests/sources_and_headers.json      |  4 --
 vsprojects/vcxproj/grpc/grpc.vcxproj          |  1 -
 vsprojects/vcxproj/grpc/grpc.vcxproj.filters  |  3 -
 .../grpc_unsecure/grpc_unsecure.vcxproj       |  1 -
 .../grpc_unsecure.vcxproj.filters             |  3 -
 20 files changed, 48 insertions(+), 103 deletions(-)
 delete mode 100644 src/core/iomgr/timer_internal.h

diff --git a/BUILD b/BUILD
index 72d5caa8d4..24e3e54066 100644
--- a/BUILD
+++ b/BUILD
@@ -231,7 +231,6 @@ cc_library(
     "src/core/iomgr/time_averaged_stats.h",
     "src/core/iomgr/timer.h",
     "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/timer_internal.h",
     "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
@@ -533,7 +532,6 @@ cc_library(
     "src/core/iomgr/time_averaged_stats.h",
     "src/core/iomgr/timer.h",
     "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/timer_internal.h",
     "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
@@ -1490,7 +1488,6 @@ objc_library(
     "src/core/iomgr/time_averaged_stats.h",
     "src/core/iomgr/timer.h",
     "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/timer_internal.h",
     "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
diff --git a/build.yaml b/build.yaml
index 7f33ef3f0e..f8fc488383 100644
--- a/build.yaml
+++ b/build.yaml
@@ -307,7 +307,6 @@ filegroups:
   - src/core/iomgr/time_averaged_stats.h
   - src/core/iomgr/timer.h
   - src/core/iomgr/timer_heap.h
-  - src/core/iomgr/timer_internal.h
   - src/core/iomgr/udp_server.h
   - src/core/iomgr/wakeup_fd_pipe.h
   - src/core/iomgr/wakeup_fd_posix.h
diff --git a/gRPC.podspec b/gRPC.podspec
index 5b4d24e482..13c303a8c7 100644
--- a/gRPC.podspec
+++ b/gRPC.podspec
@@ -235,7 +235,6 @@ Pod::Spec.new do |s|
                       'src/core/iomgr/time_averaged_stats.h',
                       'src/core/iomgr/timer.h',
                       'src/core/iomgr/timer_heap.h',
-                      'src/core/iomgr/timer_internal.h',
                       'src/core/iomgr/udp_server.h',
                       'src/core/iomgr/wakeup_fd_pipe.h',
                       'src/core/iomgr/wakeup_fd_posix.h',
@@ -541,7 +540,6 @@ Pod::Spec.new do |s|
                               'src/core/iomgr/time_averaged_stats.h',
                               'src/core/iomgr/timer.h',
                               'src/core/iomgr/timer_heap.h',
-                              'src/core/iomgr/timer_internal.h',
                               'src/core/iomgr/udp_server.h',
                               'src/core/iomgr/wakeup_fd_pipe.h',
                               'src/core/iomgr/wakeup_fd_posix.h',
diff --git a/grpc.gemspec b/grpc.gemspec
index 32fe4932a9..4485b440d6 100755
--- a/grpc.gemspec
+++ b/grpc.gemspec
@@ -231,7 +231,6 @@ Gem::Specification.new do |s|
   s.files += %w( src/core/iomgr/time_averaged_stats.h )
   s.files += %w( src/core/iomgr/timer.h )
   s.files += %w( src/core/iomgr/timer_heap.h )
-  s.files += %w( src/core/iomgr/timer_internal.h )
   s.files += %w( src/core/iomgr/udp_server.h )
   s.files += %w( src/core/iomgr/wakeup_fd_pipe.h )
   s.files += %w( src/core/iomgr/wakeup_fd_posix.h )
diff --git a/package.json b/package.json
index 8cbfb29055..3042c91680 100644
--- a/package.json
+++ b/package.json
@@ -176,7 +176,6 @@
     "src/core/iomgr/time_averaged_stats.h",
     "src/core/iomgr/timer.h",
     "src/core/iomgr/timer_heap.h",
-    "src/core/iomgr/timer_internal.h",
     "src/core/iomgr/udp_server.h",
     "src/core/iomgr/wakeup_fd_pipe.h",
     "src/core/iomgr/wakeup_fd_posix.h",
diff --git a/src/core/iomgr/iocp_windows.c b/src/core/iomgr/iocp_windows.c
index 759340e00e..807729708e 100644
--- a/src/core/iomgr/iocp_windows.c
+++ b/src/core/iomgr/iocp_windows.c
@@ -42,7 +42,7 @@
 #include <grpc/support/alloc.h>
 #include <grpc/support/thd.h>
 
-#include "src/core/iomgr/timer_internal.h"
+#include "src/core/iomgr/timer.h"
 #include "src/core/iomgr/iocp_windows.h"
 #include "src/core/iomgr/iomgr_internal.h"
 #include "src/core/iomgr/socket_windows.h"
diff --git a/src/core/iomgr/iomgr.c b/src/core/iomgr/iomgr.c
index 212ce5534d..3283b586b0 100644
--- a/src/core/iomgr/iomgr.c
+++ b/src/core/iomgr/iomgr.c
@@ -43,7 +43,7 @@
 #include <grpc/support/thd.h>
 
 #include "src/core/iomgr/iomgr_internal.h"
-#include "src/core/iomgr/timer_internal.h"
+#include "src/core/iomgr/timer.h"
 #include "src/core/support/string.h"
 
 static gpr_mu g_mu;
diff --git a/src/core/iomgr/pollset_posix.c b/src/core/iomgr/pollset_posix.c
index 19ee6650f0..1063727248 100644
--- a/src/core/iomgr/pollset_posix.c
+++ b/src/core/iomgr/pollset_posix.c
@@ -42,7 +42,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include "src/core/iomgr/timer_internal.h"
 #include "src/core/iomgr/fd_posix.h"
 #include "src/core/iomgr/iomgr_internal.h"
 #include "src/core/iomgr/socket_utils_posix.h"
@@ -274,16 +273,6 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
     grpc_exec_ctx_enqueue_list(exec_ctx, &pollset->idle_jobs, NULL);
     goto done;
   }
-  /* Check alarms - these are a global resource so we just ping
-     each time through on every pollset.
-     May update deadline to ensure timely wakeups.
-     TODO(ctiller): can this work be localized? */
-  if (grpc_timer_check(exec_ctx, now, &deadline)) {
-    GPR_TIMER_MARK("grpc_pollset_work.alarm_triggered", 0);
-    gpr_mu_unlock(&pollset->mu);
-    locked = 0;
-    goto done;
-  }
   /* If we're shutting down then we don't execute any extended work */
   if (pollset->shutting_down) {
     GPR_TIMER_MARK("grpc_pollset_work.shutting_down", 0);
diff --git a/src/core/iomgr/pollset_windows.c b/src/core/iomgr/pollset_windows.c
index 02c6678363..35a956b27f 100644
--- a/src/core/iomgr/pollset_windows.c
+++ b/src/core/iomgr/pollset_windows.c
@@ -38,7 +38,6 @@
 #include <grpc/support/log.h>
 #include <grpc/support/thd.h>
 
-#include "src/core/iomgr/timer_internal.h"
 #include "src/core/iomgr/iomgr_internal.h"
 #include "src/core/iomgr/iocp_windows.h"
 #include "src/core/iomgr/pollset.h"
@@ -136,9 +135,6 @@ void grpc_pollset_work(grpc_exec_ctx *exec_ctx, grpc_pollset *pollset,
   worker->kicked = 0;
   worker->pollset = pollset;
   gpr_cv_init(&worker->cv);
-  if (grpc_timer_check(exec_ctx, now, &deadline)) {
-    goto done;
-  }
   if (!pollset->kicked_without_pollers && !pollset->shutting_down) {
     if (g_active_poller == NULL) {
       grpc_pollset_worker *next_worker;
diff --git a/src/core/iomgr/timer.c b/src/core/iomgr/timer.c
index a33d8f63a0..5e7fadb790 100644
--- a/src/core/iomgr/timer.c
+++ b/src/core/iomgr/timer.c
@@ -34,7 +34,6 @@
 #include "src/core/iomgr/timer.h"
 
 #include "src/core/iomgr/timer_heap.h"
-#include "src/core/iomgr/timer_internal.h"
 #include "src/core/iomgr/time_averaged_stats.h"
 #include <grpc/support/log.h>
 #include <grpc/support/sync.h>
diff --git a/src/core/iomgr/timer.h b/src/core/iomgr/timer.h
index 720c9d5ab9..2f74b6e5d3 100644
--- a/src/core/iomgr/timer.h
+++ b/src/core/iomgr/timer.h
@@ -86,4 +86,24 @@ void grpc_timer_init(grpc_exec_ctx *exec_ctx, grpc_timer *timer,
    Requires:  cancel() must happen after add() on a given timer */
 void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer);
 
+/* iomgr internal api for dealing with timers */
+
+/* Check for timers to be run, and run them.
+   Return non zero if timer callbacks were executed.
+   Drops drop_mu if it is non-null before executing callbacks.
+   If next is non-null, TRY to update *next with the next running timer
+   IF that timer occurs before *next current value.
+   *next is never guaranteed to be updated on any given execution; however,
+   with high probability at least one thread in the system will see an update
+   at any time slice. */
+
+int grpc_timer_check(grpc_exec_ctx* exec_ctx, gpr_timespec now,
+                     gpr_timespec* next);
+void grpc_timer_list_init(gpr_timespec now);
+void grpc_timer_list_shutdown(grpc_exec_ctx* exec_ctx);
+
+/* the following must be implemented by each iomgr implementation */
+
+void grpc_kick_poller(void);
+
 #endif /* GRPC_INTERNAL_CORE_IOMGR_TIMER_H */
diff --git a/src/core/iomgr/timer_internal.h b/src/core/iomgr/timer_internal.h
deleted file mode 100644
index f182e73764..0000000000
--- a/src/core/iomgr/timer_internal.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *
- * Copyright 2015, Google Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#ifndef GRPC_INTERNAL_CORE_IOMGR_TIMER_INTERNAL_H
-#define GRPC_INTERNAL_CORE_IOMGR_TIMER_INTERNAL_H
-
-#include "src/core/iomgr/exec_ctx.h"
-#include <grpc/support/sync.h>
-#include <grpc/support/time.h>
-
-/* iomgr internal api for dealing with timers */
-
-/* Check for timers to be run, and run them.
-   Return non zero if timer callbacks were executed.
-   Drops drop_mu if it is non-null before executing callbacks.
-   If next is non-null, TRY to update *next with the next running timer
-   IF that timer occurs before *next current value.
-   *next is never guaranteed to be updated on any given execution; however,
-   with high probability at least one thread in the system will see an update
-   at any time slice. */
-
-int grpc_timer_check(grpc_exec_ctx* exec_ctx, gpr_timespec now,
-                     gpr_timespec* next);
-void grpc_timer_list_init(gpr_timespec now);
-void grpc_timer_list_shutdown(grpc_exec_ctx* exec_ctx);
-
-/* the following must be implemented by each iomgr implementation */
-
-void grpc_kick_poller(void);
-
-#endif /* GRPC_INTERNAL_CORE_IOMGR_TIMER_INTERNAL_H */
diff --git a/src/core/surface/completion_queue.c b/src/core/surface/completion_queue.c
index 75298eb795..6597c83cdc 100644
--- a/src/core/surface/completion_queue.c
+++ b/src/core/surface/completion_queue.c
@@ -323,7 +323,19 @@ grpc_event grpc_completion_queue_next(grpc_completion_queue *cc,
       break;
     }
     first_loop = 0;
-    grpc_pollset_work(&exec_ctx, &cc->pollset, &worker, now, deadline);
+    /* Check alarms - these are a global resource so we just ping
+       each time through on every pollset.
+       May update deadline to ensure timely wakeups.
+       TODO(ctiller): can this work be localized? */
+    gpr_timespec iteration_deadline = deadline;
+    if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
+      GPR_TIMER_MARK("alarm_triggered", 0);
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      grpc_exec_ctx_flush(&exec_ctx);
+      gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+      continue;
+    }
+    grpc_pollset_work(&exec_ctx, &cc->pollset, &worker, now, iteration_deadline);
   }
   GRPC_SURFACE_TRACE_RETURNED_EVENT(cc, &ret);
   GRPC_CQ_INTERNAL_UNREF(cc, "next");
@@ -427,7 +439,19 @@ grpc_event grpc_completion_queue_pluck(grpc_completion_queue *cc, void *tag,
       break;
     }
     first_loop = 0;
-    grpc_pollset_work(&exec_ctx, &cc->pollset, &worker, now, deadline);
+    /* Check alarms - these are a global resource so we just ping
+       each time through on every pollset.
+       May update deadline to ensure timely wakeups.
+       TODO(ctiller): can this work be localized? */
+    gpr_timespec iteration_deadline = deadline;
+    if (grpc_timer_check(&exec_ctx, now, &iteration_deadline)) {
+      GPR_TIMER_MARK("alarm_triggered", 0);
+      gpr_mu_unlock(GRPC_POLLSET_MU(&cc->pollset));
+      grpc_exec_ctx_flush(&exec_ctx);
+      gpr_mu_lock(GRPC_POLLSET_MU(&cc->pollset));
+      continue;
+    }
+    grpc_pollset_work(&exec_ctx, &cc->pollset, &worker, now, iteration_deadline);
     del_plucker(cc, tag, &worker);
   }
 done:
diff --git a/test/core/iomgr/timer_list_test.c b/test/core/iomgr/timer_list_test.c
index 15de87c5a1..487527fbf5 100644
--- a/test/core/iomgr/timer_list_test.c
+++ b/test/core/iomgr/timer_list_test.c
@@ -35,7 +35,6 @@
 
 #include <string.h>
 
-#include "src/core/iomgr/timer_internal.h"
 #include <grpc/support/log.h>
 #include "test/core/util/test_config.h"
 
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index b626843233..ffc40dfc19 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -850,7 +850,6 @@ src/core/iomgr/tcp_windows.h \
 src/core/iomgr/time_averaged_stats.h \
 src/core/iomgr/timer.h \
 src/core/iomgr/timer_heap.h \
-src/core/iomgr/timer_internal.h \
 src/core/iomgr/udp_server.h \
 src/core/iomgr/wakeup_fd_pipe.h \
 src/core/iomgr/wakeup_fd_posix.h \
diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json
index 6538ddc37e..fdba0417ca 100644
--- a/tools/run_tests/sources_and_headers.json
+++ b/tools/run_tests/sources_and_headers.json
@@ -3032,7 +3032,6 @@
       "src/core/iomgr/time_averaged_stats.h", 
       "src/core/iomgr/timer.h", 
       "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/timer_internal.h", 
       "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_pipe.h", 
       "src/core/iomgr/wakeup_fd_posix.h", 
@@ -3251,7 +3250,6 @@
       "src/core/iomgr/timer.h", 
       "src/core/iomgr/timer_heap.c", 
       "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/timer_internal.h", 
       "src/core/iomgr/udp_server.c", 
       "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_eventfd.c", 
@@ -3557,7 +3555,6 @@
       "src/core/iomgr/time_averaged_stats.h", 
       "src/core/iomgr/timer.h", 
       "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/timer_internal.h", 
       "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_pipe.h", 
       "src/core/iomgr/wakeup_fd_posix.h", 
@@ -3760,7 +3757,6 @@
       "src/core/iomgr/timer.h", 
       "src/core/iomgr/timer_heap.c", 
       "src/core/iomgr/timer_heap.h", 
-      "src/core/iomgr/timer_internal.h", 
       "src/core/iomgr/udp_server.c", 
       "src/core/iomgr/udp_server.h", 
       "src/core/iomgr/wakeup_fd_eventfd.c", 
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj
index 76975322be..8e8f29aee9 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj
@@ -359,7 +359,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.h" />
diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
index 4660572f97..e55c6673ce 100644
--- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters
@@ -734,9 +734,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_internal.h">
-      <Filter>src\core\iomgr</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
index 541000af40..af89435885 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj
@@ -335,7 +335,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\time_averaged_stats.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h" />
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_internal.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_pipe.h" />
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\wakeup_fd_posix.h" />
diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
index 48814f997e..809ea59c5f 100644
--- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
+++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters
@@ -629,9 +629,6 @@
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_heap.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-    <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\timer_internal.h">
-      <Filter>src\core\iomgr</Filter>
-    </ClInclude>
     <ClInclude Include="$(SolutionDir)\..\src\core\iomgr\udp_server.h">
       <Filter>src\core\iomgr</Filter>
     </ClInclude>
-- 
GitLab