在Unix和其他多任务计算机操作系统中,后台程序是指,作为后台进程运行的计算机,而不是由交互用户直接控制。
后台程序概念的主要好处是,后台程序可以直接启动,而不需要将其发送到精确的用户或者shell的后台(然而,这不适用于Nuttx),其状态可以在运行的时候,通过shell查询。也可以终止。
Step 1: 创建一个小的标准应用
根据 FirstOnboard Application Tutorial (Hello Sky)教程(见PX4源码开发人员文档(二)),这是一个基本程序(简化):
- ..
- __EXPORT int px4_daemon_app_main(int argc, char *argv[]);
- ..
- int px4_daemon_app_main(int argc, char *argv[])
- {
- while (true) {
- warnx("Hello Daemon!\n");
- sleep(1);
- }
- return 0;
- }
..
__EXPORT int px4_daemon_app_main(int argc, char *argv[]);
..
int px4_daemon_app_main(int argc, char *argv[])
{
while (true) {
warnx("Hello Daemon!\n");
sleep(1);
}
return 0;
}
这个应用的问题非常明显,如果不使用&启动,将会阻塞shell(Nuttx,并不如此,并且会出于small footprint和可靠性的原因,支持CTRL-Z / fg / bg)。为了回避这个问题,下面部分将应用转换为一个后台程序。
Step 2: 创建后台进程管理函数
主函数由后台进程管理函数替代,旧的主函数的内容现在位于后台任务/进程中
- #include <systemlib/systemlib.h>
- ..
- __EXPORT int px4_daemon_app_main(int argc, char *argv[]);
- ..
- int mavlink_thread_main(int argc, char *argv[]);
- ..
- int mavlink_thread_main(int argc, char *argv[])
- {
- while (true) {
- warnx("Hello Daemon!\n");
- sleep(1);
- if (thread_should_exit) break;
- }
- return 0;
- }
- ..
- int px4_daemon_app_main(int argc, char *argv[])
- {
- if (argc < 1)
- usage("missing command");
- if (!strcmp(argv[1], "start")) {
- if (thread_running) {
- warnx("daemon already running\n");
- /* this is not an error */
- exit(0);
- }
- thread_should_exit = false;
- daemon_task = task_spawn_cmd("daemon",
- SCHED_RR,
- SCHED_PRIORITY_DEFAULT,
- 4096,
- px4_daemon_thread_main,
- (argv) ? (const char **)&argv[2] : (const char **)NULL);
- thread_running = true;
- exit(0);
- }
- usage("unrecognized command");
- exit(1);
- }
#include <systemlib/systemlib.h>
..
__EXPORT int px4_daemon_app_main(int argc, char *argv[]);
..
int mavlink_thread_main(int argc, char *argv[]);
..
int mavlink_thread_main(int argc, char *argv[])
{
while (true) {
warnx("Hello Daemon!\n");
sleep(1);
if (thread_should_exit) break;
}
return 0;
}
..
int px4_daemon_app_main(int argc, char *argv[])
{
if (argc < 1)
usage("missing command");
if (!strcmp(argv[1], "start")) {
if (thread_running) {
warnx("daemon already running\n");
/* this is not an error */
exit(0);
}
thread_should_exit = false;
daemon_task = task_spawn_cmd("daemon",
SCHED_RR,
SCHED_PRIORITY_DEFAULT,
4096,
px4_daemon_thread_main,
(argv) ? (const char **)&argv[2] : (const char **)NULL);
thread_running = true;
exit(0);
}
usage("unrecognized command");
exit(1);
}
这将会启动一个新的任务,具有4096字节的堆栈,并传递非后台程序的具体指令行选项到后台主函数。典型的调用如下所示:
- px4_daemon_app start
px4_daemon_app start
上面的代码没有报告状态,并且没有对多次调用后台进程进行保护。
Step 3: 添加停止/状态指令以及安全保护
具有合适的启动/停止/状态建立和附加安全保护的完整px4_daemon_app代码如下:
- /**
- * @file px4_daemon_app.c
- * daemon application example for PX4 autopilot
- *
- * @author Example User <mail@example.com>
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <px4_config.h>
- #include <nuttx/sched.h>
- #include <systemlib/systemlib.h>
- #include <systemlib/err.h>
- static bool thread_should_exit = false; /**< daemon exit flag */
- static bool thread_running = false; /**< daemon status flag */
- static int daemon_task; /**< Handle of daemon task / thread */
- /**
- * daemon management function.
- */
- __EXPORT int px4_daemon_app_main(int argc, char *argv[]);
- /**
- * Mainloop of daemon.
- */
- int px4_daemon_thread_main(int argc, char *argv[]);
- /**
- * Print the correct usage.
- */
- static void usage(const char *reason);
- static void
- usage(const char *reason)
- {
- if (reason) {
- warnx("%s\n", reason);
- }
- warnx("usage: daemon {start|stop|status} [-p <additional params>]\n\n");
- }
- /**
- * The daemon app only briefly exists to start
- * the background job. The stack size assigned in the
- * Makefile does only apply to this management task.
- *
- * The actual stack size should be set in the call
- * to task_create().
- */
- int px4_daemon_app_main(int argc, char *argv[])
- {
- if (argc < 2) {
- usage("missing command");
- return 1;
- }
- if (!strcmp(argv[1], "start")) {
- if (thread_running) {
- warnx("daemon already running\n");
- /* this is not an error */
- return 0;
- }
- thread_should_exit = false;
- daemon_task = px4_task_spawn_cmd("daemon",
- SCHED_DEFAULT,
- SCHED_PRIORITY_DEFAULT,
- 2000,
- px4_daemon_thread_main,
- (argv) ? (char *const *)&argv[2] : (char *const *)NULL);
- return 0;
- }
- if (!strcmp(argv[1], "stop")) {
- thread_should_exit = true;
- return 0;
- }
- if (!strcmp(argv[1], "status")) {
- if (thread_running) {
- warnx("\trunning\n");
- } else {
- warnx("\tnot started\n");
- }
- return 0;
- }
- usage("unrecognized command");
- return 1;
- }
- int px4_daemon_thread_main(int argc, char *argv[])
- {
- warnx("[daemon] starting\n");
- thread_running = true;
- while (!thread_should_exit) {
- warnx("Hello daemon!\n");
- sleep(10);
- }
- warnx("[daemon] exiting.\n");
- thread_running = false;
- return 0;
- }
/**
* @file px4_daemon_app.c
* daemon application example for PX4 autopilot
*
* @author Example User <mail@example.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <px4_config.h>
#include <nuttx/sched.h>
#include <systemlib/systemlib.h>
#include <systemlib/err.h>
static bool thread_should_exit = false; /**< daemon exit flag */
static bool thread_running = false; /**< daemon status flag */
static int daemon_task; /**< Handle of daemon task / thread */
/**
* daemon management function.
*/
__EXPORT int px4_daemon_app_main(int argc, char *argv[]);
/**
* Mainloop of daemon.
*/
int px4_daemon_thread_main(int argc, char *argv[]);
/**
* Print the correct usage.
*/
static void usage(const char *reason);
static void
usage(const char *reason)
{
if (reason) {
warnx("%s\n", reason);
}
warnx("usage: daemon {start|stop|status} [-p <additional params>]\n\n");
}
/**
* The daemon app only briefly exists to start
* the background job. The stack size assigned in the
* Makefile does only apply to this management task.
*
* The actual stack size should be set in the call
* to task_create().
*/
int px4_daemon_app_main(int argc, char *argv[])
{
if (argc < 2) {
usage("missing command");
return 1;
}
if (!strcmp(argv[1], "start")) {
if (thread_running) {
warnx("daemon already running\n");
/* this is not an error */
return 0;
}
thread_should_exit = false;
daemon_task = px4_task_spawn_cmd("daemon",
SCHED_DEFAULT,
SCHED_PRIORITY_DEFAULT,
2000,
px4_daemon_thread_main,
(argv) ? (char *const *)&argv[2] : (char *const *)NULL);
return 0;
}
if (!strcmp(argv[1], "stop")) {
thread_should_exit = true;
return 0;
}
if (!strcmp(argv[1], "status")) {
if (thread_running) {
warnx("\trunning\n");
} else {
warnx("\tnot started\n");
}
return 0;
}
usage("unrecognized command");
return 1;
}
int px4_daemon_thread_main(int argc, char *argv[])
{
warnx("[daemon] starting\n");
thread_running = true;
while (!thread_should_exit) {
warnx("Hello daemon!\n");
sleep(10);
}
warnx("[daemon] exiting.\n");
thread_running = false;
return 0;
}
代码测试将会产生如下的输出:
- nsh> px4_daemon_app start
- [daemon] starting
- Hello Daemon!
nsh> px4_daemon_app start
[daemon] starting
Hello Daemon!
为了使用这一APP,只需在Firmware/makefiles/config_px4fmu_default.mk中,取消对这一示例部分的注释。