osTimer.c 5.7 KB
Newer Older
S
Shengliang Guan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

wafwerar's avatar
wafwerar 已提交
16
#define ALLOW_FORBID_FUNC
S
Shengliang Guan 已提交
17 18 19
#define _DEFAULT_SOURCE
#include "os.h"

wafwerar's avatar
wafwerar 已提交
20
#ifdef WINDOWS
S
Shengliang Guan 已提交
21
#include <Mmsystem.h>
dengyihao's avatar
fix bug  
dengyihao 已提交
22
#include <Windows.h>
S
Shengliang Guan 已提交
23
#include <stdint.h>
dengyihao's avatar
fix bug  
dengyihao 已提交
24
#include <stdio.h>
S
Shengliang Guan 已提交
25

dengyihao's avatar
fix bug  
dengyihao 已提交
26
#pragma warning(disable : 4244)
S
Shengliang Guan 已提交
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

typedef void (*win_timer_f)(int signo);

void WINAPI taosWinOnTimer(UINT wTimerID, UINT msg, DWORD_PTR dwUser, DWORD_PTR dwl, DWORD_PTR dw2) {
  win_timer_f callback = *((win_timer_f *)&dwUser);
  if (callback != NULL) {
    callback(0);
  }
}

static MMRESULT timerId;

#elif defined(_TD_DARWIN_64)

#include <sys/event.h>
dengyihao's avatar
fix bug  
dengyihao 已提交
42
#include <sys/syscall.h>
S
Shengliang Guan 已提交
43
#include <unistd.h>
S
Shengliang Guan 已提交
44 45

static void (*timer_callback)(int);
dengyihao's avatar
fix bug  
dengyihao 已提交
46
static int          timer_ms = 0;
H
Hongze Cheng 已提交
47
static TdThread     timer_thread;
dengyihao's avatar
fix bug  
dengyihao 已提交
48 49
static int          timer_kq = -1;
static volatile int timer_stop = 0;
S
Shengliang Guan 已提交
50

dengyihao's avatar
fix bug  
dengyihao 已提交
51
static void* timer_routine(void* arg) {
S
Shengliang Guan 已提交
52 53 54
  (void)arg;
  setThreadName("timer");

dengyihao's avatar
fix bug  
dengyihao 已提交
55
  int             r = 0;
S
Shengliang Guan 已提交
56
  struct timespec to = {0};
dengyihao's avatar
fix bug  
dengyihao 已提交
57 58
  to.tv_sec = timer_ms / 1000;
  to.tv_nsec = (timer_ms % 1000) * 1000000;
S
Shengliang Guan 已提交
59 60
  while (!timer_stop) {
    struct kevent64_s kev[10] = {0};
dengyihao's avatar
fix bug  
dengyihao 已提交
61 62
    r = kevent64(timer_kq, NULL, 0, kev, sizeof(kev) / sizeof(kev[0]), 0, &to);
    if (r != 0) {
wafwerar's avatar
wafwerar 已提交
63
      fprintf(stderr, "==%s[%d]%s()==kevent64 failed\n", taosDirEntryBaseName(__FILE__), __LINE__, __func__);
S
Shengliang Guan 已提交
64 65
      abort();
    }
dengyihao's avatar
fix bug  
dengyihao 已提交
66
    timer_callback(SIGALRM);  // just mock
S
Shengliang Guan 已提交
67 68 69 70 71 72 73 74 75 76 77 78
  }

  return NULL;
}

void taos_block_sigalrm(void) {
  // we don't know if there's any specific API for SIGALRM to deliver to specific thread
  // this implementation relies on kqueue rather than SIGALRM
}

#else
#include <sys/syscall.h>
S
Shengliang Guan 已提交
79
#include <unistd.h>
S
Shengliang Guan 已提交
80 81 82 83 84 85

static void taosDeleteTimer(void *tharg) {
  timer_t *pTimer = tharg;
  timer_delete(*pTimer);
}

H
Hongze Cheng 已提交
86
static TdThread      timerThread;
dengyihao's avatar
fix bug  
dengyihao 已提交
87
static timer_t       timerId;
S
Shengliang Guan 已提交
88
static volatile bool stopTimer = false;
H
Hongze Cheng 已提交
89 90
static void         *taosProcessAlarmSignal(void *tharg) {
          // Block the signal
S
Shengliang Guan 已提交
91 92 93 94 95 96 97 98 99 100
  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGALRM);
  sigprocmask(SIG_BLOCK, &sigset, NULL);
  void (*callback)(int) = tharg;

  struct sigevent sevent = {{0}};

  setThreadName("tmr");

dengyihao's avatar
fix bug  
dengyihao 已提交
101
#ifdef _ALPINE
sangshuduo's avatar
sangshuduo 已提交
102 103
  sevent.sigev_notify = SIGEV_THREAD_ID;
  sevent.sigev_notify_thread_id = syscall(__NR_gettid);
dengyihao's avatar
fix bug  
dengyihao 已提交
104 105 106 107 108
#else
  sevent.sigev_notify = SIGEV_THREAD_ID;
  sevent._sigev_un._tid = syscall(__NR_gettid);
#endif

S
Shengliang Guan 已提交
109 110 111
  sevent.sigev_signo = SIGALRM;

  if (timer_create(CLOCK_REALTIME, &sevent, &timerId) == -1) {
H
Hongze Cheng 已提交
112
            // printf("Failed to create timer");
S
Shengliang Guan 已提交
113 114
  }

wafwerar's avatar
wafwerar 已提交
115
  taosThreadCleanupPush(taosDeleteTimer, &timerId);
