From e76938c1566d3f03467091e3c127fa08c3b7a403 Mon Sep 17 00:00:00 2001 From: anjiahao Date: Wed, 27 Dec 2023 14:57:30 +0800 Subject: [PATCH] nsh:support wait command to wait task exit. usage like: nsh> sleep 10 & [5:100] nsh>set pid1=$! nsh>sleep 15 & [6:100] nsh>set pid2=$! nsh>wait $pid1 $pid2 'wait' command will block nsh from running until pid1 and pid2 finish. This is useful for parallel requirements to perform certain tasks Signed-off-by: anjiahao --- nshlib/CMakeLists.txt | 4 ++ nshlib/Kconfig | 5 ++ nshlib/Makefile | 4 ++ nshlib/nsh.h | 4 ++ nshlib/nsh_command.c | 4 ++ nshlib/nsh_parse.c | 12 ++-- nshlib/nsh_wait.c | 147 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 nshlib/nsh_wait.c diff --git a/nshlib/CMakeLists.txt b/nshlib/CMakeLists.txt index ae3b8dcd8f3..b7d3fc50d88 100644 --- a/nshlib/CMakeLists.txt +++ b/nshlib/CMakeLists.txt @@ -98,6 +98,10 @@ if(CONFIG_NSH_LIBRARY) list(APPEND CSRCS nsh_test.c) endif() + if(NOT CONFIG_NSH_DISABLE_WAIT) + list(APPEND CSRCS nsh_wait.c) + endif() + if(CONFIG_USBDEV) list(APPEND CSRCS nsh_usbconsole.c) endif() diff --git a/nshlib/Kconfig b/nshlib/Kconfig index b6899b452c0..72e117c0a78 100644 --- a/nshlib/Kconfig +++ b/nshlib/Kconfig @@ -699,6 +699,11 @@ config NSH_DISABLE_IRQ_AFFINITY default DEFAULT_SMALL depends on BOARDCTL_IRQ_AFFINITY +config NSH_DISABLE_WAIT + bool "Disable wait" + default DEFAULT_SMALL + depends on SCHED_WAITPID + endmenu if MMCSD diff --git a/nshlib/Makefile b/nshlib/Makefile index fb7aed89c23..808d63af500 100644 --- a/nshlib/Makefile +++ b/nshlib/Makefile @@ -82,6 +82,10 @@ ifneq ($(CONFIG_NSH_DISABLESCRIPT),y) CSRCS += nsh_test.c endif +ifneq ($(CONFIG_NSH_DISABLE_WAIT),y) +CSRCS += nsh_wait.c +endif + ifeq ($(CONFIG_USBDEV),y) CSRCS += nsh_usbconsole.c endif diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 9220502f392..afdf73814e2 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -1226,6 +1226,10 @@ int cmd_alias(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv); int cmd_unalias(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv); #endif +#if !defined(CONFIG_NSH_DISABLE_WAIT) && defined(CONFIG_SCHED_WAITPID) +int cmd_wait(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv); +#endif + /**************************************************************************** * Name: nsh_extmatch_count * diff --git a/nshlib/nsh_command.c b/nshlib/nsh_command.c index 64932e419f9..41808f5e4e6 100644 --- a/nshlib/nsh_command.c +++ b/nshlib/nsh_command.c @@ -666,6 +666,10 @@ static const struct cmdmap_s g_cmdmap[] = #ifndef CONFIG_NSH_DISABLE_XD CMD_MAP("xd", cmd_xd, 3, 3, " "), +#endif +#if !defined(CONFIG_NSH_DISABLE_WAIT) && defined(CONFIG_SCHED_WAITPID) + CMD_MAP("wait", cmd_wait, 1, CONFIG_NSH_MAXARGUMENTS, + "pid1 [pid2 [pid3] ...]"), #endif CMD_MAP(NULL, NULL, 1, 1, NULL) }; diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index 14cf1e87977..d75920854e8 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -503,6 +503,12 @@ static pthread_addr_t nsh_child(pthread_addr_t arg) _info("BG %s complete\n", carg->argv[0]); nsh_releaseargs(carg); + + /* Detach from the pthread since we are not going to join with it. + * Otherwise, we would have a memory leak. + */ + + pthread_detach(pthread_self()); return (pthread_addr_t)((uintptr_t)ret); } #endif @@ -843,12 +849,6 @@ static int nsh_execute(FAR struct nsh_vtbl_s *vtbl, goto errout; } - /* Detach from the pthread since we are not going to join with it. - * Otherwise, we would have a memory leak. - */ - - pthread_detach(thread); - nsh_output(vtbl, "%s [%d:%d]\n", argv[0], thread, param.sched_priority); } diff --git a/nshlib/nsh_wait.c b/nshlib/nsh_wait.c new file mode 100644 index 00000000000..f91c0b74f1f --- /dev/null +++ b/nshlib/nsh_wait.c @@ -0,0 +1,147 @@ +/**************************************************************************** + * apps/nshlib/nsh_wait.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 + +#include +#include +#include +#include +#include + +#include "nsh.h" +#include "nsh_console.h" + +#if !defined(CONFIG_NSH_DISABLE_WAIT) && defined(CONFIG_SCHED_WAITPID) + +static const char g_groupid[] = "Group:"; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: cmd_wait + * + * Description: + * Handle 'cmd_wait' command from terminal. + * wait pid1 [pid2 [pid3] ..] - wait for a pid to exit. + * + * Input Parameters: + * vtbl - The NSH console. + * argc - Amount of argument strings in command. + * argv - The argument strings. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int cmd_wait(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv) +{ + FAR char *nextline; + FAR char *line; + char buf[128]; + char path[32]; + int status = 0; + int ret = OK; + pid_t self; + pid_t tid; + int fd; + + if (argc == 1) + { + return OK; + } + + self = getpid(); + for (int i = 1; i < argc; i++) + { + tid = atoi(argv[i]); + if (tid == 0) + { + continue; + } + + snprintf(path, sizeof(path), "/proc/%d/status", tid); + fd = open(path, O_RDONLY); + if (fd < 0) + { + nsh_error(vtbl, g_fmtcmdfailed, argv[0], "wait", NSH_ERRNO); + continue; + } + + ret = read(fd, buf, sizeof(buf) - 1); + if (ret < 0) + { + nsh_error(vtbl, g_fmtcmdfailed, argv[0], "wait", NSH_ERRNO); + close(fd); + continue; + } + + close(fd); + nextline = buf; + do + { + line = nextline; + for (nextline++; + *nextline != '\0' && *nextline != '\n'; + nextline++); + + if (*nextline == '\n') + { + *nextline++ = '\0'; + } + else + { + nextline = NULL; + } + + if (strncmp(line, g_groupid, sizeof(g_groupid) - 1) == 0) + { + if (atoi(line + sizeof(g_groupid)) == self) + { + ret = pthread_join(tid, (FAR pthread_addr_t *)&status); + } + else + { + ret = waitpid(tid, &status, 0); + } + + if (ret < 0) + { + nsh_error(vtbl, g_fmtcmdfailed, + argv[0], "wait", NSH_ERRNO); + } + + break; + } + } + while (nextline != NULL); + } + + return ret < 0 ? ret : status; +} + +#endif /* CONFIG_NSH_DISABLE_WAIT */