From: Wade Cherry Date: Thu, 12 Jul 2012 15:29:16 +0000 (+0100) Subject: gator-driver: Move work scheduling to timers X-Git-Url: https://git.ti.com/gitweb?p=android-sdk%2Farm-ds5-gator.git;a=commitdiff_plain;h=2ccfda6ba471ba1722fe48d23767d9d024bd0750 gator-driver: Move work scheduling to timers ... in order to work around deadlocks in kernel >= 3.5... Signed-off-by: Wade Cherry Signed-off-by: Pawel Moll --- diff --git a/driver/gator_cookies.c b/driver/gator_cookies.c index 7b50916..df14d09 100644 --- a/driver/gator_cookies.c +++ b/driver/gator_cookies.c @@ -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; } diff --git a/driver/gator_events_meminfo.c b/driver/gator_events_meminfo.c index ad552ef..f9dfa9a 100644 --- a/driver/gator_events_meminfo.c +++ b/driver/gator_events_meminfo.c @@ -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) diff --git a/driver/gator_events_net.c b/driver/gator_events_net.c index 9298905..a3ae3f0 100644 --- a/driver/gator_events_net.c +++ b/driver/gator_events_net.c @@ -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); diff --git a/driver/gator_main.c b/driver/gator_main.c index 988045f..994e35d 100644 --- a/driver/gator_main.c +++ b/driver/gator_main.c @@ -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(); }