add posix shell

squashed & rebased version, not including:
- listener changes
- src/firmware renaming

Commits:

tag_to_version.py: fix Python3 error

subprocess.communicate returns bytes instead of a str which is not the
same for Python3. Therefore, we need to decode the bytes.

cmake: remove folder src/firmware

The folder src/firmware was not intuitive. Why would the binaries for
SITL be inside a src and why even inside a src/firmware folder. Also,
the rootfs was put there which made it even more confusing.

The CMakeLists.txt files are moved into cmake/ and get now called from
the main CMakeLists.txt.

qshell: support for return value

Instead of just sending commands, qshell will now also wait until
the command has finished on QURT and sent back a return value. This will
allow all modules on the DSP side to be spawned from the Linux side
meaning that we only need one config/startup file instead of two.

adb_upload: create folders before pushing

Previously the script failed if the folder on the destination was not
already existing. This therefore makes pushing easier.

posix: spawn PX4 modules in bash

This adds the possibility to spawn PX4 modules out of bash. Basically,
the main executable can now be started as a server/daemon or as a
client.
The server replaces the existing functionality of the main exe with
the pxh shell, however, it also opens a pipe that clients can talk to.

Clients can run or spawn PX4 modules or commands by connecting to the
server over the pipe. They clients will get the stdout and return value
of their commands via a client specific pipe back.

This work will allow to start all modules using a bash script similar to
the way it is done in NuttX where the NuttShell scripts the startup
scripts and starts the modules.

SITL: use new client shell in SITL

This is a first step to use the new shell capabilities for SITL.
The new startup bash script rcS merges (and therefore replaces) the two
existing scripts rcS_gazebo_iris and rcS_jmavsim_iris.

More cleanup will be necessary for the rest of the SITL startup scripts.

Snapdragon: use new shell to start all modules

Instead of different mainapp.config and px4.config files, we can now use
a unified rcS bash script which starts all the modules based on
parameters, mainly the SYS_AUTOSTART param.

Snapdragon: fix the airframe description

pxh: argv needs to end with a nullptr

The comment was wrong that argv needs an additional 0 termination.
Instead it needs a nullptr at the end.

px4_posix_tasks: variable cleanup

The px4_task_spawn_cmd function got a cleanup while debugging, however,
no functional changes.

Snapdragon: move some drivers to 4100 config

These drivers are supported by the community, so they go into the 4100
config.

Snapdragon: update 210qc platform

px4_daemon: use doxygen comments

apps.h_in: fix string printf: use .c_str()

px4_daemon: \b -> \n in printf

px4_daemon: handle error in generate_uuid (close the file on error)

