Skip to content

Commit

Permalink
Fix pure virtual method called error when running CI tests (#1930)
Browse files Browse the repository at this point in the history
* Fix `pure virtual method called` error when running CI tests

Unsafe to call methods from virtual CThread destructor.
Add `terminate()` method to all derived classes and call explicitly _before_ destroying the object.

* Added debug statements to confirm thread sequencing correct.

* Fix keyboard thread race condition.

Small test applications can execute and finish before the keyboard thread has started running.
Adding a small delay and an additional check handles this situation and avoids calling the keyb_XX functions.

This doesn't guarantee that `keyb_raw()` isn't called during cleanup as the race condition still exists.
This isn't a problem in itself, except for the call to `atexit()` which results in undefined behaviour
and in practice, a deadlock. It's not required as the keyboard thread calls `keyb_restore()` when it's done.
  • Loading branch information
mikee47 authored and slaff committed Nov 1, 2019
1 parent d936a99 commit 4ac4ccb
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .travis/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ if [ "$TRAVIS_BUILD_STAGE_NAME" == "Test" ]; then

# Build and run tests
export SMING_TARGET_OPTIONS='--flashfile=$(FLASH_BIN) --flashsize=$(SPI_SIZE)'
$MAKE_PARALLEL tests || true
$MAKE_PARALLEL tests

# Build the documentation
mv $SMING_PROJECTS_DIR/samples ..
Expand Down
12 changes: 9 additions & 3 deletions Sming/Arch/Host/Components/driver/hw_timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ class CTimerThread : public CThread
execute();
}

~CTimerThread()
void terminate()
{
state = terminating;
sem.post();
join();
}

void attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg)
Expand Down Expand Up @@ -138,8 +139,6 @@ class CTimerThread : public CThread
bool auto_load = false;
};

static CTimerThread timer1("Timer1");

void* CTimerThread::thread_routine()
{
#ifdef __WIN32
Expand Down Expand Up @@ -208,6 +207,13 @@ void* CTimerThread::thread_routine()
return nullptr;
}

static CTimerThread timer1("Timer1");

void hw_timer_cleanup()
{
timer1.terminate();
}

void hw_timer1_attach_interrupt(hw_timer_source_type_t source_type, hw_timer_callback_t callback, void* arg)
{
timer1.attach_interrupt(source_type, callback, arg);
Expand Down
2 changes: 2 additions & 0 deletions Sming/Arch/Host/Components/driver/include/driver/hw_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ inline void hw_timer_init(void)
{
}

void hw_timer_cleanup();

#ifdef __cplusplus
}
#endif
37 changes: 30 additions & 7 deletions Sming/Arch/Host/Components/driver/uart_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ class KeyboardThread : public CThread
{
}

~KeyboardThread()
void terminate()
{
done = true;
join();
}

protected:
Expand All @@ -50,6 +51,12 @@ class KeyboardThread : public CThread

void* KeyboardThread::thread_routine()
{
// Small applications can complete before we even get here!
msleep(50);
if(done) {
return nullptr;
}

keyb_raw();
while(!done) {
int c = getkey();
Expand Down Expand Up @@ -84,6 +91,17 @@ void* KeyboardThread::thread_routine()

static KeyboardThread* keyboardThread;

static void destroyKeyboardThread()
{
if(keyboardThread == nullptr) {
return;
}

keyboardThread->terminate();
delete keyboardThread;
keyboardThread = nullptr;
}

static void onUart0Notify(uart_t* uart, uart_notify_code_t code)
{
switch(code) {
Expand All @@ -105,12 +123,9 @@ static void onUart0Notify(uart_t* uart, uart_notify_code_t code)
}
break;

case UART_NOTIFY_BEFORE_CLOSE: {
auto thread = keyboardThread;
keyboardThread = nullptr;
delete thread;
case UART_NOTIFY_BEFORE_CLOSE:
destroyKeyboardThread();
break;
}

default:; // ignore
}
Expand Down Expand Up @@ -150,16 +165,24 @@ void CUartServer::startup(const UartServerConfig& config)

void CUartServer::shutdown()
{
destroyKeyboardThread();

for(unsigned i = 0; i < UART_COUNT; ++i) {
auto& server = uartServers[i];
if(server == nullptr) {
continue;
}

server->terminate();
delete server;
server = nullptr;
}
}

CUartServer::~CUartServer()
void CUartServer::terminate()
{
close();
join();
hostmsg("UART%u server destroyed", uart_nr);
}

Expand Down
2 changes: 1 addition & 1 deletion Sming/Arch/Host/Components/driver/uart_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class CUartServer : public CThread, public CServerSocket
{
}

~CUartServer();
void terminate();

protected:
void onNotify(uart_t* uart, uart_notify_code_t code);
Expand Down
1 change: 0 additions & 1 deletion Sming/Arch/Host/Components/hostlib/keyb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,6 @@ void keyb_raw()
// make stdin non-blocking
g_orig_flags = fcntl(0, F_GETFL);
tcgetattr(STDIN_FILENO, &g_orig_attr);
atexit(keyb_restore);
}

// make stdin non-blocking
Expand Down
1 change: 1 addition & 0 deletions Sming/Arch/Host/Components/hostlib/startup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ extern void host_init_bootloader();

static void cleanup()
{
hw_timer_cleanup();
host_flashmem_cleanup();
CUartServer::shutdown();
sockets_finalise();
Expand Down
11 changes: 10 additions & 1 deletion Sming/Arch/Host/Components/hostlib/threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@
#pragma once

#include "hostlib.h"
#include "hostmsg.h"
#include <pthread.h>
#include <semaphore.h>

#if defined(DEBUG_VERBOSE_LEVEL) && (DEBUG_VERBOSE_LEVEL == 3)
#define HOST_THREAD_DEBUG(fmt, ...) host_printf(fmt "\n", ##__VA_ARGS__)
#else
#define HOST_THREAD_DEBUG(fmt, ...)
#endif

class CMutex;

class CThread
Expand All @@ -39,7 +46,7 @@ class CThread

virtual ~CThread()
{
join();
HOST_THREAD_DEBUG("Thread '%s' destroyed", name);
}

bool execute()
Expand All @@ -60,6 +67,7 @@ class CThread
void join()
{
pthread_join(m_thread, nullptr);
HOST_THREAD_DEBUG("Thread '%s' complete", name);
}

/*
Expand Down Expand Up @@ -92,6 +100,7 @@ class CThread
static void* thread_start(void* param)
{
auto thread = static_cast<CThread*>(param);
HOST_THREAD_DEBUG("Thread '%s' running", thread->name);
return thread->thread_routine();
}

Expand Down

0 comments on commit 4ac4ccb

Please sign in to comment.