From 8bef23c4e42f0d89b7a43dcf03dd304ce32f10c3 Mon Sep 17 00:00:00 2001
From: Constantin Papizh <p.const@bk.ru>
Date: Fri, 6 Nov 2020 19:50:50 +0300
Subject: [PATCH] Timer type

---
 dap-sdk/core/include/dap_common.h      |  4 ++
 dap-sdk/core/src/dap_common.c          |  2 -
 dap-sdk/net/core/dap_events_socket.c   |  2 +-
 dap-sdk/net/core/dap_timerfd.c         | 86 ++++++++++++++++++++------
 dap-sdk/net/core/include/dap_timerfd.h |  8 +++
 5 files changed, 80 insertions(+), 22 deletions(-)

diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index 430c7af507..5ed8b225ad 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -33,6 +33,10 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
+#ifdef DAP_OS_WINDOWS
+#include <fcntl.h>
+#define pipe(pfds) _pipe(pfds, 4096, _O_BINARY)
+#endif
 #ifdef __MACH__
 #include <dispatch/dispatch.h>
 #endif
diff --git a/dap-sdk/core/src/dap_common.c b/dap-sdk/core/src/dap_common.c
index f5565971c8..1be7ab9cf7 100755
--- a/dap-sdk/core/src/dap_common.c
+++ b/dap-sdk/core/src/dap_common.c
@@ -55,8 +55,6 @@
 
   #define popen _popen
   #define pclose _pclose
-  #define pipe(pfds) _pipe(pfds, 4096, 0x8000)
-
 #endif
 
 #include "dap_common.h"
diff --git a/dap-sdk/net/core/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c
index 1985ba9985..b711ceae5b 100644
--- a/dap-sdk/net/core/dap_events_socket.c
+++ b/dap-sdk/net/core/dap_events_socket.c
@@ -32,7 +32,6 @@
 #include <sys/epoll.h>
 #include <sys/select.h>
 #include <unistd.h>
-#include <fcntl.h>
 #else
 #include <winsock2.h>
 #include <windows.h>
@@ -41,6 +40,7 @@
 #include <io.h>
 #include "wepoll.h"
 #endif
+#include <fcntl.h>
 #include <pthread.h>
 
 #include "dap_common.h"
diff --git a/dap-sdk/net/core/dap_timerfd.c b/dap-sdk/net/core/dap_timerfd.c
index 51be755a2c..a74724f230 100644
--- a/dap-sdk/net/core/dap_timerfd.c
+++ b/dap-sdk/net/core/dap_timerfd.c
@@ -20,17 +20,19 @@
     You should have received a copy of the GNU General Public License
     along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
-#ifdef DAP_OS_UNIX
+
 #include <stdint.h>
 #include <stdbool.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
-#include <sys/time.h>
-#include <sys/timerfd.h>
 #include <inttypes.h>
 
+#ifdef DAP_OS_WINDOWS
+#include <winsock2.h>
+#endif
+
 #include "dap_common.h"
 #include "dap_events.h"
 #include "dap_worker.h"
@@ -62,6 +64,15 @@ dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t a
      return dap_timerfd_start_on_worker(dap_events_worker_get_auto(), a_timeout_ms, a_callback, a_callback_arg, a_repeated);
 }
 
