Skip to content

Commit e00b06c

Browse files
shell: fix threadless option
The shell at some point supported CONFIG_MULTITHREADING=n but this has not been maintained. Adjust the shell to support threadless operation similar to how logging works with no logging thread. With these adjustments, building with CONFIG_SHELL_MINIMAL and CONFIG_MULTITHREADING=n, shells can now be used like logging by calling shell_process() with non-polling backends, like async or irq driven UART based backends. Signed-off-by: Bjarki Arge Andreasen <bjarki.andreasen@nordicsemi.no>
1 parent e5d91b3 commit e00b06c

File tree

4 files changed

+80
-16
lines changed

4 files changed

+80
-16
lines changed

include/zephyr/shell/shell.h

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -961,10 +961,12 @@ struct shell_ctx {
961961
volatile union shell_backend_cfg cfg;
962962
volatile union shell_backend_ctx ctx;
963963

964+
#if CONFIG_MULTITHREADING
964965
struct k_event signal_event;
965-
966966
struct k_mutex wr_mtx;
967967
k_tid_t tid;
968+
#endif
969+
968970
int ret_val;
969971
};
970972

@@ -1000,13 +1002,29 @@ struct shell {
10001002
LOG_INSTANCE_PTR_DECLARE(log);
10011003

10021004
const char *name;
1005+
1006+
#if CONFIG_MULTITHREADING
10031007
struct k_thread *thread;
10041008
k_thread_stack_t *stack;
1009+
#endif
10051010
};
10061011

10071012
extern void z_shell_print_stream(const void *user_ctx, const char *data,
10081013
size_t data_len);
10091014

1015+
#if CONFIG_MULTITHREADING
1016+
#define Z_SHELL_THREAD_DEFINE(_name) \
1017+
static K_KERNEL_STACK_DEFINE(_name##_stack, CONFIG_SHELL_STACK_SIZE); \
1018+
static struct k_thread _name##_thread
1019+
1020+
#define Z_SHELL_THREAD_INIT(_name) \
1021+
.thread = &_name##_thread, \
1022+
.stack = _name##_stack,
1023+
#else
1024+
#define Z_SHELL_THREAD_DEFINE(_name)
1025+
#define Z_SHELL_THREAD_INIT(_name)
1026+
#endif
1027+
10101028
/** @brief Internal macro for defining a shell instance.
10111029
*
10121030
* As it does not create the default shell logging backend it allows to use
@@ -1027,8 +1045,7 @@ extern void z_shell_print_stream(const void *user_ctx, const char *data,
10271045
IS_ENABLED(CONFIG_SHELL_PRINTF_AUTOFLUSH), z_shell_print_stream); \
10281046
LOG_INSTANCE_REGISTER(shell, _name, CONFIG_SHELL_LOG_LEVEL); \
10291047
Z_SHELL_STATS_DEFINE(_name); \
1030-
static K_KERNEL_STACK_DEFINE(_name##_stack, CONFIG_SHELL_STACK_SIZE); \
1031-
static struct k_thread _name##_thread; \
1048+
Z_SHELL_THREAD_DEFINE(_name); \
10321049
static const STRUCT_SECTION_ITERABLE(shell, _name) = { \
10331050
.default_prompt = _prompt, \
10341051
.iface = _transport_iface, \
@@ -1038,8 +1055,9 @@ extern void z_shell_print_stream(const void *user_ctx, const char *data,
10381055
.fprintf_ctx = &_name##_fprintf, \
10391056
.stats = Z_SHELL_STATS_PTR(_name), \
10401057
.log_backend = _log_backend, \
1041-
LOG_INSTANCE_PTR_INIT(log, shell, _name).name = \
1042-
STRINGIFY(_name), .thread = &_name##_thread, .stack = _name##_stack}
1058+
LOG_INSTANCE_PTR_INIT(log, shell, _name).name = STRINGIFY(_name), \
1059+
Z_SHELL_THREAD_INIT(_name) \
1060+
}
10431061

10441062
/**
10451063
* @brief Macro for defining a shell instance.

subsys/shell/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
menuconfig SHELL
99
bool "Shell"
1010
imply LOG_RUNTIME_FILTERING
11-
select EVENTS
11+
select EVENTS if MULTITHREADING
1212

1313
if SHELL
1414

subsys/shell/shell.c

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -559,14 +559,18 @@ static int exec_cmd(const struct shell *sh, size_t argc, const char **argv,
559559
#endif
560560

561561
z_flag_cmd_ctx_set(sh, true);
562+
#if CONFIG_MULTITHREADING
562563
/* Unlock thread mutex in case command would like to borrow
563564
* shell context to other thread to avoid mutex deadlock.
564565
*/
565566
k_mutex_unlock(&sh->ctx->wr_mtx);
567+
#endif
566568
ret_val = sh->ctx->active_cmd.handler(sh, argc,
567569
(char **)argv);
570+
#if CONFIG_MULTITHREADING
568571
/* Bring back mutex to shell thread. */
569572
k_mutex_lock(&sh->ctx->wr_mtx, K_FOREVER);
573+
#endif
570574
z_flag_cmd_ctx_set(sh, false);
571575
}
572576

