Because AuxTaskNonRT
is meant for a thread that sleeps until it receives data from a RT thread. That is not what's happening here: OscReceiver::waitForMessage()
is simply polling a socket and calling a callback when new data is available, so a std::thread
is semantically more appropriate. Also, there was no need for it to be a Xenomai thread and that added a dependency that made it harder to reuse elsewhere (though I can't remember whether I actually used it anywhere else). Furthermore, note that the issue you are encountering is not with OscReceiver
, but with OscSender
, or rather with AuxTaskNonRT
.
Here's some tested-working (verbose and future-proof) code to turn a thread into a Xenomai thread (from here):
static bool turnIntoCobaltThread(bool recurred = false) {
struct sched_param param;
memset(¶m, 0, sizeof(param));
int policy;
// Guaranteed to succeed as pthread_self() cannot fail and pthread_getschedparam()'s only error condition is when
// the given thread does not exist.
pthread_getschedparam(pthread_self(), &policy, ¶m);
pid_t tid = getTid();
if (int ret = __wrap_sched_setscheduler(tid, policy, ¶m)) {
fprintf(stderr, "Warning: unable to turn current thread into a Xenomai thread : (%d) %s\n", -ret,
strerror(-ret));
initializeXenomai();
if (!recurred)
return turnIntoCobaltThread(true);
else
return false;
}
xprintf("Turned thread %d into a Cobalt thread %s\n", tid, recurred ? "with recursion" : "");
return true;
}
In your case you can simplify the error handling by skipping the initializeXenomai()
(which is defined elsewhere in the document) part. Just remember not to run this code before setup()
is called (i.e.: don't put it in the constructor of a global object), or it will take place before Xenomai is initialised.
If this works then we could do a further step to integrate it into the AuxTaskNonRT::schedule(const void* ptr, size_t size)
method, following the logic we use in Supercollider: if writing to the pipe fails with -EPERM
it means that you should call turnIntoCobaltThread()
and then write to the pipe again. This way turnIntoCobaltThread()
will be called at most once per thread. Something like this (untested and not super elegant):
diff --git a/core/AuxTaskNonRT.cpp b/core/AuxTaskNonRT.cpp
index 6bc8c11c..c5b40c92 100644
--- a/core/AuxTaskNonRT.cpp
+++ b/core/AuxTaskNonRT.cpp
@@ -84,8 +84,19 @@ int AuxTaskNonRT::schedule(const void* ptr, size_t size){
#endif
if(ret < 0)
{
- rt_fprintf(stderr, "Error while sending to pipe from %s: (%d) %s (size: %d)\n", name.c_str(), errno, strerror(errno), size);
- return errno;
+ if(errno == EPERM)
+ initializeXenomai();
+#ifdef XENOMAI_SKIN_native
+ ret = rt_pipe_write(&pipe, ptr, size, P_NORMAL);
+#endif
+#ifdef XENOMAI_SKIN_posix
+ ret = __wrap_sendto(pipeSocket, ptr, size, 0, NULL, 0);
+#endif
+ if(ret < 0)
+ {
+ rt_fprintf(stderr, "Error while sending to pipe from %s: (%d) %s (size: %d)\n", name.c_str(), errno, strerror(errno), size);
+ return errno;
+ }
}
return 0;
}