summaryrefslogtreecommitdiff
path: root/server/alarm-manager-timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/alarm-manager-timer.c')
-rw-r--r--server/alarm-manager-timer.c227
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(&current_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(&current_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;
+}