osTimer.c 5.8 KB
Newer Older
S
Shengliang Guan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * 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/>.
 */

#define _DEFAULT_SOURCE
#include "os.h"

#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)

/*
 * windows implementation
 */

#include <Mmsystem.h>
dengyihao's avatar
fix bug  
dengyihao 已提交
26
#include <Windows.h>
S
Shengliang Guan 已提交
27
#include <stdint.h>
dengyihao's avatar
fix bug  
dengyihao 已提交
28
#include <stdio.h>
S
Shengliang Guan 已提交
29

dengyihao's avatar
fix bug  
dengyihao 已提交
30
#pragma warning(disable : 4244)
S
Shengliang Guan 已提交
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;
dengyihao's avatar
fix bug  
dengyihao 已提交
42 43
int             taosInitTimer(win_timer_f callback, int ms) {
  DWORD_PTR param = *((int64_t *)&callback);
S
Shengliang Guan 已提交
44 45 46 47 48 49 50 51

  timerId = timeSetEvent(ms, 1, (LPTIMECALLBACK)taosWinOnTimer, param, TIME_PERIODIC);
  if (timerId == 0) {
    return -1;
  }
  return 0;
}

dengyihao's avatar
fix bug  
dengyihao 已提交
52
void taosUninitTimer() { timeKillEvent(timerId); }
S
Shengliang Guan 已提交
53 54 55 56 57 58 59 60

#elif defined(_TD_DARWIN_64)

/*
 * darwin implementation
 */

#include <sys/event.h>
dengyihao's avatar
fix bug  
dengyihao 已提交
61
#include <sys/syscall.h>
S
Shengliang Guan 已提交
62
#include <unistd.h>
S
Shengliang Guan 已提交
63 64

static void (*timer_callback)(int);
dengyihao's avatar
fix bug  
dengyihao 已提交
65 66 67 68
static int          timer_ms = 0;
static pthread_t    timer_thread;
static int          timer_kq = -1;
static volatile int timer_stop = 0;
S
Shengliang Guan 已提交
69

dengyihao's avatar
fix bug  
dengyihao 已提交
70
static void* timer_routine(void* arg) {
S
Shengliang Guan 已提交
71 72 73
  (void)arg;
  setThreadName("timer");

dengyihao's avatar
fix bug  
dengyihao 已提交
74
  int             r = 0;
S
Shengliang Guan 已提交
75
  struct timespec to = {0};
dengyihao's avatar
fix bug  
dengyihao 已提交
76 77
  to.tv_sec = timer_ms / 1000;
  to.tv_nsec = (timer_ms % 1000) * 1000000;
S
Shengliang Guan 已提交
78 79
  while (!timer_stop) {
    struct kevent64_s kev[10] = {0};
dengyihao's avatar
fix bug  
dengyihao 已提交
80 81
    r = kevent64(timer_kq, NULL, 0, kev, sizeof(kev) / sizeof(kev[0]), 0, &to);
    if (r != 0) {
S
Shengliang Guan 已提交
82 83 84
      fprintf(stderr, "==%s[%d]%s()==kevent64 failed\n", basename(__FILE__), __LINE__, __func__);
      abort();
    }
dengyihao's avatar
fix bug  
dengyihao 已提交
85
    timer_callback(SIGALRM);  // just mock
S
Shengliang Guan 已提交
86 87 88 89 90 91 92
  }

  return NULL;
}

int taosInitTimer(void (*callback)(int), int ms) {
  int r = 0;
dengyihao's avatar
fix bug  
dengyihao 已提交
93 94 95
  timer_kq = -1;
  timer_stop = 0;
  timer_ms = ms;
S
Shengliang Guan 已提交
96 97 98
  timer_callback = callback;

  timer_kq = kqueue();
dengyihao's avatar
fix bug  
dengyihao 已提交
99
  if (timer_kq == -1) {
S
Shengliang Guan 已提交
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    fprintf(stderr, "==%s[%d]%s()==failed to create timer kq\n", basename(__FILE__), __LINE__, __func__);
    // since no caller of this func checks the return value for the moment
    abort();
  }

  r = pthread_create(&timer_thread, NULL, timer_routine, NULL);
  if (r) {
    fprintf(stderr, "==%s[%d]%s()==failed to create timer thread\n", basename(__FILE__), __LINE__, __func__);
    // since no caller of this func checks the return value for the moment
    abort();
  }
  return 0;
}