+#ifdef DAP_OS_WINDOWS
+void __stdcall TimerAPCb(void* arg, DWORD low, DWORD high) {  // Timer high value.
+    UNREFERENCED_PARAMETER(low)
+    UNREFERENCED_PARAMETER(high)
+    dap_timerfd_t *l_timerfd = (dap_timerfd_t *)arg;
+    write(l_timerfd->tfd2, 0, sizeof(void*));
+}
+#endif
+
 /**
  * @brief dap_timerfd_start_on_worker
  * @param a_worker
@@ -73,10 +84,13 @@ dap_timerfd_t* dap_timerfd_start(uint64_t a_timeout_ms, dap_timerfd_callback_t a
 dap_timerfd_t* dap_timerfd_start_on_worker(dap_worker_t * a_worker, uint64_t a_timeout_ms, dap_timerfd_callback_t a_callback, void *a_callback_arg, bool a_repeated)
 
 {
+    dap_timerfd_t *l_timerfd = DAP_NEW(dap_timerfd_t);
+#if defined DAP_OS_UNIX
     struct itimerspec l_ts;
     int l_tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
     if(l_tfd == -1) {
         log_it(L_WARNING, "dap_timerfd_start() failed: timerfd_create() errno=%d\n", errno);
+        DAP_DELETE(l_timerfd);
         return NULL;
     }
     // repeat never
@@ -88,11 +102,33 @@ dap_timerfd_t* dap_timerfd_start_on_worker(dap_worker_t * a_worker, uint64_t a_t
     if(timerfd_settime(l_tfd, 0, &l_ts, NULL) < 0) {
         log_it(L_WARNING, "dap_timerfd_start() failed: timerfd_settime() errno=%d\n", errno);
         close(l_tfd);
+        DAP_DELETE(l_timerfd);
         return NULL;
     }
-
-    // create dap_timerfd_t structure
-    dap_timerfd_t *l_timerfd = DAP_NEW(dap_timerfd_t);
+#elif defined DAP_OS_WINDOWS
+    HANDLE l_th = CreateWaitableTimer(NULL, true, NULL);
+    if (!l_th) {
+        log_it(L_CRITICAL, "Waitable timer not created, error %d", GetLastError());
+        DAP_DELETE(l_timerfd);
+        return NULL;
+    }
+    int l_pipe[2];
+    if (pipe(l_pipe) < 0) {
+        log_it(L_ERROR, "Can't create pipe, error: %d", errno);
+        DAP_DELETE(l_timerfd);
+        return NULL;
+    }
+    unsigned long l_mode = 0;
+    int l_tfd = l_pipe[0];
+    LARGE_INTEGER l_due_time;
+    l_due_time.QuadPart = (long long)a_timeout_ms * _MSEC;
+    if (!SetWaitableTimer(l_th, &l_due_time, 0, TimerAPCb, l_timerfd, false)) {
+        log_it(L_CRITICAL, "Waitable timer not set, error %d", GetLastError());
+        CloseHandle(l_th);
+        DAP_DELETE(l_timerfd);
+        return NULL;
+    }
+#endif
 
     // create events_socket for timer file descriptor
     dap_events_socket_callbacks_t l_s_callbacks;
@@ -105,14 +141,20 @@ dap_timerfd_t* dap_timerfd_start_on_worker(dap_worker_t * a_worker, uint64_t a_t
     l_events_socket->_inheritor = l_timerfd;
 
     // fill out dap_timerfd_t structure
-    l_timerfd->timeout_ms = a_timeout_ms;
-    l_timerfd->tfd = l_tfd;
-    l_timerfd->events_socket = l_events_socket;
-    l_timerfd->callback = a_callback;
-    l_timerfd->callback_arg = a_callback_arg;
-    l_timerfd->repeated = a_repeated;
+    l_timerfd->timeout_ms       = a_timeout_ms;
+    l_timerfd->tfd              = l_tfd;
+    l_timerfd->events_socket    = l_events_socket;
+    l_timerfd->callback         = a_callback;
+    l_timerfd->callback_arg     = a_callback_arg;
+    l_timerfd->repeated         = a_repeated;
+#ifdef DAP_OS_WINDOWS
+    l_timerfd->th               = l_th;
+    l_timerfd->tfd2             = l_pipe[1];
+    ioctlsocket(l_pipe[0], FIONBIO, &l_mode);
+    l_mode = 0;
+    ioctlsocket(l_pipe[1], FIONBIO, &l_mode);
+#endif
     dap_worker_add_events_socket(l_events_socket, a_worker);
-
     return l_timerfd;
 }
 
@@ -122,13 +164,11 @@ dap_timerfd_t* dap_timerfd_start_on_worker(dap_worker_t * a_worker, uint64_t a_t
  */
 static void s_es_callback_timer(struct dap_events_socket *a_event_sock)
 {
-    uint64_t l_ptiu64;
     dap_timerfd_t *l_timerfd = a_event_sock->_inheritor;
-    // run user's callback
     if(l_timerfd->callback)
         l_timerfd->callback(l_timerfd->callback_arg);
     if (l_timerfd->repeated) {
-        //printf("\nread() returned %d, %d\n", l_ptiu64, l_read_ret);
+#if defined DAP_OS_UNIX
         struct itimerspec l_ts;
         // repeat never
         l_ts.it_interval.tv_sec = 0;
@@ -139,8 +179,19 @@ static void s_es_callback_timer(struct dap_events_socket *a_event_sock)
         if(timerfd_settime(l_timerfd->tfd, 0, &l_ts, NULL) < 0) {
             log_it(L_WARNING, "callback_timerfd_read() failed: timerfd_settime() errno=%d\n", errno);
         }
+#elif defined DAP_OS_WINDOWS
+        LARGE_INTEGER l_due_time;
+        l_due_time.QuadPart = (long long)l_timerfd->timeout_ms * _MSEC;
+        if (!SetWaitableTimer(l_timerfd->th, &l_due_time, 0, TimerAPCb, l_timerfd, false)) {
+            log_it(L_CRITICAL, "Waitable timer not reset, error %d", GetLastError());
+            CloseHandle(l_timerfd->th);
+        }
+#endif
         dap_events_socket_set_readable_unsafe(a_event_sock, true);
     } else {
+#if defined DAP_OS_WINDOWS
+        CloseHandle(l_timerfd->th);
+#endif
         dap_events_socket_remove_and_delete_unsafe(l_timerfd->events_socket, false);
     }
 }
@@ -154,6 +205,3 @@ void dap_timerfd_delete(dap_timerfd_t *l_timerfd)
 {
     dap_events_socket_remove_and_delete_mt(l_timerfd->events_socket->worker, l_timerfd->events_socket);
 }
-#else
-#error "No dap_timerfd realization for your platform"
-#endif
diff --git a/dap-sdk/net/core/include/dap_timerfd.h b/dap-sdk/net/core/include/dap_timerfd.h
index 0f600fe557..c8c524b3a2 100644
--- a/dap-sdk/net/core/include/dap_timerfd.h
+++ b/dap-sdk/net/core/include/dap_timerfd.h
@@ -27,8 +27,12 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#if defined DAP_OS_UNIX
 #include <sys/time.h>
 #include <sys/timerfd.h>
+#elif defined DAP_OS_WINDOWS
+#define _MSEC -10000
+#endif
 #include <inttypes.h>
 
 #include "dap_common.h"
@@ -43,6 +47,10 @@ typedef struct dap_timerfd {
     dap_timerfd_callback_t callback;
     void *callback_arg;
     bool repeated;
+#ifdef DAP_OS_WINDOWS
+    HANDLE th;
+    int tfd2;
+#endif
 } dap_timerfd_t;
 
 int dap_timerfd_init();
-- 
GitLab