/* Copyright Prize * Author: Eileen * process monitor in kernel. */ #include #include #include #include #include #include #include #include #include #include #include #include /*lijimeng*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*lijimeng*/ #include #include #include #include #include #include #include #include #include #include #include #include "resmon.h" #define P2M(x) ((((unsigned long)x) << (PAGE_SHIFT - 10)) >> (10)) #define RESMON_FILTER "app" #define SYSTEM_FILTER "system_server" struct resmon_struct *resmon_obj; static struct proc_dir_entry *resmon_procfs; #ifdef arch_idle_time static u64 get_pri_idle_time(struct kernel_cpustat *kcs, int cpu) { u64 idle; idle = kcs->cpustat[CPUTIME_IDLE]; if (cpu_online(cpu) && !nr_iowait_cpu(cpu)) idle += arch_idle_time(cpu); return idle; } static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu) { u64 iowait; iowait = kcs->cpustat[CPUTIME_IOWAIT]; if (cpu_online(cpu) && nr_iowait_cpu(cpu)) iowait += arch_idle_time(cpu); return iowait; } #else static u64 get_pri_idle_time(struct kernel_cpustat *kcs, int cpu) { u64 idle, idle_usecs = -1ULL; //if (cpu_online(cpu)) idle_usecs = get_cpu_idle_time_us(cpu, NULL); if (idle_usecs == -1ULL) /* !NO_HZ or cpu offline so we can rely on cpustat.idle */ idle = kcs->cpustat[CPUTIME_IDLE]; else idle = idle_usecs * NSEC_PER_USEC; return idle; } static u64 get_iowait_time(struct kernel_cpustat *kcs, int cpu) { u64 iowait, iowait_usecs = -1ULL; if (cpu_online(cpu)) iowait_usecs = get_cpu_iowait_time_us(cpu, NULL); if (iowait_usecs == -1ULL) /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */ iowait = kcs->cpustat[CPUTIME_IOWAIT]; else iowait = iowait_usecs * NSEC_PER_USEC; return iowait; } #endif struct sighand_struct *__pri_lock_task_sighand(struct task_struct *tsk, unsigned long *flags) { struct sighand_struct *sighand; rcu_read_lock(); for (;;) { sighand = rcu_dereference(tsk->sighand); if (unlikely(sighand == NULL)) break; /* * This sighand can be already freed and even reused, but * we rely on SLAB_TYPESAFE_BY_RCU and sighand_ctor() which * initializes ->siglock: this slab can't go away, it has * the same object type, ->siglock can't be reinitialized. * * We need to ensure that tsk->sighand is still the same * after we take the lock, we can race with de_thread() or * __exit_signal(). In the latter case the next iteration * must see ->sighand == NULL. */ spin_lock_irqsave(&sighand->siglock, *flags); if (likely(sighand == rcu_access_pointer(tsk->sighand))) break; spin_unlock_irqrestore(&sighand->siglock, *flags); } rcu_read_unlock(); return sighand; } struct sighand_struct *pri_lock_task_sighand(struct task_struct *tsk, unsigned long *flags) { struct sighand_struct *ret; ret = __pri_lock_task_sighand(tsk, flags); (void)__cond_lock(&tsk->sighand->siglock, ret); return ret; } static int show_resmon_stat(struct seq_file *m, void *v) { #ifdef CONFIG_RESMON_DEBUG int i = 0; #endif struct task_struct *task; struct task_struct *t; //int result = 0; unsigned long long read_bytes, write_bytes = 0; u64 utime, stime = 0; unsigned long mm_size = 0; int oom_adj = OOM_ADJUST_MIN; struct task_io_accounting acct; unsigned long flags; //char value[64] = {0}; //char *secctx = value; //char *secctx = NULL; //bool from_system = false; rcu_read_lock(); for_each_process(task) { if (task->flags & PF_KTHREAD) continue; if (pri_lock_task_sighand(task, &flags)) { oom_adj = task->signal->oom_score_adj; if (oom_adj < 0) { unlock_task_sighand(task, &flags); continue; } // if (in_egroup_p(KGIDT_INIT(6666))) // { // from_system = true; // } // if (!from_system) // { // //kfree(secctx); // unlock_task_sighand(task, &flags); // continue; // } //from_system = false; //kfree(secctx); thread_group_cputime_adjusted(task, &utime, &stime); if (task->mm) mm_size = P2M(get_mm_rss(task->mm)); acct = task->ioac; task_io_accounting_add(&acct, &task->signal->ioac); t = task; while_each_thread(task, t) task_io_accounting_add(&acct, &t->ioac); #ifdef CONFIG_TASK_IO_ACCOUNTING read_bytes = acct.read_bytes; write_bytes = acct.write_bytes; #endif //if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) //oom_adj = OOM_ADJUST_MAX; //else /*modify for oom_score_adj->oom_adj round*/ //oom_adj = ((task->signal->oom_score_adj * -OOM_DISABLE * 10)/OOM_SCORE_ADJ_MAX+5)/10; seq_printf(m, "%d ", task->pid); seq_printf(m, "%llu " , (long long unsigned int)nsec_to_clock_t(utime)); //seq_put_decimal_ull(m, " ", (long long unsigned int)nsec_to_clock_t(utime)); seq_printf(m, "%llu ", (long long unsigned int)nsec_to_clock_t(stime)); //seq_put_decimal_ull(m, " ", (long long unsigned int)nsec_to_clock_t(stime)); //seq_put_decimal_ull(m, " ", (long long unsigned int)mm_size); seq_printf(m, "%llu ", (long long unsigned int)mm_size); //seq_put_decimal_ull(m, " ", read_bytes); seq_printf(m, "%llu ", read_bytes); //seq_put_decimal_ull(m, " ", write_bytes); seq_printf(m, "%llu ", write_bytes); seq_printf(m, " %d\n", oom_adj); #ifdef CONFIG_RESMON_DEBUG pos += sprintf(test + pos, "%d ", task->pid); pos += sprintf(test + pos, "%llu ", (long long unsigned int)nsec_to_clock_t(utime) ); pos += sprintf(test + pos, "%llu ", (long long unsigned int)nsec_to_clock_t(stime) ); pos += sprintf(test + pos, "%llu ", (long long unsigned int)mm_size); pos += sprintf(test + pos, "%llu ", read_bytes); pos += sprintf(test + pos, "%llu ", write_bytes); pos += sprintf(test + pos, "%d\n", oom_adj ); #endif #ifdef CONFIG_RESMON_KILL_DEBUG test_set_pid(count ++, task->pid); #endif unlock_task_sighand(task, &flags); } } rcu_read_unlock(); #ifdef CONFIG_RESMON_DEBUG printk("+ %s \n", __func__); for (i = 0; i < pos; i++) printk("%c", test[i]); printk("- %s \n", __func__); pos = 0; #endif #ifdef CONFIG_RESMON_KILL_DEBUG count = 0; #endif return 0; } static void cpustat_info(unsigned long long *info, int len) { int i; if (len >= NR_STATS) { for_each_possible_cpu(i) { struct kernel_cpustat kcpustat; u64 *cpustat = kcpustat.cpustat; kcpustat_cpu_fetch(&kcpustat, i); info[CPUTIME_USER] += cpustat[CPUTIME_USER]; info[CPUTIME_NICE] += cpustat[CPUTIME_NICE]; info[CPUTIME_SYSTEM] += cpustat[CPUTIME_SYSTEM]; info[CPUTIME_IDLE] += get_pri_idle_time(&kcpustat, i); info[CPUTIME_IOWAIT] += get_iowait_time(&kcpustat, i); info[CPUTIME_IRQ] += cpustat[CPUTIME_IRQ]; info[CPUTIME_SOFTIRQ] += cpustat[CPUTIME_SOFTIRQ]; info[CPUTIME_STEAL] += cpustat[CPUTIME_STEAL]; info[CPUTIME_GUEST] += cpustat[CPUTIME_GUEST]; info[CPUTIME_GUEST_NICE] += cpustat[CPUTIME_GUEST_NICE]; } } } MODULE_IMPORT_NS(MINIDUMP); static long meminfo_available(void) { struct sysinfo i; long cached; long available; si_meminfo(&i); si_swapinfo(&i); cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; if (cached < 0) cached = 0; available = i.freeram + cached; return P2M(available); } static int send_event(enum resmon_trigger trigger, int value) { char name_buf[32]; char state_buf[32]; char *envp[3]; int env_offset = 0; int ret = 0; snprintf(name_buf, sizeof(name_buf),"TYPE=%d", trigger); envp[env_offset++] = name_buf; snprintf(state_buf, sizeof(state_buf),"LOAD=%d", value); envp[env_offset++] = state_buf; envp[env_offset] = NULL; //resmon_error("resmon send_event - sending event - %s in %s\n", *envp, kobject_get_path(&resmon_obj->mdev.this_device->kobj, GFP_KERNEL)); ret = kobject_uevent_env(&resmon_obj->mdev.this_device->kobj, KOBJ_CHANGE, envp); if (ret < 0) resmon_error("uevent sending failed with ret = %d\n", ret); return ret; } #ifdef CONFIG_RESMON_KILL_DEBUG int test_pid[1024] = {0}; static int test_count = 0; void test_set_pid(int id, int pid) { test_pid[id] = pid; } #endif static void resmon_process(void) { unsigned long long cpustat[NR_STATS] = {0}; unsigned long long cpuloads, cpuidle, iowait = 0; long long cpu_delta, idle_delta, io_delta= 0; long long cur_loads, cur_iowait, cur_mem = 0; /* prizem modify compile error */ mutex_lock(&resmon_obj->lock); cpustat_info(cpustat, NR_STATS); cpuloads = cpustat[CPUTIME_USER] + cpustat[CPUTIME_NICE] + cpustat[CPUTIME_SYSTEM] + cpustat[CPUTIME_SOFTIRQ] + cpustat[CPUTIME_IRQ] + cpustat[CPUTIME_IDLE] + cpustat[CPUTIME_IOWAIT]; cpuidle = cpustat[CPUTIME_IDLE]; iowait = cpustat[CPUTIME_IOWAIT]; if (resmon_obj->cpuloads != 0) { cpu_delta = cpuloads - resmon_obj->cpuloads; idle_delta = cpuidle - resmon_obj->cpuidle; io_delta = iowait - resmon_obj->iowait; cur_mem = meminfo_available(); resmon_debug("%s cpu_delta:%lld idle_delta:%lld io_delta:%lld\n", __func__, cpu_delta, idle_delta, io_delta); #if BITS_PER_LONG == 32 cur_loads = (cpu_delta - idle_delta) * 100; do_div(cur_loads, cpu_delta); cur_iowait = io_delta * 100; do_div(cur_iowait, cpu_delta); #else cur_loads = 100 * (cpu_delta - idle_delta) / (cpu_delta); cur_iowait = 100 * (io_delta) / (cpu_delta); #endif resmon_error("resmon %s cur_loads:%d cur_iowait:%d cur_mem:%d\n", __func__, cur_loads, cur_iowait, cur_mem); if (cur_loads > resmon_obj->cpuload_thresh) send_event(CPU_TRIGGER, cur_loads); if (cur_iowait > resmon_obj->io_thresh) send_event(IOW_TRIGGER, cur_iowait); if (cur_mem < resmon_obj->mem_thresh) send_event(MEM_TRIGGER, cur_mem); } resmon_obj->cpuloads = cpuloads; resmon_obj->cpuidle = cpuidle; resmon_obj->iowait = iowait; mutex_unlock(&resmon_obj->lock); #ifdef CONFIG_RESMON_KILL_DEBUG while(test_pid[test_count] && (test_count < 5)) { resmon_error("kil pid = %d\n", test_pid[test_count]); kill_pid(find_vpid(test_pid[test_count]), SIGKILL, 1); test_count ++; } test_count = 0; #endif } static int _resmon_task_main(void *data) { resmon_warn("enter _resmon_task_main\n"); while (1) { resmon_process(); #if RESMON_PERIODICAL_BY_HR_TIMER hrtimer_cancel(&resmon_obj->hr_timer); ktime = ktime_set(resmon_obj->trigger_time / 1000, (resmon_obj->trigger_time % 1000) * 1000000); hrtimer_start(&resmon_obj->hr_timer, ktime, HRTIMER_MODE_REL); set_current_state(TASK_INTERRUPTIBLE); schedule(); #else mod_timer(&resmon_obj->tmr_list, (jiffies + msecs_to_jiffies(resmon_obj->trigger_time))); set_current_state(TASK_INTERRUPTIBLE); schedule(); #endif if (kthread_should_stop()) break; } resmon_warn("leave _resmon_task_main\n"); return 0; } static void _resmon_timer_callback(struct timer_list *t) { /* resmon_warn("_resmon_timer_callback\n"); */ if (resmon_obj->tsk_struct_ptr) wake_up_process(resmon_obj->tsk_struct_ptr); //return HRTIMER_NORESTART; } static int resmon_task_start(void) { resmon_warn("resmon resmon_task_start"); if (!atomic_read(&resmon_obj->state)) { atomic_set(&resmon_obj->state, 1); //struct sched_param param = {.sched_priority = RESMON_TASK_PRIORITY }; if (resmon_obj->tsk_struct_ptr == NULL) { //resmon_obj->cpuloads = 1; resmon_obj->tsk_struct_ptr = kthread_create(_resmon_task_main, NULL, "resmon_main"); if (IS_ERR(resmon_obj->tsk_struct_ptr)) return PTR_ERR(resmon_obj->tsk_struct_ptr); //sched_setscheduler_nocheck(resmon_obj->tsk_struct_ptr, SCHED_FIFO, ¶m); get_task_struct(resmon_obj->tsk_struct_ptr); wake_up_process(resmon_obj->tsk_struct_ptr); resmon_warn("resmon task start success, ptr: %p, pid: %d\n", resmon_obj->tsk_struct_ptr, resmon_obj->tsk_struct_ptr->pid); } else { resmon_warn("resmon task already exist, ptr: %p, pid: %d\n", resmon_obj->tsk_struct_ptr, resmon_obj->tsk_struct_ptr->pid); } } return 0; } static int resmon_task_stop(void) { int r = 0; resmon_warn("resmon_task_stop\n"); if (atomic_read(&resmon_obj->state)) { atomic_set(&resmon_obj->state, 0); #if RESMON_PERIODICAL_BY_HR_TIMER /*deinit timer */ r = hrtimer_cancel(&resmon_obj->hr_timer); if (r) resmon_error("resmon hr timer delete error!\n"); #else /*deinit timer */ del_timer_sync(&resmon_obj->tmr_list); #endif if (resmon_obj->tsk_struct_ptr) { kthread_stop(resmon_obj->tsk_struct_ptr); put_task_struct(resmon_obj->tsk_struct_ptr); resmon_obj->tsk_struct_ptr = NULL; resmon_obj->cpuloads = 0; resmon_obj->cpuidle = 0; resmon_obj->iowait = 0; } } return r; } static ssize_t show_system_stat(struct device *dev, struct device_attribute *attr, char *buf) { int i, pos = 0; unsigned long long cpustat[NR_STATS] = {0}; cpustat_info(cpustat, NR_STATS); for(i = CPUTIME_USER; i < NR_STATS; i++) pos += snprintf(buf + pos, 64, " %llu", nsec_to_clock_t(cpustat[i])); for_each_possible_cpu(i) { pos += snprintf(buf + pos, 64, " %u", cpufreq_quick_get_max(i)); } pos += snprintf(buf + pos, 64, " %lu\n", meminfo_available()); return pos; } static DEVICE_ATTR(system_stat, S_IRUGO, show_system_stat, NULL); static ssize_t show_system_io_mem_stat(struct device *dev, struct device_attribute *attr, char *buf) { #ifdef CONFIG_RESMON_DEBUG int i = 0; #endif int pos = 0; struct task_struct *task; struct task_struct *t; //int result = 0; unsigned long long read_bytes, write_bytes = 0; u64 utime, stime = 0; unsigned long mm_size = 0; int oom_adj = OOM_ADJUST_MIN; struct task_io_accounting acct; unsigned long flags; //char value[64] = {0}; //char *secctx = value; //char *secctx = NULL; //bool from_system = false; rcu_read_lock(); for_each_process(task) { if (task->flags & PF_KTHREAD) continue; if (pri_lock_task_sighand(task, &flags)) { // result = security_getprocattr(task, NULL, "current", &secctx); // if (result <= 0) // { // kfree(secctx); // unlock_task_sighand(task, &flags); // continue; // } oom_adj = task->signal->oom_score_adj; if (oom_adj < 0) { unlock_task_sighand(task, &flags); continue; } // if (in_egroup_p(KGIDT_INIT(6666))) // { // from_system = true; // } // if (!from_system) // { // //kfree(secctx); // unlock_task_sighand(task, &flags); // continue; // } // from_system = false; //kfree(secctx); thread_group_cputime_adjusted(task, &utime, &stime); if (task->mm) mm_size = P2M(get_mm_rss(task->mm)); acct = task->ioac; task_io_accounting_add(&acct, &task->signal->ioac); t = task; while_each_thread(task, t) task_io_accounting_add(&acct, &t->ioac); #ifdef CONFIG_TASK_IO_ACCOUNTING read_bytes = acct.read_bytes; write_bytes = acct.write_bytes; #endif //if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) //oom_adj = OOM_ADJUST_MAX; //else /*modify for oom_score_adj->oom_adj round*/ //oom_adj = ((task->signal->oom_score_adj * -OOM_DISABLE * 10)/OOM_SCORE_ADJ_MAX+5)/10; oom_adj = task->signal->oom_score_adj; //resmon_error("resmon pid:%d, utime:%llu, stime:%llu,mm:%llu, read:%llu,write:%llu,oom_adj:%d",task->pid,nsec_to_clock_t(utime),nsec_to_clock_t(stime),mm_size,read_bytes,write_bytes,oom_adj); pos += sprintf(buf + pos, "%d ", task->pid); pos += sprintf(buf + pos, "%llu ", (long long unsigned int)nsec_to_clock_t(utime) ); pos += sprintf(buf + pos, "%llu ", (long long unsigned int)nsec_to_clock_t(stime) ); pos += sprintf(buf + pos, "%llu ", (long long unsigned int)mm_size); pos += sprintf(buf + pos, "%llu ", read_bytes); pos += sprintf(buf + pos, "%llu ", write_bytes); pos += sprintf(buf + pos, "%d\n", oom_adj ); #ifdef CONFIG_RESMON_KILL_DEBUG test_set_pid(count ++, task->pid); #endif unlock_task_sighand(task, &flags); } } rcu_read_unlock(); #ifdef CONFIG_RESMON_KILL_DEBUG count = 0; #endif return pos; } static DEVICE_ATTR(system_io_mem_stat, S_IRUGO, show_system_io_mem_stat, NULL); static ssize_t resmon_sysfs_cpuload_thresh_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, 8, "%d\n", resmon_obj->cpuload_thresh); } static ssize_t resmon_sysfs_cpuload_thresh_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { long int val = 0; /* We only accept numbers. */ if (kstrtol(buf, 10, &val) < 0) return -EINVAL; resmon_obj->cpuload_thresh = val; return count; } static DEVICE_ATTR(cpuload_thresh, S_IRUGO | S_IWUSR, resmon_sysfs_cpuload_thresh_show, resmon_sysfs_cpuload_thresh_store); static ssize_t resmon_sysfs_io_thresh_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, 8, "%d\n", resmon_obj->io_thresh); } static ssize_t resmon_sysfs_io_thresh_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { long int val = 0; /* We only accept numbers. */ if (kstrtol(buf, 10, &val) < 0) return -EINVAL; resmon_obj->io_thresh = val; return count; } static DEVICE_ATTR(io_thresh, S_IRUGO | S_IWUSR, resmon_sysfs_io_thresh_show, resmon_sysfs_io_thresh_store); static ssize_t resmon_sysfs_mem_thresh_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, 8, "%d\n", resmon_obj->mem_thresh); } static ssize_t resmon_sysfs_mem_thresh_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { long int val = 0; /* We only accept numbers. */ if (kstrtol(buf, 10, &val) < 0) return -EINVAL; resmon_obj->mem_thresh = val; return count; } static DEVICE_ATTR(mem_thresh, S_IRUGO | S_IWUSR, resmon_sysfs_mem_thresh_show, resmon_sysfs_mem_thresh_store); static ssize_t resmon_sysfs_trigger_time_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, 8, "%d\n", resmon_obj->trigger_time); } static ssize_t resmon_sysfs_trigger_time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { long int val = 0; /* We only accept numbers. */ if (kstrtol(buf, 10, &val) < 0) return -EINVAL; resmon_obj->trigger_time = val; return count; } static DEVICE_ATTR(trigger_time, S_IRUGO | S_IWUSR, resmon_sysfs_trigger_time_show, resmon_sysfs_trigger_time_store); static ssize_t resmon_sysfs_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, 8, "%d\n", resmon_obj->enable); } static ssize_t resmon_sysfs_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { long int val = 0; /* We only accept numbers. */ if (kstrtol(buf, 10, &val) < 0) return -EINVAL; resmon_obj->enable = !!val; //resmon_error("resmon resmon_sysfs_enable_store enable=%d, in_suspend=%d",resmon_obj->enable,resmon_obj->in_suspend); if(!atomic_read(&resmon_obj->in_suspend)) { if (resmon_obj->enable == 1) resmon_task_start(); else resmon_task_stop(); } return count; } static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, resmon_sysfs_enable_show, resmon_sysfs_enable_store); static struct attribute* resmon_sysfs_parameters_attrs[] = { &dev_attr_cpuload_thresh.attr, &dev_attr_io_thresh.attr, &dev_attr_mem_thresh.attr, &dev_attr_trigger_time.attr, &dev_attr_enable.attr, NULL, }; static const struct attribute_group resmon_sysfs_parameters_grp = { .name = "parameters", .attrs = resmon_sysfs_parameters_attrs, }; static int resmon_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; unsigned int blank; int retval = 0; /* If we aren't interested in this event, skip it immediately ... */ if (event != FB_EVENT_BLANK /* FB_EARLY_EVENT_BLANK */) return 0; blank = *(int *)evdata->data; switch (blank) { case FB_BLANK_UNBLANK: atomic_set(&resmon_obj->in_suspend, 0); /* thread state is controlled by user cmd rather than kernel fb notification */ if (resmon_obj->enable == 1) resmon_task_start(); break; case FB_BLANK_POWERDOWN: atomic_set(&resmon_obj->in_suspend, 1); //if (resmon_obj->enable == 1) resmon_task_stop(); break; default: resmon_debug("[%s] : other notifier, ignore\n", __func__); break; } return retval; } static struct resmon_struct *resmon_alloc_object(void) { struct resmon_struct *obj = kzalloc(sizeof(*obj), GFP_KERNEL); if (!obj) { resmon_error("Alloc resmon object error!\n"); return NULL; } obj->cpuload_thresh = RESMON_CPU_P; obj->io_thresh = RESMON_IO_P; obj->mem_thresh = 0; obj->trigger_time = RESMON_TIMER_INTERVAL_MS; obj->enable = RESMON_DEFAULT_ENABLE; obj->tsk_struct_ptr = NULL; obj->cpuloads = 0; obj->cpuidle = 0; obj->iowait = 0; atomic_set(&obj->in_suspend, 0); atomic_set(&obj->state, 0); mutex_init(&obj->lock); #if RESMON_PERIODICAL_BY_HR_TIMER /*init Hrtimer */ hrtimer_init(&obj->hr_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); obj->hr_timer.function = (void *)&_resmon_timer_callback; #else /*init timer */ //init_timer(&obj->tmr_list); //obj->tmr_list.function = (void *)&_resmon_timer_callback; //obj->tmr_list.data = (unsigned long)obj; timer_setup(&obj->tmr_list, _resmon_timer_callback, 0); obj->tmr_list.expires = jiffies + msecs_to_jiffies(obj->trigger_time); #endif return obj; } static int stat_open(struct inode *inode, struct file *file) { size_t size = PAGE_SIZE * 3; return single_open_size(file, show_resmon_stat, NULL, size); } static const struct proc_ops proc_stat_operations = { .proc_read = seq_read, .proc_open = stat_open, .proc_release = single_release, .proc_lseek = seq_lseek, }; static int __init proc_resmon_init(void) { resmon_procfs = proc_create("resmon_stat", 0, NULL, &proc_stat_operations); return 0; } static int resmon_init(void) { int ret = 0; resmon_obj = resmon_alloc_object(); if (!resmon_obj) { ret = -ENOMEM; resmon_error("unable to allocate resmon obj!\n"); return ret; } resmon_obj->mdev.minor = MISC_DYNAMIC_MINOR; resmon_obj->mdev.name = RESMON_DEV_NAME; ret = misc_register(&resmon_obj->mdev); if (ret) { resmon_error("misc_register error:%d\n", ret); goto exit_alloc_data_failed; } /* register screen on/off callback */ resmon_obj->notifier.notifier_call = resmon_fb_notifier_callback; ret = fb_register_client(&resmon_obj->notifier); if (ret) goto exit_misc_register_failed; ret = device_create_file(resmon_obj->mdev.this_device, &dev_attr_system_stat); if (ret) goto err_create_file_failed; ret = device_create_file(resmon_obj->mdev.this_device, &dev_attr_system_io_mem_stat); if (ret) goto err_create_system_failed; ret = sysfs_create_group(&resmon_obj->mdev.this_device->kobj, &resmon_sysfs_parameters_grp); if (ret) goto err_create_attr_failed; if (resmon_obj->enable == 1) { ret = resmon_task_start(); if (ret) goto err_create_attr_failed; } proc_resmon_init(); return 0; err_create_attr_failed: sysfs_remove_group(&resmon_obj->mdev.this_device->kobj, &resmon_sysfs_parameters_grp); err_create_system_failed: device_remove_file(resmon_obj->mdev.this_device, &dev_attr_system_io_mem_stat); err_create_file_failed: device_remove_file(resmon_obj->mdev.this_device, &dev_attr_system_stat); exit_misc_register_failed: misc_deregister(&resmon_obj->mdev); exit_alloc_data_failed: kfree(resmon_obj); return ret; } module_init(resmon_init); static void resmon_exit(void) { proc_remove(resmon_procfs); resmon_task_stop(); device_remove_file(resmon_obj->mdev.this_device, &dev_attr_system_io_mem_stat); device_remove_file(resmon_obj->mdev.this_device, &dev_attr_system_stat); sysfs_remove_group(&resmon_obj->mdev.this_device->kobj, &resmon_sysfs_parameters_grp); misc_deregister(&resmon_obj->mdev); kfree(resmon_obj); } module_exit(resmon_exit); MODULE_LICENSE("GPL");