2020-11-19 19:41:37 +01:00
|
|
|
/****************************************************************************
|
2021-03-08 14:32:13 +01:00
|
|
|
* apps/examples/watcher/task_mn.c
|
2020-11-19 19:41:37 +01:00
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
{
|
2021-03-08 14:32:13 +01:00
|
|
|
printf("Error: cannot open /dev/note\n");
|
2020-11-19 19:41:37 +01:00
|
|
|
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)
|
|
|
|
{
|
2021-03-08 14:32:13 +01:00
|
|
|
printf("%s fed the dog.\n", task.taskname);
|
2020-11-19 19:41:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-08 14:32:13 +01:00
|
|
|
printf("%s starved the dog.\n", task.taskname);
|
2020-11-19 19:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close the note driver */
|
|
|
|
|
|
|
|
close(notefd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-08 14:32:13 +01:00
|
|
|
printf("Error: Task list is empty to print\n");
|
2020-11-19 19:41:37 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|