acassis commented on code in PR #3192: URL: https://github.com/apache/nuttx-apps/pull/3192#discussion_r2444912471
########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, Review Comment: Please consider using strncmp() instead to avoid stack overflow ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); Review Comment: Please always start error, warn, info message with Upper case, because if the text get mixed with other logs it will be easy to spot the beginning of the new message ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); + } + else + { + init_warn("command '%s' pid %d took %d ms", am->running->argv[0], Review Comment: Ditto: Command ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); + } + else + { + init_warn("command '%s' pid %d took %d ms", am->running->argv[0], + am->pid_running, ms); + } + } +#endif + + am->pid_running = -1; + if (list_is_tail(&ready->cmds, &am->running->node)) + { + am->running = NULL; + list_delete(&ready->ready_node); + } + else + { + am->running = list_next_entry(am->running, struct action_cmd_s, node); + } +} + +int init_action_parse(FAR const struct parser_s *parser, + bool create, FAR char *buf) +{ + FAR struct action_manager_s *am = parser->priv; + FAR char *argv[ACTION_ARGUMENTS_MAX]; + FAR struct action_cmd_s *cmd; + FAR struct action_s *a; + int ret; + + if (create) + { + ret = init_parse_arguments(buf, false, nitems(argv), argv); + if (ret < 2) + { + init_err("invalid argument: %s", buf); + return -EINVAL; + } + + a = calloc(1, sizeof(*a)); + if (a == NULL) + { + init_err("alloc"); Review Comment: Alloc action failed ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); + } + else + { + init_warn("command '%s' pid %d took %d ms", am->running->argv[0], + am->pid_running, ms); + } + } +#endif + + am->pid_running = -1; + if (list_is_tail(&ready->cmds, &am->running->node)) + { + am->running = NULL; + list_delete(&ready->ready_node); + } + else + { + am->running = list_next_entry(am->running, struct action_cmd_s, node); + } +} + +int init_action_parse(FAR const struct parser_s *parser, + bool create, FAR char *buf) +{ + FAR struct action_manager_s *am = parser->priv; + FAR char *argv[ACTION_ARGUMENTS_MAX]; + FAR struct action_cmd_s *cmd; + FAR struct action_s *a; + int ret; + + if (create) + { + ret = init_parse_arguments(buf, false, nitems(argv), argv); + if (ret < 2) + { + init_err("invalid argument: %s", buf); + return -EINVAL; + } + + a = calloc(1, sizeof(*a)); + if (a == NULL) + { + init_err("alloc"); + return -errno; + } + + list_initialize(&a->cmds); + + a->event = strdup(argv[--ret]); + if (a->event == NULL) + { + init_err("event trigger"); + free(a); + return -errno; + } + + list_add_tail(&am->actions, &a->node); + init_debug("add action %p(%s) to manager %p", a, argv[1], am); + } + else + { + cmd = calloc(1, sizeof(*cmd)); + if (cmd == NULL) + { + init_err("alloc"); Review Comment: Alloc cmd failed! There are many "alloc" errors, it will be difficult to users discover where it is failing if you don't use unique error messages ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); + } + else + { + init_warn("command '%s' pid %d took %d ms", am->running->argv[0], + am->pid_running, ms); + } + } +#endif + + am->pid_running = -1; + if (list_is_tail(&ready->cmds, &am->running->node)) + { + am->running = NULL; + list_delete(&ready->ready_node); + } + else + { + am->running = list_next_entry(am->running, struct action_cmd_s, node); + } +} + +int init_action_parse(FAR const struct parser_s *parser, + bool create, FAR char *buf) +{ + FAR struct action_manager_s *am = parser->priv; + FAR char *argv[ACTION_ARGUMENTS_MAX]; + FAR struct action_cmd_s *cmd; + FAR struct action_s *a; + int ret; + + if (create) + { + ret = init_parse_arguments(buf, false, nitems(argv), argv); + if (ret < 2) + { + init_err("invalid argument: %s", buf); + return -EINVAL; + } + + a = calloc(1, sizeof(*a)); + if (a == NULL) + { + init_err("alloc"); + return -errno; + } + + list_initialize(&a->cmds); + + a->event = strdup(argv[--ret]); + if (a->event == NULL) + { + init_err("event trigger"); + free(a); + return -errno; + } + + list_add_tail(&am->actions, &a->node); + init_debug("add action %p(%s) to manager %p", a, argv[1], am); + } + else + { + cmd = calloc(1, sizeof(*cmd)); + if (cmd == NULL) + { + init_err("alloc"); + return -errno; + } + + cmd->argc = init_parse_arguments(buf, true, nitems(cmd->argv) - 1, + cmd->argv); + if (cmd->argc < 1) + { + free(cmd); + init_err("invalid argument"); Review Comment: Invalid cmd argument ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); + } + else + { + init_warn("command '%s' pid %d took %d ms", am->running->argv[0], + am->pid_running, ms); + } + } +#endif + + am->pid_running = -1; + if (list_is_tail(&ready->cmds, &am->running->node)) + { + am->running = NULL; + list_delete(&ready->ready_node); + } + else + { + am->running = list_next_entry(am->running, struct action_cmd_s, node); + } +} + +int init_action_parse(FAR const struct parser_s *parser, + bool create, FAR char *buf) +{ + FAR struct action_manager_s *am = parser->priv; + FAR char *argv[ACTION_ARGUMENTS_MAX]; + FAR struct action_cmd_s *cmd; + FAR struct action_s *a; + int ret; + + if (create) + { + ret = init_parse_arguments(buf, false, nitems(argv), argv); + if (ret < 2) + { + init_err("invalid argument: %s", buf); Review Comment: Ditto ########## system/init/action.c: ########## @@ -0,0 +1,346 @@ +/**************************************************************************** + * apps/system/init/action.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/types.h> +#include <sys/param.h> +#include <unistd.h> + +#include "action.h" +#include "builtin.h" +#include "init.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Maximum number of parameters for the action trigger. + * Format: `on <trigger>` + */ + +#define ACTION_ARGUMENTS_MAX 2 + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action); +#else +# define init_dump_action(a) +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SYSTEM_INIT_DEBUG +static void init_dump_action(FAR struct action_s *action) +{ + FAR struct action_cmd_s *cmd; + + init_debug("action %p", action); + init_debug(" event trigger: '%s'", action->event ? action->event : ""); + list_for_every_entry(&action->cmds, cmd, struct action_cmd_s, node) + { + init_dump_args(cmd->argc, cmd->argv); + } +} +#endif + +static void add_ready(FAR struct action_manager_s *am, + FAR struct action_s *a) +{ + FAR struct action_s *ready; +#ifdef CONFIG_SYSTEM_INIT_DEBUG + FAR struct action_cmd_s *cmd; + + list_for_every_entry(&a->cmds, cmd, struct action_cmd_s, node) + { + init_debug("add ready %p %s", cmd, cmd->argv[0]); + } +#endif + + list_for_every_entry(&am->ready_actions, ready, struct action_s, + ready_node) + { + if (ready == a) + { + init_debug("action %p(%s) already on the queue", a, + a->event ? a->event : ""); + init_dump_action(a); + return; + } + } + + list_add_tail(&am->ready_actions, &a->ready_node); +} + +static void update_ready(FAR struct action_manager_s *am) +{ + size_t i; + + /* Actions with event trigger */ + + for (i = 0; i < nitems(am->events); i++) + { + if (!am->events[i]) + { + continue; + } + + am->current = list_prepare_entry(am->current, &am->actions, + struct action_s, node); + list_for_every_entry_continue(am->current, &am->actions, + struct action_s, node) + { + if (am->current->event && !strcmp(am->current->event, + am->events[i])) + { + add_ready(am, am->current); + return; + } + } + + init_debug("remove event [%zu] '%s'", i, am->events[i]); + am->current = NULL; + free(am->events[i]); + am->events[i] = NULL; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int init_action_add_event(FAR struct action_manager_s *am, + FAR const char *event) +{ + int ret = -ENOBUFS; + size_t i; + + for (i = 0; i < nitems(am->events); i++) + { + if (am->events[i]) + { + continue; + } + + am->events[i] = strdup(event); + if (am->events[i]) + { + init_debug("add event [%zu] '%s'", i, am->events[i]); + return 0; + } + + ret = -errno; + break; + } + + init_warn("drop event '%s' %d", event, ret); + return ret; +} + +/**************************************************************************** + * Name: init_action_run_command + * + * Description: + * Execute the ready commands in the action. + * + * Input Parameters: + * am - Instance of Action Manager + * + * Returned Value: + * The expected next call interval (in milliseconds), where INT_MAX + * indicates blocking. + ****************************************************************************/ + +int init_action_run_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready; + int ret; + + if (am->pid_running != -1) + { + init_debug("waiting '%s' pid %d", am->running->argv[0], + am->pid_running); + return INT_MAX; + } + + update_ready(am); + if (list_is_empty(&am->ready_actions)) + { + return INT_MAX; + } + + ready = list_peek_head_type(&am->ready_actions, struct action_s, + ready_node); + + if (!am->running) + { + am->running = list_peek_head_type(&ready->cmds, + struct action_cmd_s, node); + } + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + clock_gettime(CLOCK_MONOTONIC, &am->time_run); +#endif + ret = init_builtin_run(am, am->running->argc, am->running->argv); + if (ret > 0) + { + am->pid_running = ret; + } + else + { + init_action_reap_command(am); + } + + return 0; +} + +void init_action_reap_command(FAR struct action_manager_s *am) +{ + FAR struct action_s *ready = list_peek_head_type(&am->ready_actions, + struct action_s, + ready_node); + +#if defined(CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) && \ + CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW > 0 + struct timespec time; + int ms; + + clock_gettime(CLOCK_MONOTONIC, &time); + clock_timespec_subtract(&time, &am->time_run, &time); + ms = TIMESPEC2MS(time); + if (ms > CONFIG_SYSTEM_INIT_ACTION_WARN_SLOW) + { + if (am->pid_running <= 0) + { + init_warn("command '%s' took %d ms", am->running->argv[0], ms); + } + else + { + init_warn("command '%s' pid %d took %d ms", am->running->argv[0], + am->pid_running, ms); + } + } +#endif + + am->pid_running = -1; + if (list_is_tail(&ready->cmds, &am->running->node)) + { + am->running = NULL; + list_delete(&ready->ready_node); + } + else + { + am->running = list_next_entry(am->running, struct action_cmd_s, node); + } +} + +int init_action_parse(FAR const struct parser_s *parser, + bool create, FAR char *buf) +{ + FAR struct action_manager_s *am = parser->priv; + FAR char *argv[ACTION_ARGUMENTS_MAX]; + FAR struct action_cmd_s *cmd; + FAR struct action_s *a; + int ret; + + if (create) + { + ret = init_parse_arguments(buf, false, nitems(argv), argv); + if (ret < 2) + { + init_err("invalid argument: %s", buf); + return -EINVAL; + } + + a = calloc(1, sizeof(*a)); + if (a == NULL) + { + init_err("alloc"); + return -errno; + } + + list_initialize(&a->cmds); + + a->event = strdup(argv[--ret]); + if (a->event == NULL) + { + init_err("event trigger"); Review Comment: Event trigger -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
