src/resource/resource-bus.c
src/resource/resource-gpu.c
src/resource/resource-memory.c
+ src/monitor/monitor.c
+ src/monitor/monitor-thread.c
+ src/monitor/monitor-command.c
)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2022 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 __MONITOR_H__
+#define __MONITOR_H__
+
+#include <util/resource.h>
+#include <util/thread.h>
+#include <util/queue.h>
+
+#define MONITOR_POLLING_DURATION 100
+
+struct monitor_command {
+ struct resource *resource;
+ volatile bool done;
+ mtx_t lock;
+ cnd_t signal;
+};
+
+struct monitor {
+ struct thread *thread;
+ struct queue *q;
+ void *priv;
+ mtx_t lock;
+ cnd_t signal;
+};
+
+struct monitor *monitor_get(void);
+int monitor_thread_init(struct monitor *monitor);
+void monitor_thread_exit(struct monitor *monitor);
+
+void monitor_command_wait_done(struct monitor_command *cmd);
+void monitor_command_submit(struct monitor_command *cmd);
+void monitor_command_submit_sync(struct monitor_command *cmd);
+void monitor_command_bind_resource(struct monitor_command *cmd, struct resource *res);
+void monitor_command_unbind_resource(struct monitor_command *cmd);
+int monitor_command_init(struct monitor_command **cmd);
+void monitor_command_exit(struct monitor_command *cmd);
+
+#endif
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2022 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 <util/log.h>
+#include <util/resource.h>
+#include <monitor/monitor.h>
+
+static void _monitor_command_wait_done(struct monitor_command *cmd, int polling)
+{
+ while (!cmd->done) {
+ smp_rmb();
+ if (polling-- <= 0) {
+ mtx_lock(&cmd->lock);
+ cnd_wait(&cmd->signal, &cmd->lock);
+ mtx_unlock(&cmd->lock);
+ /* done at this time */
+ break;
+ }
+ }
+}
+
+void monitor_command_wait_done(struct monitor_command *cmd)
+{
+ _monitor_command_wait_done(cmd, 0);
+}
+
+void monitor_command_submit(struct monitor_command *cmd)
+{
+ struct monitor *monitor = monitor_get();
+
+ cmd->done = false;
+ enqueue(monitor->q, (void *)cmd);
+
+ cnd_signal(&monitor->signal);
+}
+
+void monitor_command_submit_sync(struct monitor_command *cmd)
+{
+ monitor_command_submit(cmd);
+ _monitor_command_wait_done(cmd, MONITOR_POLLING_DURATION);
+}
+
+void monitor_command_bind_resource(struct monitor_command *cmd, struct resource *res)
+{
+ if (cmd->resource) {
+ _E("resource is already bound\n");
+ return;
+ }
+
+ cmd->resource = res;
+}
+
+void monitor_command_unbind_resource(struct monitor_command *cmd)
+{
+ if (!cmd->resource) {
+ _E("resource is not bound yet\n");
+ return;
+ }
+
+ cmd->resource = NULL;
+}
+
+int monitor_command_init(struct monitor_command **cmd)
+{
+ struct monitor_command *new_cmd;
+
+ new_cmd = calloc(1, sizeof(struct monitor_command));
+ if (!new_cmd)
+ return -ENOMEM;
+
+ mtx_init(&new_cmd->lock, mtx_plain);
+ cnd_init(&new_cmd->signal);
+ new_cmd->done = false;
+
+ *cmd = new_cmd;
+
+ return 0;
+}
+
+void monitor_command_exit(struct monitor_command *cmd)
+{
+ cnd_destroy(&cmd->signal);
+ mtx_destroy(&cmd->lock);
+
+ if (cmd->resource)
+ _W("resource is not unbound before destroying request\n");
+
+ free(cmd);
+}
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * Copyright (c) 2022 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 <util/log.h>
+#include <monitor/monitor.h>
+
+thread_local int empty_counter = 0;
+
+static int monitor_func(void *data, void **result)
+{
+ struct monitor *monitor = data;
+ struct monitor_command *cmd;
+
+new_command:
+ if (dequeue(monitor->q, (void *)&cmd) < 0) {
+ if (empty_counter++ > MONITOR_POLLING_DURATION) {
+ empty_counter = 0;
+ mtx_lock(&monitor->lock);
+ cnd_wait(&monitor->signal, &monitor->lock);
+ mtx_unlock(&monitor->lock);
+ goto new_command;
+ }
+ return THREAD_RETURN_CONTINUE;
+ }
+
+ update_resource_attrs(cmd->resource);
+
+ cmd->done = true;
+ smp_wmb();
+
+ cnd_signal(&cmd->signal);
+
+ return THREAD_RETURN_CONTINUE;
+}
+
+int monitor_thread_init(struct monitor *monitor)
+{
+ struct thread *thread;
+ struct queue *queue;
+ int ret;
+
+ ret = create_queue(&queue);
+ if (ret < 0) {
+ _E("failed to create command queue\n");
+ return ret;
+ }
+
+ /* q should be assigned before create daemon thread */
+ monitor->q = queue;
+ monitor->priv = NULL;
+ mtx_init(&monitor->lock, mtx_plain);
+ cnd_init(&monitor->signal);
+
+ ret = create_daemon_thread(&thread, monitor_func, monitor);
+ if (ret < 0) {
+ _E("failed to create monitor thread\n");
+ cnd_destroy(&monitor->signal);
+ mtx_destroy(&monitor->lock);
+ destroy_queue(queue);
+ monitor->q = NULL;
+ return ret;
+ }
+
+ monitor->thread = thread;
+
+ return 0;
+}
+
+void monitor_thread_exit(struct monitor *monitor)
+{
+ if (monitor->thread) {
+ cnd_signal(&monitor->signal);
+ destroy_thread(monitor->thread);
+ monitor->thread = NULL;
+ }
+
+ cnd_destroy(&monitor->signal);
+ mtx_destroy(&monitor->lock);
+
+ if (monitor->q) {
+ destroy_queue(monitor->q);
+ monitor->q = NULL;
+ }
+}
--- /dev/null
+/*
+ * PASS (Power Aware System Service)
+ *
+ * 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.
+ */
+
+#include <glib.h>
+
+#include <util/device-notifier.h>
+#include <util/log.h>
+#include <util/devices.h>
+#include <monitor/monitor.h>
+
+static struct monitor g_monitor;
+
+struct monitor *monitor_get(void)
+{
+ return &g_monitor;
+}
+
+static int monitor_setup(void *data, void *user_data)
+{
+ int ret;
+
+ ret = monitor_thread_init(&g_monitor);
+ if (ret < 0) {
+ _E("failed to initialize monitor thread\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void monitor_init(void *data)
+{
+ /* This is the case of daemon creation: DO NOTHING */
+}
+
+static void monitor_exit(void *data)
+{
+ monitor_thread_exit(&g_monitor);
+ unregister_notifier(DEVICE_NOTIFIER_INIT_DONE, monitor_setup, NULL);
+}
+
+static int monitor_probe(void *data)
+{
+ int ret = 0;
+
+ /*
+ * Register a notifier for the booting-done event. The actual
+ * initialization of the daemon is performed by this notifier after
+ * booting is completely done.
+ */
+ ret = register_notifier(DEVICE_NOTIFIER_INIT_DONE,
+ monitor_setup, NULL);
+ if (ret < 0) {
+ _E("cannot register a callback function \
+ for the booting-done event (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct device_ops monitor_device_ops = {
+ .name = "monitor",
+ .probe = monitor_probe,
+ .init = monitor_init,
+ .exit = monitor_exit,
+};
+
+DEVICE_OPS_REGISTER(&monitor_device_ops)