diff options
Diffstat (limited to 'server/alarm-manager-timer.c')
-rw-r--r-- | server/alarm-manager-timer.c | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/server/alarm-manager-timer.c b/server/alarm-manager-timer.c new file mode 100644 index 0000000..fd20049 --- /dev/null +++ b/server/alarm-manager-timer.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2000 - 2019 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <sys/timerfd.h> +#include <glib.h> + +#include "alarm.h" +#include "alarm-internal.h" +#include "alarm-manager-dbus.h" + +extern __alarm_server_context_t alarm_context; + +bool g_dummy_timer_is_set = false; + +static gboolean __alarm_handler_idle(gpointer user_data) +{ + GPollFD *gpollfd = (GPollFD *) user_data; + uint64_t exp; + time_t current_time; + +#ifdef TIZEN_TEST_GCOV + void __gcov_flush(void); + __gcov_flush(); +#endif + + if (gpollfd == NULL) { + LOGE("gpollfd is NULL"); + return false; + } + + if (read(gpollfd->fd, &exp, sizeof(uint64_t)) < 0) { + LOGE("Reading the fd is failed."); + return false; + } + + _display_lock_state(DEVICED_LCD_OFF, DEVICED_STAY_CUR_STATE, 0); + + if (g_dummy_timer_is_set == true) { + LOGD("dummy alarm timer has expired."); + } else { + LOGD("__alarm_handler_idle"); + _alarm_expired(); + } + + _alarm_schedule(); + + /* + * Previous alarm can be expired late as tolerance of RTC. + * In this case, Expire alarms forcibly if real duetime is same to current time. + */ + time(¤t_time); + if (alarm_context.c_due_time == current_time) { + LOGD("Expire alarms forcibly when duetime is same to current time(%ld).", current_time); + _alarm_expired(); + _alarm_schedule(); + } + + _rtc_set(); + + _display_unlock_state(DEVICED_LCD_OFF, DEVICED_SLEEP_MARGIN); + + return false; +} + + +static void __timer_glib_finalize(GSource *src) +{ + GSList *fd_list; + GPollFD *tmp; + + fd_list = src->poll_fds; + do { + tmp = (GPollFD *) fd_list->data; + g_free(tmp); + + fd_list = fd_list->next; + } while (fd_list); + + return; +} + +static gboolean __timer_glib_check(GSource *src) +{ + GSList *fd_list; + GPollFD *tmp; + + fd_list = src->poll_fds; + do { + tmp = (GPollFD *) fd_list->data; + if (tmp->revents & (G_IO_IN | G_IO_PRI)) + return TRUE; + + fd_list = fd_list->next; + } while (fd_list); + + return FALSE; +} + +static gboolean __timer_glib_dispatch(GSource *src, GSourceFunc callback, + gpointer data) +{ + callback(data); + return TRUE; +} + +static gboolean __timer_glib_prepare(GSource *src, gint *timeout) +{ + return FALSE; +} + +GSourceFuncs funcs = { + .prepare = __timer_glib_prepare, + .check = __timer_glib_check, + .dispatch = __timer_glib_dispatch, + .finalize = __timer_glib_finalize +}; + +int _initialize_timer() +{ + int fd; + GSource *src; + GPollFD *gpollfd; + int ret; + + fd = timerfd_create(CLOCK_REALTIME, 0); + if (fd == -1) { + LOGE("timerfd_create() is failed.\n"); + return -1; + } + src = g_source_new(&funcs, sizeof(GSource)); + + gpollfd = (GPollFD *) g_malloc(sizeof(GPollFD)); + if (gpollfd == NULL) { + LOGE("Out of memory\n"); + return -1; + } + gpollfd->events = G_IO_IN; + gpollfd->fd = fd; + + g_source_add_poll(src, gpollfd); + g_source_set_callback(src, (GSourceFunc) __alarm_handler_idle, + (gpointer) gpollfd, NULL); + g_source_set_priority(src, G_PRIORITY_HIGH); + + ret = g_source_attach(src, NULL); + if (ret == 0) { + LOGE("g_source_attach() is failed.\n"); + return -1; + } + + g_source_unref(src); + + return fd; +} + +void _alarm_disable_timer() +{ + struct itimerspec time_spec; + + time_spec.it_value.tv_sec = 0; + time_spec.it_value.tv_nsec = 0; + time_spec.it_interval.tv_sec = time_spec.it_interval.tv_nsec = 0; + + if (timerfd_settime(alarm_context.timer, 0, &time_spec, NULL) < 0) + LOGE("timerfd_settime has failed : errno(%d).", errno); +} + +void _alarm_set_timer(int timer, time_t due_time) +{ + struct itimerspec time_spec; + time_t current_time; + double interval; + char due_time_r[100] = { 0 }; + struct tm ts_ret; + + time(¤t_time); + + interval = difftime(due_time, current_time); + LOGD("[alarm-server][timer]: remain time from current is %f , due_time is %ld.", interval, due_time); + + /*set timer as absolute time */ + /*we create dummy timer when the interval is longer than one day. */ + /*the timer will be expired in half day. */ + + localtime_r(&due_time, &ts_ret); + + if (interval > 60 * 60 * 24) { + interval = 60 * 60 * 12; + g_dummy_timer_is_set = true; + strftime(due_time_r, 30, "%c", &ts_ret); + LOGD("create dummy alarm timer(%d), due_time(%s)", timer, due_time_r); + } else { + g_dummy_timer_is_set = false; + } + + time_spec.it_value.tv_sec = due_time; + time_spec.it_value.tv_nsec = 0; + time_spec.it_interval.tv_sec = time_spec.it_interval.tv_nsec = 0; + + if (interval > 0 && timerfd_settime(timer, TFD_TIMER_ABSTIME, &time_spec, NULL) != 0) { + LOGE("set timer has failed : timer(%d), due_time(%ld) , errno(%d).", timer, due_time, errno); + } + + /* we set c_due_time to due_time due to allow newly created alarm can + be schedlued when its interval is less than the current alarm */ + alarm_context.c_due_time = due_time; +} |