S
Shengliang Guan 已提交
116 117 118 119 120 121 122 123

  struct itimerspec ts;
  ts.it_value.tv_sec = 0;
  ts.it_value.tv_nsec = 1000000 * MSECONDS_PER_TICK;
  ts.it_interval.tv_sec = 0;
  ts.it_interval.tv_nsec = 1000000 * MSECONDS_PER_TICK;

  if (timer_settime(timerId, 0, &ts, NULL)) {
H
Hongze Cheng 已提交
124
            // printf("Failed to init timer");
S
Shengliang Guan 已提交
125 126 127 128 129
    return NULL;
  }

  int signo;
  while (!stopTimer) {
H
Hongze Cheng 已提交
130 131
            if (sigwait(&sigset, &signo)) {
              // printf("Failed to wait signal: number %d", signo);
S
Shengliang Guan 已提交
132 133
      continue;
    }
H
Hongze Cheng 已提交
134
            /* //printf("Signal handling: number %d ......\n", signo); */
S
Shengliang Guan 已提交
135

H
Hongze Cheng 已提交
136
            callback(0);
S
Shengliang Guan 已提交
137
  }
dengyihao's avatar
fix bug  
dengyihao 已提交
138

wafwerar's avatar
wafwerar 已提交
139
  taosThreadCleanupPop(1);
S
Shengliang Guan 已提交
140 141 142

  return NULL;
}
wafwerar's avatar
wafwerar 已提交
143
#endif
S
Shengliang Guan 已提交
144 145

int taosInitTimer(void (*callback)(int), int ms) {
wafwerar's avatar
wafwerar 已提交
146
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
  DWORD_PTR param = *((int64_t *)&callback);

  timerId = timeSetEvent(ms, 1, (LPTIMECALLBACK)taosWinOnTimer, param, TIME_PERIODIC);
  if (timerId == 0) {
    return -1;
  }
  return 0;
#elif defined(_TD_DARWIN_64)
  int r = 0;
  timer_kq = -1;
  timer_stop = 0;
  timer_ms = ms;
  timer_callback = callback;

  timer_kq = kqueue();
  if (timer_kq == -1) {
    fprintf(stderr, "==%s[%d]%s()==failed to create timer kq\n", taosDirEntryBaseName(__FILE__), __LINE__, __func__);
    // since no caller of this func checks the return value for the moment
    abort();
  }

wafwerar's avatar
wafwerar 已提交
168
  r = taosThreadCreate(&timer_thread, NULL, timer_routine, NULL);
wafwerar's avatar
wafwerar 已提交
169
  if (r) {
H
Hongze Cheng 已提交
170 171
    fprintf(stderr, "==%s[%d]%s()==failed to create timer thread\n", taosDirEntryBaseName(__FILE__), __LINE__,
            __func__);
wafwerar's avatar
wafwerar 已提交
172 173 174 175 176
    // since no caller of this func checks the return value for the moment
    abort();
  }
  return 0;
#else
dengyihao's avatar
fix bug  
dengyihao 已提交
177
  stopTimer = false;
wafwerar's avatar
wafwerar 已提交
178 179 180 181
  TdThreadAttr tattr;
  taosThreadAttrInit(&tattr);
  int code = taosThreadCreate(&timerThread, &tattr, taosProcessAlarmSignal, callback);
  taosThreadAttrDestroy(&tattr);
S
Shengliang Guan 已提交
182
  if (code != 0) {
dengyihao's avatar
fix bug  
dengyihao 已提交
183
    // printf("failed to create timer thread");
S
Shengliang Guan 已提交
184 185
    return -1;
  } else {
dengyihao's avatar
fix bug  
dengyihao 已提交
186
    // printf("timer thread:0x%08" PRIx64 " is created", taosGetPthreadId(timerThread));
S
Shengliang Guan 已提交
187 188 189
  }

  return 0;
wafwerar's avatar
wafwerar 已提交
190
#endif
S
Shengliang Guan 已提交
191 192 193
}

void taosUninitTimer() {
wafwerar's avatar
wafwerar 已提交
194
#ifdef WINDOWS
wafwerar's avatar
wafwerar 已提交
195 196 197 198
  timeKillEvent(timerId);
#elif defined(_TD_DARWIN_64)
  int r = 0;
  timer_stop = 1;
wafwerar's avatar
wafwerar 已提交
199
  r = taosThreadJoin(timer_thread, NULL);
wafwerar's avatar
wafwerar 已提交
200 201 202 203 204 205 206 207
  if (r) {
    fprintf(stderr, "==%s[%d]%s()==failed to join timer thread\n", taosDirEntryBaseName(__FILE__), __LINE__, __func__);
    // since no caller of this func checks the return value for the moment
    abort();
  }
  close(timer_kq);
  timer_kq = -1;
#else
S
Shengliang Guan 已提交
208 209
  stopTimer = true;

dengyihao's avatar
fix bug  
dengyihao 已提交
210
  // printf("join timer thread:0x%08" PRIx64, taosGetPthreadId(timerThread));
wafwerar's avatar
wafwerar 已提交
211
  taosThreadJoin(timerThread, NULL);
wafwerar's avatar
wafwerar 已提交
212
#endif
S
Shengliang Guan 已提交
213 214
}

215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
int64_t taosGetMonotonicMs() {
#if 0  
  return getMonotonicUs() / 1000;
#else
  return taosGetTimestampMs();
#endif
}

const char *taosMonotonicInit() {
#if 0
  return monotonicInit();
#else
  return NULL;
#endif
}