summaryrefslogtreecommitdiff
path: root/source/module/monitor_timer.c
blob: ef40d94a6842b057717fb394f2d4afdeaff739ac (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
193
194
195
#include "monitor_timer.h"

#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...");

  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &(kernel_wtimer_list[i]);
    timer_del_watch_by_pid(timer, pid);
  }
  for (i = 0; i < kernel_wtimer_num; i++) {
    timer = &(kernel_wtimer_list[i]);
    if (TIMER_NO_KWARG(timer)) // no available kwarg
    {
      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) {
    printk(KERN_ERR "No timer available\n");
    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 "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 hrTimer handler
enum hrtimer_restart check_variable_cb(struct hrtimer *timer) {
  kernel_watch_timer *k_watch_timer =
      container_of(timer, kernel_watch_timer, hr_timer);
  int i = 0, j = 0;
  int buffer[TIMER_MAX_WATCH_NUM]; // Buffer to store the messages

  // check all watched kernel_watch_arg
  for (i = 0; i < k_watch_timer->sentinel; i++) {
    if (read_and_compare(&k_watch_timer->k_watch_args[i])) {
      // snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "
      // name: %s, threshold: %lld, pid: %d\n",
      //          k_watch_timer->k_watch_args[i].name,
      //          k_watch_timer->k_watch_args[i].threshold,
      //          k_watch_timer->k_watch_args[i].task_id);
      buffer[j] = i;
      j++;

      // printk(KERN_INFO "j: name %s, threshold: %lld\n",
      // k_watch_timer->k_watch_args[i].name,
      //        k_watch_timer->k_watch_args[i].threshold);
      // printk(KERN_INFO "j: %d\n", j);
    }
  }
  if (j > 0) // if any threshold reached
  {
    printk("-------------------------------------\n");
    printk("-------------watch monitor-----------\n");
    printk("Threshold reached:\n");

    for (i = 0; i < j; i++) {
      printk(" name: %s, threshold: %lld, pid: %d\n",
             k_watch_timer->k_watch_args[buffer[i]].name, //! todo
             k_watch_timer->k_watch_args[buffer[i]].threshold,
             k_watch_timer->k_watch_args[buffer[i]].task_id);
    }
    print_task_stack();
    // restart timer after 1s
    hrtimer_forward(timer, timer->base->get_time(), ktime_set(1, 0)); //! todo
    printk("-------------------------------------\n");
  } else {
    // keep frequency
    hrtimer_forward(timer, timer->base->get_time(), k_watch_timer->kt);
  }
  return HRTIMER_RESTART; // restart timer
}

/// @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("HrTimer start,module keep %d hrtimer for now\n", kernel_wtimer_num);
}

/// @brief cancel hrTimer
/// @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("HrTimer cancel,module keep %d hrtimer for now\n", kernel_wtimer_num);
}