argos-watchdog: support multiple types of watchdog 69/189669/6 submit/tizen/20181004.144412
authorByungSoo Kim <bs1770.kim@samsung.com>
Mon, 6 Aug 2018 10:15:18 +0000 (19:15 +0900)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 4 Oct 2018 09:05:24 +0000 (11:05 +0200)
- systemd watchdog :
  systemd daemon can use watchdog by calling the function sd_notify
  If each service wants to run the systemd watchdog,
  it have to declare "NotifyAccess=main" or "WatchdogSec=xx" in the service file.

- application watchdog :
  All process including system daemon, UI app, service app and so on can use the watchdog
  with type dbus.
  It will trigger the watchdog to resourced with dbus asynchronous call.
  Resourced will consider the device suspend / reusme as well as application life cycle.

- thread watchdog :
  If some process doesn't have any dependency with other daemon,
  it can trigger the watchdog by itself using pthread.
  It is the basic method which is used in many parts.

Change-Id: I3ef136b173f7649debffa0440bbecb9ebb76f78e
Signed-off-by: ByungSoo Kim <bs1770.kim@samsung.com>
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
CMakeLists.txt
include/argos.h
include/common.h
src/argos.c
src/argos_dbus.c [new file with mode: 0644]
src/argos_internal.c [new file with mode: 0644]
src/argos_thread.c [new file with mode: 0644]

index 80f9979..4f52587 100644 (file)
@@ -7,7 +7,11 @@ SET(EXEC_PREFIX "${PREFIX}/bin")
 SET(LIBDIR "${LIB_INSTALL_DIR}")
 SET(INCLUDEDIR "${PREFIX}/include/${PROJECT_NAME}")
 SET(SRCS
-       src/argos.c)
+       src/argos.c
+       src/argos_dbus.c
+       src/argos_thread.c
+       src/argos_internal.c
+)
 
 SET(HEADERS
        include/argos.h)
index 1a8ad79..2c9c786 100644 (file)
@@ -34,6 +34,12 @@ typedef enum {
        AW_OP_CHANGE_TIMEOUT,   /**< change watchdog timeout **/
 } aw_op_e;
 
+typedef enum {
+       AW_TYPE_DEFAULT,        /**< use systemd or smdl **/
+       AW_TYPE_THREAD,         /**< use internal pthread **/
+       AW_TYPE_DBUS,           /**< use resourced by dbus **/
+} aw_type_e;
+
 /**
  * @brief Register watchdog.
  *
@@ -47,6 +53,16 @@ typedef enum {
 int aw_register(unsigned int timeout);
 
 /**
+ * @brief Register watchdog with specific type
+ *
+ * @remarks
+ *
+ * @return 0 on success, otherwise a errno-style error value.
+ *
+ */
+int aw_register_ex(aw_type_e type, unsigned int timeout);
+
+/**
  * @brief Control watchdog operation.
  *
  * @since_tizen 2.4
index f7a7c5f..0f594bb 100644 (file)
 #define _W(fmt, arg...) SLOGW(fmt, ##arg)
 #define _E(fmt, arg...) SLOGE(fmt, ##arg)
 
+/* basic watchdog functions */
 int _aw_register(unsigned int timeout);
 int _aw_control(aw_op_e op, void *data);
 int _aw_notify(void);
 
+/* for detecting watchdog in internal pthread */
+int aw_register_thread(unsigned int timeout);
+int aw_control_thread(aw_op_e op, void *data);
+int aw_notify_thread(void);
+
+/* for detecting watchdog in resourced using dbus */
+int aw_register_dbus(unsigned int timeout);
+int aw_control_dbus(aw_op_e op, void *data);
+int aw_notify_dbus(void);
+
+void aw_notify_watchdog(void);
+
 #endif
index 62d2824..dfaa8ad 100644 (file)
 
 #include "common.h"
 
