diff options
Diffstat (limited to 'firmware/target/hosted/android/kernel-android.c')
-rw-r--r-- | firmware/target/hosted/android/kernel-android.c | 110 |
1 files changed, 60 insertions, 50 deletions
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 | { |