nuttx-apps/examples/watcher/task_mn.c
2021-03-16 11:30:04 -07:00

313 lines
7.4 KiB
C

/****************************************************************************
* apps/examples/watcher/task_mn.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/boardctl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <nuttx/note/noteram_driver.h>
#include "task_mn.h"
/****************************************************************************
* Private Definitions
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
volatile struct request_s request;
struct task_list_s watched_tasks =
{
.head = NULL,
.tail = NULL
};
/****************************************************************************
* Public Functions
****************************************************************************/
void task_mn_print_tasks_status(void)
{
int notefd;
struct noteram_get_taskname_s task;
struct task_node_s *node;
/* If the list is not empty */
if (watched_tasks.head != NULL)
{
/* Open the note driver */
notefd = open("/dev/note", O_RDONLY);
if (notefd < 0)
{
printf("Error: cannot open /dev/note\n");
return;
}
/* Print all the nodes */
for (node = watched_tasks.head; node != NULL; node = node->next)
{
task.pid = node->task_id;
ioctl(notefd, NOTERAM_GETTASKNAME, (unsigned long)&task);
if (node->reset)
{
printf("%s fed the dog.\n", task.taskname);
}
else
{
printf("%s starved the dog.\n", task.taskname);
}
}
/* Close the note driver */
close(notefd);
}
else
{
printf("Error: Task list is empty to print\n");
}
}
void task_mn_reset_all(void)
{
struct task_node_s *node;
for (node = watched_tasks.head; node != NULL; node = node->next)
{
node->reset = false;
}
}
struct task_node_s *task_mn_is_task_subscribed(pid_t id)
{
struct task_node_s *node;
/* If list is not empty */
if (watched_tasks.head != NULL)
{
/* Search for the node */
for (node = watched_tasks.head; node != NULL; node = node->next)
{
if (node->task_id == id)
{
return node;
}
}
}
return NULL;
}
void task_mn_add_to_list(pid_t id)
{
struct task_node_s *node;
/* Alloc the node */
node = malloc(sizeof(struct task_node_s));
if (node == NULL)
{
fprintf(stderr, "watcher daemon: Couldn't alloc a node to list\n");
return;
}
node->task_id = id;
/* NOTE: Once a task is subscribed, its initial status is that it fed the
* dog. This approach was used first to avoid a false-positive result,
* e.g., the task has been subscribed immediately before the watchdog
* expiration and it did not feed the dog within this interval,
* so the wdt handler would be triggered even if the subscribed
* task would feed the dog in time.
* The second reason is that we can consider the subscription request
* itself an advertisement that the watched task is alive and not stuck.
*/
node->reset = true;
node->next = NULL;
/* If list is not empty */
if (watched_tasks.head != NULL)
{
watched_tasks.tail->next = node;
}
else
{
watched_tasks.head = node;
}
watched_tasks.tail = node;
}
void task_mn_remove_from_list(pid_t id)
{
struct task_node_s *prev;
struct task_node_s *current;
/* If list is empty */
if (watched_tasks.head == NULL)
{
fprintf(stderr, "watcher daemon: List is empty\n");
return;
}
/* First element */
else if (watched_tasks.head->task_id == id)
{
if (watched_tasks.head == watched_tasks.tail)
{
free(watched_tasks.head);
watched_tasks.head = NULL;
watched_tasks.tail = NULL;
return;
}
else
{
prev = watched_tasks.head;
watched_tasks.head = prev->next;
free(prev);
return;
}
}
else
{
/* Search the node */
prev = watched_tasks.head;
current = prev->next;
while (current != NULL)
{
if (current->task_id == id)
{
prev->next = current->next;
/* In case the one that will be removed is the tail */
if (prev->next == NULL)
{
watched_tasks.tail = prev;
}
free(current);
return;
}
prev = prev->next;
current = current->next;
}
}
fprintf(stderr, "watcher daemon: This node is not in the list.\n");
}
void task_mn_get_task_name(struct noteram_get_taskname_s *task)
{
int notefd;
notefd = open("/dev/note", O_RDONLY);
if (notefd < 0)
{
fprintf(stderr, "trace: cannot open /dev/note\n");
return;
}
ioctl(notefd, NOTERAM_GETTASKNAME, (unsigned long)task);
close(notefd);
}
void task_mn_subscribe(pid_t id)
{
struct noteram_get_taskname_s task;
/* Verify if the task exists in the list */
if (task_mn_is_task_subscribed(id) != NULL)
{
task.pid = id;
task_mn_get_task_name(&task);
printf("Task %s was already subscribed\n", task.taskname);
}
else
{
/* If it doesn't, include it to the list */
task_mn_add_to_list(id);
}
}
void task_mn_unsubscribe(pid_t id)
{
struct noteram_get_taskname_s task;
/* Verify if the task exists in the list */
if (task_mn_is_task_subscribed(id) != NULL)
{
/* If it does, remove it from the list */
task_mn_remove_from_list(id);
}
else
{
task.pid = id;
task_mn_get_task_name(&task);
printf("Task %s is not subscribed\n", task.taskname);
}
}
bool task_mn_all_tasks_fed(void)
{
struct task_node_s *node;
for (node = watched_tasks.head; node != NULL; node = node->next)
{
/* If at least one did not feed the dog, return false */
if (node->reset == false)
{
return false;
}
}
return true;
}