Skip to content
50 changes: 50 additions & 0 deletions src/lib/app/PyTwkApp/PyMuSymbolType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,37 @@
#include <MuTwkApp/EventType.h>
#include <MuTwkApp/MuInterface.h>
#include <boost/algorithm/string.hpp>
#include <boost/thread.hpp>
#include <half.h>
#include <sstream>
#include <stdexcept>
#include <iostream>

namespace TwkApp
{
using namespace std;

// Thread safety tracking
// Default constructor creates "not-a-thread" ID
static boost::thread::id s_mainThreadId;

// Helper function for direct cout printing
static PyObject* unsafe_mu_print(PyObject* args)
{
size_t nargs = PyTuple_Size(args);
if (nargs >= 1)
{
PyObject* arg = PyTuple_GetItem(args, 0);
if (PyUnicode_Check(arg))
{
const char* str = PyUnicode_AsUTF8(arg);
if (str)
cout << str;
}
}
Py_RETURN_NONE;
}

Mu::FunctionObject*
createFunctionObjectFromPyObject(const Mu::FunctionType* t, PyObject* pyobj)
{
Expand Down Expand Up @@ -300,6 +323,33 @@ namespace TwkApp
return NULL;
}

// Thread safety check - initialize main thread ID on first call
boost::thread::id currentThreadId = boost::this_thread::get_id();
if (s_mainThreadId == boost::thread::id()) // Check if uninitialized
// (default constructed)
{
s_mainThreadId = currentThreadId;
}

if (currentThreadId != s_mainThreadId)
{
// fix mu print commands from python to at least not crash from
// non-main thread
// (because python print is often used to debug python code, so
// we'll tolerate this because print is likely redirected to the RV
// console)
if (self->function->fullyQualifiedName() == "extra_commands._print")
{
return unsafe_mu_print(args);
}

// this cout will probably get redirected to the RV console, or go
// to the terminal window.
cout << "WARNING: Mu " << self->function->fullyQualifiedName()
<< "() called from non-main thread, will eventually crash "
<< "(Mu isn't thread-safe)." << endl;
}

size_t nargs = PyTuple_Size(args);

Mu::Function::ArgumentVector muargs(self->function->numArgs());
Expand Down
Loading