mirror of
https://github.com/PX4/PX4-Autopilot.git
synced 2026-05-27 18:27:05 +08:00
feat(px4): support Windows daemon and shell runtime
Make PX4 startup, daemon command handling, shell I/O, shutdown, logging, getopt, and instance state work across POSIX and native Windows runtime boundaries. Keep command-client behavior explicit by routing shell output through shared logger paths and preserving socket protocol return markers during shutdown.
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
#include <px4_platform_common/time.h>
|
#include <px4_platform_common/time.h>
|
||||||
#include <px4_platform_common/posix.h>
|
#include <px4_platform_common/posix.h>
|
||||||
#include <px4_platform_common/log.h>
|
#include <px4_platform_common/log.h>
|
||||||
|
#include <px4_platform_common/exit.h>
|
||||||
#include <uORB/uORB.h>
|
#include <uORB/uORB.h>
|
||||||
|
|
||||||
#include "apps.h"
|
#include "apps.h"
|
||||||
@@ -43,9 +44,21 @@ void list_builtins(apps_map_type &apps)
|
|||||||
|
|
||||||
int shutdown_main(int argc, char *argv[])
|
int shutdown_main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
// Reject any leftover positional arguments (e.g. "status", "start", "stop").
|
||||||
|
// shutdown takes no flags or subcommands -- it always tears the daemon
|
||||||
|
// down -- so silently ignoring extra args would terminate the daemon when
|
||||||
|
// the user almost certainly meant a different module (e.g.
|
||||||
|
// "<module> status"). Print usage and exit non-zero instead.
|
||||||
|
if (argc > 1) {
|
||||||
|
PX4_ERR("unrecognized argument: %s", argv[1]);
|
||||||
|
printf("Usage:\n shutdown\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
printf("Exiting NOW.\n");
|
printf("Exiting NOW.\n");
|
||||||
uorb_shutdown();
|
uorb_shutdown();
|
||||||
system_exit(0);
|
px4_platform_exit(0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int list_tasks_main(int argc, char *argv[])
|
int list_tasks_main(int argc, char *argv[])
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2026 PX4 Development Team. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file exit.h
|
||||||
|
*
|
||||||
|
* Platform-level process exit hook.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <visibility.h>
|
||||||
|
|
||||||
|
#if defined(__PX4_WINDOWS)
|
||||||
|
#include <px4_windows/platform.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void px4_platform_exit(int status) noreturn_function;
|
||||||
|
static inline void px4_platform_exit(int status)
|
||||||
|
{
|
||||||
|
#if defined(__PX4_WINDOWS)
|
||||||
|
px4_windows_exit(status);
|
||||||
|
#else
|
||||||
|
system_exit(status);
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
__assume(0);
|
||||||
|
#else
|
||||||
|
__builtin_unreachable();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -123,14 +123,24 @@ __END_DECLS
|
|||||||
#include <px4_platform_common/defines.h>
|
#include <px4_platform_common/defines.h>
|
||||||
#include <drivers/drv_hrt.h>
|
#include <drivers/drv_hrt.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
# define __px4_log_format(_fmt, _args)
|
||||||
|
#elif defined(__PX4_WINDOWS)
|
||||||
|
# define __px4_log_format(_fmt, _args) __attribute__((format(gnu_printf, _fmt, _args)))
|
||||||
|
#else
|
||||||
|
# define __px4_log_format(_fmt, _args) __attribute__((format(printf, _fmt, _args)))
|
||||||
|
#endif
|
||||||
|
|
||||||
__BEGIN_DECLS
|
__BEGIN_DECLS
|
||||||
|
|
||||||
__EXPORT extern const char *__px4_log_level_str[_PX4_LOG_LEVEL_PANIC + 1];
|
__EXPORT extern const char *__px4_log_level_str[_PX4_LOG_LEVEL_PANIC + 1];
|
||||||
__EXPORT void px4_log_modulename(int level, const char *moduleName, const char *fmt, ...)
|
__EXPORT void px4_log_modulename(int level, const char *moduleName, const char *fmt, ...)
|
||||||
__attribute__((format(printf, 3, 4)));
|
__px4_log_format(3, 4);
|
||||||
__EXPORT void px4_log_raw(int level, const char *fmt, ...)
|
__EXPORT void px4_log_raw(int level, const char *fmt, ...)
|
||||||
__attribute__((format(printf, 2, 3)));
|
__px4_log_format(2, 3);
|
||||||
__EXPORT void px4_log_history(FILE *out);
|
__EXPORT void px4_log_history(FILE *out);
|
||||||
|
__EXPORT int px4_log_modulename_from_text(const char *line);
|
||||||
|
__EXPORT void px4_log_write_text(FILE *out, const char *data, size_t length);
|
||||||
|
|
||||||
#if __GNUC__
|
#if __GNUC__
|
||||||
// Allow empty format strings.
|
// Allow empty format strings.
|
||||||
@@ -168,8 +178,9 @@ __END_DECLS
|
|||||||
#define __px4__log_end_fmt "\n"
|
#define __px4__log_end_fmt "\n"
|
||||||
|
|
||||||
#ifdef __PX4_POSIX
|
#ifdef __PX4_POSIX
|
||||||
#define PX4_LOG_COLORIZED_OUTPUT //if defined and output is a tty, colorize the output according to the log level
|
// If defined and output is a tty, colorize the output according to the log level.
|
||||||
#endif /* __PX4_POSIX */
|
#define PX4_LOG_COLORIZED_OUTPUT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2026 PX4 Development Team. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace px4
|
||||||
|
{
|
||||||
|
|
||||||
|
// Run a POSIX shell init script (rcS, test_*_generated, etc.) to start a
|
||||||
|
// PX4 instance. The platform backend is responsible for actually executing
|
||||||
|
// the script. On POSIX this typically shells out to /bin/sh. On Windows the
|
||||||
|
// intended production path is a bundled in-process shell backend so px4.exe
|
||||||
|
// can be embedded and redistributed without an external shell dependency.
|
||||||
|
//
|
||||||
|
// script_path : absolute or cwd-relative path to the shell script
|
||||||
|
// binary_dir : directory containing px4.exe / px4-* commands; added
|
||||||
|
// to PATH so the script can invoke them unqualified
|
||||||
|
// instance : PX4 instance id, forwarded as $1 to the script
|
||||||
|
//
|
||||||
|
// Returns the script's exit status (0 on success).
|
||||||
|
int run_shell_script(const std::string &script_path,
|
||||||
|
const std::string &binary_dir,
|
||||||
|
int instance);
|
||||||
|
|
||||||
|
} // namespace px4
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#include <px4_platform_common/getopt.h>
|
#include <px4_platform_common/getopt.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
// check if p is a valid option and if the option takes an arg
|
// check if p is a valid option and if the option takes an arg
|
||||||
static char isvalidopt(char p, const char *options, int *takesarg)
|
static char isvalidopt(char p, const char *options, int *takesarg)
|
||||||
@@ -63,11 +64,16 @@ static char isvalidopt(char p, const char *options, int *takesarg)
|
|||||||
// reorder argv and put non-options at the end
|
// reorder argv and put non-options at the end
|
||||||
static int reorder(int argc, char **argv, const char *options)
|
static int reorder(int argc, char **argv, const char *options)
|
||||||
{
|
{
|
||||||
char *tmp_argv[argc];
|
char **tmp_argv = (char **)malloc(sizeof(*tmp_argv) * (size_t)argc);
|
||||||
char c;
|
char c;
|
||||||
int idx = 1;
|
int idx = 1;
|
||||||
int tmpidx = 1;
|
int tmpidx = 1;
|
||||||
int takesarg;
|
int takesarg;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (tmp_argv == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// move the options to the front
|
// move the options to the front
|
||||||
while (idx < argc && argv[idx] != 0) {
|
while (idx < argc && argv[idx] != 0) {
|
||||||
@@ -75,7 +81,8 @@ static int reorder(int argc, char **argv, const char *options)
|
|||||||
c = isvalidopt(argv[idx][1], options, &takesarg);
|
c = isvalidopt(argv[idx][1], options, &takesarg);
|
||||||
|
|
||||||
if (c == '?') {
|
if (c == '?') {
|
||||||
return 1;
|
ret = 1;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_argv[tmpidx] = argv[idx];
|
tmp_argv[tmpidx] = argv[idx];
|
||||||
@@ -83,7 +90,8 @@ static int reorder(int argc, char **argv, const char *options)
|
|||||||
|
|
||||||
if (takesarg) {
|
if (takesarg) {
|
||||||
if (idx + 1 >= argc) { //Error: option takes an argument, but there is no more argument
|
if (idx + 1 >= argc) { //Error: option takes an argument, but there is no more argument
|
||||||
return 1;
|
ret = 1;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_argv[tmpidx] = argv[idx + 1];
|
tmp_argv[tmpidx] = argv[idx + 1];
|
||||||
@@ -104,7 +112,8 @@ static int reorder(int argc, char **argv, const char *options)
|
|||||||
c = isvalidopt(argv[idx][1], options, &takesarg);
|
c = isvalidopt(argv[idx][1], options, &takesarg);
|
||||||
|
|
||||||
if (c == '?') {
|
if (c == '?') {
|
||||||
return c;
|
ret = c;
|
||||||
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (takesarg) {
|
if (takesarg) {
|
||||||
@@ -124,7 +133,9 @@ static int reorder(int argc, char **argv, const char *options)
|
|||||||
argv[idx] = tmp_argv[idx];
|
argv[idx] = tmp_argv[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
cleanup:
|
||||||
|
free(tmp_argv);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
+552
-17
File diff suppressed because it is too large
Load Diff
@@ -40,6 +40,8 @@
|
|||||||
#include <px4_platform_common/workqueue.h>
|
#include <px4_platform_common/workqueue.h>
|
||||||
#include <px4_platform_common/shutdown.h>
|
#include <px4_platform_common/shutdown.h>
|
||||||
#include <px4_platform_common/tasks.h>
|
#include <px4_platform_common/tasks.h>
|
||||||
|
#include <px4_platform_common/time.h>
|
||||||
|
#include <px4_platform_common/exit.h>
|
||||||
|
|
||||||
#include <drivers/drv_hrt.h>
|
#include <drivers/drv_hrt.h>
|
||||||
|
|
||||||
@@ -104,6 +106,20 @@ int px4_shutdown_unlock()
|
|||||||
|
|
||||||
#if defined(CONFIG_SCHED_WORKQUEUE) || (!defined(CONFIG_BUILD_FLAT) && defined(CONFIG_LIBC_USRWORK))
|
#if defined(CONFIG_SCHED_WORKQUEUE) || (!defined(CONFIG_BUILD_FLAT) && defined(CONFIG_LIBC_USRWORK))
|
||||||
|
|
||||||
|
#if defined(ENABLE_LOCKSTEP_SCHEDULER) && defined(__PX4_WINDOWS)
|
||||||
|
static hrt_abstime shutdown_time_us_now()
|
||||||
|
{
|
||||||
|
timespec ts{};
|
||||||
|
system_clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
return (static_cast<hrt_abstime>(ts.tv_sec) * 1000000ULL) + (static_cast<hrt_abstime>(ts.tv_nsec) / 1000ULL);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static hrt_abstime shutdown_time_us_now()
|
||||||
|
{
|
||||||
|
return hrt_absolute_time();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct work_s shutdown_work = {};
|
static struct work_s shutdown_work = {};
|
||||||
static uint16_t shutdown_counter = 0; ///< count how many times the shutdown worker was executed
|
static uint16_t shutdown_counter = 0; ///< count how many times the shutdown worker was executed
|
||||||
|
|
||||||
@@ -171,7 +187,7 @@ static void shutdown_worker(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hrt_abstime now = hrt_absolute_time();
|
const hrt_abstime now = shutdown_time_us_now();
|
||||||
const bool delay_elapsed = (now > shutdown_time_us);
|
const bool delay_elapsed = (now > shutdown_time_us);
|
||||||
|
|
||||||
if (delay_elapsed && ((done && shutdown_lock_counter == 0) || (now > (shutdown_time_us + shutdown_timeout_us)))) {
|
if (delay_elapsed && ((done && shutdown_lock_counter == 0) || (now > (shutdown_time_us + shutdown_timeout_us)))) {
|
||||||
@@ -206,7 +222,7 @@ static void shutdown_worker(void *arg)
|
|||||||
#elif defined(__PX4_POSIX)
|
#elif defined(__PX4_POSIX)
|
||||||
// simply exit on posix if real shutdown (poweroff) not available
|
// simply exit on posix if real shutdown (poweroff) not available
|
||||||
PX4_INFO_RAW("Exiting NOW.");
|
PX4_INFO_RAW("Exiting NOW.");
|
||||||
system_exit(0);
|
px4_platform_exit(0);
|
||||||
#else
|
#else
|
||||||
PX4_PANIC("board shutdown not available");
|
PX4_PANIC("board shutdown not available");
|
||||||
#endif
|
#endif
|
||||||
@@ -239,7 +255,7 @@ int px4_reboot_request(reboot_request_t request, uint32_t delay_us)
|
|||||||
shutdown_args |= SHUTDOWN_ARG_TO_ISP;
|
shutdown_args |= SHUTDOWN_ARG_TO_ISP;
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown_time_us = hrt_absolute_time();
|
shutdown_time_us = shutdown_time_us_now();
|
||||||
|
|
||||||
if (delay_us > 0) {
|
if (delay_us > 0) {
|
||||||
shutdown_time_us += delay_us;
|
shutdown_time_us += delay_us;
|
||||||
@@ -263,7 +279,7 @@ int px4_shutdown_request(uint32_t delay_us)
|
|||||||
|
|
||||||
shutdown_args |= SHUTDOWN_ARG_IN_PROGRESS;
|
shutdown_args |= SHUTDOWN_ARG_IN_PROGRESS;
|
||||||
|
|
||||||
shutdown_time_us = hrt_absolute_time();
|
shutdown_time_us = shutdown_time_us_now();
|
||||||
|
|
||||||
if (delay_us > 0) {
|
if (delay_us > 0) {
|
||||||
shutdown_time_us += delay_us;
|
shutdown_time_us += delay_us;
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ uORB::DeviceNode::write(cdev::file_t *filp, const char *buffer, size_t buflen)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
uORB::DeviceNode::ioctl(cdev::file_t *filp, int cmd, unsigned long arg)
|
uORB::DeviceNode::ioctl(cdev::file_t *filp, int cmd, uintptr_t arg)
|
||||||
{
|
{
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case ORBIOCUPDATED: {
|
case ORBIOCUPDATED: {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* IOCTL control for the subscriber.
|
* IOCTL control for the subscriber.
|
||||||
*/
|
*/
|
||||||
int ioctl(cdev::file_t *filp, int cmd, unsigned long arg) override;
|
int ioctl(cdev::file_t *filp, int cmd, uintptr_t arg) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method to publish a data to this node.
|
* Method to publish a data to this node.
|
||||||
|
|||||||
@@ -302,7 +302,7 @@ orb_advert_t uORB::Manager::orb_advertise_multi(const struct orb_metadata *meta,
|
|||||||
/* get the advertiser handle and close the node */
|
/* get the advertiser handle and close the node */
|
||||||
orb_advert_t advertiser;
|
orb_advert_t advertiser;
|
||||||
|
|
||||||
int result = px4_ioctl(fd, ORBIOCGADVERTISER, (unsigned long)&advertiser);
|
int result = px4_ioctl(fd, ORBIOCGADVERTISER, (uintptr_t)&advertiser);
|
||||||
px4_close(fd);
|
px4_close(fd);
|
||||||
|
|
||||||
if (result == PX4_ERROR) {
|
if (result == PX4_ERROR) {
|
||||||
@@ -397,7 +397,7 @@ int uORB::Manager::orb_check(int handle, bool *updated)
|
|||||||
{
|
{
|
||||||
/* Set to false here so that if `px4_ioctl` fails to false. */
|
/* Set to false here so that if `px4_ioctl` fails to false. */
|
||||||
*updated = false;
|
*updated = false;
|
||||||
return px4_ioctl(handle, ORBIOCUPDATED, (unsigned long)(uintptr_t)updated);
|
return px4_ioctl(handle, ORBIOCUPDATED, (uintptr_t)updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
int uORB::Manager::orb_set_interval(int handle, unsigned interval)
|
int uORB::Manager::orb_set_interval(int handle, unsigned interval)
|
||||||
@@ -407,7 +407,7 @@ int uORB::Manager::orb_set_interval(int handle, unsigned interval)
|
|||||||
|
|
||||||
int uORB::Manager::orb_get_interval(int handle, unsigned *interval)
|
int uORB::Manager::orb_get_interval(int handle, unsigned *interval)
|
||||||
{
|
{
|
||||||
int ret = px4_ioctl(handle, ORBIOCGETINTERVAL, (unsigned long)interval);
|
int ret = px4_ioctl(handle, ORBIOCGETINTERVAL, (uintptr_t)interval);
|
||||||
*interval /= 1000;
|
*interval /= 1000;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ orb_advert_t uORB::Manager::orb_advertise_multi(const struct orb_metadata *meta,
|
|||||||
/* get the advertiser handle and close the node */
|
/* get the advertiser handle and close the node */
|
||||||
orb_advert_t advertiser;
|
orb_advert_t advertiser;
|
||||||
|
|
||||||
int result = px4_ioctl(fd, ORBIOCGADVERTISER, (unsigned long)&advertiser);
|
int result = px4_ioctl(fd, ORBIOCGADVERTISER, (uintptr_t)&advertiser);
|
||||||
px4_close(fd);
|
px4_close(fd);
|
||||||
|
|
||||||
if (result == PX4_ERROR) {
|
if (result == PX4_ERROR) {
|
||||||
@@ -177,7 +177,7 @@ int uORB::Manager::orb_check(int handle, bool *updated)
|
|||||||
{
|
{
|
||||||
/* Set to false here so that if `px4_ioctl` fails to false. */
|
/* Set to false here so that if `px4_ioctl` fails to false. */
|
||||||
*updated = false;
|
*updated = false;
|
||||||
return px4_ioctl(handle, ORBIOCUPDATED, (unsigned long)(uintptr_t)updated);
|
return px4_ioctl(handle, ORBIOCUPDATED, (uintptr_t)updated);
|
||||||
}
|
}
|
||||||
|
|
||||||
int uORB::Manager::orb_set_interval(int handle, unsigned interval)
|
int uORB::Manager::orb_set_interval(int handle, unsigned interval)
|
||||||
@@ -187,7 +187,7 @@ int uORB::Manager::orb_set_interval(int handle, unsigned interval)
|
|||||||
|
|
||||||
int uORB::Manager::orb_get_interval(int handle, unsigned *interval)
|
int uORB::Manager::orb_get_interval(int handle, unsigned *interval)
|
||||||
{
|
{
|
||||||
int ret = px4_ioctl(handle, ORBIOCGETINTERVAL, (unsigned long)interval);
|
int ret = px4_ioctl(handle, ORBIOCGETINTERVAL, (uintptr_t)interval);
|
||||||
*interval /= 1000;
|
*interval /= 1000;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,5 +48,7 @@ __BEGIN_DECLS
|
|||||||
* @return The FILE* which represents the standard output of the current thread.
|
* @return The FILE* which represents the standard output of the current thread.
|
||||||
*/
|
*/
|
||||||
__EXPORT FILE *get_stdout(bool *isatty_);
|
__EXPORT FILE *get_stdout(bool *isatty_);
|
||||||
|
__EXPORT void set_stdout_isatty_override(bool isatty_);
|
||||||
|
__EXPORT void clear_stdout_isatty_override();
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -45,10 +45,17 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#endif
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include <px4_platform_common/log.h>
|
#include <px4_platform_common/log.h>
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
@@ -56,14 +63,133 @@
|
|||||||
namespace px4_daemon
|
namespace px4_daemon
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
// SHUT_WR is the POSIX value of the half-close-send constant; on Winsock,
|
||||||
|
// the equivalent is SD_SEND. Use a portable alias so the relay code below is
|
||||||
|
// platform-neutral.
|
||||||
|
static constexpr int kShutWr = SD_SEND;
|
||||||
|
#else
|
||||||
|
static constexpr int kShutWr = SHUT_WR;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
bool ends_with_exe_suffix(const std::string &arg)
|
||||||
|
{
|
||||||
|
if (arg.size() < 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string suffix = arg.substr(arg.size() - 4);
|
||||||
|
return suffix == ".exe" || suffix == ".EXE"
|
||||||
|
|| suffix == ".Exe" || suffix == ".eXe"
|
||||||
|
|| suffix == ".exE" || suffix == ".EXe"
|
||||||
|
|| suffix == ".eXE" || suffix == ".ExE";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Reads up to `n` bytes from this process's standard input. Returns 0 on EOF
|
||||||
|
// and -1 on error. Wraps the platform-specific stdin-read primitive so the
|
||||||
|
// forwarding loop below stays platform-neutral.
|
||||||
|
static ssize_t read_local_stdin(char *buf, size_t n)
|
||||||
|
{
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
HANDLE stdin_h = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
|
if (stdin_h == INVALID_HANDLE_VALUE || stdin_h == nullptr) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD got = 0;
|
||||||
|
|
||||||
|
if (!ReadFile(stdin_h, buf, (DWORD)n, &got, nullptr)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ssize_t)got;
|
||||||
|
#else
|
||||||
|
return read(STDIN_FILENO, buf, n);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Worker that reads bytes from this process's stdin and forwards them over
|
||||||
|
// the socket so the daemon can hand them to the running module's stdin pipe.
|
||||||
|
// Stops on stdin EOF (half-closes the socket's send side, signalling EOF to
|
||||||
|
// the daemon) or on any send() error (typically the daemon already closed
|
||||||
|
// the connection because the command finished).
|
||||||
|
static void stdin_forward_loop(socket_handle_t fd)
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const ssize_t bytes_read = read_local_stdin(buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
if (bytes_read <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *buf = buffer;
|
||||||
|
ssize_t remaining = bytes_read;
|
||||||
|
|
||||||
|
while (remaining > 0) {
|
||||||
|
const int n_sent = send(fd, buf, (int)remaining, 0);
|
||||||
|
|
||||||
|
if (n_sent <= 0) {
|
||||||
|
// Daemon closed the connection (command finished). Done.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf += n_sent;
|
||||||
|
remaining -= n_sent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local stdin reached EOF — half-close the send side so the daemon's
|
||||||
|
// stdin relay sees EOF on its recv() and drains the module's stdin pipe.
|
||||||
|
shutdown(fd, kShutWr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
Client::Client(int instance_id) :
|
Client::Client(int instance_id) :
|
||||||
_fd(-1),
|
_fd(invalid_socket_handle),
|
||||||
_instance_id(instance_id)
|
_instance_id(instance_id)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
int
|
int
|
||||||
Client::process_args(const int argc, const char **argv)
|
Client::process_args(const int argc, const char **argv)
|
||||||
{
|
{
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
const uint16_t port = get_socket_port(_instance_id);
|
||||||
|
|
||||||
|
_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
if (_fd == invalid_socket_handle) {
|
||||||
|
PX4_ERR("error creating socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr_in addr = {};
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
if (connect(_fd, (sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
PX4_ERR("error connecting to 127.0.0.1:%u: %s", port, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No SO_RCVTIMEO: match POSIX/AF_UNIX behaviour where the client blocks
|
||||||
|
// in recv() until the daemon either replies or shuts the connection
|
||||||
|
// down. A short timeout here (the previous 5 s default) would fire
|
||||||
|
// before commands that legitimately take longer to return — most
|
||||||
|
// notably `commander takeoff`, whose lockstep wait_for_vehicle_command_reply
|
||||||
|
// can sit idle for the full 5 s acknowledgement window followed by a
|
||||||
|
// second 5 s wait for the arming reply. Letting the OS deliver an EOF
|
||||||
|
// or RST from the server is the correct termination signal here.
|
||||||
|
#else
|
||||||
std::string sock_path = get_socket_path(_instance_id);
|
std::string sock_path = get_socket_path(_instance_id);
|
||||||
|
|
||||||
_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
@@ -82,6 +208,8 @@ Client::process_args(const int argc, const char **argv)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
int ret = _send_cmds(argc, argv);
|
int ret = _send_cmds(argc, argv);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@@ -89,6 +217,21 @@ Client::process_args(const int argc, const char **argv)
|
|||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward this process's stdin to the daemon while we wait for the
|
||||||
|
// command's stdout. The thread is detached and will exit when the local
|
||||||
|
// stdin closes or the daemon hangs up the socket — process exit reaps it.
|
||||||
|
// Best-effort: commands that don't read stdin are unaffected; interactive
|
||||||
|
// ones simply won't see keystrokes if thread creation fails.
|
||||||
|
try {
|
||||||
|
std::thread(stdin_forward_loop, _fd).detach();
|
||||||
|
|
||||||
|
} catch (const std::system_error &) {
|
||||||
|
// intentionally swallowed: stdin relay is best-effort. If the OS cannot
|
||||||
|
// spawn the helper thread, interactive commands lose keystroke
|
||||||
|
// forwarding but the command itself still runs to completion.
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
|
|
||||||
return _listen();
|
return _listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +241,20 @@ Client::_send_cmds(const int argc, const char **argv)
|
|||||||
std::string cmd_buf;
|
std::string cmd_buf;
|
||||||
|
|
||||||
for (int i = 0; i < argc; ++i) {
|
for (int i = 0; i < argc; ++i) {
|
||||||
cmd_buf += argv[i];
|
std::string arg = argv[i];
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
|
||||||
|
// Client executables are real .exe files on Windows, not POSIX
|
||||||
|
// symlinks. The pxh command namespace remains extensionless
|
||||||
|
// ("commander", "shutdown", ...), so strip only argv[0].
|
||||||
|
if (i == 0 && ends_with_exe_suffix(arg)) {
|
||||||
|
arg.resize(arg.size() - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
cmd_buf += arg;
|
||||||
|
|
||||||
if (i + 1 != argc) {
|
if (i + 1 != argc) {
|
||||||
// TODO: Use '\0' as argument separator (and parse this server-side as well),
|
// TODO: Use '\0' as argument separator (and parse this server-side as well),
|
||||||
@@ -114,10 +270,13 @@ Client::_send_cmds(const int argc, const char **argv)
|
|||||||
const char *buf = cmd_buf.data();
|
const char *buf = cmd_buf.data();
|
||||||
|
|
||||||
while (n > 0) {
|
while (n > 0) {
|
||||||
int n_sent = write(_fd, buf, n);
|
// send() instead of write() so the same code path works with AF_UNIX
|
||||||
|
// on POSIX and AF_INET SOCKETs on Windows — write() does not operate
|
||||||
|
// on WinSock SOCKET handles.
|
||||||
|
int n_sent = send(_fd, buf, n, 0);
|
||||||
|
|
||||||
if (n_sent < 0) {
|
if (n_sent < 0) {
|
||||||
PX4_ERR("write() failed: %s", strerror(errno));
|
PX4_ERR("send() failed: %s", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,10 +297,43 @@ Client::_listen()
|
|||||||
// by another byte, we don't output it yet, until we know whether it was
|
// by another byte, we don't output it yet, until we know whether it was
|
||||||
// the end of the stream or not.
|
// the end of the stream or not.
|
||||||
while (true) {
|
while (true) {
|
||||||
int n_read = read(_fd, buffer + n_buffer_used, sizeof buffer - n_buffer_used);
|
int n_read = recv(_fd, buffer + n_buffer_used, sizeof buffer - n_buffer_used, 0);
|
||||||
|
|
||||||
if (n_read < 0) {
|
if (n_read < 0) {
|
||||||
PX4_ERR("unable to read from socket");
|
#ifdef __PX4_WINDOWS
|
||||||
|
const int wsa_err = WSAGetLastError();
|
||||||
|
|
||||||
|
// WSAECONNRESET / WSAESHUTDOWN can fire instead of a clean
|
||||||
|
// recv() == 0 if the daemon's closesocket() races our recv()
|
||||||
|
// (the OS already delivered the bytes — TCP just abandoned the
|
||||||
|
// graceful FIN). Treat it as end-of-stream so we still pick up
|
||||||
|
// the {0, retval} sentinel that was already buffered.
|
||||||
|
if (wsa_err == WSAECONNRESET || wsa_err == WSAESHUTDOWN) {
|
||||||
|
if (n_buffer_used == 2) {
|
||||||
|
return buffer[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PX4_ERR("unable to read from socket: WSA error = %d", wsa_err);
|
||||||
|
#else
|
||||||
|
|
||||||
|
// ECONNRESET / EPIPE can fire on AF_UNIX too if the daemon
|
||||||
|
// closes the socket between sending the {0, retval} sentinel
|
||||||
|
// and our recv() picking up the EOF. The bytes have already
|
||||||
|
// been delivered into our kernel buffer, so honour the
|
||||||
|
// sentinel rather than reporting a spurious socket error.
|
||||||
|
if (errno == ECONNRESET || errno == EPIPE) {
|
||||||
|
if (n_buffer_used == 2) {
|
||||||
|
return buffer[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PX4_ERR("unable to read from socket: %s", strerror(errno));
|
||||||
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
} else if (n_read == 0) {
|
} else if (n_read == 0) {
|
||||||
@@ -179,8 +371,12 @@ Client::_listen()
|
|||||||
|
|
||||||
Client::~Client()
|
Client::~Client()
|
||||||
{
|
{
|
||||||
if (_fd >= 0) {
|
if (_fd != invalid_socket_handle) {
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
closesocket(_fd);
|
||||||
|
#else
|
||||||
close(_fd);
|
close(_fd);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public:
|
|||||||
Client(Client &&other) : _fd(other._fd), _instance_id(other._instance_id)
|
Client(Client &&other) : _fd(other._fd), _instance_id(other._instance_id)
|
||||||
{
|
{
|
||||||
// Steal the fd from the moved-from client.
|
// Steal the fd from the moved-from client.
|
||||||
other._fd = -1;
|
other._fd = invalid_socket_handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +80,7 @@ private:
|
|||||||
int _send_cmds(const int argc, const char **argv);
|
int _send_cmds(const int argc, const char **argv);
|
||||||
int _listen();
|
int _listen();
|
||||||
|
|
||||||
int _fd;
|
socket_handle_t _fd;
|
||||||
int _instance_id; ///< instance ID for running multiple instances of the px4 server
|
int _instance_id; ///< instance ID for running multiple instances of the px4 server
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,12 +49,117 @@
|
|||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
#include <conio.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <px4_windows/platform.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "pxh.h"
|
#include "pxh.h"
|
||||||
|
|
||||||
namespace px4_daemon
|
namespace px4_daemon
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
bool read_windows_console_line(std::string &line)
|
||||||
|
{
|
||||||
|
HANDLE stdin_h = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
|
if (stdin_h == INVALID_HANDLE_VALUE || stdin_h == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.clear();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
char buffer[128] {};
|
||||||
|
DWORD bytes_read = 0;
|
||||||
|
|
||||||
|
if (!ReadFile(stdin_h, buffer, sizeof(buffer), &bytes_read, nullptr)) {
|
||||||
|
return !line.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read == 0) {
|
||||||
|
return !line.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (DWORD i = 0; i < bytes_read; ++i) {
|
||||||
|
const char c = buffer[i];
|
||||||
|
|
||||||
|
if (c == '\r') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_pending_windows_stdin()
|
||||||
|
{
|
||||||
|
px4_windows_restore_console_modes();
|
||||||
|
px4_windows_discard_pending_input();
|
||||||
|
px4_windows_restore_console_modes();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stdin_is_windows_console()
|
||||||
|
{
|
||||||
|
HANDLE stdin_h = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
|
||||||
|
if (stdin_h == INVALID_HANDLE_VALUE || stdin_h == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD mode = 0;
|
||||||
|
return GetConsoleMode(stdin_h, &mode) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_windows_redirected_line(std::string &line)
|
||||||
|
{
|
||||||
|
line.clear();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
char c = '\0';
|
||||||
|
const ssize_t bytes_read = ::read(STDIN_FILENO, &c, 1);
|
||||||
|
|
||||||
|
if (bytes_read <= 0) {
|
||||||
|
return !line.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\r') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
static SOCKET poll_socket(int fd)
|
||||||
|
{
|
||||||
|
return static_cast<SOCKET>(fd);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int poll_socket(int fd)
|
||||||
|
{
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
apps_map_type Pxh::_apps = {};
|
apps_map_type Pxh::_apps = {};
|
||||||
Pxh *Pxh::_instance = nullptr;
|
Pxh *Pxh::_instance = nullptr;
|
||||||
|
|
||||||
@@ -126,6 +231,13 @@ int Pxh::process_line(const std::string &line, bool silently_fail)
|
|||||||
list_builtins(_apps);
|
list_builtins(_apps);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
} else if (command == "exit" || command == "quit") {
|
||||||
|
if (_instance) {
|
||||||
|
_instance->_should_exit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
} else if (command.length() == 0 || command[0] == '#') {
|
} else if (command.length() == 0 || command[0] == '#') {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
return 0;
|
return 0;
|
||||||
@@ -199,7 +311,7 @@ void Pxh::run_remote_pxh(int remote_in_fd, int remote_out_fd)
|
|||||||
// Any data from remote_in_fd will be process as shell commands when an '\n' is received
|
// Any data from remote_in_fd will be process as shell commands when an '\n' is received
|
||||||
while (!_should_exit) {
|
while (!_should_exit) {
|
||||||
|
|
||||||
struct pollfd fds[3] { {pipe_stderr, POLLIN}, {pipe_stdout, POLLIN}, {remote_in_fd, POLLIN}};
|
struct pollfd fds[3] { {poll_socket(pipe_stderr), POLLIN}, {poll_socket(pipe_stdout), POLLIN}, {poll_socket(remote_in_fd), POLLIN}};
|
||||||
|
|
||||||
if (poll(fds, 3, -1) == -1) {
|
if (poll(fds, 3, -1) == -1) {
|
||||||
perror("Mavlink Shell Poll Error");
|
perror("Mavlink Shell Poll Error");
|
||||||
@@ -301,8 +413,61 @@ void Pxh::run_pxh()
|
|||||||
// Only the local_terminal needed for static calls
|
// Only the local_terminal needed for static calls
|
||||||
_instance = this;
|
_instance = this;
|
||||||
_local_terminal = true;
|
_local_terminal = true;
|
||||||
|
#ifndef __PX4_WINDOWS
|
||||||
_setup_term();
|
_setup_term();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
_print_prompt();
|
||||||
|
const bool stdin_is_tty = isatty(STDIN_FILENO) != 0;
|
||||||
|
const bool use_console_input = stdin_is_tty && stdin_is_windows_console();
|
||||||
|
|
||||||
|
while (!_should_exit) {
|
||||||
|
std::string line;
|
||||||
|
bool got_line = false;
|
||||||
|
|
||||||
|
if (use_console_input) {
|
||||||
|
got_line = read_windows_console_line(line);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
got_line = read_windows_redirected_line(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!got_line) {
|
||||||
|
if (_should_exit) {
|
||||||
|
flush_pending_windows_stdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearerr(stdin);
|
||||||
|
usleep(10000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_should_exit) {
|
||||||
|
flush_pending_windows_stdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_history.try_to_add(line);
|
||||||
|
_history.reset_to_end();
|
||||||
|
|
||||||
|
if (!stdin_is_tty) {
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
process_line(line, false);
|
||||||
|
|
||||||
|
if (_should_exit) {
|
||||||
|
flush_pending_windows_stdin();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_print_prompt();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
#else
|
||||||
std::string mystr;
|
std::string mystr;
|
||||||
int cursor_position = 0; // position of the cursor from right to left
|
int cursor_position = 0; // position of the cursor from right to left
|
||||||
// (0: all the way to the right, mystr.length: all the way to the left)
|
// (0: all the way to the right, mystr.length: all the way to the left)
|
||||||
@@ -310,7 +475,6 @@ void Pxh::run_pxh()
|
|||||||
_print_prompt();
|
_print_prompt();
|
||||||
|
|
||||||
while (!_should_exit) {
|
while (!_should_exit) {
|
||||||
|
|
||||||
int c = getchar();
|
int c = getchar();
|
||||||
std::string add_string; // string to add at current cursor position
|
std::string add_string; // string to add at current cursor position
|
||||||
bool update_prompt = true;
|
bool update_prompt = true;
|
||||||
@@ -330,6 +494,7 @@ void Pxh::run_pxh()
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case '\r': // Windows _getch() reports Enter as CR
|
||||||
case '\n': // user hit enter
|
case '\n': // user hit enter
|
||||||
_history.try_to_add(mystr);
|
_history.try_to_add(mystr);
|
||||||
_history.reset_to_end();
|
_history.reset_to_end();
|
||||||
@@ -409,6 +574,8 @@ void Pxh::run_pxh()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pxh::stop()
|
void Pxh::stop()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -115,7 +115,7 @@ private:
|
|||||||
|
|
||||||
int _instance_id; ///< instance ID for running multiple instances of the px4 server
|
int _instance_id; ///< instance ID for running multiple instances of the px4 server
|
||||||
|
|
||||||
int _fd;
|
socket_handle_t _fd;
|
||||||
|
|
||||||
static void _pthread_key_destructor(void *arg);
|
static void _pthread_key_destructor(void *arg);
|
||||||
|
|
||||||
|
|||||||
@@ -57,12 +57,22 @@
|
|||||||
|
|
||||||
using namespace px4_daemon;
|
using namespace px4_daemon;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
thread_local int stdout_isatty_override = -1;
|
||||||
|
}
|
||||||
|
|
||||||
FILE *get_stdout(bool *isatty_)
|
FILE *get_stdout(bool *isatty_)
|
||||||
{
|
{
|
||||||
|
if (stdout_isatty_override >= 0) {
|
||||||
|
if (isatty_) {
|
||||||
|
*isatty_ = stdout_isatty_override != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the server is not running, we are not in a thread that has been started
|
// If the server is not running, we are not in a thread that has been started
|
||||||
if (!Server::is_running()) {
|
if (!Server::is_running()) {
|
||||||
if (isatty_) { *isatty_ = isatty(1); }
|
if (isatty_ && stdout_isatty_override < 0) { *isatty_ = isatty(1); }
|
||||||
|
|
||||||
return stdout;
|
return stdout;
|
||||||
}
|
}
|
||||||
@@ -74,12 +84,22 @@ FILE *get_stdout(bool *isatty_)
|
|||||||
// have any thread specific data set and we won't have a pipe to write
|
// have any thread specific data set and we won't have a pipe to write
|
||||||
// stdout to.
|
// stdout to.
|
||||||
if (thread_data_ptr == nullptr || thread_data_ptr->thread_stdout == nullptr) {
|
if (thread_data_ptr == nullptr || thread_data_ptr->thread_stdout == nullptr) {
|
||||||
if (isatty_) { *isatty_ = isatty(1); }
|
if (isatty_ && stdout_isatty_override < 0) { *isatty_ = isatty(1); }
|
||||||
|
|
||||||
return stdout;
|
return stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isatty_) { *isatty_ = thread_data_ptr->is_atty; }
|
if (isatty_ && stdout_isatty_override < 0) { *isatty_ = thread_data_ptr->is_atty; }
|
||||||
|
|
||||||
return thread_data_ptr->thread_stdout;
|
return thread_data_ptr->thread_stdout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_stdout_isatty_override(bool isatty_)
|
||||||
|
{
|
||||||
|
stdout_isatty_override = isatty_ ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_stdout_isatty_override()
|
||||||
|
{
|
||||||
|
stdout_isatty_override = -1;
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,13 +38,32 @@
|
|||||||
|
|
||||||
#include "sock_protocol.h"
|
#include "sock_protocol.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace px4_daemon
|
namespace px4_daemon
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
uint16_t get_socket_port(int instance_id)
|
||||||
|
{
|
||||||
|
// Keep the local daemon control socket away from the default SITL MAVLink
|
||||||
|
// UDP ranges (for example 14580 + instance is used by px4-rc.mavlink).
|
||||||
|
// Override by setting PX4_DAEMON_PORT if the default collides with another
|
||||||
|
// app embedding PX4.
|
||||||
|
const char *override_port = std::getenv("PX4_DAEMON_PORT");
|
||||||
|
|
||||||
|
if (override_port) {
|
||||||
|
return static_cast<uint16_t>(std::atoi(override_port) + instance_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<uint16_t>(14680 + instance_id);
|
||||||
|
}
|
||||||
|
#else
|
||||||
std::string get_socket_path(int instance_id)
|
std::string get_socket_path(int instance_id)
|
||||||
{
|
{
|
||||||
// TODO: Use /var/run/px4/$instance/sock (or /var/run/user/$UID/... for non-root).
|
// TODO: Use /var/run/px4/$instance/sock (or /var/run/user/$UID/... for non-root).
|
||||||
return "/tmp/px4-sock-" + std::to_string(instance_id);
|
return "/tmp/px4-sock-" + std::to_string(instance_id);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace px4_daemon
|
} // namespace px4_daemon
|
||||||
|
|||||||
@@ -37,11 +37,30 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
#include <winsock2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace px4_daemon
|
namespace px4_daemon
|
||||||
{
|
{
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
using socket_handle_t = SOCKET;
|
||||||
|
static constexpr socket_handle_t invalid_socket_handle = INVALID_SOCKET;
|
||||||
|
|
||||||
|
// Windows: AF_INET TCP loopback. AF_UNIX was introduced in Windows 10 1803
|
||||||
|
// (WinSock2) and in principle would work, but Wine (used for SITL CI) did
|
||||||
|
// not support AF_UNIX until 7.x — 6.x still returns WSAEAFNOSUPPORT. TCP
|
||||||
|
// loopback sidesteps the portability gap without changing the rest of the
|
||||||
|
// daemon protocol.
|
||||||
|
uint16_t get_socket_port(int instance_id);
|
||||||
|
#else
|
||||||
|
using socket_handle_t = int;
|
||||||
|
static constexpr socket_handle_t invalid_socket_handle = -1;
|
||||||
std::string get_socket_path(int instance_id);
|
std::string get_socket_path(int instance_id);
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace px4_daemon
|
} // namespace px4_daemon
|
||||||
|
|||||||
@@ -55,16 +55,21 @@ int px4_sem_init(px4_sem_t *s, int pshared, unsigned value)
|
|||||||
// We do not used the process shared arg
|
// We do not used the process shared arg
|
||||||
(void)pshared;
|
(void)pshared;
|
||||||
s->value = value;
|
s->value = value;
|
||||||
pthread_cond_init(&(s->wait), nullptr);
|
|
||||||
pthread_mutex_init(&(s->lock), nullptr);
|
pthread_mutex_init(&(s->lock), nullptr);
|
||||||
|
|
||||||
#if !defined(__PX4_DARWIN)
|
#if !defined(__PX4_DARWIN) && !defined(__PX4_WINDOWS)
|
||||||
// We want to use CLOCK_MONOTONIC if possible but we can't on macOS
|
// Use CLOCK_MONOTONIC so the abstime passed to px4_sem_timedwait is not
|
||||||
// because it's not available.
|
// affected by wall-clock jumps. Not available on macOS; on MinGW
|
||||||
|
// winpthreads (up to at least 8.0), pthread_condattr_setclock is a
|
||||||
|
// no-op — pthread_cond_timedwait always interprets abstime as
|
||||||
|
// CLOCK_REALTIME. For Windows we default-init the cond and rewrite
|
||||||
|
// the abstime at wait time (see px4_sem_timedwait below).
|
||||||
pthread_condattr_t attr;
|
pthread_condattr_t attr;
|
||||||
pthread_condattr_init(&attr);
|
pthread_condattr_init(&attr);
|
||||||
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||||
pthread_cond_init(&(s->wait), &attr);
|
pthread_cond_init(&(s->wait), &attr);
|
||||||
|
#else
|
||||||
|
pthread_cond_init(&(s->wait), nullptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -133,6 +138,41 @@ int px4_sem_timedwait(px4_sem_t *s, const struct timespec *abstime)
|
|||||||
s->value--;
|
s->value--;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
|
#if defined(__PX4_WINDOWS) && !defined(ENABLE_LOCKSTEP_SCHEDULER)
|
||||||
|
// Callers build `abstime` from CLOCK_MONOTONIC, but MinGW winpthreads'
|
||||||
|
// pthread_cond_timedwait interprets it as CLOCK_REALTIME. Rebase onto
|
||||||
|
// CLOCK_REALTIME by taking the remaining duration against MONOTONIC
|
||||||
|
// now and adding it to REALTIME now.
|
||||||
|
struct timespec abstime_realtime = *abstime;
|
||||||
|
|
||||||
|
if (s->value < 0) {
|
||||||
|
struct timespec now_mono;
|
||||||
|
struct timespec now_real;
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now_mono);
|
||||||
|
clock_gettime(CLOCK_REALTIME, &now_real);
|
||||||
|
|
||||||
|
int64_t remaining_ns =
|
||||||
|
((int64_t)abstime->tv_sec - (int64_t)now_mono.tv_sec) * 1000000000LL +
|
||||||
|
((int64_t)abstime->tv_nsec - (int64_t)now_mono.tv_nsec);
|
||||||
|
|
||||||
|
if (remaining_ns < 0) {
|
||||||
|
remaining_ns = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t total_ns = (int64_t)now_real.tv_nsec + remaining_ns;
|
||||||
|
abstime_realtime.tv_sec = now_real.tv_sec + total_ns / 1000000000LL;
|
||||||
|
abstime_realtime.tv_nsec = total_ns % 1000000000LL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->value < 0) {
|
||||||
|
ret = px4_pthread_cond_timedwait(&(s->wait), &(s->lock), &abstime_realtime);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
if (s->value < 0) {
|
if (s->value < 0) {
|
||||||
ret = px4_pthread_cond_timedwait(&(s->wait), &(s->lock), abstime);
|
ret = px4_pthread_cond_timedwait(&(s->wait), &(s->lock), abstime);
|
||||||
|
|
||||||
@@ -140,6 +180,15 @@ int px4_sem_timedwait(px4_sem_t *s, const struct timespec *abstime)
|
|||||||
ret = 0;
|
ret = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
// The decrement above represents this waiter. If the timed wait
|
||||||
|
// expires or fails, the waiter is leaving and must not consume a
|
||||||
|
// future post.
|
||||||
|
s->value++;
|
||||||
|
}
|
||||||
|
|
||||||
errno = ret;
|
errno = ret;
|
||||||
|
|
||||||
if (ret != 0 && ret != ETIMEDOUT) {
|
if (ret != 0 && ret != ETIMEDOUT) {
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2026 PX4 Development Team. All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||||
|
* used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <px4_platform_common/shell.h>
|
||||||
|
|
||||||
|
#define MODULE_NAME "px4"
|
||||||
|
#include <px4_platform_common/log.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace px4
|
||||||
|
{
|
||||||
|
|
||||||
|
static std::string shell_quote(const std::string &value)
|
||||||
|
{
|
||||||
|
std::string quoted = "'";
|
||||||
|
|
||||||
|
for (char ch : value) {
|
||||||
|
if (ch == '\'') {
|
||||||
|
quoted += "'\\''";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
quoted += ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
quoted += "'";
|
||||||
|
return quoted;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *startup_shell_wrapper = R"sh(
|
||||||
|
__px4_echo() {
|
||||||
|
__px4_line=$*
|
||||||
|
__px4_level=
|
||||||
|
case "$__px4_line" in
|
||||||
|
"DEBUG ["*) __px4_level=DEBUG; __px4_rest=${__px4_line#DEBUG } ;;
|
||||||
|
"DEBUG ["*) __px4_level=DEBUG; __px4_rest=${__px4_line#DEBUG } ;;
|
||||||
|
"INFO ["*) __px4_level=INFO; __px4_rest=${__px4_line#INFO } ;;
|
||||||
|
"INFO ["*) __px4_level=INFO; __px4_rest=${__px4_line#INFO } ;;
|
||||||
|
"WARN ["*) __px4_level=WARN; __px4_rest=${__px4_line#WARN } ;;
|
||||||
|
"WARN ["*) __px4_level=WARN; __px4_rest=${__px4_line#WARN } ;;
|
||||||
|
"ERROR ["*) __px4_level=ERROR; __px4_rest=${__px4_line#ERROR } ;;
|
||||||
|
"ERROR ["*) __px4_level=ERROR; __px4_rest=${__px4_line#ERROR } ;;
|
||||||
|
"PANIC ["*) __px4_level=PANIC; __px4_rest=${__px4_line#PANIC } ;;
|
||||||
|
"PANIC ["*) __px4_level=PANIC; __px4_rest=${__px4_line#PANIC } ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -z "$__px4_level" ]; then
|
||||||
|
command echo "$@"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
__px4_module=${__px4_rest#\[}
|
||||||
|
__px4_module=${__px4_module%%\]*}
|
||||||
|
__px4_message=${__px4_rest#*\]}
|
||||||
|
__px4_message=${__px4_message# }
|
||||||
|
|
||||||
|
if { [ -t 1 ] || [ "${PX4_FORCE_COLOR:-}" = 1 ]; } && [ -z "${NO_COLOR:-}" ]; then
|
||||||
|
case "$__px4_level" in
|
||||||
|
DEBUG) __px4_color='\033[32m' ;;
|
||||||
|
WARN) __px4_color='\033[33m' ;;
|
||||||
|
ERROR|PANIC) __px4_color='\033[31m' ;;
|
||||||
|
*) __px4_color='\033[0m' ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
printf '%b%-5s %b[%s] %b%s%b\n' "$__px4_color" "$__px4_level" '\033[37m' "$__px4_module" "$__px4_color" "$__px4_message" '\033[0m'
|
||||||
|
else
|
||||||
|
printf '%s\n' "$__px4_line"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
echo() {
|
||||||
|
__px4_echo "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
__px4_script=$1
|
||||||
|
set -- "$2"
|
||||||
|
. "$__px4_script"
|
||||||
|
)sh";
|
||||||
|
|
||||||
|
int run_shell_script(const std::string &script_path,
|
||||||
|
const std::string &binary_dir,
|
||||||
|
int instance)
|
||||||
|
{
|
||||||
|
// Prepend binary_dir to PATH so the script's `. px4-alias.sh` and
|
||||||
|
// px4-<module> invocations resolve regardless of the user's cwd.
|
||||||
|
const char *path = getenv("PATH");
|
||||||
|
|
||||||
|
if (path && strstr(path, binary_dir.c_str()) == nullptr) {
|
||||||
|
std::string updated = binary_dir + ':' + path;
|
||||||
|
setenv("PATH", updated.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
PX4_INFO("startup script: /bin/sh %s %d", script_path.c_str(), instance);
|
||||||
|
const std::string cmd = "/bin/sh -c " + shell_quote(startup_shell_wrapper)
|
||||||
|
+ " px4-rc " + shell_quote(script_path) + ' ' + std::to_string(instance);
|
||||||
|
return system(cmd.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace px4
|
||||||
@@ -195,7 +195,15 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
|
|||||||
return (rv < 0) ? rv : -rv;
|
return (rv < 0) ? rv : -rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __PX4_WINDOWS
|
||||||
|
/* MinGW winpthreads only supports SCHED_OTHER for unprivileged threads;
|
||||||
|
* SCHED_FIFO/SCHED_RR require RT permissions that a SITL test run does
|
||||||
|
* not have. Ignore the requested policy and fall back to SCHED_OTHER. */
|
||||||
|
(void)scheduler;
|
||||||
|
rv = pthread_attr_setschedpolicy(&attr, SCHED_OTHER);
|
||||||
|
#else
|
||||||
rv = pthread_attr_setschedpolicy(&attr, scheduler);
|
rv = pthread_attr_setschedpolicy(&attr, scheduler);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
PX4_ERR("px4_task_spawn_cmd: failed to set sched policy");
|
PX4_ERR("px4_task_spawn_cmd: failed to set sched policy");
|
||||||
@@ -204,7 +212,7 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
|
|||||||
return (rv < 0) ? rv : -rv;
|
return (rv < 0) ? rv : -rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __PX4_CYGWIN
|
#if defined(__PX4_CYGWIN) || defined(__PX4_WINDOWS)
|
||||||
/* Priorities on Windows are defined a lot differently */
|
/* Priorities on Windows are defined a lot differently */
|
||||||
priority = SCHED_PRIORITY_DEFAULT;
|
priority = SCHED_PRIORITY_DEFAULT;
|
||||||
#endif
|
#endif
|
||||||
@@ -329,7 +337,7 @@ void px4_task_exit(int ret)
|
|||||||
|
|
||||||
pthread_mutex_unlock(&task_mutex);
|
pthread_mutex_unlock(&task_mutex);
|
||||||
|
|
||||||
pthread_exit((void *)(unsigned long)ret);
|
pthread_exit(reinterpret_cast<void *>(static_cast<intptr_t>(ret)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int px4_task_kill(px4_task_t id, int sig)
|
int px4_task_kill(px4_task_t id, int sig)
|
||||||
|
|||||||
Reference in New Issue
Block a user