@@ -1171,13 +1175,21 @@ static void state_collect(const struct shell *sh)
11711175
static void transport_evt_handler(enum shell_transport_evt evt_type, void *ctx)
11721176
{
11731177
struct shell *sh = (struct shell *)ctx;
1178+
1179+
#if CONFIG_MULTITHREADING
11741180
enum shell_signal sig = evt_type == SHELL_TRANSPORT_EVT_RX_RDY
11751181
? SHELL_SIGNAL_RXRDY
11761182
: SHELL_SIGNAL_TXDONE;
11771183

11781184
k_event_post(&sh->ctx->signal_event, sig);
1185+
#endif
1186+
1187+
if (evt_type == SHELL_TRANSPORT_EVT_TX_RDY) {
1188+
z_flag_tx_rdy_set(sh, true);
1189+
}
11791190
}
11801191

1192+
#if CONFIG_MULTITHREADING
11811193
static void shell_log_process(const struct shell *sh)
11821194
{
11831195
bool processed = false;
@@ -1201,6 +1213,7 @@ static void shell_log_process(const struct shell *sh)
12011213

12021214
} while (processed && !k_event_test(&sh->ctx->signal_event, SHELL_SIGNAL_RXRDY));
12031215
}
1216+
#endif
12041217

12051218
static int instance_init(const struct shell *sh,
12061219
const void *transport_config,
@@ -1216,15 +1229,15 @@ static int instance_init(const struct shell *sh,
12161229

12171230
history_init(sh);
12181231

1232+
#if CONFIG_MULTITHREADING
12191233
k_event_init(&sh->ctx->signal_event);
12201234
k_mutex_init(&sh->ctx->wr_mtx);
1235+
#endif
12211236

12221237
if (IS_ENABLED(CONFIG_SHELL_STATS)) {
12231238
sh->stats->log_lost_cnt = 0;
12241239
}
12251240

1226-
z_flag_tx_rdy_set(sh, true);
1227-
12281241
sh->ctx->vt100_ctx.cons.terminal_wid =
12291242
CONFIG_SHELL_DEFAULT_TERMINAL_WIDTH;
12301243
sh->ctx->vt100_ctx.cons.terminal_hei =
@@ -1284,6 +1297,7 @@ static int instance_uninit(const struct shell *sh)
12841297
return 0;
12851298
}
12861299

1300+
#if CONFIG_MULTITHREADING
12871301
typedef void (*shell_signal_handler_t)(const struct shell *sh);
12881302

12891303
static void shell_signal_handle(const struct shell *sh,
@@ -1297,7 +1311,9 @@ static void shell_signal_handle(const struct shell *sh,
12971311
handler(sh);
12981312
k_event_clear(&sh->ctx->signal_event, sig);
12991313
}
1314+
#endif
13001315

1316+
#if CONFIG_MULTITHREADING
13011317
static void kill_handler(const struct shell *sh)
13021318
{
13031319
int err = instance_uninit(sh);
@@ -1311,7 +1327,9 @@ static void kill_handler(const struct shell *sh)
13111327

13121328
CODE_UNREACHABLE;
13131329
}
1330+
#endif
13141331

1332+
#if CONFIG_MULTITHREADING
13151333
void shell_thread(void *shell_handle, void *arg_log_backend,
13161334
void *arg_log_level)
13171335
{
@@ -1358,6 +1376,7 @@ void shell_thread(void *shell_handle, void *arg_log_backend,
13581376
k_mutex_unlock(&sh->ctx->wr_mtx);
13591377
}
13601378
}
1379+
#endif
13611380

13621381
int shell_init(const struct shell *sh, const void *transport_config,
13631382
struct shell_backend_config_flags cfg_flags,
@@ -1366,16 +1385,19 @@ int shell_init(const struct shell *sh, const void *transport_config,
13661385
__ASSERT_NO_MSG(sh);
13671386
__ASSERT_NO_MSG(sh->ctx && sh->iface && sh->default_prompt);
13681387

1388+
#if CONFIG_MULTITHREADING
13691389
if (sh->ctx->tid) {
13701390
return -EALREADY;
13711391
}
1392+
#endif
13721393

13731394
int err = instance_init(sh, transport_config, cfg_flags);
13741395

13751396
if (err != 0) {
13761397
return err;
13771398
}
13781399

1400+
#if CONFIG_MULTITHREADING
13791401
k_tid_t tid = k_thread_create(sh->thread,
13801402
sh->stack, CONFIG_SHELL_STACK_SIZE,
13811403
shell_thread, (void *)sh, (void *)log_backend,
@@ -1384,6 +1406,7 @@ int shell_init(const struct shell *sh, const void *transport_config,
13841406

13851407
sh->ctx->tid = tid;
13861408
k_thread_name_set(tid, sh->name);
1409+
#endif
13871410

13881411
return 0;
13891412
}
@@ -1392,18 +1415,17 @@ void shell_uninit(const struct shell *sh, shell_uninit_cb_t cb)
13921415
{
13931416
__ASSERT_NO_MSG(sh);
13941417

1395-
if (IS_ENABLED(CONFIG_MULTITHREADING)) {
1396-
k_event_post(&sh->ctx->signal_event, SHELL_SIGNAL_KILL);
1397-
return;
1398-
}
1399-
1418+
#if CONFIG_MULTITHREADING
1419+
k_event_post(&sh->ctx->signal_event, SHELL_SIGNAL_KILL);
1420+
#else
14001421
int err = instance_uninit(sh);
14011422

14021423
if (cb) {
14031424
cb(sh, err);
14041425
} else {
14051426
__ASSERT_NO_MSG(0);
14061427
}
1428+
#endif
14071429
}
14081430

14091431
int shell_start(const struct shell *sh)
@@ -1420,9 +1442,11 @@ int shell_start(const struct shell *sh)
14201442
z_shell_log_backend_enable(sh->log_backend, (void *)sh, sh->ctx->log_level);
14211443
}
14221444

1445+
#if CONFIG_MULTITHREADING
14231446
if (k_mutex_lock(&sh->ctx->wr_mtx, SHELL_TX_MTX_TIMEOUT) != 0) {
14241447
return -EBUSY;
14251448
}
1449+
#endif
14261450

14271451
if (IS_ENABLED(CONFIG_SHELL_VT100_COLORS)) {
14281452
z_shell_vt100_color_set(sh, SHELL_NORMAL);
@@ -1442,7 +1466,9 @@ int shell_start(const struct shell *sh)
14421466
*/
14431467
z_shell_backend_rx_buffer_flush(sh);
14441468

1469+
#if CONFIG_MULTITHREADING
14451470
k_mutex_unlock(&sh->ctx->wr_mtx);
1471+
#endif
14461472

14471473
return 0;
14481474
}
@@ -1524,9 +1550,11 @@ void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color,
15241550
return;
15251551
}
15261552

1553+
#if CONFIG_MULTITHREADING
15271554
if (k_mutex_lock(&sh->ctx->wr_mtx, SHELL_TX_MTX_TIMEOUT) != 0) {
15281555
return;
15291556
}
1557+
#endif
15301558

15311559
if (!z_flag_cmd_ctx_get(sh) && !sh->ctx->bypass && z_flag_use_vt100_get(sh)) {
15321560
z_shell_cmd_line_erase(sh);
@@ -1537,7 +1565,9 @@ void shell_vfprintf(const struct shell *sh, enum shell_vt100_color color,
15371565
}
15381566
z_transport_buffer_flush(sh);
15391567

1568+
#if CONFIG_MULTITHREADING
15401569
k_mutex_unlock(&sh->ctx->wr_mtx);
1570+
#endif
15411571
}
15421572

15431573
/* These functions mustn't be used from shell context to avoid deadlock:
@@ -1664,20 +1694,26 @@ int shell_prompt_change(const struct shell *sh, const char *prompt)
16641694

16651695
size_t prompt_length = z_shell_strlen(prompt);
16661696

1697+
#if CONFIG_MULTITHREADING
16671698
if (k_mutex_lock(&sh->ctx->wr_mtx, SHELL_TX_MTX_TIMEOUT) != 0) {
16681699
return -EBUSY;
16691700
}
1701+
#endif
16701702

16711703
if ((prompt_length + 1 > CONFIG_SHELL_PROMPT_BUFF_SIZE) || (prompt_length == 0)) {
1704+
#if CONFIG_MULTITHREADING
16721705
k_mutex_unlock(&sh->ctx->wr_mtx);
1706+
#endif
16731707
return -EINVAL;
16741708
}
16751709

16761710
strcpy(sh->ctx->prompt, prompt);
16771711

16781712
sh->ctx->vt100_ctx.cons.name_len = prompt_length;
16791713

1714+
#if CONFIG_MULTITHREADING
16801715
k_mutex_unlock(&sh->ctx->wr_mtx);
1716+
#endif
16811717

16821718
return 0;
16831719
#else
@@ -1687,11 +1723,15 @@ int shell_prompt_change(const struct shell *sh, const char *prompt)
16871723

16881724
void shell_help(const struct shell *sh)
16891725
{
1726+
#if CONFIG_MULTITHREADING
16901727
if (k_mutex_lock(&sh->ctx->wr_mtx, SHELL_TX_MTX_TIMEOUT) != 0) {
16911728
return;
16921729
}
1730+
#endif
16931731
shell_internal_help_print(sh);
1732+
#if CONFIG_MULTITHREADING
16941733
k_mutex_unlock(&sh->ctx->wr_mtx);
1734+
#endif
16951735
}
16961736

16971737
int shell_execute_cmd(const struct shell *sh, const char *cmd)
@@ -1722,12 +1762,15 @@ int shell_execute_cmd(const struct shell *sh, const char *cmd)
17221762
sh->ctx->cmd_buff_len = cmd_len;
17231763
sh->ctx->cmd_buff_pos = cmd_len;
17241764

1765+
#if CONFIG_MULTITHREADING
17251766
if (k_mutex_lock(&sh->ctx->wr_mtx, SHELL_TX_MTX_TIMEOUT) != 0) {
17261767
return -ENOEXEC;
17271768
}
1769+
#endif
17281770
ret_val = execute(sh);
1771+
#if CONFIG_MULTITHREADING
17291772
k_mutex_unlock(&sh->ctx->wr_mtx);
1730-
1773+
#endif
17311774
cmd_buffer_clear(sh);
17321775

17331776
return ret_val;

subsys/shell/shell_ops.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,11 +430,14 @@ void z_shell_print_prompt_and_cmd(const struct shell *sh)
430430

431431
static void shell_pend_on_txdone(const struct shell *sh)
432432
{
433-
if (IS_ENABLED(CONFIG_MULTITHREADING) &&
434-
(sh->ctx->state < SHELL_STATE_PANIC_MODE_ACTIVE)) {
433+
#if CONFIG_MULTITHREADING
434+
if (sh->ctx->state < SHELL_STATE_PANIC_MODE_ACTIVE) {
435435
k_event_wait(&sh->ctx->signal_event, SHELL_SIGNAL_TXDONE, false, K_FOREVER);
436436
k_event_clear(&sh->ctx->signal_event, SHELL_SIGNAL_TXDONE);
437437
} else {
438+
#else
439+
{
440+
#endif
438441
/* Blocking wait in case of bare metal. */
439442
while (!z_flag_tx_rdy_get(sh)) {
440443
}

0 commit comments

Comments
 (0)