posix main: some clarifications in comment (it's the symlinks not the script aliases)

cmake: remove new install command again

This one was probably wrong and untested. Installing needs revisiting.

POSIX: remove argument USES_TERMINAL

POSIX: copy init and mixer files for SITL

Instead of using non-working install commands, the mixer and startup
files are now copied as part of the build in cmake.

adb_upload.sh: remove leftover commented printf

POSIX main: just the pointer instead of memmove

POSIX main: remove chroot

chroot is removed because it hasn't been used anywhere and seems
untested.

px4_daemon: remove client pipe when cleaning up

px4_daemon: fail if the client pipe already exists

The client pipe is supposed to be specific (by UUID), so the path
shouldn't exist already.

history: limit the number of history entries

This is a protection to avoid filling the memory if we are entering a
lot of commands (e.g. auto-generated).

px4_daemon: add a threadsafe map and use it

px4_daemon: whitespace

px4_daemon: fix client parsing

Sometimes the client ends up reading more than one packet in one read.
The parsing is not made for this and would require a (ring)buffer for
it.

The solution of this commit just reads as much as needed from the pipe
which avoids having to do buffering and parsing.

posix: changes sitl_run.sh and main.cpp cleanup

This changes the paths in sitl_run.sh quite a bit to allow the px4
binary to run in the rootfs directory which should make it convenient
and very close to the NuttX variant.

Also main.cpp got a big cleanup after the big rebase with some
conflicts. Quite some functionality was removed but it has yet to be
seen if it needs to be re-added.

px4_log: cleanup log levels, now they make sense

Before DEBUG and INFO log levels where inverted which didn't make much
sense in my eyes.

dataman: fix path for bash shell

logger: fix paths for bash shell

mavlink: fix paths for bash shell

param: fix path for bash shell

inav: fix paths for bash shell

sdlog2: fix paths for bash shell

ROMFS: add forgotten mixer to list

SITL init: more models, more options

- Support for different models using the unified startup
script rcS.
- Support to choose the estimator by setting the environment variable
  PX4_ESTIMATOR.
- Support to choose the logger by setting the environment variable
  PX4_LOGGER.

rcS: fix string comparison

listener: use template file

Instead of having all of the C++ code inside the Python file it is
nicer to have a separate template file with the C++ headers, etc.

px4_log: add PX4_INFO_RAW for raw printfs

This allows to do custom formatting but is still transported over
sockets to clients.

topic_listener: use PX4_INFO_RAW instead of printf

commander: use PX4_INFO_RAW for status

listener: rewrite to classes and factory

posix: fix some argument warnings

generate_listener.py: by accident changed shebang

listener: big refactor of the generator

Hopefully this makes it easier to read and change in the future.

rcS: manually take over rebase changes

listener: remove leftover try

listener: properly clean up topic instance

rcS: take over some vehicle specific changes

posix-configs: vehicle specifics to separate files

posix-configs: remove leftover lines

uORBDevices: new PX4_INFO_RAW instead of printf

px4_log: just use printf on NuttX

listener: use less binary space, strip on NuttX

generate_listener.py: remove commented code

cmake: fix syntax error from merge

px4_daemon: fixes after rebase of apps.h/cpp fix

px4_daemon: namespace missing

posix: only create stub for fsync on QURT

unitests: reduce dependencies of param test

This makes the unit test compile and link again after the bash changes.

QURT: some compile fixes after a rebase

SITL: arg change for sitl_run.sh to use rcS_test

This allows to use a custom startup file for testing.

SITL: add the folder test_data

SITL: implement shutdown command as systemcmd

The shutdown command needs to be a proper systemcmd, otherwise the alias
and symlink generation doesn't work and we end up calling shutdown of
the host computer which is to be avoided.

px4fmu_test: same IO_pass mixer as px4fmu_default

px4fmu_test: use normal quad x mixer

There is no good reason to use a specific test mixer, except more cmake
code around it. Therefore just use the same mixer as default, and at
some point px4fmu_test and px4fmu_default can get merged

POSIX: cleanup, dir and symlink fixes

This cleans up the logic behind the symlinking and creating directories.

POSIX: correct arg order in usage info

tests: fix paths for SITL tests

POSIX: printf fix

sitl_run.sh: try to make this run on Mac as well

cmake: try to make jenkins happier

Path cleanup, the bin is no longer in src/firmware

POSIX: fix symlink logic

SITL: prefix all exported env variables

cmake: fix path for ROS tests

integrationtests: fix log path

launch: try to make tets with ROS working again

px4_defines: fix after wrong merge deconflicting

px4_defines: get paths for POSIX correct

cmake: fix cmake arguments

This was fine with cmake 3.6 but did not work with cmake 3.2.2

cmake: use cp instead of cmake -E copy

cmake -E copy does not support copying multiple files with versions <
3.5. Therefore, just use cp for now.

ROMFS: fix build error after rebase

cmake: fix paths in configs

launch: use `spawn_model` again

cmake: various fixes after big rebase

param: path fixes after rebase

posix platform: fixes after rebase

test_mixer: fix screwed up rebase
This commit is contained in:
Julian Oes
2018-08-02 21:32:51 +02:00
committed by Lorenz Meier
parent 7bdfac786d
commit 0c5c741b1a
62 changed files with 3606 additions and 812 deletions
+46 -1
View File
@@ -5,10 +5,22 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
get_property(module_libraries GLOBAL PROPERTY PX4_MODULE_LIBRARIES)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(PX4_BASH_PREFIX "px4-")
add_definitions("-DPX4_BASH_PREFIX=\"${PX4_BASH_PREFIX}\"")
px4_posix_generate_builtin_commands(
OUT apps
MODULE_LIST ${module_libraries})
px4_posix_generate_alias(
OUT ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/px4-alias.sh
MODULE_LIST ${module_libraries}
PREFIX ${PX4_BASH_PREFIX}
)
if (("${BOARD}" STREQUAL "eagle") OR ("${BOARD}" STREQUAL "excelsior"))
include(fastrpc)
include(linux_app)
@@ -185,4 +197,37 @@ install(
${PROJECT_SOURCE_DIR}/Tools/sitl_gazebo/package.xml
DESTINATION
${PROJECT_NAME}/Tools/sitl_gazebo
)
)
# symlinks
px4_posix_generate_symlinks(
MODULE_LIST ${module_libraries}
PREFIX ${PX4_BASH_PREFIX}
TARGET px4
)
add_custom_command(TARGET px4
POST_BUILD
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/rootfs/etc/
)
add_custom_command(TARGET px4
POST_BUILD
COMMAND mkdir -p ${CMAKE_BINARY_DIR}/rootfs/etc/
)
add_custom_command(TARGET px4
POST_BUILD
COMMAND cp -R ${PROJECT_SOURCE_DIR}/posix-configs/SITL/init ${CMAKE_BINARY_DIR}/rootfs/etc/
)
add_custom_command(TARGET px4
POST_BUILD
COMMAND cp -R ${PROJECT_SOURCE_DIR}/ROMFS/sitl/mixers ${CMAKE_BINARY_DIR}/rootfs/etc/
)
add_custom_command(TARGET px4
POST_BUILD
COMMAND cp -R ${PROJECT_SOURCE_DIR}/ROMFS/px4fmu_common/mixers ${CMAKE_BINARY_DIR}/rootfs/etc/
)
+59
View File
@@ -103,6 +103,65 @@ function(px4_posix_generate_builtin_commands)
configure_file(${PX4_SOURCE_DIR}/src/platforms/apps.h.in ${OUT}.h)
endfunction()
# TODO: document API
function(px4_posix_generate_alias)
px4_parse_function_args(
NAME px4_posix_generate_alias
ONE_VALUE OUT PREFIX
MULTI_VALUE MODULE_LIST
REQUIRED OUT PREFIX MODULE_LIST
ARGN ${ARGN})
set(alias_string)
foreach(module ${MODULE_LIST})
foreach(property MAIN STACK PRIORITY)
get_target_property(${property} ${module} ${property})
if(NOT ${property})
set(${property} ${${property}_DEFAULT})
endif()
endforeach()
if (MAIN)
set(alias_string
"${alias_string}alias ${MAIN}='${PREFIX}${MAIN}'\n"
)
endif()
endforeach()
configure_file(${PX4_SOURCE_DIR}/cmake/posix/px4-alias.sh_in
${OUT}
)
endfunction()
# TODO: document API
function(px4_posix_generate_symlinks)
px4_parse_function_args(
NAME px4_posix_generate_symlinks
ONE_VALUE TARGET PREFIX
MULTI_VALUE MODULE_LIST
REQUIRED TARGET PREFIX MODULE_LIST
ARGN ${ARGN})
foreach(module ${MODULE_LIST})
foreach(property MAIN STACK PRIORITY)
get_target_property(${property} ${module} ${property})
if(NOT ${property})
set(${property} ${${property}_DEFAULT})
endif()
endforeach()
if (MAIN)
set(ln_name "${PREFIX}${MAIN}")
add_custom_command(TARGET ${TARGET}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E create_symlink ${TARGET} ${ln_name}
WORKING_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
)
endif()
endforeach()
endfunction()
#=============================================================================
#
# px4_os_add_flags
@@ -0,0 +1,65 @@
/****************************************************************************
*
* Copyright (C) 2016 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 server_io.h
*
* These are helper functions to send the stdout over a pipe
* back to the client.
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#pragma once
#include <stdio.h>
__BEGIN_DECLS
/**
* Get the stdout pipe buffer in order to write to fill it.
*
* @param buffer: pointer to buffer that will be set in function.
* @param max_length: length of the assigned buffer.
* @param is_atty: true if we are writing to a terminal (and can e.g. use colors).
* @return 0 on success
*/
__EXPORT int get_stdout_pipe_buffer(char **buffer, unsigned *max_length, bool *is_atty);
/**
* Write the filled bytes to the pipe.
*
* @param buffer_length: the number of bytes that should be written.
* @return 0 on success
*/
__EXPORT int send_stdout_pipe_buffer(unsigned buffer_length);
__END_DECLS
+1
View File
@@ -31,4 +31,5 @@
#
############################################################################
add_subdirectory(px4_daemon)
add_subdirectory(px4_layer)
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,42 @@
############################################################################
#
# Copyright (c) 2016 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.
#
############################################################################
px4_add_library(px4_daemon
pxh.cpp
history.cpp
client.cpp
server.cpp
server_io.cpp
pipe_protocol.cpp
)
+345
View File
@@ -0,0 +1,345 @@
/****************************************************************************
*
* Copyright (C) 2016 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 client.cpp
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <string>
#include <px4_log.h>
#include "client.h"
namespace px4_daemon
{
namespace client
{
static Client *_instance;
}
Client::Client() :
_uuid(0),
_client_send_pipe_fd(-1)
{
client::_instance = this;
}
Client::~Client()
{
client::_instance = nullptr;
}
int
Client::generate_uuid()
{
int rand_fd = open("/dev/urandom", O_RDONLY);
if (rand_fd < 0) {
PX4_ERR("open urandom");
return rand_fd;
}
int ret = 0;
int rand_read = read(rand_fd, &_uuid, sizeof(_uuid));
if (rand_read != sizeof(_uuid)) {
PX4_ERR("rand read fail");
ret = -errno;
}
close(rand_fd);
return ret;
}
int
Client::process_args(const int argc, const char **argv)
{
// Prepare return pipe first to avoid a race.
int ret = _prepare_recv_pipe();
if (ret != 0) {
PX4_ERR("Could not prepare recv pipe");
return -2;
}
ret = _send_cmds(argc, argv);
if (ret != 0) {
PX4_ERR("Could not send commands");
return -3;
}
return _listen();
}
int
Client::_prepare_recv_pipe()
{
int ret = get_client_recv_pipe_path(_uuid, _recv_pipe_path, sizeof(_recv_pipe_path));
if (ret < 0) {
PX4_ERR("failed to assemble path");
return ret;
}
ret = mkfifo(_recv_pipe_path, 0666);
if (ret < 0) {
PX4_ERR("pipe %s already exists, errno: %d, %s", _recv_pipe_path, errno, strerror(errno));
return ret;
}
return 0;
}
int
Client::_send_cmds(const int argc, const char **argv)
{
// Send the command to server.
client_send_packet_s packet;
packet.header.msg_id = client_send_packet_s::message_header_s::e_msg_id::EXECUTE;
packet.header.client_uuid = _uuid;
packet.payload.execute_msg.is_atty = isatty(STDOUT_FILENO);
// Concat arguments to send them.
std::string cmd_buf;
for (int i = 0; i < argc; ++i) {
cmd_buf += argv[i];
if (i + 1 != argc) {
cmd_buf += " ";
}
}
if (cmd_buf.size() >= sizeof(packet.payload.execute_msg.cmd)) {
PX4_ERR("commmand too long");
return -1;
}
strcpy((char *)packet.payload.execute_msg.cmd, cmd_buf.c_str());
// The size is +1 because we want to include the null termination.
packet.header.payload_length = cmd_buf.size() + 1;
_client_send_pipe_fd = open(CLIENT_SEND_PIPE_PATH, O_WRONLY);
if (_client_send_pipe_fd < 0) {
PX4_ERR("pipe open fail");
return _client_send_pipe_fd;
}
int bytes_to_send = get_client_send_packet_length(&packet);
int bytes_sent = write(_client_send_pipe_fd, &packet, bytes_to_send);
if (bytes_sent != bytes_to_send) {
PX4_ERR("write fail");
return bytes_sent;
}
return 0;
}
int
Client::_listen()
{
int client_recv_pipe_fd = open(_recv_pipe_path, O_RDONLY);
if (client_recv_pipe_fd < 0) {
PX4_ERR("open failed, errno: %d, %s", errno, strerror(errno));
}
bool exit_loop = false;
int exit_arg = 0;
while (!exit_loop) {
// We only read as much as we need, otherwise we might get out of
// sync with packets.
client_recv_packet_s packet_recv;
int bytes_read = read(client_recv_pipe_fd, &packet_recv, sizeof(client_recv_packet_s::header));
if (bytes_read > 0) {
// Using the header we can determine how big the payload is.
int payload_to_read = sizeof(packet_recv)
- sizeof(packet_recv.header)
- sizeof(packet_recv.payload)
+ packet_recv.header.payload_length;
// Again, we only read as much as we need because otherwise we need
// hold a buffer and parse it.
bytes_read = read(client_recv_pipe_fd, (char *)&packet_recv + bytes_read, payload_to_read);
if (bytes_read > 0) {
int retval = 0;
bool should_exit = false;
int parse_ret = _parse_client_recv_packet(packet_recv, retval, should_exit);
if (parse_ret != 0) {
PX4_ERR("retval could not be parsed");
exit_arg = -1;
} else {
exit_arg = retval;
}
exit_loop = should_exit;
} else if (bytes_read == 0) {
exit_arg = 0;
exit_loop = true;
}
} else if (bytes_read == 0) {
// 0 means the pipe has been closed by all clients.
exit_arg = 0;
exit_loop = true;
}
}
close(_client_send_pipe_fd);
return exit_arg;
}
int
Client::_parse_client_recv_packet(const client_recv_packet_s &packet, int &retval, bool &should_exit)
{
switch (packet.header.msg_id) {
case client_recv_packet_s::message_header_s::e_msg_id::RETVAL:
should_exit = true;
return _retval_cmd_packet(packet, retval);
case client_recv_packet_s::message_header_s::e_msg_id::STDOUT:
should_exit = false;
return _stdout_msg_packet(packet);
default:
should_exit = true;
PX4_ERR("recv msg_id not handled: %d", (int)packet.header.msg_id);
return -1;
}
}
int
Client::_retval_cmd_packet(const client_recv_packet_s &packet, int &retval)
{
if (packet.header.payload_length == sizeof(packet.payload.retval_msg.retval)) {
retval = packet.payload.retval_msg.retval;
return 0;
} else {
PX4_ERR("payload size wrong");
return -1;
}
}
int
Client::_stdout_msg_packet(const client_recv_packet_s &packet)
{
if (packet.header.payload_length <= sizeof(packet.payload.stdout_msg.text)) {
printf("%s", packet.payload.stdout_msg.text);
return 0;
} else {
PX4_ERR("payload size wrong");
return -1;
}
}
void
Client::register_sig_handler()
{
// Register handlers for Ctrl+C to kill the thread if something hangs.
struct sigaction sig_int {};
sig_int.sa_handler = Client::_static_sig_handler;
// Without the flag SA_RESTART, we can't use open() after Ctrl+C has
// been pressed, and we can't wait for the return value from the
// cancelled command.
sig_int.sa_flags = SA_RESTART;
sigaction(SIGINT, &sig_int, NULL);
sigaction(SIGTERM, &sig_int, NULL);
}
void
Client::_static_sig_handler(int sig_num)
{
client::_instance->_sig_handler(sig_num);
}
void
Client::_sig_handler(int sig_num)
{
client_send_packet_s packet;
packet.header.msg_id = client_send_packet_s::message_header_s::e_msg_id::KILL;
packet.header.client_uuid = _uuid;
packet.payload.kill_msg.cmd_id = sig_num;
packet.header.payload_length = sizeof(packet.payload.kill_msg.cmd_id);
if (_client_send_pipe_fd < 0) {
PX4_ERR("pipe open fail");
exit(-1);
}
int bytes_to_send = get_client_send_packet_length(&packet);
int bytes_sent = write(_client_send_pipe_fd, &packet, bytes_to_send);
if (bytes_sent != bytes_to_send) {
PX4_ERR("write fail");
exit(-1);
}
}
} // namespace px4_daemon
+103
View File
@@ -0,0 +1,103 @@
/****************************************************************************
*
* Copyright (C) 2016 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 client.h
*
* The client can write a command to the pipe that is supplied by the server.
* It will then open another pipe with its own UUID encoded and listen for
* stdout of the process that it started and the return value.
*
* It the client receives a signal (e.g. Ctrl+C) it will catch it and send it
* as a message to the server in order to terminate the thread.
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#pragma once
#include <stdint.h>
#include "pipe_protocol.h"
namespace px4_daemon
{
class Client
{
public:
Client();
~Client();
/**
* Initialize the unique ID of the client.
*
* @return 0 on success.
*/
int generate_uuid();
/**
* Make sure to catch signals in order to forward them to the server.
*/
void register_sig_handler();
/**
* Process the supplied command line arguments and send them to server.
*
* @param argc: number of arguments
* @param argv: argument values
* @return 0 on success
*/
int process_args(const int argc, const char **argv);
private:
int _prepare_recv_pipe();
int _send_cmds(const int argc, const char **argv);
int _listen();
int _parse_client_recv_packet(const client_recv_packet_s &packet, int &retval, bool &should_exit);
int _retval_cmd_packet(const client_recv_packet_s &packet, int &retval);
int _stdout_msg_packet(const client_recv_packet_s &packet);
static void _static_sig_handler(int sig_num);
void _sig_handler(int sig_num);
uint64_t _uuid;
int _client_send_pipe_fd;
char _recv_pipe_path[RECV_PIPE_PATH_LEN];
};
} // namespace px4_daemon
+126
View File
@@ -0,0 +1,126 @@
/****************************************************************************
*
* Copyright (C) 2015-2016 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 history.cpp
*
* @author Julian Oes <julian@oes.ch>
*/
#include <string>
#include <vector>
#include "history.h"
namespace px4_daemon
{
void History::try_to_add(const std::string &line)
{
// Don't save an empty line.
if (line.empty()) {
return;
}
// Don't add duplicate entries.
if (!_history.empty() && line.compare(_history.back()) == 0) {
return;
}
if (_history.size() == MAX_HISTORY_SIZE) {
_history.erase(_history.begin());
}
_history.push_back(line);
}
void History::reset_to_end()
{
_current_history_entry = _history.end();
}
void History::try_to_save_current_line(const std::string &line)
{
// Don't save what's currently entered line if there is no history
// entry to switch to.
if (_history.empty()) {
return;
}
// Don't save the current line if we are already jumping around in
// the history, and we must have already saved it.
if (_current_history_entry != _history.end()) {
return;
}
_current_line = line;
}
void History::get_previous(std::string &line)
{
if (_history.empty()) {
return;
}
if (_current_history_entry == _history.begin()) {
return;
}
_current_history_entry = std::prev(_current_history_entry);
line = *_current_history_entry;
}
void History::get_next(std::string &line)
{
if (_history.empty()) {
return;
}
// Already at the end, don't even try to get the next.
if (_current_history_entry == _history.end()) {
line = _current_line;
return;
}
_current_history_entry = std::next(_current_history_entry);
// We might have reached next now, ignore it and use what we saved
// in the beginning.
if (_current_history_entry == _history.end()) {
line = _current_line;
return;
}
line = *_current_history_entry;
}
} // namespace px4_daemon
+104
View File
@@ -0,0 +1,104 @@
/****************************************************************************
*
* Copyright (C) 2016 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 history.h
*
* Simple command history for the PX4 shell (pxh).
*
* This allows to go back in the history of entered commands.
* Additionally, before going back in the history, the current prompt can get saved.
*
* @author Julian Oes <julian@oes.ch>
*/
#pragma once
#include <vector>
#include <string>
namespace px4_daemon
{
class History
{
public:
/**
* Try to append the current line to the history.
* Ignore the line if it is empty or duplicate of the
* last added one.
*
* Drop the first entry of the history if we reach the
* MAX_HISTORY_SIZE.
*
* @param line: command line to be added.
*/
void try_to_add(const std::string &line);
/**
* After executing a command in the shell, we want to be at
* the end of the history again.
*/
void reset_to_end();
/**
* If we start scrolling up in the history, we can try to save
* the current command line. When we scroll back down, we can
* get it out again.
*
* @param line: line to be saved
*/
void try_to_save_current_line(const std::string &line);
/**
* Set the previous (earlier) command from the history.
*
* @param line: swap to previous line if available.
*/
void get_previous(std::string &line);
/**
* Set the next (more recent) command from the history.
*
* @param line: swap to next line if available, otherwise saved current.
*/
void get_next(std::string &line);
static const unsigned MAX_HISTORY_SIZE = 100;
private:
std::vector<std::string> _history;
std::vector<std::string>::iterator _current_history_entry;
std::string _current_line;
};
} // namespace px4_daemon
@@ -0,0 +1,67 @@
/****************************************************************************
*
* Copyright (C) 2016 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 pipe_protocol.cpp
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
#include "pipe_protocol.h"
namespace px4_daemon
{
unsigned get_client_send_packet_length(const client_send_packet_s *packet)
{
return sizeof(client_send_packet_s) - sizeof(packet->payload) + packet->header.payload_length + sizeof(uint8_t);
}
unsigned get_client_recv_packet_length(const client_recv_packet_s *packet)
{
return sizeof(client_recv_packet_s) - sizeof(packet->payload) + packet->header.payload_length;
}
int get_client_recv_pipe_path(const uint64_t uuid, char *path, const size_t path_len)
{
return snprintf(path, path_len, "%s_%016" PRIx64, CLIENT_RECV_PIPE_PATH, uuid);
}
} // namespace px4_daemon
@@ -0,0 +1,98 @@
/****************************************************************************
*
* Copyright (C) 2016 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 pipe_protocol.h
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#pragma once
#include <stdint.h>
namespace px4_daemon
{
static const char CLIENT_SEND_PIPE_PATH[] = "/tmp/px4_client_send_pipe";
static const char CLIENT_RECV_PIPE_PATH[] = "/tmp/px4_client_recv_pipe";
static const unsigned RECV_PIPE_PATH_LEN = 64;
struct client_send_packet_s {
struct message_header_s {
enum class e_msg_id : uint8_t {
EXECUTE,
KILL
} msg_id;
uint64_t client_uuid;
unsigned payload_length;
} header;
union {
struct execute_msg_s {
uint8_t is_atty;
uint8_t cmd[512 - sizeof(message_header_s) - sizeof(uint8_t)];
} execute_msg;
struct kill_msg_s {
int cmd_id;
} kill_msg;
} payload;
};
// We have per client receiver a pipe with the uuid in its file path.
struct client_recv_packet_s {
struct message_header_s {
enum class e_msg_id : uint8_t {
RETVAL,
STDOUT
} msg_id;
unsigned payload_length;
} header;
union {
struct retval_msg_s {
int retval;
} retval_msg;
struct stdout_msg_s {
uint8_t text[512 - sizeof(message_header_s)];
} stdout_msg;
} payload;
};
unsigned get_client_send_packet_length(const client_send_packet_s *packet);
unsigned get_client_recv_packet_length(const client_recv_packet_s *packet);
int get_client_recv_pipe_path(const uint64_t uuid, char *path, const size_t path_len);
} // namespace px4_daemon
+293
View File
@@ -0,0 +1,293 @@
/****************************************************************************
*
* Copyright (C) 2015-2016 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 pxh.cpp
*
* This is a simple PX4 shell implementation used to start modules.
*
* @author Mark Charlebois <charlebm@gmail.com>
* @author Roman Bapst <bapstroman@gmail.com>
* @author Julian Oes <julian@oes.ch>
*/
#include <string>
#include <sstream>
#include <vector>
#include <stdio.h>
#include "pxh.h"
namespace px4_daemon
{
Pxh *Pxh::_instance = nullptr;
apps_map_type Pxh::_apps = {};
Pxh::Pxh()
{
_instance = this;
}
Pxh::~Pxh()
{
_instance = nullptr;
}
int Pxh::process_line(const std::string &line, bool silently_fail)
{
if (line.empty()) {
return 0;
}
if (_apps.size() == 0) {
init_app_map(_apps);
}
std::stringstream line_stream(line);
std::string word;
std::vector<std::string> words;
// First arg should be the command.
while (line_stream >> word) {
words.push_back(word);
}
const std::string &command(words.front());
if (_apps.find(command) != _apps.end()) {
// Note that argv[argc] always needs to be a nullptr.
// Therefore add one more entry.
const char *arg[words.size() + 1];
for (unsigned i = 0; i < words.size(); ++i) {
arg[i] = (char *)words[i].c_str();
}
// Explicitly set this nullptr.
arg[words.size()] = nullptr;
int retval = _apps[command](words.size(), (char **)arg);
if (retval) {
if (!silently_fail) {
printf("Command '%s' failed, returned %d.\n", command.c_str(), retval);
}
}
return retval;
} else if (command.compare("help") == 0) {
list_builtins(_apps);
return 0;
} else if (command.length() == 0 || command[0] == '#') {
// Do nothing
return 0;
} else if (!silently_fail) {
//std::cout << "Invalid command: " << command << "\ntype 'help' for a list of commands" << endl;
printf("Invalid command: %s\ntype 'help' for a list of commands\n", command.c_str());
return -1;
} else {
return -1;
}
}
void Pxh::run_pxh()
{
_should_exit = false;
_setup_term();
std::string mystr = "";
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)
_print_prompt();
while (!_should_exit) {
int c = getchar();
std::string add_string; // string to add at current cursor position
bool update_prompt = true;
switch (c) {
case EOF:
_should_exit = true;
break;
case 127: // backslash
if ((int)mystr.length() - cursor_position > 0) {
mystr.erase(mystr.length() - cursor_position - 1, 1);
}
break;
case '\n': // user hit enter
_history.try_to_add(mystr);
_history.reset_to_end();
printf("\n");
process_line(mystr, false);
// reset string and cursor position
mystr = "";
cursor_position = 0;
update_prompt = false;
_print_prompt();
break;
case '\033': { // arrow keys
c = getchar(); // skip first one, does not have the info
c = getchar();
if (c == 'A') { // arrow up
_history.try_to_save_current_line(mystr);
_history.get_previous(mystr);
cursor_position = 0; // move cursor to end of line
} else if (c == 'B') { // arrow down
_history.get_next(mystr);
cursor_position = 0; // move cursor to end of line
} else if (c == 'C') { // arrow right
if (cursor_position > 0) {
cursor_position--;
}
} else if (c == 'D') { // arrow left
if (cursor_position < (int)mystr.length()) {
cursor_position++;
}
} else if (c == 'H') { // Home (go to the beginning of the command)
cursor_position = mystr.length();
} else if (c == '1') { // Home (go to the beginning of the command, Editing key)
(void)getchar(); // swallow '~'
cursor_position = mystr.length();
} else if (c == 'F') { // End (go to the end of the command)
cursor_position = 0;
} else if (c == '4') { // End (go to the end of the command, Editing key)
(void)getchar(); // swallow '~'
cursor_position = 0;
}
break;
}
default: // any other input
if (c > 3) {
add_string += (char)c;
} else {
update_prompt = false;
}
break;
}
if (update_prompt) {
// reprint prompt with mystr
mystr.insert(mystr.length() - cursor_position, add_string);
_clear_line();
_print_prompt();
printf("%s", mystr.c_str());
// Move the cursor to its position
if (cursor_position > 0) {
_move_cursor(cursor_position);
}
}
}
return;
}
void Pxh::stop()
{
_restore_term();
if (_instance) {
_instance->_should_exit = true;
}
}
void Pxh::_setup_term()
{
// Make sure we restore terminal at exit.
tcgetattr(0, &_orig_term);
atexit(Pxh::_restore_term);
// change input mode so that we can manage shell
struct termios term;
tcgetattr(0, &term);
term.c_lflag &= ~ICANON;
term.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &term);
setbuf(stdin, NULL);
}
void Pxh::_restore_term(void)
{
if (_instance) {
tcsetattr(0, TCSANOW, &_instance->_orig_term);
}
}
void Pxh::_print_prompt()
{
fflush(stdout);
printf("pxh> ");
fflush(stdout);
}
void Pxh::_clear_line()
{
printf("%c[2K%c", (char)27, (char)13);
}
void Pxh::_move_cursor(int position)
{
printf("\033[%dD", position);
}
} // namespace px4_daemon
+98
View File
@@ -0,0 +1,98 @@
/****************************************************************************
*
* Copyright (C) 2016 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 pxh.h
*
* The POSIX PX4 implementation features a simple shell to start modules
* or use system commands.
*
* @author Mark Charlebois <charlebm@gmail.com>
* @author Roman Bapst <bapstroman@gmail.com>
* @author Julian Oes <julian@oes.ch>
*/
#pragma once
#include <vector>
#include <string>
#include <termios.h>
#include <platforms/posix/apps.h>
#include "history.h"
namespace px4_daemon
{
class Pxh
{
public:
Pxh();
~Pxh();
/**
* Process and run one command line.
*
* @param silently_fail: don't make a fuss on failure
* @return 0 if successful. */
static int process_line(const std::string &line, bool silently_fail);
/**
* Run the pxh shell. This will only return if stop() is called.
*/
void run_pxh();
/**
* Can be called to stop pxh.
*/
static void stop();
private:
void _print_prompt();
void _move_cursor(int position);
void _clear_line();
void _setup_term();
static void _restore_term();
bool _should_exit;
History _history;
struct termios _orig_term;
static apps_map_type _apps;
static Pxh *_instance;
};
} // namespace px4_daemon
+304
View File
@@ -0,0 +1,304 @@
/****************************************************************************
*
* Copyright (C) 2016 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 server.cpp
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <pthread.h>
#include <poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <px4_log.h>
#include "pxh.h"
#include "server.h"
namespace px4_daemon
{
Server *Server::_instance = nullptr;
Server::Server()
{
_instance = this;
}
Server::~Server()
{
_instance = nullptr;
}
int
Server::start()
{
if (0 != pthread_create(&_server_main_pthread,
NULL,
_server_main_trampoline,
NULL)) {
PX4_ERR("error creating client handler thread");
return -1;
}
return 0;
}
void *
Server::_server_main_trampoline(void *arg)
{
if (_instance) {
_instance->_server_main(arg);
}
return NULL;
}
void Server::_pthread_key_destructor(void *arg)
{
delete ((CmdThreadSpecificData *)arg);
}
void
Server::_server_main(void *arg)
{
// Set thread specific pipe to supplied file descriptor.
int ret = pthread_key_create(&_key, _pthread_key_destructor);
if (ret != 0) {
PX4_ERR("failed to create pthread key");
return;
}
// Delete pipe in case it exists already.
unlink(CLIENT_SEND_PIPE_PATH);
// Create new pipe to listen to clients.
mkfifo(CLIENT_SEND_PIPE_PATH, 0666);
int client_send_pipe_fd = open(CLIENT_SEND_PIPE_PATH, O_RDONLY);
while (true) {
client_send_packet_s packet;
int bytes_read = read(client_send_pipe_fd, &packet, sizeof(packet));
if (bytes_read > 0) {
_parse_client_send_packet(packet);
} else if (bytes_read == 0) {
// 0 means the pipe has been closed by all clients
// and we need to re-open it.
close(client_send_pipe_fd);
client_send_pipe_fd = open(CLIENT_SEND_PIPE_PATH, O_RDONLY);
}
}
close(client_send_pipe_fd);
return;
}
void
Server::_parse_client_send_packet(const client_send_packet_s &packet)
{
switch (packet.header.msg_id) {
case client_send_packet_s::message_header_s::e_msg_id::EXECUTE:
_execute_cmd_packet(packet);
break;
case client_send_packet_s::message_header_s::e_msg_id::KILL:
_kill_cmd_packet(packet);
break;
default:
PX4_ERR("send msg_id not handled");
break;
}
}
void
Server::_execute_cmd_packet(const client_send_packet_s &packet)
{
if (packet.header.payload_length == 0) {
PX4_ERR("command length 0");
return;
}
// We open the client's specific pipe to write the return value and stdout back to.
// The pipe's path is created knowing the UUID of the client.
char path[RECV_PIPE_PATH_LEN] = {};
int ret = get_client_recv_pipe_path(packet.header.client_uuid, path, RECV_PIPE_PATH_LEN);
if (ret < 0) {
PX4_ERR("failed to assemble path");
return;
}
int pipe_fd = open(path, O_WRONLY);
if (pipe_fd < 0) {
PX4_ERR("pipe open fail");
return;
}
// To execute a command we start a new thread.
pthread_t new_pthread;
// We need to copy everything that the new thread needs because we will go
// out of scope.
RunCmdArgs *args = new RunCmdArgs;
memcpy(args->cmd, packet.payload.execute_msg.cmd, sizeof(args->cmd));
args->client_uuid = packet.header.client_uuid;
args->pipe_fd = pipe_fd;
args->is_atty = packet.payload.execute_msg.is_atty;
if (0 != pthread_create(&new_pthread, NULL, Server::_run_cmd, (void *)args)) {
PX4_ERR("could not start pthread");
delete args;
return;
}
// We keep two maps for cleanup if a thread is finished or killed.
_client_uuid_to_pthread.insert(std::pair<uint64_t, pthread_t>
(packet.header.client_uuid, new_pthread));
_pthread_to_pipe_fd.insert(std::pair<pthread_t, int>
(new_pthread, pipe_fd));
}
void
Server::_kill_cmd_packet(const client_send_packet_s &packet)
{
// TODO: we currently ignore the signal type.
pthread_t pthread_to_kill = _client_uuid_to_pthread.get(packet.header.client_uuid);
// TODO: use a more graceful exit method to avoid resource leaks
int ret = pthread_cancel(pthread_to_kill);
if (ret != 0) {
PX4_ERR("failed to cancel thread");
}
_cleanup_thread(packet.header.client_uuid);
// We don't send retval when we get killed.
// The client knows this and just exits without confirmation.
}
void
*Server::_run_cmd(void *arg)
{
RunCmdArgs *args = (RunCmdArgs *)arg;
// Copy arguments so that we can cleanup the arg structure.
uint64_t client_uuid = args->client_uuid;
int pipe_fd = args->pipe_fd;
bool is_atty = args->is_atty;
std::string message_str(args->cmd);
// Clean up the args from the heap in case the thread gets canceled
// from outside.
delete args;
// We register thread specific data. This is used for PX4_INFO (etc.) log calls.
CmdThreadSpecificData *thread_data_ptr;
if ((thread_data_ptr = (CmdThreadSpecificData *)pthread_getspecific(_instance->_key)) == NULL) {
thread_data_ptr = new CmdThreadSpecificData;
thread_data_ptr->pipe_fd = pipe_fd;
thread_data_ptr->is_atty = is_atty;
thread_data_ptr->packet.header.msg_id = client_recv_packet_s::message_header_s::e_msg_id::STDOUT;
(void)pthread_setspecific(_instance->_key, (void *)thread_data_ptr);
}
// Run the actual command.
int retval = Pxh::process_line(message_str, true);
// Report return value.
_send_retval(pipe_fd, retval, client_uuid);
// Clean up before returning.
_instance->_cleanup_thread(client_uuid);
return NULL;
}
void
Server::_send_retval(const int pipe_fd, const int retval, const uint64_t client_uuid)
{
client_recv_packet_s packet;
packet.header.msg_id = client_recv_packet_s::message_header_s::e_msg_id::RETVAL;
packet.header.payload_length = sizeof(packet.payload.retval_msg);
packet.payload.retval_msg.retval = retval;
int bytes_to_send = get_client_recv_packet_length(&packet);
int bytes_sent = write(pipe_fd, &packet, bytes_to_send);
if (bytes_sent != bytes_to_send) {
printf("write fail\n");
return;
}
}
void
Server::_cleanup_thread(const uint64_t client_uuid)
{
pthread_t pthread_killed = _client_uuid_to_pthread.get(client_uuid);
int pipe_fd = _pthread_to_pipe_fd.get(pthread_killed);
close(pipe_fd);
char path[RECV_PIPE_PATH_LEN] = {};
get_client_recv_pipe_path(client_uuid, path, RECV_PIPE_PATH_LEN);
unlink(path);
_client_uuid_to_pthread.erase(client_uuid);
_pthread_to_pipe_fd.erase(pthread_killed);
}
} //namespace px4_daemon
+128
View File
@@ -0,0 +1,128 @@
/****************************************************************************
*
* Copyright (C) 2016 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 server.h
*
* The server (also called daemon) opens a pipe for clients to write to.
*
* Once a client connects it will send a command as well as a unique ID.
* The server will return the stdout of the executing command, as well as the return
* value to the client on a client specific pipe.
* The client specific pipe are idenified by the unique ID of the client.
*
* There should only every be one server running, therefore the static instance.
* The Singleton implementation is not complete, but it should be obvious not
* to instantiate multiple servers.
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include <map>
#include "pipe_protocol.h"
#include "threadsafe_map.h"
namespace px4_daemon
{
class Server
{
public:
Server();
~Server();
/**
* Start the server. This will spawn a thread with a
* while loop waiting for clients sending commands.
*
* @return 0 if started successfully
*/
int start();
struct CmdThreadSpecificData {
int pipe_fd; // pipe fd to send data to descriptor
bool is_atty; // whether file descriptor refers to a terminal
client_recv_packet_s packet;
};
static bool is_running()
{
return _instance != nullptr;
}
static pthread_key_t get_pthread_key()
{
return _instance->_key;
}
private:
static void *_server_main_trampoline(void *arg);
void _server_main(void *arg);
void _parse_client_send_packet(const client_send_packet_s &packet);
void _execute_cmd_packet(const client_send_packet_s &packet);
void _kill_cmd_packet(const client_send_packet_s &packet);
void _cleanup_thread(const uint64_t client_uuid);
static void _send_retval(const int pipe_fd, const int retval, const uint64_t client_uuid);
struct RunCmdArgs {
char cmd[sizeof(client_send_packet_s::payload.execute_msg.cmd)];
uint64_t client_uuid;
bool is_atty;
int pipe_fd;
};
static void *_run_cmd(void *arg);
pthread_t _server_main_pthread;
ThreadsafeMap <pthread_t, int> _pthread_to_pipe_fd;
ThreadsafeMap <uint64_t, pthread_t> _client_uuid_to_pthread;
pthread_key_t _key;
static void _pthread_key_destructor(void *arg);
static Server *_instance;
};
} // namespace px4_daemon
@@ -0,0 +1,135 @@
/****************************************************************************
*
* Copyright (C) 2016 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 server_io.cpp
*
* @author Julian Oes <julian@oes.ch>
* @author Beat Küng <beat-kueng@gmx.net>
*/
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <pthread.h>
#include <poll.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <px4_log.h>
#include "server.h"
#include <px4_daemon/server_io.h>
#include "pipe_protocol.h"
using namespace px4_daemon;
int get_stdout_pipe_buffer(char **buffer, unsigned *max_length, bool *is_atty)
{
// The thread specific data won't be initialized if the server is not running.
Server::CmdThreadSpecificData *thread_data_ptr;
if (!Server::is_running()) {
return -1;
}
// If we are not in a thread that has been started by a client, we don't
// have any thread specific data set and we won't have a pipe to write
// stdout to.
if ((thread_data_ptr = (Server::CmdThreadSpecificData *)pthread_getspecific(
Server::get_pthread_key())) == NULL) {
return -1;
}
#ifdef __PX4_POSIX_EAGLE
// XXX FIXME: thread_data_ptr is set to 0x1 in the main thread on Snapdragon
// even though the pthread_key has been created.
// We can catch this using the check below but we have no clue why this happens.
if (thread_data_ptr == (void *)0x1) {
return -1;
}
#endif
client_recv_packet_s *packet = &thread_data_ptr->packet;
*buffer = (char *)packet->payload.stdout_msg.text;
*max_length = sizeof(packet->payload.stdout_msg.text);
*is_atty = thread_data_ptr->is_atty;
return 0;
}
int send_stdout_pipe_buffer(unsigned buffer_length)
{
assert(buffer_length <= sizeof(client_recv_packet_s::payload.stdout_msg.text));
Server::CmdThreadSpecificData *thread_data_ptr;
if (!Server::is_running()) {
return -1;
}
if ((thread_data_ptr = (Server::CmdThreadSpecificData *)pthread_getspecific(
Server::get_pthread_key())) == NULL) {
return -1;
}
client_recv_packet_s *packet = &thread_data_ptr->packet;
packet->header.payload_length = buffer_length;
int pipe_fd = thread_data_ptr->pipe_fd;
int bytes_to_send = get_client_recv_packet_length(packet);
// Check if we can write first by writing 0 bytes.
// If we don't do this, we'll get SIGPIPE and be very unhappy
// because the whole process will go down.
int ret = write(pipe_fd, NULL, 0);
if (ret == 0 && errno == EPIPE) {
printf("Error: can't write to closed pipe, giving up.\n");
pthread_exit(NULL);
}
int bytes_sent = write(pipe_fd, packet, bytes_to_send);
if (bytes_sent != bytes_to_send) {
printf("write fail\n");
return -1;
}
return 0;
}
@@ -0,0 +1,104 @@
/****************************************************************************
*
* Copyright (C) 2016 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 threadsafe_map.h
*
* This is a small wrapper for std::map to make it thread-safe.
*
* @author Julian Oes <julian@oes.ch>
*/
#pragma once
#include <pthread.h>
#include <map>
namespace px4_daemon
{
template <class Key, class Type>
class ThreadsafeMap
{
public:
ThreadsafeMap() :
_mutex(PTHREAD_MUTEX_INITIALIZER) {};
~ThreadsafeMap() {};
/**
* Insert an entry into the map.
*/
void
insert(std::pair<Key, Type> pair)
{
_lock();
_map.insert(pair);
_unlock();
}
/**
* Get an entry into from the map.
*/
Type get(Key key)
{
// Supposedly locking is not needed to read but since we're
// not sure, let's lock anyway.
_lock();
const Type temp = _map[key];
_unlock();
return temp;
}
void erase(Key key)
{
_lock();
_map.erase(key);
_unlock();
}
private:
void _lock()
{
pthread_mutex_lock(&_mutex);
}
void _unlock()
{
pthread_mutex_unlock(&_mutex);
}
std::map<Key, Type> _map;
pthread_mutex_t _mutex;
};
} // namespace px4_daemon
@@ -54,6 +54,7 @@ add_library(px4_layer
${SHMEM_SRCS}
)
target_link_libraries(px4_layer PRIVATE work_queue)
target_link_libraries(px4_layer PRIVATE px4_daemon)
if (EXTRA_DEPENDS)
add_dependencies(px4_layer ${EXTRA_DEPENDS})
@@ -122,16 +122,11 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
char *const argv[])
{
int rv;
int argc = 0;
int i;
int argc = 0;
unsigned int len = 0;
unsigned long offset;
unsigned long structsize;
char *p = (char *)argv;
pthread_attr_t attr;
struct sched_param param = {};
char *p = (char *)argv;
// Calculate argc
while (p != (char *)nullptr) {
@@ -145,12 +140,12 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
len += strlen(p) + 1;
}
structsize = sizeof(pthdata_t) + (argc + 1) * sizeof(char *);
unsigned long structsize = sizeof(pthdata_t) + (argc + 1) * sizeof(char *);
// not safe to pass stack data to the thread creation
pthdata_t *taskdata = (pthdata_t *)malloc(structsize + len);
memset(taskdata, 0, structsize + len);
offset = ((unsigned long)taskdata) + structsize;
unsigned long offset = ((unsigned long)taskdata) + structsize;
strncpy(taskdata->name, name, 16);
taskdata->name[15] = 0;
@@ -169,7 +164,8 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
PX4_DEBUG("starting task %s", name);
rv = pthread_attr_init(&attr);
pthread_attr_t attr;
int rv = pthread_attr_init(&attr);
if (rv != 0) {
PX4_ERR("px4_task_spawn_cmd: failed to init thread attrs");
@@ -230,10 +226,9 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
pthread_mutex_lock(&task_mutex);
int taskid = 0;
px4_task_t taskid = 0;
for (i = 0; i < PX4_MAX_TASKS; ++i) {
if (taskmap[i].isused == false) {
if (!taskmap[i].isused) {
taskmap[i].name = name;
taskmap[i].isused = true;
taskid = i;
@@ -276,7 +271,7 @@ px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int
pthread_attr_destroy(&attr);
pthread_mutex_unlock(&task_mutex);
return i;
return taskid;
}
int px4_task_delete(px4_task_t id)