aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWade Cherry <wade.cherry@arm.com>2012-07-12 16:29:16 +0100
committerJon Medhurst <tixy@linaro.org>2012-07-16 14:21:41 +0100
commit9b644ca1dd7c5028ab60108b2562c9897b979353 (patch)
treec05c1fc6456aab0568d42e8ea9165d7a814b93f6
parent9dfd42b6882c4d9cbfbaab4458bc7407c0f544d6 (diff)
gator-driver: Move work scheduling to timers
... 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>
-rw-r--r--drivers/gator/gator_cookies.c15
-rw-r--r--drivers/gator/gator_events_meminfo.c19
-rw-r--r--drivers/gator/gator_events_net.c18
-rw-r--r--drivers/gator/gator_main.c13
4 files changed, 51 insertions, 14 deletions
diff --git a/drivers/gator/gator_cookies.c b/drivers/gator/gator_cookies.c
index 7b5091696bf..df14d095107 100644
--- a/drivers/gator/gator_cookies.c
+++ b/drivers/gator/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/drivers/gator/gator_events_meminfo.c b/drivers/gator/gator_events_meminfo.c
index ad552ef6c6e..f9dfa9a04eb 100644
--- a/drivers/gator/gator_events_meminfo.c
+++ b/drivers/gator/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/drivers/gator/gator_events_net.c b/drivers/gator/gator_events_net.c
index 9298905e626..a3ae3f03e29 100644
--- a/drivers/gator/gator_events_net.c
+++ b/drivers/gator/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/drivers/gator/gator_main.c b/drivers/gator/gator_main.c
index 988045f187d..994e35d67d8 100644
--- a/drivers/gator/gator_main.c
+++ b/drivers/gator/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();
}