void taosUninitTimer() {
  int r = 0;
  timer_stop = 1;
  r = pthread_join(timer_thread, NULL);
  if (r) {
    fprintf(stderr, "==%s[%d]%s()==failed to join timer thread\n", basename(__FILE__), __LINE__, __func__);
    // since no caller of this func checks the return value for the moment
    abort();
  }
  close(timer_kq);
  timer_kq = -1;
}

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

/*
 * linux implementation
 */

#include <sys/syscall.h>
S
Shengliang Guan 已提交
139
#include <unistd.h>
S
Shengliang Guan 已提交
140 141 142 143 144 145

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

dengyihao's avatar
fix bug  
dengyihao 已提交
146 147
static pthread_t     timerThread;
static timer_t       timerId;
S
Shengliang Guan 已提交
148
static volatile bool stopTimer = false;
dengyihao's avatar
fix bug  
dengyihao 已提交
149
static void *        taosProcessAlarmSignal(void *tharg) {
S
Shengliang Guan 已提交
150 151 152 153 154 155 156 157 158 159 160
  // Block the signal
  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 已提交
161 162 163 164 165 166 167 168
#ifdef _ALPINE
  sevent.sigev_notify = SIGEV_THREAD;
  sevent.sigev_value.sival_int = syscall(__NR_gettid);
#else
  sevent.sigev_notify = SIGEV_THREAD_ID;
  sevent._sigev_un._tid = syscall(__NR_gettid);
#endif

S
Shengliang Guan 已提交
169 170 171
  sevent.sigev_signo = SIGALRM;

  if (timer_create(CLOCK_REALTIME, &sevent, &timerId) == -1) {
dengyihao's avatar
fix bug  
dengyihao 已提交
172
    // printf("Failed to create timer");
S
Shengliang Guan 已提交
173 174 175 176 177 178 179 180 181 182 183
  }

  pthread_cleanup_push(taosDeleteTimer, &timerId);

  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)) {
dengyihao's avatar
fix bug  
dengyihao 已提交
184
    // printf("Failed to init timer");
S
Shengliang Guan 已提交
185 186 187 188 189 190
    return NULL;
  }

  int signo;
  while (!stopTimer) {
    if (sigwait(&sigset, &signo)) {
dengyihao's avatar
fix bug  
dengyihao 已提交
191
      // printf("Failed to wait signal: number %d", signo);
S
Shengliang Guan 已提交
192 193
      continue;
    }
S
Shengliang Guan 已提交
194
    /* //printf("Signal handling: number %d ......\n", signo); */
S
Shengliang Guan 已提交
195 196 197

    callback(0);
  }
dengyihao's avatar
fix bug  
dengyihao 已提交
198

S
Shengliang Guan 已提交
199 200 201 202 203 204
  pthread_cleanup_pop(1);

  return NULL;
}

int taosInitTimer(void (*callback)(int), int ms) {
dengyihao's avatar
fix bug  
dengyihao 已提交
205
  stopTimer = false;
S
Shengliang Guan 已提交
206 207 208 209 210
  pthread_attr_t tattr;
  pthread_attr_init(&tattr);
  int code = pthread_create(&timerThread, &tattr, taosProcessAlarmSignal, callback);
  pthread_attr_destroy(&tattr);
  if (code != 0) {
dengyihao's avatar
fix bug  
dengyihao 已提交
211
    // printf("failed to create timer thread");
S
Shengliang Guan 已提交
212 213
    return -1;
  } else {
dengyihao's avatar
fix bug  
dengyihao 已提交
214
    // printf("timer thread:0x%08" PRIx64 " is created", taosGetPthreadId(timerThread));
S
Shengliang Guan 已提交
215 216 217 218 219 220 221 222
  }

  return 0;
}

void taosUninitTimer() {
  stopTimer = true;

dengyihao's avatar
fix bug  
dengyihao 已提交
223
  // printf("join timer thread:0x%08" PRIx64, taosGetPthreadId(timerThread));
S
Shengliang Guan 已提交
224 225 226
  pthread_join(timerThread, NULL);
}

227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
int64_t taosGetMonotonicMs() {
#if 0  
  return getMonotonicUs() / 1000;
#else
  return taosGetTimestampMs();
#endif
}

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

S
Shengliang Guan 已提交
243
#endif