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 80f9979d2e50c100bc78e9b0948c75b261d5c419..4f52587fd3da5ab5b7b0b749067f7b6c8c6d1457 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 1a8ad794e61968ab2e03b24dd8605d605ae6c467..2c9c7869074ff6842e3edbdf0b9d1d8f52ffb448 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.
  *
@@ -46,6 +52,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.
  *
index f7a7c5f3637066584acc8b2134f6ee21dda5f20a..0f594bb546da3b3d980c4ff06c812d48538fc9c9 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 62d2824d668fd026aa55df3df1754e58f4332a54..dfaa8ad6d8c4c0fc22657ca03d3d6a541a668e94 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;
+}