diff options
author | Thomas Martitz <kugel@rockbox.org> | 2010-12-10 15:14:18 +0000 |
---|---|---|
committer | Thomas Martitz <kugel@rockbox.org> | 2010-12-10 15:14:18 +0000 |
commit | c47d81345151166083ab10d6f5d11e56462056d5 (patch) | |
tree | f01d6b866113ca8998147d98425fa700db42ca48 | |
parent | 44cdce9b290d4ae9e1a436ef85c5b0ed56827784 (diff) | |
download | rockbox-c47d81345151166083ab10d6f5d11e56462056d5.tar.gz rockbox-c47d81345151166083ab10d6f5d11e56462056d5.zip |
Android: Replace the java based tick timer implemented with a not as bloated and more accurate linux hrtimer based one. Further reduces idle cpu usage (0% on my phone but still 1-2% on a Samsung Galaxy S).
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28784 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | android/src/org/rockbox/RockboxTimer.java | 76 | ||||
-rw-r--r-- | firmware/target/hosted/android/kernel-android.c | 110 | ||||
-rw-r--r-- | firmware/target/hosted/android/system-target.h | 2 | ||||
-rw-r--r-- | firmware/target/hosted/android/thread-android-arm.c | 2 |
4 files changed, 63 insertions, 127 deletions
diff --git a/android/src/org/rockbox/RockboxTimer.java b/android/src/org/rockbox/RockboxTimer.java deleted file mode 100644 index ff48b3f53a..0000000000 --- a/android/src/org/rockbox/RockboxTimer.java +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Thomas Martitz | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | package org.rockbox; | ||
23 | |||
24 | import java.util.Timer; | ||
25 | import java.util.TimerTask; | ||
26 | |||
27 | import android.content.Context; | ||
28 | import android.util.Log; | ||
29 | |||
30 | public class RockboxTimer extends Timer | ||
31 | { | ||
32 | private class RockboxTimerTask extends TimerTask { | ||
33 | private RockboxTimer timer; | ||
34 | public RockboxTimerTask(RockboxTimer parent) | ||
35 | { | ||
36 | super(); | ||
37 | timer = parent; | ||
38 | } | ||
39 | |||
40 | @Override | ||
41 | public void run() | ||
42 | { | ||
43 | timerTask(); | ||
44 | synchronized(timer) { | ||
45 | timer.notify(); | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | |||
50 | public RockboxTimer(Context c, long period_inverval_in_ms) | ||
51 | { | ||
52 | super("tick timer"); | ||
53 | schedule(new RockboxTimerTask(this), 0, period_inverval_in_ms); | ||
54 | } | ||
55 | |||
56 | @SuppressWarnings("unused") | ||
57 | private void LOG(CharSequence text) | ||
58 | { | ||
59 | Log.d("Rockbox", (String) text); | ||
60 | } | ||
61 | |||
62 | |||
63 | /* methods called from native, keep them simple */ | ||
64 | public void java_wait_for_interrupt() | ||
65 | { | ||
66 | synchronized(this) | ||
67 | { | ||
68 | try { | ||
69 | this.wait(); | ||
70 | } catch (InterruptedException e) { | ||
71 | /* Not an error: wakeup and return */ | ||
72 | } | ||
73 | } | ||
74 | } | ||
75 | public native void timerTask(); | ||
76 | } | ||
diff --git a/firmware/target/hosted/android/kernel-android.c b/firmware/target/hosted/android/kernel-android.c index c0d927d026..bac6d2a8fd 100644 --- a/firmware/target/hosted/android/kernel-android.c +++ b/firmware/target/hosted/android/kernel-android.c | |||
@@ -20,73 +20,83 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | 22 | ||
23 | #include <jni.h> | 23 | #include <time.h> |
24 | #include <signal.h> | ||
25 | #include <errno.h> | ||
26 | #include <unistd.h> | ||
27 | #include <semaphore.h> | ||
24 | #include "config.h" | 28 | #include "config.h" |
25 | #include "system.h" | 29 | #include "system.h" |
26 | #include "button.h" | 30 | #include "button.h" |
27 | #include "audio.h" | 31 | #include "audio.h" |
32 | #include "panic.h" | ||
28 | 33 | ||
29 | extern JNIEnv *env_ptr; | ||
30 | 34 | ||
31 | extern jobject RockboxService_instance; | 35 | static sem_t wfi_sem; |
36 | /* | ||
37 | * call tick tasks and wake the scheduler up */ | ||
38 | void timer_signal(int sig) | ||
39 | { | ||
40 | (void)sig; | ||
41 | call_tick_tasks(); | ||
42 | interrupt(); | ||
43 | } | ||
32 | 44 | ||
33 | static jclass RockboxTimer_class; | ||
34 | static jobject RockboxTimer_instance; | ||
35 | static jmethodID java_wait_for_interrupt; | ||
36 | static bool initialized = false; | ||
37 | /* | 45 | /* |
38 | * This is called from the separate Timer java thread. I have not added any | 46 | * wait on the sem which the signal handler posts to save cpu time (aka sleep) |
39 | * interrupt simulation to it (like the sdl counterpart does), | ||
40 | * I think this is probably not needed, unless code calls disable_interrupt() | ||
41 | * in order to be protected from tick tasks, but I can't remember a place right | ||
42 | * now. | ||
43 | * | 47 | * |
44 | * No synchronisation mechanism either. This could possibly be problematic, | 48 | * other mechanisms could use them as well */ |
45 | * but we'll see :) | 49 | void wait_for_interrupt(void) |
46 | */ | ||
47 | JNIEXPORT void JNICALL | ||
48 | Java_org_rockbox_RockboxTimer_timerTask(JNIEnv *env, jobject this) | ||
49 | { | 50 | { |
50 | (void)env; | 51 | sem_wait(&wfi_sem); |
51 | (void)this; | ||
52 | call_tick_tasks(); | ||
53 | } | 52 | } |
54 | 53 | ||
55 | void tick_start(unsigned int interval_in_ms) | 54 | void interrupt(void) |
56 | { | 55 | { |
57 | JNIEnv e = *env_ptr; | 56 | int s; |
58 | /* first, create a new Timer instance */ | 57 | /* unless idling, we usually have more interrupt() than wait_for_interrupt() |
59 | RockboxTimer_class = e->FindClass(env_ptr, "org/rockbox/RockboxTimer"); | 58 | * don't post unecessarily because wait_for_interrupt() would need to |
60 | jmethodID constructor = e->GetMethodID(env_ptr, | 59 | * decrement for each wasted sem_post(), instead of sleeping directly */ |
61 | RockboxTimer_class, | 60 | sem_getvalue(&wfi_sem, &s); |
62 | "<init>", | 61 | if (s <= 0) |
63 | "(Landroid/content/Context;J)V"); | 62 | sem_post(&wfi_sem); |
64 | /* the constructor will do the tick_start */ | ||
65 | RockboxTimer_instance = e->NewObject(env_ptr, | ||
66 | RockboxTimer_class, | ||
67 | constructor, | ||
68 | RockboxService_instance, | ||
69 | (jlong)interval_in_ms); | ||
70 | |||
71 | /* get our wfi func also */ | ||
72 | java_wait_for_interrupt = e->GetMethodID(env_ptr, | ||
73 | RockboxTimer_class, | ||
74 | "java_wait_for_interrupt", | ||
75 | "()V"); | ||
76 | /* it's now safe to call java_wait_for_interrupt */ | ||
77 | initialized = true; | ||
78 | } | 63 | } |
79 | 64 | ||
80 | void wait_for_interrupt(void) | 65 | /* |
66 | * setup a hrtimer to send a signal to our process every tick */ | ||
67 | void tick_start(unsigned int interval_in_ms) | ||
81 | { | 68 | { |
82 | if (LIKELY(initialized)) | 69 | int ret = 0; |
83 | { | 70 | sigset_t proc_set; |
84 | (*env_ptr)->CallVoidMethod(env_ptr, | 71 | timer_t timerid; |
85 | RockboxTimer_instance, | 72 | struct itimerspec ts; |
86 | java_wait_for_interrupt); | 73 | sigevent_t sigev = { |
87 | } | 74 | .sigev_notify = SIGEV_SIGNAL, |
75 | .sigev_signo = SIGUSR2, | ||
76 | }; | ||
77 | |||
78 | ts.it_value.tv_sec = ts.it_interval.tv_sec = 0; | ||
79 | ts.it_value.tv_nsec = ts.it_interval.tv_nsec = interval_in_ms*1000*1000; | ||
80 | |||
81 | /* add the signal handler */ | ||
82 | signal(SIGUSR2, timer_signal); | ||
83 | |||
84 | /* add the timer */ | ||
85 | ret |= timer_create(CLOCK_REALTIME, &sigev, &timerid); | ||
86 | ret |= timer_settime(timerid, 0, &ts, NULL); | ||
87 | |||
88 | /* unblock SIGUSR2 so the handler can run */ | ||
89 | ret |= sigprocmask(0, NULL, &proc_set); | ||
90 | ret |= sigdelset(&proc_set, SIGUSR2); | ||
91 | ret |= sigprocmask(SIG_SETMASK, &proc_set, NULL); | ||
92 | |||
93 | ret |= sem_init(&wfi_sem, 0, 0); | ||
94 | |||
95 | if (ret != 0) | ||
96 | panicf("%s(): %s\n", __func__, strerror(errno)); | ||
88 | } | 97 | } |
89 | 98 | ||
99 | |||
90 | bool timer_register(int reg_prio, void (*unregister_callback)(void), | 100 | bool timer_register(int reg_prio, void (*unregister_callback)(void), |
91 | long cycles, void (*timer_callback)(void)) | 101 | long cycles, void (*timer_callback)(void)) |
92 | { | 102 | { |
diff --git a/firmware/target/hosted/android/system-target.h b/firmware/target/hosted/android/system-target.h index 0bd6d78fe0..3938ad5fba 100644 --- a/firmware/target/hosted/android/system-target.h +++ b/firmware/target/hosted/android/system-target.h | |||
@@ -27,6 +27,8 @@ | |||
27 | #define restore_irq(level) (void)level | 27 | #define restore_irq(level) (void)level |
28 | 28 | ||
29 | void power_off(void); | 29 | void power_off(void); |
30 | void wait_for_interrupt(void); | ||
31 | void interrupt(void); | ||
30 | 32 | ||
31 | #endif /* __SYSTEM_TARGET_H__ */ | 33 | #endif /* __SYSTEM_TARGET_H__ */ |
32 | 34 | ||
diff --git a/firmware/target/hosted/android/thread-android-arm.c b/firmware/target/hosted/android/thread-android-arm.c index baf8b84b65..0bfd2b6c44 100644 --- a/firmware/target/hosted/android/thread-android-arm.c +++ b/firmware/target/hosted/android/thread-android-arm.c | |||
@@ -23,6 +23,7 @@ | |||
23 | ****************************************************************************/ | 23 | ****************************************************************************/ |
24 | 24 | ||
25 | #include <jni.h> | 25 | #include <jni.h> |
26 | #include <system.h> | ||
26 | /*--------------------------------------------------------------------------- | 27 | /*--------------------------------------------------------------------------- |
27 | * Start the thread running and terminate it if it returns | 28 | * Start the thread running and terminate it if it returns |
28 | *--------------------------------------------------------------------------- | 29 | *--------------------------------------------------------------------------- |
@@ -89,7 +90,6 @@ static inline void load_context(const void* addr) | |||
89 | * wait_for_interrupt is implemented in kernel-android.c | 90 | * wait_for_interrupt is implemented in kernel-android.c |
90 | **/ | 91 | **/ |
91 | 92 | ||
92 | extern void wait_for_interrupt(void); | ||
93 | static inline void core_sleep(void) | 93 | static inline void core_sleep(void) |
94 | { | 94 | { |
95 | wait_for_interrupt(); | 95 | wait_for_interrupt(); |