summaryrefslogtreecommitdiff
path: root/source/module/monitor_timer.c
blob: 4652bc446ecc206314cd763c37266fd1c1f272b9 (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include "monitor_timer.h"

// Global variable
kernel_watch_timer kernel_wtimer_list[MAX_TIMER_NUM] = {
    0};                    // all kernel_watch_timer
volatile int kernel_wtimer_num = 0; // current kernel_watch_timer number

EXPORT_SYMBOL(kernel_wtimer_list); // export kernel_watch_timer_list
EXPORT_SYMBOL(kernel_wtimer_num);  // export kernel_watch_timer_num


#define TIMER_FILLED(timer) ((timer)->sentinel >= TIMER_MAX_WATCH_NUM)
#define TIMER_EMPTY(timer) (!((timer)->time_ns | (timer)->sentinel))
#define TIMER_NO_KWARG(timer) ((timer)->sentinel == 0)

unsigned char del_all_kwarg_by_pid(pid_t pid) {
  int i = 0;
  kernel_watch_timer *timer = NULL;

  printk(KERN_INFO "del kwarg...");
  // printk(KERN_INFO "del kwarg kernel_wtimer_num:%d", kernel_wtimer_num);
  for (i = 0; i < kernel_wtimer_num; i++) {
    // printk(KERN_INFO "del watch i:%d", i);
    timer = &(kernel_wtimer_list[i]);
    timer_del_watch_by_pid(timer, pid);
  }
  // printk(KERN_INFO "del kwarg kernel_wtimer_num:%d", kernel_wtimer_num);
  for (i = 0; i < kernel_wtimer_num; i++) {
    // printk(KERN_INFO "del timer i:%d", i);
    timer = &(kernel_wtimer_list[i]);
    if (TIMER_NO_KWARG(timer)) // no available kwarg
    {
      // printk(KERN_INFO "del timer empty %d", i);
      // cancel and destroy timer.work
      // make sure empty timer has no work active
      cancel_work_sync(&timer->wk);
      destroy_work_on_stack(&timer->wk);

      if (i != kernel_wtimer_num - 1) {
        memcpy(timer, &kernel_wtimer_list[kernel_wtimer_num - 1],
               sizeof(kernel_watch_timer));
      }
      kernel_wtimer_num--;
      i--;

    }
  }
  return 0;
}

/// @brief get a valuable timer
/// @param time_ns
/// @return kernel_watch_timer *, NULL means fail
kernel_watch_timer *get_timer(unsigned long long time_ns) {
  int i = 0;
  kernel_watch_timer *timer = NULL;
  // chose a timer
  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &kernel_wtimer_list[i];

    if (TIMER_EMPTY(timer)) {
      break;
    }
    if ((timer->time_ns == time_ns) && (!TIMER_FILLED(timer))) {
      break;
    }
  }
  // if all timer is full
  if (i >= MAX_TIMER_NUM) {
    return NULL;
  }
  // if a new timer, init it
  if (i > kernel_wtimer_num - 1) {
    printk(KERN_INFO "New timer\n");

    kernel_wtimer_list[i].time_ns = time_ns;
    kernel_wtimer_list[i].sentinel = 0;

    kernel_wtimer_list[i].kt = ktime_set(0, (unsigned long)time_ns); // ns
    // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time
    hrtimer_init(&(kernel_wtimer_list[i].hr_timer), CLOCK_MONOTONIC,
                 HRTIMER_MODE_REL);
    kernel_wtimer_list[i].hr_timer.function =
        check_variable_cb; // callback function

    kernel_wtimer_num = i + 1;
  }
  printk(KERN_INFO "now, we have %d timers\n", kernel_wtimer_num);
  return &kernel_wtimer_list[i];
}

/// @brief hrTimer add watch
/// @param timer
/// @param k_watch_arg
/// @return 0 is success
unsigned char timer_add_watch(kernel_watch_timer *timer,
                              kernel_watch_arg k_watch_arg) {
  if (TIMER_FILLED(timer)) {
    printk(KERN_ERR "ALL Timer is full\n");
    return -1;
  }
  memcpy(&timer->k_watch_args[timer->sentinel], &k_watch_arg,
         sizeof(k_watch_arg));
  // timer->k_watch_args[timer->sentinel] = k_watch_arg;
  timer->sentinel++;
  return 0;
}

unsigned char timer_del_watch_by_pid(kernel_watch_timer *timer, pid_t pid) {
  int i = 0;
  for (i = 0; i < timer->sentinel; i++) {
    // if pid match, delete it and move the last one to this position, check
    // again
    if (timer->k_watch_args[i].task_id == pid) {
      if (i != timer->sentinel - 1) {
        memcpy(&timer->k_watch_args[i],
               &timer->k_watch_args[timer->sentinel - 1],
               sizeof(kernel_watch_arg));
      }
      timer->sentinel--;
      i--;
    }
  }
  return 0;
}

/// @brief start hrTimer
/// @param timeout: timeout in us
/// @return 0 is success
// int start_hrTimer(unsigned long timeout)
// {
//     printk("HrTimer Start\n");

//     kt = ktime_set(0, (unsigned long)timeout); //  us -> ns
//     // CLOCK_MONOTONIC: time since boot | HRTIMER_MODE_REL : relative time
//     hrtimer_init(&hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
//     hr_timer.function = check_variable_cb;
//     // mode the same as hrtimer_init
//     hrtimer_start(&hr_timer, kt, HRTIMER_MODE_REL);
//     return 0;
// }

/// @brief start all hrTimer
/// @param
void start_all_hrTimer(void) {
  int i = 0;
  kernel_watch_timer *timer = NULL;
  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &(kernel_wtimer_list[i]);
    TIMER_START(timer);
  }
  printk(KERN_INFO "HrTimer start,module keep %d hrtimer for now\n", kernel_wtimer_num);
}

/// @brief cancel hrTimer and stop all work
/// @param
void cancel_all_hrTimer(void) {
  int i = 0;
  kernel_watch_timer *timer = NULL;
  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &(kernel_wtimer_list[i]);
    TIMER_CANCEL(timer);
  }
  printk(KERN_INFO "HrTimer cancel,module keep %d hrtimer for now\n", kernel_wtimer_num);
}

/**
 * @brief cancel all work
 * 
 */
void cancel_all_work(void) {
  int i = 0;
  kernel_watch_timer *timer = NULL;
  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &(kernel_wtimer_list[i]);
    cancel_work_sync(&timer->wk);
  }
}

/**
 * @brief destory all work
 * 
 */
void cancel_destory_all_work(void) {
  int i = 0;
  kernel_watch_timer *timer = NULL;
  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &(kernel_wtimer_list[i]);
    cancel_work_sync(&timer->wk);
    destroy_work_on_stack(&timer->wk);
  }
}