+static aw_type_e current_type;
+
 API int aw_register(unsigned int timeout)
 {
-       return _aw_register(timeout);
+       return aw_register_ex(AW_TYPE_DEFAULT, timeout);
+}
+
+API int aw_register_ex(aw_type_e type, unsigned int timeout)
+{
+       current_type = type;
+
+       if (type == AW_TYPE_THREAD)
+               return aw_register_thread(timeout);
+       else if (type == AW_TYPE_DBUS)
+               return aw_register_dbus(timeout);
+       else
+               return _aw_register(timeout);
 }
 
 API int aw_control(aw_op_e op, void *data)
 {
-       return _aw_control(op,data);
+       aw_type_e type = current_type;
+
+       if (type == AW_TYPE_THREAD)
+               return aw_control_thread(op,data);
+       else if (type == AW_TYPE_DBUS)
+               return aw_control_dbus(op,data);
+       else
+               return _aw_control(op,data);
 }
 
 API int aw_notify(void)
 {
-       return _aw_notify();
+       aw_type_e type = current_type;
+
+       if (type == AW_TYPE_THREAD)
+               return aw_notify_thread();
+       else if (type == AW_TYPE_DBUS)
+               return aw_notify_dbus();
+       else
+               return _aw_notify();
 }
diff --git a/src/argos_dbus.c b/src/argos_dbus.c
new file mode 100644 (file)
index 0000000..69539cd
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2018 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 "common.h"
+#include <stdlib.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define RESOURCED_DBUS_BUS_NAME        "org.tizen.resourced"
+#define RESOURCED_PATH_PROCESS         "/Org/Tizen/ResourceD/Watchdog"
+#define RESOURCED_INTERFACE_PROCESS    "org.tizen.resourced.watchdog"
+#define WATCHDOG_START                 "Start"
+
+static unsigned int dbus_watchdog_timeout=0;
+
+static int aw_send_watchdog(unsigned int timeout)
+{
+       int ret = 0;
+       static GDBusConnection *g_dbus_conn = NULL;
+       GVariant *param = NULL;
+
+       if (!g_dbus_conn)
+               g_dbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+
+       if (!g_dbus_conn)
+               return -EINVAL;
+
+       param = g_variant_new("(iu)", getpid(), timeout);
+       g_dbus_connection_call(g_dbus_conn, RESOURCED_DBUS_BUS_NAME,
+                       RESOURCED_PATH_PROCESS, RESOURCED_INTERFACE_PROCESS, WATCHDOG_START,
+                       param, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+
+       return ret;
+}
+
+int aw_register_dbus(unsigned int timeout)
+{
+       int ret = 0;
+
+       if (timeout == 0)
+               return -EINVAL;
+
+       aw_send_watchdog(timeout);
+       dbus_watchdog_timeout = timeout;
+       return ret;
+}
+
+int aw_control_dbus(aw_op_e op, void *data)
+{
+       int ret = 0;
+       unsigned int* timeout;
+
+       switch(op){
+       case AW_OP_DISABLE:
+               ret = aw_send_watchdog(0);
+               break;
+
+       case AW_OP_ENABLE:
+               ret = aw_send_watchdog(dbus_watchdog_timeout);
+               break;
+
+       case AW_OP_CHANGE_TIMEOUT:
+               timeout = (unsigned int*)(data);
+               if(timeout == NULL){
+                       ret = -1;
+                       break;
+               }
+               dbus_watchdog_timeout = *timeout;
+               ret = aw_send_watchdog(*timeout);
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+
+       return ret;
+}
+
+int aw_notify_dbus(void)
+{
+       return aw_send_watchdog(dbus_watchdog_timeout);
+}
+
diff --git a/src/argos_internal.c b/src/argos_internal.c
new file mode 100644 (file)
index 0000000..8891e4d
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 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 "common.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <glib.h>
+#include <gio/gio.h>
+
+#define RESOURCED_WATCHDOG_PATH        "/Org/Tizen/ResourceD/Process"
+#define RESOURCED_WATCHDOG_INTERFACE   "org.tizen.resourced.process"
+#define RESOURCED_WATCHDOG_SIGNAL      "ProcWatchdog"
+
+void aw_notify_watchdog(void)
+{
+       GDBusConnection *conn;
+       GError *err = NULL;
+       int pid, pgid;
+       int command = SIGKILL;
+
+       pid = getpid();
+       if (pid < 1)
+               return;
+
+       pgid = getpgid(pid);
+       if (pgid < 1)
+               return;
+
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+       if (!conn)
+               return;
+
+       _I("detect watchdog %d", pgid);
+       g_dbus_connection_emit_signal(conn, NULL, RESOURCED_WATCHDOG_PATH,
+                               RESOURCED_WATCHDOG_INTERFACE, RESOURCED_WATCHDOG_SIGNAL,
+                               g_variant_new("(ii)", pgid, command), &err);
+
+       g_dbus_connection_flush_sync (conn, NULL, &err);
+}
diff --git a/src/argos_thread.c b/src/argos_thread.c
new file mode 100644 (file)
index 0000000..59fc4dc
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018 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 "common.h"
+#include <stdlib.h>
+#include <stdbool.h>
+#include <time.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+static pthread_mutex_t aw_mutex;
+static pthread_cond_t aw_cond;
+
+static unsigned int thread_timeout;
+static bool thread_watchdog_running;
+
+static void *aw_thread_main(void * data)
+{
+       int ret;
+       struct timespec ts;
+
+       while (1) {
+               pthread_mutex_lock(&aw_mutex);
+
+               memset(&ts, 0, sizeof(ts));
+               clock_gettime(CLOCK_MONOTONIC, &ts);
+               _D("current time %lld.%.9ld", (long long)ts.tv_sec, ts.tv_nsec);
+               ts.tv_sec += thread_timeout;
+               _D("wait time %lld.%.9ld", (long long)ts.tv_sec, ts.tv_nsec);
+               ret = pthread_cond_timedwait(&aw_cond, &aw_mutex, &ts);
+               _D("wakeup : %d", ret);
+               if (ret == ETIMEDOUT && thread_watchdog_running) {
+                       aw_notify_watchdog();
+                       break;
+               }
+
+               pthread_mutex_unlock(&aw_mutex);
+       }
+       return NULL;
+}
+
+int aw_register_thread(unsigned int timeout)
+{
+       int ret = 0;
+       pthread_t pth = 0;
+       pthread_condattr_t cattr;
+
+       if (timeout == 0)
+               return -EINVAL;
+
+       pthread_mutex_init(&aw_mutex, NULL);
+       pthread_condattr_init(&cattr);
+       pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
+       pthread_cond_init(&aw_cond, &cattr);
+       thread_timeout = timeout;
+       thread_watchdog_running = true;
+
+       _D("create watchdog thread with %d", thread_timeout);
+       ret = pthread_create(&pth, NULL, &aw_thread_main, (void *)NULL);
+       if (ret)
+               return ret;
+
+       pthread_detach(pth);
+       return ret;
+}
+
+int aw_control_thread(aw_op_e op, void *data)
+{
+       int ret = 0;
+       unsigned int* timeout;
+
+       pthread_mutex_lock(&aw_mutex);
+       switch(op){
+       case AW_OP_DISABLE:
+               thread_watchdog_running = false;
+               break;
+
+       case AW_OP_ENABLE:
+               thread_watchdog_running = true;
+               break;
+
+       case AW_OP_CHANGE_TIMEOUT:
+               timeout = (unsigned int*)(data);
+               if(timeout == NULL){
+                       ret = -1;
+                       break;
+               }
+               thread_timeout = *timeout;
+               break;
+       default:
+               ret = -1;
+               break;
+       }
+       pthread_mutex_unlock(&aw_mutex);
+
+       return ret;
+}
+
+int aw_notify_thread(void)
+{
+       int ret;
+
+       ret = pthread_mutex_trylock(&aw_mutex);
+       if (ret == 0) {
+               _D("send notify");
+               pthread_cond_signal(&aw_cond);
+               pthread_mutex_unlock(&aw_mutex);
+       }
+
+       return ret;
+}