Schedulers

Jancy implements the concept of function pointer scheduling. When passing a function pointers as a callback of some sort (completion routine, event handler etc) you are free to assign it a user-defined “scheduler”. The purpose of this scheduler is to ensure the execution of your callback in the correct environment (i.e. a specific worker thread, from within a Windows Message handler, under lock/mutex, and so on).

The scheduler is a built-in interface of the Jancy compiler:

namespace jnc {

class Scheduler {
    abstract schedule(function* f ());
}

} // namespace jnc {

Note that even the schedule method accepts a pointer to a function with no arguments, and you can schedule functions with arbitrary argument list, as arguments will be captured in the closure object.

To assign a scheduler you use @ operator (at):

class WorkerThread: jnc.Scheduler {
    override schedule(function* f()) {
        // enqueue f and signal worker thread event
    }

    void workerThread() {
        for (;;) {
            // wait for worker thread event

            function* f() = getNextRequest ();
            f();
        }
    }
}

void foo(int x);

void bar() {
    WorkerThread workerThread;

    function* f(int) = foo @ workerThread; // create a scheduled pointer

    (foo @ workerThread)(100); // or schedule now

    // ...

    f(200); // call through a scheduled pointer
}

Below is a real-life example (from our IO Ninja software) of assigning a socket event handler (which gets fired from within the socket IO thread) and scheduling it to be called from the main UI thread:

TcpListenerSession.construct(doc.PluginHost* pluginHost) {
    // ...

    m_listenerSocket = new io.Socket();
    m_listenerSocket.m_onSocketEvent +=
        onListenerSocketEvent @ pluginHost.m_mainThreadScheduler;

    // ...
}