util: timer: Add timer management 84/269984/6
authorChanwoo Choi <cw00.choi@samsung.com>
Thu, 20 Jan 2022 08:14:01 +0000 (17:14 +0900)
committerChanwoo Choi <cw00.choi@samsung.com>
Mon, 24 Jan 2022 09:23:58 +0000 (18:23 +0900)
Add internal helper functions of timer and uevent code. It will be used
on multiple point in PASS daemon.

Change-Id: Id9abc31433021eb850ad0529cc1ee6b6fcf31cab
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
CMakeLists.txt
include/util/timer.h [new file with mode: 0644]
src/main.c
src/util/timer.c [new file with mode: 0644]

index 76e647d..ecf536d 100644 (file)
@@ -29,6 +29,7 @@ SET(SRCS
        src/util/devices.c
        src/util/resource.c
        src/util/gdbus-util.c
+       src/util/timer.c
        src/main.c
        #Generated by a custom command 'gdbus-codegen' below
        src/pass/pass-dbus-stub.c
diff --git a/include/util/timer.h b/include/util/timer.h
new file mode 100644 (file)
index 0000000..c50653e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * PASS
+ *
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ */
+
+
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include <libudev.h>
+#include <glib-unix.h>
+
+void init_timer(void);
+void exit_timer(void);
+
+int add_timer_handler(unsigned int interval,
+                       gboolean (*timer_func)(gpointer data), void *user_data);
+void delete_timer_handler(int timer_id);
+
+struct udev_monitor *add_uevent_handler(
+                       const char *uevent_subsystem[],
+                       const char *uevent_devtype[],
+                       const int number_of_uevent,
+                       gboolean (*uevent_func)(gint fd, GIOCondition cond, void *data),
+                       void *user_data);
+void delete_uevent_handler(struct udev_monitor *udev_monitor);
+
+#endif
index 180a326..bbcd618 100644 (file)
@@ -26,6 +26,7 @@
 #include <util/common.h>
 #include <util/device-notifier.h>
 #include <util/devices.h>
+#include <util/timer.h>
 #include <util/gdbus-util.h>
 #include <util/log.h>
 
@@ -64,12 +65,14 @@ int main(int argc, char **argv)
        g_mainloop = g_main_loop_new(NULL, FALSE);
        pass_gdbus_get_system_connection(PASS_DBUS_CORE);
 
+       init_timer();
        init_devices(NULL);
        if (late_init() < 0)
                _E("cannot init pass core system\n");
 
        g_main_loop_run(g_mainloop);
        exit_devices(NULL);
+       exit_timer();
 
        pass_gdbus_put_system_connection(PASS_DBUS_CORE);
        g_main_loop_unref(g_mainloop);
diff --git a/src/util/timer.c b/src/util/timer.c
new file mode 100644 (file)
index 0000000..849baef
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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 <glib.h>
+#include <stdio.h>
+#include <libudev.h>
+#include <glib-unix.h>
+
+#include <util/common.h>
+#include <util/log.h>
+#include <util/timer.h>
+
+#define TYPE_TIMER     0
+#define TYPE_UEVENT    1
+
+static struct udev *g_udev;
+
+static GList *g_timer_list;
+static GList *g_uevent_list;
+
+struct uevent_data {
+       struct udev_monitor *udev_monitor;
+       int fd;
+};
+
+static gint __compare_timer_id(gconstpointer data, gconstpointer input)
+{
+       guint id= *(guint *)data;
+       guint input_id = *(guint *)input;
+
+       return (id == input_id) ? 0 : -1;
+}
+
+static bool find_timer(int id)
+{
+       GList *node;
+
+       node = g_list_find_custom(g_timer_list, &id, __compare_timer_id);
+
+       if (!node)
+               return false;
+       return true;
+}
+
+static gint __compare_uevent_data(gconstpointer data, gconstpointer input)
+{
+       struct uevent_data *uevent_data = (struct uevent_data *)data;
+       struct udev_monitor *udev_monitor = (struct udev_monitor *)input;
+
+       if (uevent_data->udev_monitor == udev_monitor)
+               return 0;
+       return -1;
+}
+
+static struct uevent_data *find_uevent_data(struct udev_monitor *udev_monitor)
+{
+       GList *node;
+
+       node = g_list_find_custom(g_uevent_list, udev_monitor,
+                                       __compare_uevent_data);
+
+       if (!node)
+               return NULL;
+       return (struct uevent_data *)node->data;
+}
+
+int add_timer_handler(unsigned int interval,
+                       gboolean (*timer_func)(gpointer data), void *user_data)
+{
+       guint timer_id;
+
+       timer_id = g_timeout_add((guint)interval, (GSourceFunc)timer_func,
+                                       (gpointer)user_data);
+       if (!timer_id)
+               return -EPERM;
+
+       g_timer_list = g_list_append(g_timer_list,
+                                       (gpointer)&timer_id);
+
+       return timer_id;
+}
+
+void delete_timer_handler(int timer_id)
+{
+       if (!find_timer(timer_id))
+               return;
+
+       g_source_remove(timer_id);
+       g_timer_list = g_list_remove(g_timer_list,
+                                       (gpointer)&timer_id);
+}
+
+struct udev_monitor *add_uevent_handler(
+                       const char *uevent_subsystem[],
+                       const char *uevent_devtype[],
+                       const int number_of_uevent,
+                       gboolean (*uevent_func)(gint fd, GIOCondition cond, void *data),
+                       void *user_data)
+{
+       struct uevent_data *uevent_data;
+       struct udev_monitor *udev_monitor;
+       guint gfd;
+       int ret;
+       int fd;
+       int i;
+
+       /* Initialize the udev-monitor instance and set buffer size */
+       udev_monitor = udev_monitor_new_from_netlink(g_udev, "kernel");
+       if (!udev_monitor) {
+               _E("failed to create the udev monitor\n");
+               return NULL;
+       }
+
+       /*
+        * Number of uevent subsystem must be more than 0 at least.
+        */
+       if (number_of_uevent <= 0) {
+               _E("failed to add filter due to subsystem/devtype are NULL\n");
+               ret = -EINVAL;
+               goto err_udev_monitor;
+       }
+
+       /* Update the kernel's subsystem and devtype for filtering */
+       for (i = 0; i < number_of_uevent; i++) {
+               ret = udev_monitor_filter_add_match_subsystem_devtype(
+                                               udev_monitor,
+                                               uevent_subsystem[i],
+                                               uevent_devtype[i]);
+               if (ret < 0) {
+                       _E("failed to add filter with subsystem(%s)/devtype(%s)\n",
+                                       uevent_subsystem[i], uevent_devtype[i]);
+                       goto err_udev_monitor;
+               }
+       }
+
+       ret = udev_monitor_filter_update(udev_monitor);
+       if (ret < 0) {
+               for (i = 0; i < number_of_uevent; i++) {
+                       _E("failed to update filter with subsystem(%s)/devtype(%s)\n",
+                               uevent_subsystem[i], uevent_devtype[i]);
+               }
+               goto err_udev_monitor;
+       }
+
+       /* Register callback to subscribe the event */
+       fd = udev_monitor_get_fd(udev_monitor);
+       if (fd <= 0) {
+               _E("failed to get file descriptor of udev monitor\n");
+               ret = -EINVAL;
+               goto err_udev_monitor;
+       }
+
+       gfd = g_unix_fd_add(fd, G_IO_IN, uevent_func, user_data);
+       if (gfd <= 0) {
+               _E("failed to add uevent-based callback function\n");
+               ret = -EINVAL;
+               goto err_udev_monitor;
+       }
+
+       /* Bind udev-monitor to enable the udev monitoring */
+       ret = udev_monitor_enable_receiving(udev_monitor);
+       if (ret < 0) {
+               _E("failed to bind udev monitor for receiving the event\n");
+               ret = -EAGAIN;
+               goto err_udev_monitor_fd;
+       }
+
+       /* Add new uevent-based handler to uevent_list */
+       uevent_data = calloc(1, sizeof(*uevent_data));
+       uevent_data->udev_monitor = udev_monitor;
+       uevent_data->fd = gfd;
+       g_uevent_list = g_list_append(g_uevent_list, (gpointer)uevent_data);
+
+       return udev_monitor;
+
+err_udev_monitor_fd:
+       g_source_remove(gfd);
+       gfd = -1;
+err_udev_monitor:
+       udev_monitor_unref(udev_monitor);
+       udev_monitor = NULL;
+
+       return NULL;
+}
+
+void delete_uevent_handler(struct udev_monitor *udev_monitor)
+{
+       struct uevent_data *uevent_data;
+
+       if (!udev_monitor)
+               return;
+
+       uevent_data = find_uevent_data(udev_monitor);
+       if (!uevent_data)
+               return;
+
+       g_uevent_list = g_list_remove(g_uevent_list, (gpointer)uevent_data->udev_monitor);
+       udev_monitor_unref(uevent_data->udev_monitor);
+       uevent_data->udev_monitor = NULL;
+
+       g_source_remove(uevent_data->fd);
+       uevent_data->fd = -1;
+}
+
+void init_timer(void)
+{
+       g_timer_list = NULL;
+       g_uevent_list = NULL;
+
+       g_udev = udev_new();
+       if (!g_udev)
+               _E("failed to create udev for uevent-based monitor\n");
+}
+
+void exit_timer(void)
+{
+       /*
+        * FIXME: Need to iterate the g_timer_list, g_uevent_list
+        * in order to release memory
+        */
+
+       g_list_free(g_timer_list);
+       g_list_free(g_uevent_list);
+
+       g_timer_list = NULL;
+       g_uevent_list = NULL;
+
+       udev_unref(g_udev);
+}