gator-driver: Move work scheduling to timers
authorWade Cherry <wade.cherry@arm.com>
Thu, 12 Jul 2012 15:29:16 +0000 (16:29 +0100)
committerJon Medhurst <tixy@linaro.org>
Fri, 13 Jul 2012 09:56:57 +0000 (10:56 +0100)
... in order to work around deadlocks in kernel >= 3.5...

Signed-off-by: Wade Cherry <wade.cherry@arm.com>
Signed-off-by: Pawel Moll <pawel.moll@arm.com>
driver/gator_cookies.c
driver/gator_events_meminfo.c
driver/gator_events_net.c
driver/gator_main.c

index 7b5091696bfaa2443b84cc50b875ccb2f3997617..df14d095107c2b5344ee5346c2aae7588450c717 100644 (file)
@@ -25,6 +25,10 @@ static DEFINE_PER_CPU(unsigned int *, translate_buffer);
 static inline uint32_t get_cookie(int cpu, int buftype, struct task_struct *task, struct vm_area_struct *vma, struct module *mod, bool in_interrupt);
 static void wq_cookie_handler(struct work_struct *unused);
 DECLARE_WORK(cookie_work, wq_cookie_handler);
+static struct timer_list app_process_wake_up_timer;
+static void app_process_wake_up_handler(unsigned long unused_data);
+static struct timer_list app_process_wake_up_timer;
+static void app_process_wake_up_handler(unsigned long unused_data);
 
 static uint32_t cookiemap_code(uint64_t value64) {
        uint32_t value = (uint32_t)((value64 >> 32) + value64);
@@ -136,6 +140,12 @@ static void wq_cookie_handler(struct work_struct *unused)
        mutex_unlock(&start_mutex);
 }
 
+static void app_process_wake_up_handler(unsigned long unused_data)
+{
+       // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+       schedule_work(&cookie_work);
+}
+
 // Retrieve full name from proc/pid/cmdline for java processes on Android
 static int translate_app_process(char** text, int cpu, struct task_struct * task, struct vm_area_struct *vma, bool in_interrupt)
 {
@@ -162,7 +172,7 @@ static int translate_app_process(char** text, int cpu, struct task_struct * task
 
                translate_buffer_write_int(cpu, (unsigned int)task);
                translate_buffer_write_int(cpu, (unsigned int)vma);
-               schedule_work(&cookie_work);
+               mod_timer(&app_process_wake_up_timer, jiffies + 1);
                goto out;
        }
 
@@ -372,6 +382,8 @@ static int cookies_initialize(void)
                gator_crc32_table[i] = crc;
        }
 
+        setup_timer(&app_process_wake_up_timer, app_process_wake_up_handler, 0);
+
 cookie_setup_error:
        return err;
 }
@@ -396,6 +408,7 @@ static void cookies_release(void)
                per_cpu(translate_text, cpu) = NULL;
        }
 
+       del_timer_sync(&app_process_wake_up_timer);
        kfree(gator_crc32_table);
        gator_crc32_table = NULL;
 }
index ad552ef6c6e5885217f92ca105ca369b1197eace..f9dfa9a04eb443594d793284b6aec793449cdb1d 100644 (file)
@@ -28,6 +28,8 @@ static bool new_data_avail;
 static void wq_sched_handler(struct work_struct *wsptr);
 
 DECLARE_WORK(work, wq_sched_handler);
+static struct timer_list meminfo_wake_up_timer;
+static void meminfo_wake_up_handler(unsigned long unused_data);
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
 GATOR_DEFINE_PROBE(mm_page_free_direct, TP_PROTO(struct page *page, unsigned int order)) {
@@ -107,6 +109,7 @@ static int gator_events_meminfo_start(void)
        if (GATOR_REGISTER_TRACE(mm_page_alloc))
                goto mm_page_alloc_exit;
 
+       setup_timer(&meminfo_wake_up_timer, meminfo_wake_up_handler, 0);
        return 0;
 
 mm_page_alloc_exit:
@@ -140,13 +143,15 @@ static void gator_events_meminfo_stop(void)
                GATOR_UNREGISTER_TRACE(mm_page_alloc);
        }
 
+       del_timer_sync(&meminfo_wake_up_timer);
+
        meminfo_global_enabled = 0;
        for (i = 0; i < MEMINFO_TOTAL; i++) {
                meminfo_enabled[i] = 0;
        }
 }
 
