1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (c) 2010 Thomas Martitz
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
37 static pthread_cond_t wfi_cond
= PTHREAD_COND_INITIALIZER
;
38 static pthread_mutex_t wfi_mtx
= PTHREAD_MUTEX_INITIALIZER
;
40 * call tick tasks and wake the scheduler up */
41 void timer_signal(union sigval arg
)
49 * wait on the sem which the signal handler posts to save cpu time (aka sleep)
51 * other mechanisms could use them as well */
52 void wait_for_interrupt(void)
54 pthread_cond_wait(&wfi_cond
, &wfi_mtx
);
58 * Wakeup the kernel, if sleeping (shall not be called from a signal handler) */
61 pthread_cond_signal(&wfi_cond
);
66 * setup a hrtimer to send a signal to our process every tick
68 * WARNING for Android: JNI calls are not permitted from tick tasks, as the
69 * underlying thread is not attached to the Java VM
71 * Can be possibly be attached if it really needs to be. but let's
72 * keep this leightweight
75 void tick_start(unsigned int interval_in_ms
)
82 /* initializing in the declaration causes some weird warnings */
83 memset(&sigev
, 0, sizeof(sigevent_t
));
84 sigev
.sigev_notify
= SIGEV_THREAD
,
85 sigev
.sigev_notify_function
= timer_signal
;
87 ts
.it_value
.tv_sec
= ts
.it_interval
.tv_sec
= 0;
88 ts
.it_value
.tv_nsec
= ts
.it_interval
.tv_nsec
= interval_in_ms
*1000*1000;
91 ret
|= timer_create(CLOCK_REALTIME
, &sigev
, &timerid
);
92 ret
|= timer_settime(timerid
, 0, &ts
, NULL
);
94 /* Grab the mutex already now and leave it to this thread. We don't
95 * care about race conditions when signaling the condition (because
96 * they are not critical), but a mutex is necessary due to the API */
97 pthread_mutex_lock(&wfi_mtx
);
100 panicf("%s(): %s\n", __func__
, strerror(errno
));
103 #define cycles_to_microseconds(cycles) \
104 ((int)((1000000*cycles)/TIMER_FREQ))
107 static timer_t timer_tid
;
108 static int timer_prio
= -1;
109 void (*global_unreg_callback
)(void);
110 void (*global_timer_callback
)(void);
112 static void timer_cb(union sigval arg
)
115 if (global_timer_callback
)
116 global_timer_callback();
119 bool timer_register(int reg_prio
, void (*unregister_callback
)(void),
120 long cycles
, void (*timer_callback
)(void))
123 struct itimerspec ts
;
125 long in_us
= cycles_to_microseconds(cycles
);
127 if (reg_prio
<= timer_prio
|| in_us
<= 0)
130 if (timer_prio
>= 0 && global_unreg_callback
)
131 global_unreg_callback();
133 memset(&sigev
, 0, sizeof(sigevent_t
));
134 sigev
.sigev_notify
= SIGEV_THREAD
,
135 sigev
.sigev_notify_function
= timer_cb
;
137 div_t q
= div(in_us
, 1000000);
138 ts
.it_value
.tv_sec
= ts
.it_interval
.tv_sec
= q
.quot
;
139 ts
.it_value
.tv_nsec
= ts
.it_interval
.tv_nsec
= q
.rem
*1000;
142 ret
|= timer_create(CLOCK_REALTIME
, &sigev
, &timer_tid
);
143 ret
|= timer_settime(timer_tid
, 0, &ts
, NULL
);
145 global_timer_callback
= timer_callback
;
146 global_unreg_callback
= unregister_callback
;
147 timer_prio
= reg_prio
;
152 bool timer_set_period(long cycles
)
154 struct itimerspec ts
;
155 long in_us
= cycles_to_microseconds(cycles
);
156 div_t q
= div(in_us
, 1000000);
157 ts
.it_value
.tv_sec
= ts
.it_interval
.tv_sec
= q
.quot
;
158 ts
.it_value
.tv_nsec
= ts
.it_interval
.tv_nsec
= q
.rem
*1000;
160 return timer_settime(timer_tid
, 0, &ts
, NULL
) == 0;
163 void timer_unregister(void)
165 timer_delete(timer_tid
);