Skip to content

Commit

Permalink
Merge branch 'master' into v3.5
Browse files Browse the repository at this point in the history
  • Loading branch information
dkulp committed Dec 7, 2019
2 parents 39d1646 + f5865f6 commit 997b881
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 16 deletions.
21 changes: 18 additions & 3 deletions src/PixelOverlay.cpp
Expand Up @@ -761,14 +761,26 @@ void PixelOverlayManager::SetupPixelMapForBlock(FPPChannelMemoryMapControlBlock

int TtoB = (cb->startCorner[0] == 'T') ? 1 : 0;
int LtoR = (cb->startCorner[1] == 'L') ? 1 : 0;
int stringSize = cb->channelCount / 3 / cb->stringCount;

int channelsPerNode = 3;
if (cb->channelCount == cb->stringCount) {
//single channel model.. we really don't support this, but let's not crash
channelsPerNode = 1;
}
int stringSize = cb->channelCount / channelsPerNode / cb->stringCount;
if (stringSize < 1) {
stringSize = 1;
}
int width = 0;
int height = 0;

if (cb->orientation == 'H') {
// Horizontal Orientation
width = stringSize / cb->strandsPerString;
height = cb->channelCount / 3 / width;
if (width == 0) {
width = 1;
}
height = cb->channelCount / channelsPerNode / width;

int y = 0;
for (y = 0; y < height; y++) {
Expand Down Expand Up @@ -801,7 +813,10 @@ void PixelOverlayManager::SetupPixelMapForBlock(FPPChannelMemoryMapControlBlock
} else {
// Vertical Orientation
height = stringSize / cb->strandsPerString;
width = cb->channelCount / 3 / height;
if (height == 0) {
height = 1;
}
width = cb->channelCount / channelsPerNode / height;

int x = 0;
for (x = 0; x < width; x++) {
Expand Down
10 changes: 8 additions & 2 deletions src/commands/Commands.cpp
Expand Up @@ -55,10 +55,11 @@ CommandManager::CommandManager() {

class GPIOCommand : public Command {
public:
GPIOCommand(std::vector<std::string> &pins) : Command("GPIO") {
GPIOCommand(std::vector<std::string> pins) : Command("GPIO") {
args.push_back(CommandArg("pin", "string", "Pin").setContentList(pins));
args.push_back(CommandArg("on", "bool", "On"));
}
virtual ~GPIOCommand() {}
virtual std::unique_ptr<Command::Result> run(const std::vector<std::string> &args) override {
if (args.size() != 2) {
return std::make_unique<Command::ErrorResult>("Invalid number of arguments. GPIO needs two arguments.");
Expand Down Expand Up @@ -104,7 +105,6 @@ void CommandManager::Init() {
addCommand(new StopRemoteEffectCommand());
addCommand(new RunRemoteScriptEvent());
addCommand(new StartRemoteFSEQEffectCommand());


std::vector<std::string> pins = PinCapabilities::getPinNames();
if (!pins.empty()) {
Expand All @@ -117,6 +117,12 @@ CommandManager::~CommandManager() {
}
commands.clear();
}
void CommandManager::Cleanup() {
for (auto &a : commands) {
delete a.second;
}
commands.clear();
}

void CommandManager::addCommand(Command *cmd) {
commands[cmd->name] = cmd;
Expand Down
1 change: 1 addition & 0 deletions src/commands/Commands.h
Expand Up @@ -94,6 +94,7 @@ class Command {
class CommandManager : public httpserver::http_resource {
public:
void Init();
void Cleanup();

void addCommand(Command *cmd);
void removeCommand(Command *cmd);
Expand Down
165 changes: 155 additions & 10 deletions src/fppd.c
Expand Up @@ -48,6 +48,9 @@
#include "Sequence.h"
#include "settings.h"

#include <syscall.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <pwd.h>
#include <errno.h>
#include <unistd.h>
Expand Down Expand Up @@ -86,6 +89,144 @@ volatile int runMainFPPDLoop = 1;
void MainLoop(void);


static int IsDebuggerPresent() {
char buf[1024];
int debugger_present = 0;

int status_fd = open("/proc/self/status", O_RDONLY);
if (status_fd == -1) {
return 0;
}
ssize_t num_read = read(status_fd, buf, sizeof(buf)-1);
if (num_read > 0) {
static const char TracerPid[] = "TracerPid:";
char *tracer_pid;

buf[num_read] = 0;
tracer_pid = strstr(buf, TracerPid);
if (tracer_pid) {
debugger_present = !!atoi(tracer_pid + sizeof(TracerPid) - 1);
}
}
return debugger_present;
}


// Try to attach gdb to print stack trace (Linux only).
// The sole purpose is to improve the very poor stack traces generated by backtrace() on ARM platforms
static bool dumpstack_gdb(void) {
char pid_buf[30];
sprintf(pid_buf, "%d", getpid());
char thread_buf[30];
sprintf(thread_buf, "(LWP %ld)", syscall(__NR_gettid));
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;

if (IsDebuggerPresent()) {
return false;
}
(void) remove("/tmp/fppd_crash.log");

// Allow us to be traced
// Note: Does not currently work in WSL: https://github.com/Microsoft/WSL/issues/3053
int retval = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);

// Spawn helper process which will keep running when gdb is attached to main domoticz process
pid_t intermediate_pid = fork();
if (intermediate_pid == -1) {
return false;
}
if (!intermediate_pid) {
// Wathchdog 1: Used to kill sub processes to gdb which may hang
pid_t timeout_pid1 = fork();
if (timeout_pid1 == -1) {
_Exit(1);
}
if (timeout_pid1 == 0) {
int timeout = 1;
sleep(timeout);
_Exit(1);
}

// Wathchdog 2: Give up on gdb, if it still does not finish even after killing its sub processes
pid_t timeout_pid2 = fork();
if (timeout_pid2 == -1) {
kill(timeout_pid1, SIGKILL);
_Exit(1);
}
if (timeout_pid2 == 0) {
int timeout = 5;
sleep(timeout);
_Exit(1);
}

// Worker: Spawns gdb
pid_t worker_pid = fork();
if (worker_pid == -1) {
kill(timeout_pid1, SIGKILL);
kill(timeout_pid2, SIGKILL);
_Exit(1);
}
if (worker_pid == 0) {
(void) remove("/tmp/fppd_crash.log");
int fd = open("/tmp/fppd_crash.log", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) _Exit(1);
if (dup2(fd, STDOUT_FILENO) == -1) _Exit(1);
if (dup2(fd, STDERR_FILENO) == -1) _Exit(1);
execlp("gdb", "gdb", "--batch", "-n", "-ex", "thread apply all bt", "-ex", "info threads", "-ex", "bt", "-ex", "detach", name_buf, pid_buf, NULL);

// If gdb failed to start, signal back
close(fd);
_Exit(1);
}

int result = 1;

// Wait for all children to die
while (worker_pid || timeout_pid1 || timeout_pid2) {
int status = 0;
//pid_t exited_pid = wait(&status);
usleep(100000);
//printf("pid worker_pid: %d, timeout_pid1: %d, timeout_pid2: %d\n", worker_pid, timeout_pid1, timeout_pid2);
if (worker_pid && waitpid(worker_pid, &status, WNOHANG)) {
worker_pid = 0;
//printf("Status: %x, wifexited: %u, wexitstatus: %u\n", status, WIFEXITED(status), WEXITSTATUS(status));
//printf("Sending SIGKILL to timeout_pid1\n");
if (timeout_pid1) kill(timeout_pid1, SIGKILL);
if (timeout_pid2) kill(timeout_pid2, SIGKILL);
} else if (timeout_pid1 && waitpid(timeout_pid1, &status, WNOHANG)) {
// Watchdog 1 timed out, attempt to recover by killing all gdb's child processes
char tmp[128];
timeout_pid1 = 0;
//printf("Sending SIGKILL to worker_pid's children\n");
if (worker_pid) {
sprintf(tmp, "pkill -KILL -P %d", worker_pid);
int ret = system(tmp);
}
} else if (timeout_pid2 && waitpid(timeout_pid2, &status, WNOHANG)) {
// Watchdog 2 timed out, give up
timeout_pid2 = 0;
//printf("Sending SIGKILL to worker_pid\n");
if (worker_pid) kill(worker_pid, SIGKILL);
if (timeout_pid1) kill(timeout_pid1, SIGKILL);
}
}
_Exit(result); // Or some more informative status
} else {
int status = 0;
pid_t res = waitpid(intermediate_pid, &status, 0);
if (FileExists("/tmp/fppd_crash.log")) {
std::string s = GetFileContents("/tmp/fppd_crash.log");
if (s != "") {
LogErr(VB_ALL, "Stack: \n%s\n", s.c_str());
//printf("%s\n", s.c_str());
return true;
}
}
}
return false;
}

static void handleCrash(int s) {
static volatile bool inCrashHandler = false;
if (inCrashHandler) {
Expand All @@ -95,16 +236,18 @@ static void handleCrash(int s) {
inCrashHandler = true;
LogErr(VB_ALL, "Crash handler called: %d\n", s);

void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; i++) {
LogErr(VB_ALL, " %s\n", strs[i]);
}
for (i = 0; i < frames; i++) {
printf(" %s\n", strs[i]);
if (!dumpstack_gdb()) {
void* callstack[128];
int i, frames = backtrace(callstack, 128);
char** strs = backtrace_symbols(callstack, frames);
for (i = 0; i < frames; i++) {
LogErr(VB_ALL, " %s\n", strs[i]);
}
for (i = 0; i < frames; i++) {
printf(" %s\n", strs[i]);
}
free(strs);
}
free(strs);
inCrashHandler = false;
runMainFPPDLoop = 0;
if (s != SIGQUIT && s != SIGUSR1) {
Expand Down Expand Up @@ -532,14 +675,16 @@ int main(int argc, char *argv[])
CleanupGPIOInput();

CloseChannelOutputs();
CommandManager::INSTANCE.Cleanup();

delete multiSync;
delete scheduler;
delete playlist;
delete sequence;
runMainFPPDLoop = -1;
Sensors::INSTANCE.Close();



if (mqtt)
delete mqtt;

Expand Down
2 changes: 1 addition & 1 deletion www/js/fpp.js
Expand Up @@ -1242,7 +1242,7 @@ function updateUniverseEndChannel(row) {
}

bodyHTML += "</select></td>" +
"<td " + inputStyle + "><input class='txtIP' type='text' value='" + unicastAddress + "' size='15' maxlength='32'></td>" +
"<td " + inputStyle + "><input class='txtIP' type='text' value='" + unicastAddress + "' size='16' maxlength='32'></td>" +
"<td " + inputStyle + "><input class='txtPriority' type='number' min='0' max='9999' value='" + priority.toString() + "'/></td>" +
"<td " + inputStyle + "><input class='txtMonitor' id='txtMonitor' type='checkbox' size='4' maxlength='4' " + (monitor == 1 ? "checked" : "" ) + monitorDisabled + "/></td>" +
"<td " + inputStyle + "><input id='PingButton' type=button onClick='PingE131IP(" + i.toString() + ");' value='Ping'></td>" +
Expand Down

0 comments on commit 997b881

Please sign in to comment.