-// Must be run in process context (work queue) as the kernel function si_meminfo() can sleep
+// Must be run in process context as the kernel function si_meminfo() can sleep
 static void wq_sched_handler(struct work_struct *wsptr)
 {
        struct sysinfo info;
@@ -181,6 +186,12 @@ static void wq_sched_handler(struct work_struct *wsptr)
        new_data_avail = true;
 }
 
+static void meminfo_wake_up_handler(unsigned long unused_data)
+{
+       // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+       schedule_work(&work);
+}
+
 static int gator_events_meminfo_read(long long **buffer)
 {
        static unsigned int last_mem_event = 0;
@@ -190,11 +201,7 @@ static int gator_events_meminfo_read(long long **buffer)
 
        if (last_mem_event != mem_event) {
                last_mem_event = mem_event;
-               if (in_interrupt()) {
-                       schedule_work(&work);
-               } else {
-                       wq_sched_handler(NULL);
-               }
+               mod_timer(&meminfo_wake_up_timer, jiffies + 1);
        }
 
        if (!new_data_avail)
index 9298905e626f0ac2579e07122df7040907b2b3d6..a3ae3f03e291005a34e089ebf1437ac2abca8821 100644 (file)
@@ -23,6 +23,8 @@ static int rx_total, tx_total;
 static ulong netPrev[TOTALNET];
 static int netGet[TOTALNET * 4];
 
+static struct timer_list net_wake_up_timer;
+
 static void get_network_stats(struct work_struct *wsptr) {
        int rx = 0, tx = 0;
        struct net_device *dev;
@@ -42,6 +44,12 @@ static void get_network_stats(struct work_struct *wsptr) {
 }
 DECLARE_WORK(wq_get_stats, get_network_stats);
 
+static void net_wake_up_handler(unsigned long unused_data)
+{
+       // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+       schedule_work(&wq_get_stats);
+}
+
 static void calculate_delta(int *rx, int *tx)
 {
        int rx_calc, tx_calc;
@@ -83,14 +91,16 @@ static int gator_events_net_create_files(struct super_block *sb, struct dentry *
 
 static int gator_events_net_start(void)
 {
-       get_network_stats(NULL);
+       get_network_stats(0);
        netPrev[NETRX] = rx_total;
        netPrev[NETTX] = tx_total;
+       setup_timer(&net_wake_up_timer, net_wake_up_handler, 0);
        return 0;
 }
 
 static void gator_events_net_stop(void)
 {
+       del_timer_sync(&net_wake_up_timer);
        netrx_enabled = 0;
        nettx_enabled = 0;
 }
@@ -106,11 +116,7 @@ static int gator_events_net_read(int **buffer)
        if (!netrx_enabled && !nettx_enabled)
                return 0;
 
-       if (in_interrupt()){
-               schedule_work(&wq_get_stats);
-       } else {
-               get_network_stats(NULL);
-       }
+       mod_timer(&net_wake_up_timer, jiffies + 1);
 
        calculate_delta(&rx_delta, &tx_delta);
 
index 988045f187db99901bc3c6bc169efbbdf5d7b6d6..994e35d67d82076baef2a9149e6876372a791da4 100644 (file)
@@ -110,6 +110,7 @@ static DEFINE_MUTEX(gator_buffer_mutex);
 bool event_based_sampling;
 
 static DECLARE_WAIT_QUEUE_HEAD(gator_buffer_wait);
+static struct timer_list gator_buffer_wake_up_timer;
 static LIST_HEAD(gator_events);
 
 /******************************************************************************
@@ -163,6 +164,11 @@ u32 gator_cpuid(void)
 }
 #endif
 
+static void gator_buffer_wake_up(unsigned long data)
+{
+       wake_up(&gator_buffer_wait);
+}
+
 /******************************************************************************
  * Commit interface
  ******************************************************************************/
@@ -283,7 +289,9 @@ static void gator_commit_buffer(int cpu, int buftype)
 
        per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype];
        gator_buffer_header(cpu, buftype);
-       wake_up(&gator_buffer_wait);
+
+       // had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater
+       mod_timer(&gator_buffer_wake_up_timer, jiffies + 1);
 }
 
 static void buffer_check(int cpu, int buftype)
@@ -1069,11 +1077,14 @@ static int __init gator_module_init(void)
                return -1;
        }
 
+       setup_timer(&gator_buffer_wake_up_timer, gator_buffer_wake_up, 0);
+
        return 0;
 }
 
 static void __exit gator_module_exit(void)
 {
+       del_timer_sync(&gator_buffer_wake_up_timer);
        tracepoint_synchronize_unregister();
        gatorfs_unregister();
 }