Initial commit to the PapyrusRT repository.

This is the initial commit as submitted to CQ 9646.

The repository contains two top-level folders:

- codegen: the code-generator
- rts: the run-time system

Also-by: Andrew Eidsness, Zeligsoft contractor, andrewe@jfront.com,
Barry Maher, Zeligsoft contractor, bmaher@gpinc.ca, Ernesto Posse,
Zeligsoft, eposse@zeligsoft.com, Tim McGuire, Zeligsoft,
tmcguire@zeligsoft.com, Young-Soo Roh, Zeligsoft, ysroh@zeligsoft.com,
Toby McClean, Zeligsoft, toby@zeligsoft.com, Charles Rivet, Zeligsoft,
charles@zeligsoft.com, Andreas Henriksson, Ericsson,
andreas.henriksson@ericsson.com, Akos Horvath, IncQuery Labs,
akos.horvath@incquerylabs.com, Gabor Batori, Ericsson,
Gabor.Batori@ericsson.com, Abel Hegedus, IncQuery Labs,
abel.hegedus@incquerylabs.com, Denes Harmath, IncQuery Labs,
harmathdenes@gmail.com
Signed-off-by: Ernesto Posse <eposse@gmail.com>
diff --git a/rts/umlrt/umlrtapi.cc b/rts/umlrt/umlrtapi.cc
new file mode 100644
index 0000000..d20dc9e
--- /dev/null
+++ b/rts/umlrt/umlrtapi.cc
@@ -0,0 +1,148 @@
+// umlrtapi.cc - catch-all RTS API called from everywhere
+// Definitions here can be placed elsewhere at a later date...
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtapi.hh"
+#include "umlrtslot.hh"
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportrole.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtmessagepool.hh"
+#include "umlrtsignalelementpool.hh"
+#include "umlrttimerpool.hh"
+#include "basefatal.hh"
+#include "basedebug.hh"
+
+namespace umlrt
+{
+    // Allocate a signal from the system-pool.
+    UMLRTSignalElement * SignalElementGetFromPool()
+    {
+        UMLRTSignalElementPool * pool = UMLRTController::getSignalElementPool();
+
+        if (!pool)
+        {
+            FATAL("no signal pool defined (get)");
+        }
+        UMLRTSignalElement * element = (UMLRTSignalElement *)pool->get();
+        BDEBUG(BD_SIGNALALLOC, "get from pool signal-qid[%d] %s\n", (element == NULL) ? -1 : element->qid, (element == NULL) ? "IGNORE NULL" : "ok");
+
+        element->setAllocated(true);
+
+        return element;
+    }
+
+    // Deallocate a signal back to the system pool.
+    void SignalElementPutToPool( UMLRTSignalElement * element )
+    {
+        UMLRTSignalElementPool * pool = UMLRTController::getSignalElementPool();
+
+        if (!pool)
+        {
+            FATAL("no signal pool defined (put)");
+        }
+        BDEBUG(BD_SIGNALALLOC, "put to pool signal-qid[%d] %s\n", (element == NULL) ? -1 : element->qid, (element == NULL) ? "IGNORE NULL" : "ok");
+
+        element->setAllocated(false);
+
+        return pool->put(element);
+    }
+
+    // Allocate a message from the system-pool.
+    UMLRTMessage * MessageGetFromPool()
+    {
+        UMLRTMessagePool * pool = UMLRTController::getMessagePool();
+        UMLRTMessage * msg;
+
+        if (!pool)
+        {
+            FATAL("no message pool defined (get)");
+        }
+        if ((msg = (UMLRTMessage *)pool->get()) != NULL)
+        {
+            if (msg->allocated)
+            {
+                FATAL("Obtained an allocated message from the pool.");
+            }
+            msg->allocated = true;
+        }
+        return msg;
+    }
+
+    // Put a signal back to the system pool.
+    void MessagePutToPool( UMLRTMessage * message )
+    {
+        UMLRTMessagePool * pool = UMLRTController::getMessagePool();
+
+        UMLRTSignal invalid;
+
+        message->signal = invalid; // Causes application signal element to be 'dereferenced'.
+
+        if (!pool)
+        {
+            FATAL("no message pool defined (put)");
+        }
+        if (!message->allocated)
+        {
+            FATAL("Putting an unallocated message on the pool.");
+        }
+        message->allocated = false;
+
+        pool->put(message);
+    }
+
+    // Allocate a timer from the system-pool.
+    UMLRTTimer * TimerGetFromPool()
+    {
+        UMLRTTimerPool * pool = UMLRTController::getTimerPool();
+        UMLRTTimer * timer;
+
+        if (!pool)
+        {
+            FATAL("no timer pool defined (get)");
+        }
+        if ((timer = (UMLRTTimer *)pool->get()) != NULL)
+        {
+            if (timer->allocated)
+            {
+                FATAL("timer obtained from pool was already allocated.");
+            }
+            timer->allocated = true;
+        }
+        BDEBUG(BD_TIMERALLOC, "get from pool timer-qid[%d] %s\n", (timer == NULL) ? -1 : timer->qid, (timer == NULL) ? "IGNORE NULL" : "ok");
+
+        return timer;
+    }
+
+    // Put a timer back to the system pool.
+    void TimerPutToPool( UMLRTTimer * timer )
+    {
+        UMLRTTimerPool * pool = UMLRTController::getTimerPool();
+
+        if (!pool)
+        {
+            FATAL("no timer pool defined (put)");
+        }
+        if (!timer->allocated)
+        {
+            FATAL("attempting to return an unallocated timer to the pool.");
+        }
+        timer->allocated = false;
+
+        BDEBUG(BD_TIMERALLOC, "put to pool timer-qid[%d] signal-qid[%d] %s\n",
+                timer->qid, timer->signal.getQid());
+
+        UMLRTOutSignal invalid;
+
+        timer->signal = invalid; // Causes application signal element to be 'dereferenced'.
+
+        pool->put(timer);
+    }
+}
diff --git a/rts/umlrt/umlrtbasicthread.cc b/rts/umlrt/umlrtbasicthread.cc
new file mode 100644
index 0000000..99a8d07
--- /dev/null
+++ b/rts/umlrt/umlrtbasicthread.cc
@@ -0,0 +1,93 @@
+// umlrtbasicthread.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <string.h>
+#include "basefatal.hh"
+#include "umlrtbasicthread.hh"
+
+// See umlrtbasicthread.hh for documentation.
+
+// Bug 31 raised to move this to +/os/linux/osbasicthread.cc.
+
+/*static*/ void * UMLRTBasicThread::static_entrypoint( void * arg )
+{
+    threadargs_t *threadargs = (threadargs_t*)arg;
+
+    return threadargs->inst->run( threadargs->args );
+}
+
+
+UMLRTBasicThread::UMLRTBasicThread( const char * name_ ) : tid(0)
+{
+    memset(name, 0, sizeof(name));
+    strncpy(name, name_, sizeof(name) - 1);
+}
+
+// Start the thread, passing in a single argument.
+
+void UMLRTBasicThread::start( void * args )
+{
+    pthread_attr_t attr;
+
+    memset(&attr, 0, sizeof(attr));
+
+    if (pthread_attr_init( &attr) < 0)
+    {
+        FATAL_ERRNO("pthread_attr_init");
+    }
+    threadargs.inst = this;
+    threadargs.args = args;
+
+    if (pthread_create(&tid, &attr, static_entrypoint, &threadargs) < 0)
+    {
+        FATAL_ERRNO("pthread_create");
+    }
+#ifdef __USE_GNU
+    // May not be universally available.
+    pthread_setname_np(tid, name); // Attempt this, but ignore errors.
+#endif
+}
+
+// Wait for the thread to complete and get returned value.
+
+void * UMLRTBasicThread::join()
+{
+    void *ret;
+    if (pthread_join(tid, &ret) < 0)
+    {
+        FATAL_ERRNO("pthread_join");
+    }
+    return ret;
+}
+
+// Returns true if this thread is currently running thread.
+
+bool UMLRTBasicThread::isMyThread()
+{
+    return pthread_self() == tid;
+}
+
+// Return my name
+
+const char * UMLRTBasicThread::getName() const
+{
+    return name;
+}
+
+// Return running thread id.
+/*static*/ UMLRTBasicThread::threadid_t UMLRTBasicThread::selfId()
+{
+    return (threadid_t)pthread_self();
+}
+ 
diff --git a/rts/umlrt/umlrtcapsule.cc b/rts/umlrt/umlrtcapsule.cc
new file mode 100644
index 0000000..f508e6f
--- /dev/null
+++ b/rts/umlrt/umlrtcapsule.cc
@@ -0,0 +1,35 @@
+// umlrtcapsule.cc
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtcapsuleclass.hh"
+#include "umlrtcapsule.hh"
+#include "umlrtframeservice.hh"
+#include "basedebug.hh"
+#include "basedebugtype.hh"
+
+UMLRTCapsule::~UMLRTCapsule ( )
+{
+    BDEBUG(BD_INSTANTIATE, "%s destructor\n", slot->name);
+    UMLRTCapsuleToControllerMap::removeCapsule(slot->name, this);
+}
+
+UMLRTCapsule::UMLRTCapsule ( const UMLRTRtsInterface * rtsif_, const UMLRTCapsuleClass * capsuleClass_, UMLRTSlot * slot, const UMLRTCommsPort * * borderPorts_, const UMLRTCommsPort * internalPorts_, bool isStatic_ ) : rtsif(rtsif_), capsuleClass(capsuleClass_), slot(slot), borderPorts(borderPorts_), internalPorts(internalPorts_), isStatic(isStatic_)
+{
+    BDEBUG(BD_INSTANTIATE, "slot %s constructor\n", slot->name);
+    UMLRTCapsuleToControllerMap::addCapsule(slot->name, this);
+}
+
+void UMLRTCapsule::unbindPort ( bool isBorder, int portIndex, int farEndIndex )
+{
+}
+
+void UMLRTCapsule::bindPort ( bool isBorder, int portIndex, int farEndIndex )
+{
+}
diff --git a/rts/umlrt/umlrtcapsuleid.cc b/rts/umlrt/umlrtcapsuleid.cc
new file mode 100644
index 0000000..1ec3189
--- /dev/null
+++ b/rts/umlrt/umlrtcapsuleid.cc
@@ -0,0 +1,24 @@
+// umlrtcapsuleid.c
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtcapsule.hh"
+#include "umlrtcapsuleid.hh"
+#include "basefatal.hh"
+#include <stdlib.h>
+
+// Must have verified #isValid before calling this.
+UMLRTCapsule * UMLRTCapsuleId::getCapsule() const
+{
+    if (!capsule)
+    {
+        FATAL("no capsule defined");
+    }
+    return capsule;
+}
diff --git a/rts/umlrt/umlrtcapsuletocontrollermap.cc b/rts/umlrt/umlrtcapsuletocontrollermap.cc
new file mode 100644
index 0000000..a746025
--- /dev/null
+++ b/rts/umlrt/umlrtcapsuletocontrollermap.cc
@@ -0,0 +1,285 @@
+// umlrtcapsuletocontrollermap.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtcapsule.hh"
+#include "umlrtcapsuletocontrollermap.hh"
+#include "umlrtcontroller.hh"
+#include "umlrthashmap.hh"
+#include "basefatal.hh"
+#include "basedebug.hh"
+#include "basedebugtype.hh"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+UMLRTHashMap * UMLRTCapsuleToControllerMap::capsuleToControllerListMap = NULL;
+UMLRTHashMap * UMLRTCapsuleToControllerMap::controllerNameMap = NULL;
+UMLRTHashMap * UMLRTCapsuleToControllerMap::capsuleNameMap = NULL;
+
+/*static*/ UMLRTHashMap * UMLRTCapsuleToControllerMap::getControllerNameMap()
+{
+    if (controllerNameMap == NULL)
+    {
+        controllerNameMap = new UMLRTHashMap("controllerNameMap", UMLRTHashMap::compareString);
+    }
+    return controllerNameMap;
+}
+
+/*static*/ UMLRTHashMap * UMLRTCapsuleToControllerMap::getCapsuleToControllerListMap()
+{
+    if (capsuleToControllerListMap == NULL)
+    {
+        capsuleToControllerListMap = new UMLRTHashMap("capsuleToControllerMap", UMLRTHashMap::compareString);
+    }
+    return capsuleToControllerListMap;
+}
+
+/*static*/ UMLRTHashMap * UMLRTCapsuleToControllerMap::getCapsuleNameMap()
+{
+    if (capsuleNameMap == NULL)
+    {
+        capsuleNameMap = new UMLRTHashMap("capsuleNameMap", UMLRTHashMap::compareString);
+    }
+    return capsuleNameMap;
+}
+
+// Add a controller by name.
+/*static*/ bool UMLRTCapsuleToControllerMap::addController( const char * controllername, UMLRTController * controller )
+{
+    if (getControllerFromName(controllername) != NULL)
+    {
+        FATAL("ERROR: Controller %s has already registered.", controllername);
+    }
+    BDEBUG(BD_CONTROLLER, "add controller(%s) p(%p)\n", controllername, controller );
+
+    getControllerNameMap()->insert( controllername, (void *)controller);
+
+    return true;
+}
+
+// Add a capsule by name.
+/*static*/ void UMLRTCapsuleToControllerMap::addCapsule( const char * capsulename, UMLRTCapsule * capsule )
+{
+    getCapsuleNameMap()->insert( capsulename, (void *)capsule);
+}
+
+/*static*/ const UMLRTCapsule * UMLRTCapsuleToControllerMap::getCapsuleFromName ( const char * capsulename )
+{
+    return (const UMLRTCapsule *)getCapsuleNameMap()->getObject(capsulename);
+}
+
+// Remove a capsule instance from the list.
+/*static*/ void UMLRTCapsuleToControllerMap::removeCapsule ( const char * capsuleName, UMLRTCapsule * capsule )
+{
+    getCapsuleNameMap()->remove(capsuleName);
+}
+
+/*static*/ UMLRTController * UMLRTCapsuleToControllerMap::getControllerFromName( const char * controllerName )
+{
+    return (UMLRTController *)getControllerNameMap()->getObject(controllerName);
+}
+
+/*static*/ UMLRTController * UMLRTCapsuleToControllerMap::getFirstController()
+{
+    return (UMLRTController *)getControllerNameMap()->getFirstObject();
+}
+
+/*static*/ const char * UMLRTCapsuleToControllerMap::getControllerNameForCapsule ( const char * capsuleName, const UMLRTCapsuleClass * capsuleClass )
+{
+    const char * controllerName = NULL;
+    UMLRTHashMap * controllerList = (UMLRTHashMap *)getCapsuleToControllerListMap()->getObject(capsuleName);
+    if (controllerList)
+    {
+        // Attempt to find the class-specific controller.
+        controllerName = (const char *) controllerList->getObject(capsuleClass->name);
+        if (controllerName == NULL)
+        {
+            // Class-specific controller not assigned - look for the default.
+            controllerName = (const char *)controllerList->getObject((void*)NULL);
+        }
+    }
+    return controllerName;
+}
+
+// Return the controller assigned to this capsule. Returns NULL if no controller is assigned or doesn't exist.
+/*static*/ UMLRTController * UMLRTCapsuleToControllerMap::getControllerForCapsule ( const char * capsuleName, const UMLRTCapsuleClass * capsuleClass )
+{
+    const char * controllerName = getControllerNameForCapsule( capsuleName, capsuleClass );
+
+    return (UMLRTController *)getControllerFromName(controllerName);
+}
+
+/*static*/ void UMLRTCapsuleToControllerMap::addCapsuleToControllerSpec ( char * capsuleName, char * controllerName, char * className )
+{
+    // className can be NULL, indicating the default controller for all capsule classes incarnated into the slot.
+
+    UMLRTHashMap * controllerList = (UMLRTHashMap *)getCapsuleToControllerListMap()->getObject(capsuleName);
+
+    if (controllerList == NULL)
+    {
+        // This capsule has no previous controller assignments - no controller list - add one.
+        const char * capsuleKey = strdup(capsuleName);
+        controllerList = new UMLRTHashMap(capsuleKey, UMLRTHashMap::compareString);
+        getCapsuleToControllerListMap()->insert(capsuleKey, (void *)controllerList);
+    }
+    if ((controllerList->getObject(className)) != NULL)
+    {
+        FATAL("-C option: capsule-to-controller-map already had an entry for capsule '%s' class '%s'",
+                capsuleName, (className == NULL) ? "(default)" : className);
+    }
+    // Assign this controller to the capsule/class combination.
+    const char *classKey = className;
+    if (classKey != NULL)
+    {
+        classKey = strdup(className);
+    }
+    controllerList->insert(classKey, (void *)strdup(controllerName));
+}
+
+// Create a map of capsule to controller
+/*static*/ bool UMLRTCapsuleToControllerMap::parseCapsuleControllerLine ( char * line )
+{
+    bool ok = false;
+    char * capsuleName;
+    char * saveptr;
+    capsuleName = strtok_r( line, " =\n\r\t", &saveptr);
+    if (capsuleName != NULL)
+    {
+        char * controllerName = strtok_r(NULL, " =\n\r\t", &saveptr);
+        if (controllerName != NULL)
+        {
+            char * className = strtok_r(NULL, " = \n\r\t", &saveptr);
+            // If className is NULL, then this is the default controller assignment for this capsule - no capsule class specified.
+            addCapsuleToControllerSpec( capsuleName, controllerName, className );
+            ok = true;
+        }
+    }
+    return ok;
+}
+
+// Create a map of capsule to controller
+/*static*/ bool UMLRTCapsuleToControllerMap::readCapsuleControllerMap( const char * controllerfile )
+{
+    bool ok = true;
+    FILE *fd;
+
+    if ((fd = fopen(controllerfile, "r")) == NULL)
+    {
+        printf("ERROR: failed to open controllers file %s\n", controllerfile);
+        ok = false;
+    }
+    else
+    {
+        char * line;
+        char buf[1024];
+
+        while (((line = fgets(buf, sizeof(buf), fd)) != NULL) && ok)
+        {
+            ok = UMLRTCapsuleToControllerMap::parseCapsuleControllerLine(buf);
+        }
+    }
+    return ok;
+}
+
+// Assign static capsule controllers based on the run-time map.
+/*static*/ void UMLRTCapsuleToControllerMap::setStaticCapsuleControllers( UMLRTSlot * slots, size_t size )
+{
+    for (size_t i = 0; i < size; ++i)
+    {
+        UMLRTController * controller = getControllerForCapsule(slots[i].name, slots[i].capsuleClass);
+
+        // Only reassign static capsules (i.e. controller already assigned) whose controllers were specified in the run-time map.
+        if ((slots[i].controller != NULL) && (controller != NULL))
+        {
+            // Reassign the capsule according to the run-time map collected.
+            slots[i].controller = controller;
+        }
+    }
+}
+
+
+// Debug output the the capsule, controller and capsule-to-controller maps.
+/*static*/ void UMLRTCapsuleToControllerMap::debugOutputControllerList()
+{
+    BDEBUG(BD_MODEL, "Controller list: { <controller name>, <instance address> }\n");
+
+    UMLRTHashMap::Iterator iter = getControllerNameMap()->getIterator();
+
+    if (iter == iter.end())
+    {
+        BDEBUG(BD_MODEL, "    No controllers.\n");
+    }
+    else
+    {
+        while (iter != iter.end())
+        {
+            BDEBUG(BD_MODEL, "    { %s, %p }\n", ((UMLRTController *)((char *)iter.getObject()))->getName(), (UMLRTController *)((char *)iter.getObject()));
+            iter = iter.next();
+        }
+    }
+}
+
+/*static*/ void UMLRTCapsuleToControllerMap::debugOutputCapsuleList()
+{
+    BDEBUG(BD_MODEL, "Capsule list: { <capsule name>, <instance address>, <capsule class>, <assigned controller> }\n");
+
+    UMLRTHashMap::Iterator iter = getCapsuleNameMap()->getIterator();
+
+    if (iter == iter.end())
+    {
+        BDEBUG(BD_MODEL, "    No capsules.\n");
+    }
+    else
+    {
+        while (iter != iter.end())
+        {
+            UMLRTCapsule * capsule = (UMLRTCapsule *)iter.getObject();
+            BDEBUG(BD_MODEL, "    { %s, %p, %s, %s }\n",
+                    capsule->getName(), capsule, capsule->getClass()->name, capsule->getSlot()->controller->getName());
+            iter = iter.next();
+        }
+    }
+}
+
+// Debug output of capsule-to-controller map.
+/*static*/ void UMLRTCapsuleToControllerMap::debugOutputCaspuleToControllerMap()
+{
+    BDEBUG(BD_MODEL, "Capsule to controller map: { <slot>, <controller>, <capsule class> }\n");
+
+    UMLRTHashMap::Iterator ctclIter = getCapsuleToControllerListMap()->getIterator();
+
+    if (ctclIter == ctclIter.end())
+    {
+        BDEBUG(BD_MODEL, "    No capsule to controller assignments.\n");
+    }
+    else
+    {
+        while (ctclIter != ctclIter.end())
+        {
+            const char * capsuleName = (const char *)ctclIter.getKey();
+            UMLRTHashMap * controllerList = (UMLRTHashMap *)ctclIter.getObject();
+            if (controllerList)
+            {
+                UMLRTHashMap::Iterator clIter = controllerList->getIterator();
+                while (clIter != clIter.end())
+                {
+                    BDEBUG(BD_MODEL, "    { %s, %s, %s }\n",
+                                capsuleName,
+                                (clIter.getObject() == NULL) ? "?no controller?" : clIter.getObject(),
+                                (clIter.getKey() == NULL) ? "(default)" : clIter.getKey());
+                    clIter = clIter.next();
+                }
+            }
+            ctclIter = ctclIter.next();
+        }
+    }
+}
+
+
diff --git a/rts/umlrt/umlrtcommsport.cc b/rts/umlrt/umlrtcommsport.cc
new file mode 100644
index 0000000..f7c9eaf
--- /dev/null
+++ b/rts/umlrt/umlrtcommsport.cc
@@ -0,0 +1,78 @@
+// umlrtcommsport.c
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtcommsport.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtmessage.hh"
+#include "umlrtqueue.hh"
+
+/*static*/ bool UMLRTCommsPort::purgeMatchCompare( UMLRTMessage * msg, const PurgeRecall * purge )
+{
+    bool match = true;
+    if (purge->index != -1)
+    {
+        match = (purge->index == (int)msg->sapIndex0);
+        if (match && (purge->id != -1))
+        {
+            match = (purge->id == (int)msg->signal.getId());
+        }
+    }
+    return match;
+}
+
+/*static*/ void UMLRTCommsPort::purgeMatchNotify( UMLRTMessage * msg, const PurgeRecall * purge )
+{
+    umlrt::MessagePutToPool(msg);
+}
+
+int UMLRTCommsPort::purge( int index, int id ) const
+{
+    int count = 0;
+    const PurgeRecall purge = { index, false/*front*/, id };
+    if (deferQueue != NULL)
+    {
+        count = deferQueue->remove( (UMLRTQueue::match_compare_t)purgeMatchCompare, (UMLRTQueue::match_notify_t)purgeMatchNotify, (void *)&purge );
+    }
+    return count;
+}
+
+
+/*static*/ bool UMLRTCommsPort::recallMatchCompare( UMLRTMessage * msg, const PurgeRecall * recall )
+{
+    bool match = true;
+    if (recall->index != -1)
+    {
+        match = (recall->index == (int)msg->sapIndex0);
+    }
+    return match;
+}
+
+/*static*/ void UMLRTCommsPort::recallMatchNotify( UMLRTMessage * msg, const PurgeRecall * recall )
+{
+    msg->destPort->slot->controller->recall( msg, recall->front );
+}
+
+int UMLRTCommsPort::recall( int index, bool front, bool one, int id  ) const
+{
+    int count = 0;
+    const PurgeRecall recall = { index, front, id };
+
+    if (deferQueue != NULL)
+    {
+        count = deferQueue->remove( (UMLRTQueue::match_compare_t)recallMatchCompare, (UMLRTQueue::match_notify_t)recallMatchNotify, (void *)&recall, one );
+    }
+    return count;
+}
+
+const UMLRTCommsPortRole * UMLRTCommsPort::role() const
+{
+    return border ? ((containerClass->portRolesBorder == NULL) ? NULL : &containerClass->portRolesBorder[roleIndex]) : ((containerClass->portRolesInternal == NULL) ? NULL : &containerClass->portRolesInternal[roleIndex]);
+}
+
diff --git a/rts/umlrt/umlrtcontroller.cc b/rts/umlrt/umlrtcontroller.cc
new file mode 100644
index 0000000..55716d8
--- /dev/null
+++ b/rts/umlrt/umlrtcontroller.cc
@@ -0,0 +1,958 @@
+// umlrtcontroller.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+// UMLRTController is the main controller-class.
+
+#include "basedebug.hh"
+#include "basefatal.hh"
+#include "umlrtapi.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtcapsule.hh"
+#include "umlrtslot.hh"
+#include "umlrtcapsuletocontrollermap.hh"
+#include "umlrtcapsulerole.hh"
+#include "umlrtcapsulepart.hh"
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportfarend.hh"
+#include "umlrtcommsportrole.hh"
+#include "umlrtcontrollercommand.hh"
+#include "umlrtframeservice.hh"
+#include "umlrtmessage.hh"
+#include "umlrtobjectclass.hh"
+#include "umlrtprotocol.hh"
+#include "umlrttimer.hh"
+#include "umlrttimespec.hh"
+#include "umlrtqueue.hh"
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/select.h>
+#include <string.h>
+#include <stdarg.h>
+
+// The application-wide free message pool.
+/*static*/ UMLRTMessagePool * UMLRTController::messagePool = NULL;
+
+// The application-wide free signal pool.
+/*static*/ UMLRTSignalElementPool * UMLRTController::signalElementPool  = NULL;
+
+// The application-wide free timer pool.
+/*static*/ UMLRTTimerPool * UMLRTController::timerPool  = NULL;
+
+// Error codes to string
+static const char * errorToString[] = UMLRTCONTROLLER_ERROR_CODE_TO_STRING;
+
+
+UMLRTController::UMLRTController(const char * name_, size_t numSlots_, const UMLRTSlot slots_[])
+    : UMLRTBasicThread(name_), name(name_), incomingQueue(name), capsuleQueue(name), numSlots(numSlots_), slots(slots_), lastError(E_OK)
+{
+    // Register the controller with the capsule-to-controller map.
+    UMLRTCapsuleToControllerMap::addController(name, this);
+}
+
+bool UMLRTController::cancelTimer( const UMLRTTimerId id )
+{
+    if (id.isValid())
+    {
+        const UMLRTTimer * timer = id.getTimer();
+
+        char buf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+        BDEBUG(BD_TIMER, "cancel timer(%p) destPort(%s) isInterval(%d) priority(%d) payloadSize(%d) due(%s)\n",
+                timer, timer->destPort->role()->name, timer->isInterval, timer->signal.getPriority(), timer->signal.getPayloadSize(),
+                timer->isInterval ? timer->due.toStringRelative(buf, sizeof(buf)) : timer->due.toString(buf, sizeof(buf)));
+    }
+    return timerQueue.cancel(id);
+}
+
+/*static*/ bool UMLRTController::deallocateMsgMatchCompare( UMLRTMessage * msg, UMLRTSlot * slot )
+{
+    return !msg->isCommand && msg->destSlot == slot;
+}
+
+/*static*/ void UMLRTController::deallocateMsgMatchNotify( UMLRTMessage * msg, UMLRTSlot * slot )
+{
+    BDEBUG(BD_DESTROY, "Purging message destined for slot %s\n", slot->name);
+
+    umlrt::MessagePutToPool(msg);
+}
+
+// Callback to purge timers for a condemned slot.
+/*static*/ bool UMLRTController::deallocateTimerMatchCompare( UMLRTTimer * timer, UMLRTSlot * slot )
+{
+    return timer->destSlot == slot;
+}
+
+// Callback when a timer is being deleted.
+/*static*/ void UMLRTController::deallocateTimerMatchNotify( UMLRTTimer * timer, UMLRTSlot * slot )
+{
+    BDEBUG(BD_DESTROY, "Purging timer destined for slot %s\n", slot->name);
+
+    umlrt::TimerPutToPool(timer);
+}
+
+void UMLRTController::deallocateSlotResources( UMLRTSlot * slot )
+{
+    if (slot == NULL)
+    {
+        FATAL("attempting to deallocate the NULL slot.");
+    }
+    BDEBUG(BD_DESTROY, "Remove messages and timers for slot %s\n", slot->name);
+
+    incomingQueue.remove( (UMLRTQueue::match_compare_t)deallocateMsgMatchCompare, (UMLRTQueue::match_notify_t)deallocateMsgMatchNotify, slot );
+    capsuleQueue.remove( (UMLRTQueue::match_compare_t)deallocateMsgMatchCompare, (UMLRTQueue::match_notify_t)deallocateMsgMatchNotify, slot );
+    timerQueue.remove( (UMLRTQueue::match_compare_t)deallocateTimerMatchCompare, (UMLRTQueue::match_notify_t)deallocateTimerMatchNotify, slot );
+}
+
+// Deliver a signal to the destination port.
+bool UMLRTController::deliver ( const UMLRTCommsPort * destPort, const UMLRTSignal &signal, size_t srcPortIndex )
+{
+    // Assumes global RTS lock acquired.
+
+    UMLRTMessage * msg = umlrt::MessageGetFromPool();
+    bool ok = false;
+
+    if (!msg)
+    {
+        signal.getSrcPort()->slot->controller->setError(E_SEND_NO_MSG_AVL);
+    }
+    else if (destPort == NULL)
+    {
+        FATAL("Message from slot %s (port %s) has destination port NULL.", signal.getSrcPort()->slot->name, signal.getSrcPort()->role()->name);
+    }
+    else
+    {
+        // Look up sapIndex0 so receiver knows which index in their replicated port the message was received on.
+        msg->sapIndex0 = signal.getSrcPort()->farEnds[srcPortIndex].farEndIndex;
+        msg->signal = signal;
+        msg->destPort = destPort;
+        msg->destSlot = destPort->slot;
+        msg->srcPortIndex = srcPortIndex;
+        msg->isCommand = false;
+
+        // Source port may not exist.
+        BDEBUG(BD_SIGNALALLOC, "%s: deliver signal-qid[%d] id(%d) -> %s(%s[%d]) payloadSize(%d)\n",
+                name,
+                msg->signal.getQid(),
+                msg->signal.getId(),
+                msg->destPort->slot->name, msg->destPort->role()->name, msg->sapIndex0,
+                msg->signal.getPayloadSize());
+
+        if (isMyThread())
+        {
+            // If this is me delivering the message, I can deliver directly to my capsule queues.
+            capsuleQueue.enqueue(msg);
+        }
+        else
+        {
+            // Otherwise, I deliver to the remote capsule's incoming queue.
+            incomingQueue.enqueue(msg);
+        }
+        ok = true;
+    }
+    return ok;
+}
+
+void UMLRTController::enqueueAbort()
+{
+    UMLRTControllerCommand command;
+
+    // Explicitly reset unused command contents.
+    command.capsule = NULL;
+    command.isTopSlot = false;
+    command.serializedData = NULL;
+    command.sizeSerializedData = 0;
+    command.slot = NULL;
+
+    // Format command and enqueue it.
+    command.command = UMLRTControllerCommand::ABORT;
+    enqueueCommand(command);
+}
+
+void UMLRTController::enqueueCommand( const UMLRTControllerCommand & command )
+{
+    UMLRTMessage *msg = umlrt::MessageGetFromPool();
+
+    msg->signal.initialize(sizeof(UMLRTControllerCommand), UMLRTSignalElement::PRIORITY_SYSTEM);
+    uint8_t * payload;
+
+    BDEBUG(BD_SIGNALALLOC, "%s: deliver signal-qid[%d] as command %d\n",
+            name,
+            msg->signal.getQid(),
+            command.command);
+
+    if ((payload = msg->signal.getPayload()) == NULL)
+    {
+        FATAL("initialized signal had no payload.");
+    }
+    memcpy( payload, &command, sizeof(command));
+    msg->isCommand = true;
+
+    if (isMyThread())
+    {
+        // If this is me delivering the message, I can deliver directly to my capsule queues.
+        capsuleQueue.enqueue(msg);
+    }
+    else
+    {
+        // Otherwise, I deliver to the remote capsule's incoming queue.
+        incomingQueue.enqueue(msg);
+    }
+}
+
+void UMLRTController::enqueueDebugOutputModel()
+{
+    UMLRTControllerCommand command;
+
+    // Explicitly reset unused command contents.
+    command.capsule = NULL;
+    command.isTopSlot = false;
+    command.serializedData = NULL;
+    command.sizeSerializedData = 0;
+    command.slot = NULL;
+
+    // Format command and enqueue it.
+    command.command = UMLRTControllerCommand::DEBUG_OUTPUT_MODEL;
+
+    enqueueCommand(command);
+}
+
+void UMLRTController::enqueueDeport( UMLRTSlot * slot )
+{
+    UMLRTControllerCommand command;
+
+    // Explicitly reset unused command contents.
+    command.capsule = NULL;
+    command.isTopSlot = false;
+    command.serializedData = NULL;
+    command.sizeSerializedData = 0;
+
+    // Format command and enqueue it.
+    command.command = UMLRTControllerCommand::DEPORT;
+    command.slot = slot;
+
+    enqueueCommand(command);
+}
+
+void UMLRTController::enqueueDestroy( UMLRTSlot * slot, bool isTopSlot )
+{
+    UMLRTControllerCommand command;
+
+    // Explicitly reset unused command contents.
+    command.capsule = NULL;
+    command.serializedData = NULL;
+    command.sizeSerializedData = 0;
+
+    // Format command and enqueue it.
+    command.command = UMLRTControllerCommand::DESTROY;
+    command.slot = slot;
+    command.isTopSlot = isTopSlot;
+
+    enqueueCommand(command);
+}
+
+void UMLRTController::enqueueImport( UMLRTSlot * slot, UMLRTCapsule * capsule )
+{
+    UMLRTControllerCommand command;
+
+    // Explicitly reset unused command contents.
+    command.isTopSlot = false;
+    command.serializedData = NULL;
+    command.sizeSerializedData = 0;
+
+    // Format command and enqueue it.
+    command.command = UMLRTControllerCommand::IMPORT;
+    command.slot = slot;
+    command.capsule = capsule;
+
+    enqueueCommand(command);
+}
+
+void UMLRTController::enqueueIncarnate( UMLRTCapsule * capsule, const void * userData, const UMLRTObject_class * type )
+{
+    UMLRTControllerCommand command;
+
+    // May be called from within the context of another controller thread.
+
+    // Explicitly reset unused command contents.
+    command.isTopSlot = false;
+    command.slot = NULL;
+
+    // Format command and enqueue it.
+    command.command = UMLRTControllerCommand::INCARNATE;
+    command.capsule = capsule;
+
+    serializeIncarnateData( userData, type, &command.sizeSerializedData, &command.serializedData);
+    // Controller frees serialized data buffer back to the heap.
+
+    command.sizeSerializedData = 0;
+    command.serializedData = NULL;
+
+    // Notification to destination controller occurs as a result of this enqueue.
+    enqueueCommand(command);
+}
+
+// Return true if abort was received.
+bool UMLRTController::executeCommand( UMLRTMessage * msg )
+{
+    bool abort = false;
+    UMLRTControllerCommand * command = (UMLRTControllerCommand *)msg->signal.getPayload();
+
+    if (command != NULL)
+    {
+        switch (command->command)
+        {
+        case UMLRTControllerCommand::ABORT:
+            BDEBUG(BD_COMMAND, "%s: ABORT command received\n", getName());
+            abort = true;
+            break;
+
+        case UMLRTControllerCommand::DEBUG_OUTPUT_MODEL:
+            BDEBUG(BD_COMMAND, "%s: DEBUG_OUTPUT_MODEL command received\n", getName());
+            debugOutputModel();
+            break;
+
+        case UMLRTControllerCommand::DEPORT:
+            BDEBUG(BD_COMMAND, "%s: DEPORT from slot %s command received\n", getName(), command->slot->name);
+            UMLRTFrameService::controllerDeport(command->slot, false/*synchronous*/, false/*lockAcquired*/);
+            break;
+
+        case UMLRTControllerCommand::DESTROY:
+            BDEBUG(BD_COMMAND, "%s: DESTROY from slot %s (is %stop slot) command received\n", getName(), command->slot->name, command->isTopSlot ? "" : "NOT ");
+            UMLRTFrameService::controllerDestroy(command->slot, command->isTopSlot, false/*synchronous*/, false/*lockAcquired*/);
+            break;
+
+        case UMLRTControllerCommand::IMPORT:
+            BDEBUG(BD_COMMAND, "%s: IMPORT capsule %s to slot %s command received\n", getName(), command->capsule->getName(), command->slot->name);
+            UMLRTFrameService::controllerImport(command->slot, command->capsule, false/*synchronous*/, false/*lockAcquired*/);
+            break;
+
+        case UMLRTControllerCommand::INCARNATE:
+            BDEBUG(BD_COMMAND, "%s: INCARNATE capsule %s (size data %d) command received\n", getName(), command->capsule->getName(), command->sizeSerializedData);
+            UMLRTFrameService::controllerIncarnate(command->capsule, command->sizeSerializedData, command->serializedData);
+            break;
+
+        case UMLRTControllerCommand::UNDEFINED:
+        default:
+            FATAL("%s:unknown controller (%d) command received", getName(), command->command);
+        }
+    }
+    return abort;
+}
+
+// Initialize the free pools.
+/*static*/ void UMLRTController::initializePools( UMLRTSignalElementPool * signalElementPool_, UMLRTMessagePool * messagePool_,
+        UMLRTTimerPool * timerPool_ )
+{
+    signalElementPool = signalElementPool_;
+    messagePool = messagePool_;
+    timerPool = timerPool_;
+}
+
+// Wait for the controller thread to die.
+void UMLRTController::join()
+{
+    UMLRTBasicThread::join();
+}
+
+// Get the system-wide signal pool.
+/*static*/ UMLRTSignalElementPool * UMLRTController::getSignalElementPool()
+{
+    return signalElementPool;
+}
+
+// Get the system-wide message pool.
+/*static*/ UMLRTMessagePool * UMLRTController::getMessagePool()
+{
+    return messagePool;
+}
+
+// Get the system-wide timer pool.
+/*static*/ UMLRTTimerPool * UMLRTController::getTimerPool()
+{
+    return timerPool;
+}
+
+bool UMLRTController::isMyThread()
+{
+    return UMLRTBasicThread::isMyThread();
+}
+
+// Output an error containing a user-defined message and the 'strerror()' string.
+void UMLRTController::perror( const char * fmt, ...) const
+{
+    va_list ap;
+    va_start(ap, fmt);
+    vprintf(fmt, ap);
+    printf(": %s\n", strerror());
+    va_end(ap);
+}
+
+// Deliver a signal to the destination port.
+void UMLRTController::recall( UMLRTMessage * msg, bool front )
+{
+    capsuleQueue.enqueue(msg, front);
+}
+
+// Main loop
+void * UMLRTController::run( void * args )
+{
+    printf("Controller \"%s\" running.\n", getName());
+
+    for (size_t i = 0; i < numSlots; ++i)
+    {
+        if (slots[i].controller == this)
+        {
+            if ((slots[i].capsule != NULL) && (!slots[i].condemned))
+            {
+                if (   (slots[i].role() == NULL)
+                    || ((slots[i].role()->optional == 0) && (slots[i].role()->plugin == 0)))
+                {
+                    BDEBUG(BD_INSTANTIATE, "%s: initialize capsule %s (class %s).\n", getName(), slots[i].name, slots[i].capsuleClass->name );
+
+                    UMLRTFrameService::initializeCapsule(slots[i].capsule, 0, NULL);
+                }
+            }
+        }
+    }
+
+    bool abort = false;
+    while (!abort)
+    {
+        // Queue messages associated with all timed-out timers.
+        capsuleQueue.queueTimerMessages(&timerQueue);
+
+        // Transfer all incoming messages to capsule queues.
+        capsuleQueue.moveAll(incomingQueue);
+
+        // Inject all available messages, highest priority msgs first.
+        UMLRTMessage * msg;
+        while (!abort && (msg = capsuleQueue.dequeueHighestPriority()) != NULL)
+        {
+            if (msg->isCommand)
+            {
+                abort = executeCommand(msg);
+            }
+            else if (msg->destSlot->capsule == NULL)
+            {
+                FATAL("%s: signal id(%d) to slot %s (no capsule instance) should not occur\n",
+                        getName(), msg->signal.getId(), msg->destSlot->name);
+            }
+            else
+            {
+                if (msg->destSlot->condemned)
+                {
+                    // Drop messages to a condemned slot.
+                    BDEBUG(BD_INJECT, "%s: dropping signal-qid[%d] id(%d) to slot %s (slot condemned)\n",
+                            getName(), msg->signal.getQid(), msg->signal.getId(), msg->destSlot->name);
+                }
+                else
+                {
+                    // Source port may no longer exist.
+                    BDEBUG(BD_INJECT, "%s: inject signal-qid[%d] into %s {%s[%d]} id %d\n",
+                            getName(), msg->signal.getQid(), msg->destSlot->capsule->getName(), msg->destPort->role()->name, msg->sapIndex0, msg->signal.getId());
+
+                    base::debugLogData( BD_SIGNALDATA, msg->signal.getPayload(), msg->signal.getPayloadSize());
+
+                    // Inject the signal into the capsule.
+                    msg->destPort->slot->capsule->inject((UMLRTMessage)*msg);
+                }
+            }
+            // Put the message back in the pool (handles signal allocation also).
+            umlrt::MessagePutToPool(msg);
+        }
+        // Wait on the incoming queue or a timeout.
+        if (!abort)
+        {
+            wait();
+        }
+    }
+    // Leave this output in here for now.
+    printf("Controller %s is aborting.\n", getName());
+
+    // Bug 215 - must destroy owned capsules + slots here.
+
+    return(NULL);
+}
+
+/*static*/ void UMLRTController::serializeIncarnateData( const void * userData, const UMLRTObject_class * type, size_t * sizeSerializedDataP, void * * serializedDataP )
+{
+    (*sizeSerializedDataP) = 0;
+    (*serializedDataP) = NULL;
+
+    if (userData != NULL)
+    {
+        if (type == NULL)
+        {
+            FATAL("Type descriptor missing. Has been previously checked.");
+        }
+        // Define data pointer and size.
+        if (((*serializedDataP) = malloc((*sizeSerializedDataP) = type->getSize(type))) == NULL)
+        {
+            FATAL("could not allocate memory for serialized data.");
+        }
+        // Encode the data.
+        type->encode(type, userData, (*serializedDataP));
+    }
+    // The controller frees the serialized data buffer after it's been copied to the initialize message.
+}
+
+// Set the error code.
+void UMLRTController::setError( Error error )
+{
+    lastError = error;
+    if ((error != E_OK) && (base::debugGetEnabledTypes() & (1 << BD_ERROR)) != 0)
+    {
+        BDEBUG(BD_ERROR, "Controller %s setError(%d):'%s'\n", getName(), lastError, strerror());
+    }
+}
+
+// Start the controller thread.
+void UMLRTController::spawn()
+{
+    // No arguments for this thread.
+    start(NULL);
+}
+
+// See umlrtcontroller.hh.
+const char * UMLRTController::strerror( ) const
+{
+    Error error = getError();
+    if ((error < 0) || (error >= E_MAX))
+    {
+        SWERR("error code(%d) out of range max(%d)", error, E_MAX);
+        return "unknown error code";
+    }
+    else
+    {
+        return errorToString[error];
+    }
+}
+
+void UMLRTController::startTimer( const UMLRTTimer * timer )
+{
+    char buf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+    BDEBUG(BD_TIMER, "start timer(%p) destPort(%s) isInterval(%d) priority(%d) payloadSize(%d) due(%s)\n",
+            timer, timer->destPort->role()->name, timer->isInterval, timer->signal.getPriority(), timer->signal.getPayloadSize(),
+            timer->isInterval ? timer->due.toStringRelative(buf, sizeof(buf)) : timer->due.toString(buf, sizeof(buf)));
+
+    timerQueue.enqueue(timer);
+}
+
+// Wait on an external message or a timeout.
+void UMLRTController::wait()
+{
+    // Linux-specific implementation for the time-being.
+
+    // If there is a timer running, this holds the remaining time as the timeout of the select.
+    struct timeval remainTimeval;
+
+    // We default to 'wait forever', unless a timer is running.
+    struct timeval * selectTimeval = NULL;
+
+    bool wait = true; // Set this false if a timer is due or an incoming message appeared.
+
+    // Get the time remaining on the first timer in the queue (if one exists).
+    if (!timerQueue.isEmpty())
+    {
+        UMLRTTimespec remainTimespec = timerQueue.timeRemaining();
+
+        if (remainTimespec.isZeroOrNegative())
+        {
+            // The timer is due - don't wait.
+            wait = false;
+            BDEBUG(BD_TIMER, "%s:timer is due\n", name);
+        }
+        else
+        {
+            // A timer is waiting but is not yet due. Set up the timeout. Will be non-zero.
+            remainTimeval.tv_sec = remainTimespec.tv_sec;
+            remainTimeval.tv_usec = remainTimespec.tv_nsec / 1000;
+
+            char tmbuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+            BDEBUG(BD_TIMER, "%s: timer is not due - remain(%s)\n", name, remainTimespec.toStringRelative(tmbuf, sizeof(tmbuf)));
+
+            // Select will not wait forever.
+            selectTimeval = &remainTimeval;
+        }
+    }
+    if (!incomingQueue.isEmpty())
+    {
+        BDEBUG(BD_CONTROLLER, "%s: incoming q non-empty\n", name);
+        wait = false;
+    }
+    if (wait)
+    {
+        // selectTimeval remains NULL if no timers are running. In that case, select will wait
+        // forever until a message is delivered or a new timer is added to the timer-queue.
+
+        // Get the queue notification file descriptors.
+        int msgNotifyFd = incomingQueue.getNotifyFd();
+        int timerFd = timerQueue.getNotifyFd();
+
+        fd_set fds;
+
+        FD_ZERO(&fds);
+        FD_SET(msgNotifyFd, &fds);
+        FD_SET(timerFd, &fds);
+
+        // select wants to know the highest-numbered fd + 1.
+        int nfds = msgNotifyFd + 1;
+        if (timerFd > msgNotifyFd)
+        {
+            nfds = timerFd + 1;
+        }
+
+        // TODO - Bug 238 - DEBUG - remove this later.
+        if (!selectTimeval)
+        {
+            // DEBUG - the intent is to wait forever until notification, since no timer is pending.
+            // However, we wake the process up every 10 seconds during debugging.
+            // No harm in doing that - the controller returns here if it finds nothing to do.
+            remainTimeval.tv_sec = 10;
+            remainTimeval.tv_usec = 0;
+            selectTimeval = &remainTimeval;
+        }
+        // end DEBUG - remove this later
+
+        BDEBUG(BD_CONTROLLER, "%s: call select msgfd(%d) timeout[%d,%d]\n",
+                name,
+                msgNotifyFd,
+                selectTimeval ? selectTimeval->tv_sec : -1,
+                selectTimeval ? selectTimeval->tv_usec : -1);
+
+
+        if ((select(nfds, &fds, NULL, NULL, selectTimeval)) < 0)
+        {
+            FATAL_ERRNO("select");
+        }
+        if (FD_ISSET(msgNotifyFd, &fds))
+        {
+            // Clear message notify-pending.
+            incomingQueue.clearNotifyFd();
+        }
+        if (FD_ISSET(timerFd, &fds))
+        {
+            // Clear message notify-pending.
+            timerQueue.clearNotifyFd();
+        }
+    }
+}
+
+/*static*/ void UMLRTController::debugOutputModelPortDeferQueueWalk( const UMLRTMessage * msg, void *userData )
+{
+    BDEBUG(BD_MODEL, "                            msg: id(%d) data [%d]\n",
+            msg->signal.getId(),
+            *(int *)msg->signal.getPayload());
+}
+
+void UMLRTController::debugOutputModelPortDeferQueue( const UMLRTCommsPort * port )
+{
+    if (port != NULL)
+    {
+        if (port->deferQueue != NULL)
+        {
+            if (!port->deferQueue->isEmpty())
+            {
+                BDEBUG(BD_MODEL,
+                        "                        defer queue:\n");
+                port->deferQueue->walk( (UMLRTQueue::walk_callback_t)debugOutputModelPortDeferQueueWalk, NULL);
+            }
+        }
+    }
+}
+
+void UMLRTController::debugOutputModelPort( const UMLRTCommsPort * port, size_t index )
+{
+    if (!port)
+    {
+        BDEBUG(BD_MODEL,
+"            port [%u]: (null)\n", index);
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"            %s[%u] (id %d) %s%s %s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+            port->role()->name,
+            port->role()->numFarEnd,
+            port->role()->id,
+            port->role()->protocol,
+            port->role()->conjugated ? "~" : "",
+            port->proxy ? "(proxy)" : "",
+            port->spp ? "(SPP " : "",
+            port->spp ? ((port->registeredName == NULL) ? "?" : port->registeredName) : "",
+            port->spp ? ")" : "",
+            port->sap ? "(SAP " : "",
+            port->sap ? ((port->registeredName == NULL) ? "?" : port->registeredName) : "",
+            port->sap ? ")" : "",
+            port->automatic ? "(auto)" : "",
+            port->notification ? "(notify)" : "",
+            (port->unbound) ? "('unbound')" : "",
+            port->relay ? "(relay)" : "",
+            port->wired ? "(wired)" : "",
+            port->locked ? "(locked)" : "");
+
+        for (size_t j = 0; j < port->numFarEnd; ++j)
+        {
+            const char * farEndSlotName = "(none)";
+            const char * farEndPortName = "(none)";
+            const char * farEndSlotNoInstance = "(no instance)";
+            size_t farEndIndex = 0;
+            if (port->farEnds[j].port != NULL)
+            {
+                farEndSlotName = port->farEnds[j].port->slot->name;
+                farEndPortName = port->farEnds[j].port->role()->name;
+                farEndIndex = port->farEnds[j].farEndIndex;
+                if (port->farEnds[j].port->slot->capsule != NULL)
+                {
+                    farEndSlotNoInstance = "";
+                }
+            }
+            BDEBUG(BD_MODEL, "                    farEnd[%u] : -> { slot %s, port %s[%u] %s}\n",
+                    j, farEndSlotName, farEndPortName, farEndIndex, farEndSlotNoInstance );
+        }
+        debugOutputModelPortDeferQueue(port);
+    }
+}
+
+void UMLRTController::debugOutputModelPortsArray( size_t numPorts, const UMLRTCommsPort * ports )
+{
+    if (numPorts == 0)
+    {
+        BDEBUG(BD_MODEL,
+"                ports        : (none)\n");
+    }
+    for (size_t i = 0; i < numPorts; ++i)
+    {
+        debugOutputModelPort(&ports[i], i);
+    }
+}
+
+void UMLRTController::debugOutputModelPortsList( size_t numPorts, const UMLRTCommsPort * * ports )
+{
+    if (numPorts == 0)
+    {
+        BDEBUG(BD_MODEL,
+"                ports        : (none)\n");
+    }
+    for (size_t i = 0; i < numPorts; ++i)
+    {
+        debugOutputModelPort(ports[i], i);
+    }
+}
+
+void UMLRTController::debugOutputClassInheritance( const UMLRTCapsuleClass * capsuleClass )
+{
+    const UMLRTCapsuleClass * parent = capsuleClass->super;
+
+    if (parent == NULL)
+    {
+        BDEBUG(BD_MODEL, "(none)");
+    }
+    while (parent != NULL)
+    {
+        BDEBUG(BD_MODEL, "-> %s ", parent->name);
+        parent = parent->super;
+    }
+    BDEBUG(BD_MODEL,"\n");
+}
+
+void UMLRTController::debugOutputSlots( const UMLRTSlot * slot )
+{
+    BDEBUG(BD_MODEL,
+"    %s:\n", slot->name);
+    BDEBUG(BD_MODEL,
+"        capsule instance        : %-30s (%p)\n", slot->capsule ? slot->capsule->getName() : "(none)", slot->capsule);
+    if (slot->role() == NULL)
+    {
+    BDEBUG(BD_MODEL,
+"        role                    : (none)\n");
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"        role                    : %-30s [%d..%d] %s %s\n",
+                slot->role()->name,
+                slot->role()->multiplicityLower,
+                slot->role()->multiplicityUpper,
+                slot->role()->optional ? "optional " : "",
+                slot->role()->plugin ? "plugin " : "");
+
+    }
+    BDEBUG(BD_MODEL,
+"        index                   : %d\n", slot->capsuleIndex);
+    BDEBUG(BD_MODEL,
+"        class                   : %-30s (# sub-capsule roles : %u) (# border ports : %u) (# internal ports : %u)\n",
+            slot->capsuleClass->name,
+            slot->capsuleClass->numSubcapsuleRoles,
+            slot->capsuleClass->numPortRolesBorder,
+            slot->capsuleClass->numPortRolesInternal);
+    BDEBUG(BD_MODEL,
+"        class inheritance       : ");
+    debugOutputClassInheritance(slot->capsuleClass);
+    BDEBUG(BD_MODEL,
+"        controller              : %s\n", slot->controller->getName());
+    if (slot->slotToBorderMap == NULL)
+    {
+        BDEBUG(BD_MODEL,
+"        slot to border map      : (none)\n");
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"        slot to border map      :");
+        for (size_t i = 0; i < slot->role()->capsuleClass->numPortRolesBorder; ++i)
+        {
+            BDEBUG(BD_MODEL, " [sl %lu=cp %d]", i, slot->slotToBorderMap[i]);
+        }
+        BDEBUG(BD_MODEL,"\n");
+    }
+    if (slot->numPorts == 0)
+    {
+        BDEBUG(BD_MODEL,
+"        slot ports              : (none)\n");
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"        slot ports              :\n");
+        debugOutputModelPortsArray(slot->numPorts, slot->ports);
+    }
+    const UMLRTCommsPort * portlist;
+    const UMLRTCommsPort * * borderPorts;
+    if (slot->capsule == NULL)
+    {
+        BDEBUG(BD_MODEL,
+"        capsule border ports    : (none - no instance running in slot)\n");
+    }
+    else if ((borderPorts = slot->capsule->getBorderPorts()) == NULL)
+    {
+        BDEBUG(BD_MODEL,
+"        capsule border ports    : (no border ports)\n");
+    }
+    else if (slot->capsuleClass->numPortRolesBorder == 0)
+    {
+        BDEBUG(BD_MODEL,
+"        capsule border ports    : (class has no border ports)\n");
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"        capsule border ports    : \n");
+        debugOutputModelPortsList(slot->capsuleClass->numPortRolesBorder, borderPorts);
+    }
+    if (slot->capsule == NULL)
+    {
+        BDEBUG(BD_MODEL,
+"        capsule internal ports  : (none)\n");
+    }
+    else if ((portlist = slot->capsule->getInternalPorts()) == NULL)
+    {
+        BDEBUG(BD_MODEL,
+"        capsule internal ports  : (none)\n");
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"        capsule internal ports  :\n");
+        debugOutputModelPortsArray(slot->capsuleClass->numPortRolesInternal, portlist);
+    }
+    // recurse into parts.
+    if (slot->capsuleClass->numSubcapsuleRoles == 0)
+    {
+        BDEBUG(BD_MODEL,
+"        # sub-capsule parts     : (none)\n");
+    }
+    else
+    {
+        BDEBUG(BD_MODEL,
+"        # sub-capsule parts     : %d\n", slot->numParts);
+
+        for (size_t i = 0; i < slot->numParts; ++i)
+        {
+            BDEBUG(BD_MODEL,
+"            role [%u]: %s [%d..%d] %s %s\n",
+                    i,
+                    slot->parts[i].role()->name,
+                    slot->parts[i].role()->multiplicityLower,
+                    slot->parts[i].role()->multiplicityUpper,
+                    (slot->parts[i].role()->optional) ? "optional " : "",
+                            (slot->parts[i].role()->plugin) ? "plugin " : "");
+        }
+    }
+    // Recurse into sub-structure outputing slot info.
+    for (size_t i = 0; i < slot->numParts; ++i)
+    {
+        for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+        {
+            debugOutputSlots(slot->parts[i].slots[j]);
+        }
+    }
+}
+
+void UMLRTController::debugOutputSlotContainment( const UMLRTSlot * slot, size_t nesting )
+{
+    for (size_t i = 0; i < nesting; ++i)
+    {
+        BDEBUG(BD_MODEL, "    ");
+    }
+    BDEBUG(BD_MODEL, "{ %s, %s, %p, %s }\n",
+        slot->name,
+        (slot->capsule == NULL) ? "(none)" : slot->capsule->getName(),
+         slot->capsule,
+        slot->capsuleClass->name);
+    for (size_t i = 0; i < slot->numParts; ++i)
+    {
+        for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+        {
+            debugOutputSlotContainment(slot->parts[i].slots[j], nesting + 1);
+        }
+    }
+}
+
+void UMLRTController::debugOutputModel()
+{
+    // Acquire global RTS lock for this.
+    UMLRTFrameService::rtsLock();
+
+    char timebuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+    UMLRTTimespec tm;
+
+    UMLRTTimespec::getClock(&tm);
+    BDEBUG(BD_MODEL, "Model structure at time %s:\n", tm.toString(timebuf, sizeof(timebuf)));
+
+    UMLRTCapsuleToControllerMap::debugOutputControllerList();
+
+    UMLRTCapsuleToControllerMap::debugOutputCapsuleList();
+
+    UMLRTProtocol::debugOutputServiceRegistration();
+
+    const UMLRTCapsule * top = UMLRTCapsuleToControllerMap::getCapsuleFromName("Top");
+
+    if (top == NULL)
+    {
+        BDEBUG(BD_MODEL, "ERROR: no 'Top' capsule found - no slot containment output.\n");
+    }
+    else
+    {
+        const UMLRTSlot * slot = top->getSlot();
+        BDEBUG(BD_MODEL, "Slot containment: { <slot>, <capsule name>, <capsule instance address>, <capsule class> } \n");
+        debugOutputSlotContainment( slot, 1 );
+    }
+    if (top == NULL)
+    {
+        BDEBUG(BD_MODEL, "ERROR: no 'Top' capsule found - no slot list output.\n");
+    }
+    else
+    {
+        const UMLRTSlot * slot = top->getSlot();
+        BDEBUG(BD_MODEL, "Slot list:\n");
+        debugOutputSlots( slot );
+    }
+    UMLRTFrameService::rtsUnlock();
+}
diff --git a/rts/umlrt/umlrtframeprotocol.cc b/rts/umlrt/umlrtframeprotocol.cc
new file mode 100644
index 0000000..771b8cd
--- /dev/null
+++ b/rts/umlrt/umlrtframeprotocol.cc
@@ -0,0 +1,372 @@
+// umlrtframeprotocol.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtcapsule.hh"
+#include "umlrtcapsuleid.hh"
+#include "umlrtcapsulepart.hh"
+#include "umlrtcommsport.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtframeprotocol.hh"
+#include "umlrtframeservice.hh"
+#include "basefatal.hh"
+
+// Return true if a subClass is a sub-class of baseClass.
+bool UMLRTFrameProtocol::OutSignals::classIsKindOf( const UMLRTCommsPort * srcPort, const UMLRTCapsuleClass & subClass, const UMLRTCapsuleClass & baseClass )
+{
+    bool isKindOf = false;
+    const UMLRTCapsuleClass * parentClass = &subClass;
+
+    while ((parentClass != NULL) && !isKindOf)
+    {
+        if (parentClass == &baseClass)
+        {
+            isKindOf = true;
+        }
+        parentClass = parentClass->super;
+    }
+    return isKindOf;
+}
+
+// Return the name of a capsule class.
+const char * UMLRTFrameProtocol::OutSignals::className( const UMLRTCommsPort * srcPort, const UMLRTCapsuleClass & capsuleClass )
+{
+    return capsuleClass.name;
+}
+
+// Return the capsule class of a capsule instance.
+const UMLRTCapsuleClass & UMLRTFrameProtocol::OutSignals::classOf( const UMLRTCommsPort * srcPort, const UMLRTCapsuleId id )
+{
+    return *id.getCapsule()->getClass();
+}
+
+
+bool UMLRTFrameProtocol::OutSignals::deport( const UMLRTCommsPort * srcPort, const UMLRTCapsuleId id, const UMLRTCapsulePart * part )
+{
+    bool ok = false;
+
+    // Initialize error code to E_NONE, in case anybody looks at it after success.
+    srcPort->slot->controller->setError(UMLRTController::E_OK);
+
+    if (!id.isValid())
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_DEPORT_INVLD);
+    }
+    else if (!part->role()->plugin)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_DEPORT_NONPLUG);
+    }
+    else
+    {
+        UMLRTCapsule * capsule = id.getCapsule();
+
+        // Only specified the the capsule id within the part - we must find the slot being deported.
+        for (size_t i = 0; (i < part->role()->multiplicityUpper) && !ok; ++i)
+        {
+            if (part->slots[i]->capsule == capsule)
+            {
+                ok = true;
+                UMLRTFrameService::requestControllerDeport(part->slots[i], false/*lockAcquired*/);
+            }
+        }
+        if (!ok)
+        {
+            srcPort->slot->controller->setError(UMLRTController::E_DEPORT_NOINST);
+        }
+    }
+    return ok;
+}
+
+bool UMLRTFrameProtocol::OutSignals::destroy( const UMLRTCommsPort * srcPort, const UMLRTCapsuleId id )
+{
+    bool ok = false;
+    UMLRTCapsule * capsule = id.getCapsule();
+
+    // Initialize error code to E_NONE, in case anybody looks at it after success.
+    srcPort->slot->controller->setError(UMLRTController::E_OK);
+
+    if (capsule == NULL)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_DESTR_INVALID);
+    }
+    else if (capsule->getSlot()->role() == NULL)
+    {
+        FATAL("Destroying capsule without a role. Destroying Top?");
+    }
+    else if (capsule->getSlot()->role()->optional)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_DESTR_NONOPT);
+    }
+    else
+    {
+        // Either we destroy the capsule in this context or we send a DESTROY Controller Command to execute the destroy.
+        UMLRTFrameService::requestControllerDestroy(capsule->getSlot(), true/*isTopSlot*/, false/*lockAcquired*/);
+        ok = true;
+    }
+    return ok;
+}
+
+bool UMLRTFrameProtocol::OutSignals::destroy( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part )
+{
+    bool ok = false;
+
+    // Initialize error code to E_NONE, in case anybody looks at it after success.
+    srcPort->slot->controller->setError(UMLRTController::E_OK);
+
+    if (part->role() == NULL)
+    {
+        FATAL("Destroying part without a role. Destroying Top?");
+    }
+    if (!part->role()->optional)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_DESTR_NONOPT);
+    }
+    else
+    {
+        ok = true; // Assume ok from this point.
+
+        for (size_t i = part->role()->multiplicityLower; i < part->numSlot; ++i)
+        {
+            if (part->slots[i]->capsule != NULL)
+            {
+                // Either we destroy the capsule in this context or we send a DESTROY Controller Command to execute the destroy.
+                // This is a destroy of multiple slots and each is the 'top slot' of its associated sub-structure.
+                UMLRTFrameService::requestControllerDestroy(part->slots[i], true/*isTopSlot*/, false/*lockAcquired*/);
+                ok = true;
+            }
+        }
+    }
+    return ok;
+}
+
+bool UMLRTFrameProtocol::OutSignals::import( const UMLRTCommsPort * srcPort, const UMLRTCapsuleId id, const UMLRTCapsulePart * destPart, int index )
+{
+    bool ok = false;
+
+    if (!id.isValid())
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_IMPORT_NOINST);
+    }
+    else
+    {
+        ok = UMLRTFrameService::importCapsule(srcPort, id.getCapsule(), destPart, index);
+    }
+    return ok;
+}
+
+bool UMLRTFrameProtocol::OutSignals::import( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * srcPart, const UMLRTCapsulePart * dest, int index )
+{
+    bool ok = false;
+
+    if ((srcPart->numSlot > 1) && index == -1)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_IMPORT_PARTREPL);
+    }
+    else if (srcPart->slots[0]->capsule == NULL)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_IMPORT_NOINST);
+    }
+    else
+    {
+        ok = UMLRTFrameService::importCapsule(srcPort, srcPart->slots[0]->capsule, dest, index);
+    }
+    return ok;
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const char * logThread, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part, // part
+            NULL, // capsuleClass
+            NULL, // userData
+            NULL, // type
+            logThread,
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, UMLRTController * controller, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            NULL, // capsuleClass
+            NULL, // userData
+            NULL, // type
+            NULL, // logThread
+            controller,
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass & capsuleClass, const char * logThread, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            &capsuleClass,
+            NULL, // userData
+            NULL, // type
+            logThread,
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass & capsuleClass, UMLRTController * controller, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            &capsuleClass,
+            NULL, // userData
+            NULL, // type
+            NULL, // logThread
+            controller,
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const void * userData, const UMLRTObject_class * type, const char * logThread, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            NULL, // capsuleClass
+            userData,
+            type,
+            logThread,
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const void * userData, const UMLRTObject_class * type, UMLRTController * controller, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            NULL, // capsuleClass
+            userData,
+            type,
+            NULL, // logThread
+            controller,
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass & capsuleClass, const void * userData, const UMLRTObject_class * type, const char * logThread, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            &capsuleClass,
+            userData,
+            type,
+            logThread,
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass & capsuleClass, const void * userData, const UMLRTObject_class * type, UMLRTController * controller, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            &capsuleClass,
+            userData,
+            type,
+            NULL, // logThread
+            controller,
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTTypedValue * value, const char * logThread, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            NULL, // capsuleClass
+            value->data, // userData
+            value->type, // type
+            logThread,
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTTypedValue * value, UMLRTController * controller, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            NULL, // capsuleClass
+            value->data, // userData
+            value->type, // type
+            NULL, // logThread
+            controller,
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass & capsuleClass, const UMLRTTypedValue * value, const char * logThread, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            &capsuleClass,
+            value->data, // userData
+            value->type, // type
+            logThread,
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnate( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass & capsuleClass, const UMLRTTypedValue * value, UMLRTController * controller, int index ) const
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part,
+            &capsuleClass,
+            value->data, // userData
+            value->type, // type
+            NULL, // logThread
+            controller,
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::incarnateAt( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, int index )
+{
+    return UMLRTFrameService::incarnateCapsule(
+            srcPort,
+            part, // part
+            NULL, // capsuleClass
+            NULL, // userData
+            NULL, // type
+            NULL, // logThread
+            NULL, // controller
+            index
+            );
+}
+
+const UMLRTCapsuleId UMLRTFrameProtocol::OutSignals::me( const UMLRTCommsPort * srcPort )
+{
+    return UMLRTCapsuleId(srcPort->slot->capsule);
+}
+
+const UMLRTCapsuleClass & myClass( const UMLRTCommsPort * srcPort )
+{
+    return *srcPort->slot->capsule->getClass();
+}
diff --git a/rts/umlrt/umlrtframeservice.cc b/rts/umlrt/umlrtframeservice.cc
new file mode 100644
index 0000000..d43ef90
--- /dev/null
+++ b/rts/umlrt/umlrtframeservice.cc
@@ -0,0 +1,1800 @@
+// umlrtframeservice.cc
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtapi.hh"
+#include "umlrtcapsule.hh"
+#include "umlrtcapsulepart.hh"
+#include "umlrtcapsulerole.hh"
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportfarend.hh"
+#include "umlrtframeservice.hh"
+#include "umlrtprotocol.hh"
+#include "umlrtslot.hh"
+#include "basedebugtype.hh"
+#include "basedebug.hh"
+#include "basefatal.hh"
+
+// Use a global lock on the RTS for now for modifying ports and access far-end ports during message delivery.
+/*static*/ UMLRTMutex UMLRTFrameService::rtsGlobalLock;
+
+/*static*/ UMLRTRtsInterfaceUmlrt UMLRTFrameService::rtsifUmlrt;
+
+/*static*/ void UMLRTFrameService::bindSubcapsulePort ( bool isBorder, UMLRTCapsule * subcapsule, int portIndex, int farEndIndex )
+{
+    if (subcapsule != NULL)
+    {
+        BDEBUG(BD_CONNECT, "bind subcapsule %s portIndex %d fei %d\n", subcapsule->getName(), portIndex, farEndIndex);
+
+        subcapsule->bindPort(isBorder, portIndex, farEndIndex);
+    }
+}
+
+/*static*/ const UMLRTCommsPort * * UMLRTFrameService::bindPorts ( UMLRTSlot * slot, UMLRTCapsule * capsule, const UMLRTCapsuleClass * requestedClass,
+        const UMLRTCapsuleClass * slotClass, const UMLRTCommsPort * * borderPorts, bool bind, bool import )
+{
+    // Assumes global RTS lock acquired.
+
+    // For incarnate, the newBorderPorts will become the top capsule's border ports (caspule instance created in this context but initialized by controller.)
+    // For import, the returned border port list is discarded. It's run twice - once for checking in the context of the importer (no binding occurs)
+    // and once in the context of the slot's controller (where input border port list is actually updated.)
+
+    const UMLRTCommsPort * * newBorderPorts = new const UMLRTCommsPort * [requestedClass->numPortRolesBorder];
+
+    // The slot will get the importPortMap to assist with deport.
+    int * slotToBorderMap = new int[slotClass->numPortRolesBorder]; // Will hold index into newBorderPorts for each slot port.
+
+    // Remember the number of bound instances on each slot port for determining whether we need a proxy port or need to make connections.
+    size_t * slotBoundCount = new size_t[slotClass->numPortRolesBorder]; // Will hold the number of bound instances on each slot port.
+
+    // Each of the bound slot ports have to be bound to a capsule border port.
+    for (size_t i = 0; i < slotClass->numPortRolesBorder; ++i)
+    {
+        // Set all slotToBorderMap entries to 'capsule border port not mapped to this slot'.
+        slotToBorderMap[i] = -1;
+
+        // The number of bound instances on each slot port are remembered as each is visited.
+        slotBoundCount[i] = 0;
+    }
+    // Initialize 'newBorderPorts' - the new border ports for the capsule if binding succeeds.
+    for (size_t i = 0; i < requestedClass->numPortRolesBorder; ++i)
+    {
+        if ((borderPorts != NULL) && borderPorts[i] == NULL)
+        {
+            FATAL("slot %s capsule %s border port was NULL - should at least be the unbound port.",
+                    slot->name, capsule->getName());
+        }
+        if ((borderPorts != NULL) && !borderPorts[i]->unbound)
+        {
+            // Existing capsule border port is bound either to a slot port or is a proxy port bound to one or more slots.
+            newBorderPorts[i] = borderPorts[i];
+        }
+        else
+        {
+            // Capsule border port is unbound (or we are incarnating and didn't have a set of pre-existing caspule border ports.)
+            newBorderPorts[i] = NULL;
+        }
+    }
+    // Port compatibility check.
+    // The ports are assumed to be ordered.
+
+    size_t border_i = 0; // Port index on requesting class. We're searching the capsule's border ports for unbound ports to match bound slot ports.
+
+    bool compatible = true; // Assume compatibility until we fail.
+
+    // Go through each port on the slot. Quit if we fail to find a match for any bound slot port. Do the actual binding after we've proven the capsule fits.
+    bool done = false;
+
+    for (size_t slot_i = 0; (slot_i < slotClass->numPortRolesBorder) && compatible && !done; ++slot_i)
+    {
+        bool match = false;
+
+        // Remember how many port instances were bound on the slot port.
+        slotBoundCount[slot_i] = bindPortsCountBound( &slot->ports[slot_i]);
+
+        // Loop through the remaining requesting capsule border ports looking for a match to slot port slot_i.
+        while (!done && !match)
+        {
+            // If port-name match.
+            if (!strcmp(slotClass->portRolesBorder[slot_i].name, requestedClass->portRolesBorder[border_i].name))
+            {
+                // Get the number of bound instances on the capsules's border port.
+                size_t borderBoundCount = bindPortsCountBound(newBorderPorts[border_i]);
+
+                if (strcmp(slotClass->portRolesBorder[slot_i].protocol, requestedClass->portRolesBorder[border_i].protocol))
+                {
+                    // protocol mismatch.
+                    done = !0;
+                    BDEBUG(BD_BINDFAIL, "BIND FAIL:%d %d:slot %s (class %s) port %s (protocol %s) has MISMATCHED PROTOCOL with capsule (class %s) (protocol %s).\n",
+                            slot_i, border_i, slot->name, slot->capsuleClass, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, requestedClass->name, requestedClass->portRolesBorder[border_i].protocol);
+                }
+                else if (slotClass->portRolesBorder[slot_i].conjugated != requestedClass->portRolesBorder[border_i].conjugated)
+                {
+                    // conjugation mismatch.
+                    done = !0;
+                    BDEBUG(BD_BINDFAIL, "BIND FAIL:%d %d:slot %s port %s (protocol %s) has MISMATCHED CONJUGATION with capsule (class %s)\n",
+                            slot_i, border_i, slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, requestedClass->name);
+                }
+                else if ((requestedClass->portRolesBorder[border_i].numFarEnd - borderBoundCount) < slotBoundCount[slot_i])
+                {
+                    // capsule border port unbound instances insufficient for binding
+                    done = !0;
+                    BDEBUG(BD_BINDFAIL, "BIND FAIL:%d %d:slot %s port %s (protocol %s) BOUND PORTS [%lu] EXCEEDS CAPSULE'S UNBOUND (class %s) port repl unbound instances [%lu].\n",
+                            slot_i, border_i, slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotBoundCount[slot_i], requestedClass->name,
+                            requestedClass->portRolesBorder[border_i].numFarEnd - borderBoundCount);
+                }
+                else if (slotBoundCount[slot_i] > 0)
+                {
+                    // The slot port has to be bound to this port because it has bindings.
+
+                    BDEBUG(BD_BINDDEBUG, "BIND DEBUG:%d %d:slot %s port %s (protocol %s) repl %lu MATCHED to capsule border port (bindings reqd).\n",
+                            slot_i, border_i, slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotClass->portRolesBorder[slot_i].numFarEnd);
+
+                    // We can accommodate this port bind. Remember the details, but don't bind just yet.
+                    match = true;
+                    slotToBorderMap[slot_i] = border_i; // Remember which capsule border port index was mapped to slot slot_i.
+                    if (newBorderPorts[border_i] == NULL)
+                    {
+                        // The capsule border port was not already mapped elsewhere, so just map this slot's port to this capsule border port for now.
+                        newBorderPorts[border_i] = &slot->ports[slot_i];
+                    }
+                }
+                else
+                {
+                    // This is the case where a slot port matches the name (and protocol and conjugation) of the instantiated/incarnated
+                    // capsule border port but has no bound instances. We don't map the slot port to the capsule border port, leaveing the capsule border
+                    // port available for bindings elsewhere during future imports into other slots.
+                    match = true;
+                    BDEBUG(BD_BINDDEBUG, "BIND DEBUG:%d %d:slot %s port %s (protocol %s) repl %lu MATCH IGNORED (no bindings reqd).\n",
+                            slot_i, border_i, slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotClass->portRolesBorder[slot_i].numFarEnd);
+                }
+            }
+            // Advance to next capsule border port - and quit if we've exhausted them.
+            if (++border_i >= requestedClass->numPortRolesBorder)
+            {
+                done = !0;
+            }
+        }
+        if (!match)
+        {
+            // Slot port slot_i didn't find a home in the capsule border port list, so fail port binding.
+            compatible = false;
+            BDEBUG(BD_BINDFAIL, "BIND FAIL:slot %s port %s (protocol %s) repl %lu FAILED TO BIND.\n",
+                    slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotClass->portRolesBorder[slot_i].numFarEnd);
+        }
+    }
+    if (compatible && bind)
+    {
+        // Succeeded with the bind-check. Redefine the slot's map from slot-port-to-capsule-border-port.
+        if (slot->slotToBorderMap != NULL)
+        {
+            FATAL("Slot %s already had a slotToBorderMap during port binding.", slot->name);
+        }
+        if (bind)
+        {
+            // For both incarnate and import, we're binding and define the slotToBorderMap here for deporting or destroy.
+            slot->slotToBorderMap = slotToBorderMap;
+        }
+        // For import, we do port binding. For incarnate, we may create proxy ports.
+
+        // First, replace any matched slot ports in the new capsule border port list with proxies where they are required.
+        // We create proxy ports when the capsule border port repl > slot port repl, or the slot port has unbound instances.
+        for (size_t slot_i = 0; (slot_i < slotClass->numPortRolesBorder); ++slot_i)
+        {
+            // If this slot port was bound to a capsule border port in the check above AND the capsule didn't have a previous binding on the port.
+            if ((slotToBorderMap[slot_i] != -1) && (newBorderPorts[slotToBorderMap[slot_i]] == &slot->ports[slot_i]))
+            {
+                // If we get to here, the capsule border port that matched the slot port was not previously bound.
+                // We've assigned the slot port as a 'possible' capsule border port.
+
+                // Here we check whether the slot port can stay as the border port. If not, we create a proxy port for the capsule border port.
+
+                // If the slot port replication count is less than the capsule border port can support
+                // or the slot had unbound instances...
+                if (   (slot->ports[slot_i].numFarEnd < requestedClass->portRolesBorder[slotToBorderMap[slot_i]].numFarEnd)
+                    || (slot->ports[slot_i].numFarEnd > slotBoundCount[slot_i]))
+                {
+                    // ...create a proxy port with a new far-end list to accommodate the capsule border port's larger replication count.
+                    // Duplicate the bound connections that were already on the slot port. The slot port's far-end still points the slot port, which is good.
+
+                    // If we're importing, we notify the capsule instance of the bound instances while we copy them to the proxy port.
+                    // For incarnation, the capsule class instantiate function will handle the port binding.
+                    newBorderPorts[slotToBorderMap[slot_i]] = bindPortsCreateProxyPort(slot, capsule, borderPorts, &slot->ports[slot_i], requestedClass, slotToBorderMap[slot_i], import);
+                    BDEBUG(BD_BINDDEBUG, "BIND DEBUG:%d %d:slot %s port %s (protocol %s) repl %lu CREATE PROXY PORT repl %lu\n",
+                            slot_i, slotToBorderMap[slot_i], slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotClass->portRolesBorder[slot_i].numFarEnd,
+                            requestedClass->portRolesBorder[slotToBorderMap[slot_i]].numFarEnd);
+                }
+                else
+                {
+                    // The slot port is fully bound and the capsule border port was unbound.
+                    // The slot port becomes the capsule border port because all slot ports are bound.
+                    newBorderPorts[slotToBorderMap[slot_i]] = &slot->ports[slot_i];
+
+                    BDEBUG(BD_BINDDEBUG, "BIND DEBUG:%d %d:slot %s port %s (protocol %s) repl %lu MATCH BECOMES capsule border port\n",
+                            slot_i, slotToBorderMap[slot_i], slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotClass->portRolesBorder[slot_i].numFarEnd,
+                            requestedClass->portRolesBorder[slotToBorderMap[slot_i]].numFarEnd);
+
+                    // If this is import, we notify the capsule instance here.
+                    if (import)
+                    {
+                        for (size_t i = 0; i < requestedClass->portRolesBorder[slotToBorderMap[slot_i]].numFarEnd; ++i)
+                        {
+                            capsule->bindPort(true/*isBorder*/, slotToBorderMap[slot_i], i);
+                        }
+                        // Inform the capsule of the entire port binding.
+                        BDEBUG(BD_BIND, "capsule %s (class %s) bind entire %s port %d during import\n", slot->name, slot->capsuleClass->name,
+                                (borderPorts[slotToBorderMap[slot_i]] == &slot->ports[slot_i]) ? "slot" : "proxy", slotToBorderMap[slot_i]);
+                    }
+                }
+            }
+            else if (slotToBorderMap[slot_i] != -1)
+            {
+                // Will never be true for incarnate here, because incarnate didn't have capsule border ports to begin with.
+                // This border port (that is NOT this slot's border port) can accommodate this slot port because it has enough free instances.
+                // Previously unbound port instances of the capsule border port are used to accommodate this slot port's far-ends.
+                // Bind the bound slot instances to the far-ends of unbound capsule border port instances.
+                bindPortsAddFarEnds(borderPorts[slotToBorderMap[slot_i]], slotToBorderMap[slot_i], &slot->ports[slot_i], capsule, import);
+                BDEBUG(BD_BINDDEBUG, "BIND DEBUG:%d %d:slot %s port %s (protocol %s) repl %lu bindings added to previously existing border port\n",
+                        slot_i, slotToBorderMap[slot_i], slot->name, slotClass->portRolesBorder[slot_i].name, slotClass->portRolesBorder[slot_i].protocol, slotClass->portRolesBorder[slot_i].numFarEnd);
+            }
+            BDEBUG(BD_BINDDEBUG, "BIND OK:%d: slot %s port %s (protocol %s) (repl %d) %s capsule (class %s) border port%s.\n",
+                    slot_i,
+                    slot->name,
+                    slotClass->portRolesBorder[slot_i].name,
+                    slotClass->portRolesBorder[slot_i].protocol,
+                    slotClass->portRolesBorder[slot_i].numFarEnd,
+                    (slotToBorderMap[slot_i] != -1) ?
+                            ((newBorderPorts[slotToBorderMap[slot_i]] == &slot->ports[slot_i]) ? "BECOMES the" : "PROXY USED for the") : "NO BINDS REQUIRED and the",
+                    requestedClass->name,
+                    (slotToBorderMap[slot_i] != -1) ? "" : " was NOT BOUND");
+        }
+        // We've done all slot port binding to capsule border port. Import binding has called the capsule instance to notify of the bindings.
+        // At this point, any capsule border port that remains unbound by the algorithm above is still 'completely unbound' and we can
+        // create the 'unbound port' for this one.
+        for (size_t i = 0; i < requestedClass->numPortRolesBorder; ++i)
+        {
+            if (newBorderPorts[i] == NULL)
+            {
+                newBorderPorts[i] = createPorts(slot, requestedClass, 1, requestedClass->portRolesBorder, true/*border*/, true/*proxy*/, i/*roleIndexOffset*/, true/*isUnbound*/);
+            }
+        }
+    }
+    if (!compatible)
+    {
+        // Binding failed - delete resources. (If binding succeeded, the slot has the 'slotToBorderMap' and the newBorderPorts
+        // is returned to the caller (to be passed to the initial capsule instantiation during incarnation and discarded (but indicates
+        // success) for import in the context of the importer. Binding is re-done for import in the context of the capsule's controller.
+        delete[] slotToBorderMap;
+        slotToBorderMap = NULL;
+        delete[] newBorderPorts;
+        newBorderPorts = NULL;
+    }
+    return newBorderPorts;
+}
+
+/*static*/ void UMLRTFrameService::bindPortsAddFarEnds ( const UMLRTCommsPort * capsuleBorderPort, int border_i, const UMLRTCommsPort * slotport, UMLRTCapsule * capsule, bool import )
+{
+    // Assumes global RTS lock already acquired.
+
+    // We're adding the slot port bound far-ends to free far-end instances on a capsule proxy port.
+    // For every slot port instance, find a free home on the capsule border port.
+    for (size_t i = 0; i < slotport->numFarEnd; ++i)
+    {
+        size_t border_fei = 0; // Start at the first 'far-end instance' (fei) of the capsule border port.
+
+        if (slotport->farEnds[i].port != NULL)
+        {
+            // slot port far end is connected, search forward through the capsule border port looking for an unbound instance.
+            bool bound = false;
+            while ((border_fei < capsuleBorderPort->numFarEnd) && !bound)
+            {
+                if (capsuleBorderPort->farEnds[border_fei].port == NULL)
+                {
+                    // Connect the slot port's far-end to the (formerly) unbound far end on the capsule's border port.
+                    // NOTE: The slot port far-end is not modified.
+                    capsuleBorderPort->farEnds[border_fei].port = slotport->farEnds[i].port;
+                    capsuleBorderPort->farEnds[border_fei].farEndIndex = slotport->farEnds[i].farEndIndex;
+                    bound = true;
+
+                    BDEBUG(BD_BIND, "capsule %s (class %s) bind proxy port instance %d %d during import\n",
+                            capsuleBorderPort->slot->name, capsuleBorderPort->slot->capsuleClass->name, border_i, border_fei);
+
+                    if (import)
+                    {
+                        // For import, we notify the capsule instance of the bind.
+                        capsule->bindPort(true/*isBorder*/, border_i, border_fei);
+                    }
+                }
+                border_fei++;
+            }
+            if (border_fei >= capsuleBorderPort->numFarEnd && !bound)
+            {
+                // Should never happen. We'd already verified that the capsuleBorderPort can accommodate the slot bindings.
+                FATAL("failed to connect all slot port's far-ends to the capsule border port during import.");
+            }
+        }
+    }
+}
+
+/*static*/ size_t UMLRTFrameService::bindPortsCountBound ( const UMLRTCommsPort * port )
+{
+    // Assumes global RTS lock already acquired.
+
+    size_t count = 0; // The 'unbound port' has no far-ends.
+
+    if (port != NULL)
+    {
+        for (size_t i = 0; i < port->numFarEnd; ++i)
+        {
+            if (port->farEnds[i].port != NULL)
+            {
+                ++count;
+            }
+        }
+    }
+    return count;
+}
+
+/*static*/ const UMLRTCommsPort * UMLRTFrameService::bindPortsCreateProxyPort ( UMLRTSlot * slot, UMLRTCapsule * capsule, const UMLRTCommsPort * * borderPorts, const UMLRTCommsPort * slotPort, const UMLRTCapsuleClass * requestedClass, int border_i, bool import )
+{
+    // Assumes global RTS lock already acquired.
+
+    // Create the border port unconnected.
+    const UMLRTCommsPort * newBorderPort = createPorts( slot, requestedClass, 1, &requestedClass->portRolesBorder[border_i], true/*border*/, true/*proxy*/, border_i);
+
+    // Copy connections from the slot port. The border port is larger - the 'extra' port instances remain unconnected.
+    for (size_t i = 0; i < slotPort->numFarEnd; ++i)
+    {
+        newBorderPort->farEnds[i].farEndIndex = slotPort->farEnds[i].farEndIndex;
+        if (((newBorderPort->farEnds[i].port = slotPort->farEnds[i].port) != NULL) && import)
+        {
+            // We've just bound a far-end of a slot port to a new capsule border proxy port - notify the capsule instance when we're importing.
+            capsule->bindPort(true/*isBorder*/, border_i, i);
+        }
+    }
+    return newBorderPort;
+}
+
+/*static*/ bool UMLRTFrameService::bindServicePort ( const UMLRTCommsPort * sapPort, const UMLRTCommsPort * sppPort )
+{
+    bool ok = false;
+
+    BDEBUG(BD_SAP, "SAP [%s %s] bind to SPP [%s %s]\n", (sapPort == NULL) ? "NULL" : sapPort->slot->name, (sapPort == NULL) ? "NULL" : sapPort->role()->name,
+                    (sppPort == NULL) ? "NULL" : sppPort->slot->name, (sppPort == NULL) ? "NULL" : sppPort->role()->name);
+
+    if (sapPort && sppPort)
+    {
+        if (sapPort->numFarEnd != 1)
+        {
+            FATAL("SAP slot %s port %s has > 1 far-ends (has %d)", sapPort->slot->name, sapPort->role()->name, sapPort->numFarEnd);
+        }
+        else if (sapPort->farEnds[0].port != NULL)
+        {
+            FATAL("SAP slot %s port %s already connected to slot %s port %s", sapPort->slot->name, sapPort->role()->name,
+                    sapPort->farEnds[0].port->slot->name, sapPort->farEnds[0].port->role()->name);
+        }
+        else if (strcmp(sapPort->role()->protocol, sppPort->role()->protocol))
+        {
+            // TODO - should inform user - Bug 246
+            BDEBUG(BD_SWERR, "binding SAP[%s %s] to SPP[%s %s] mismatched protocol sap(%s) spp(%s)\n",  sapPort->slot->name, sapPort->role()->name,
+                    sppPort->slot->name, sppPort->role()->name, sapPort->role()->protocol, sppPort->role()->protocol);
+        }
+        else if (sapPort->role()->conjugated == sppPort->role()->conjugated)
+        {
+            // TODO - should inform user - Bug 246
+            BDEBUG(BD_SWERR, "binding SAP[%s %s] to SPP[%s %s] conjugation not complementary\n",  sapPort->slot->name, sapPort->role()->name,
+                    sppPort->slot->name, sppPort->role()->name);
+        }
+        else
+        {
+            for (size_t i = 0; (i < sppPort->numFarEnd) && !ok; ++i)
+            {
+                if (sppPort->farEnds[i].port == NULL)
+                {
+                    connectPorts(sapPort, 0, sppPort, i);
+                    sendBoundUnbound(sapPort, 0, sppPort, i, true/*isBind*/);
+                    sendBoundUnbound(sppPort, i, sapPort, 0, true/*isBind*/);
+                    ok = true;
+                }
+            }
+        }
+    }
+    return ok;
+}
+
+/*static*/ void UMLRTFrameService::condemnParts ( UMLRTSlot * slot )
+{
+    slot->condemned = true;
+    for (size_t i = 0; i < slot->numParts; ++i)
+    {
+        for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+        {
+            // set 'condemned' on sub-structure.
+            condemnParts(slot->parts[i].slots[j]);
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::connectPorts ( const UMLRTCommsPort * p1, size_t index1, const UMLRTCommsPort * p2, size_t index2 )
+{
+    // Assumes global RTS lock already acquired.
+
+    BDEBUG(BD_CONNECT, "connectPorts: ");
+    if (p1 == NULL)
+    {
+        BDEBUG(BD_CONNECT, "P1 NULL");
+    }
+    else if (p1->unbound)
+    {
+        BDEBUG(BD_CONNECT, "P1 UNBOUND");
+    }
+    else
+    {
+        BDEBUG(BD_CONNECT, "P1 slot(%s) port(%s[%lu]) id(%d) (%s) repl sz(%d)\n",
+                p1->slot->name,
+                p1->role()->name,
+                index1,
+                p1->role()->id,
+                p1->role()->protocol,
+                p1->role()->numFarEnd);
+
+        // if p1 has a far end, connect p1's far-end to p2.
+        if (p1->farEnds[index1].port)
+        {
+            size_t original_index1 = index1;
+            index1 = p1->farEnds[index1].farEndIndex;
+            p1 = p1->farEnds[original_index1].port;
+            BDEBUG(BD_CONNECT, "              *** connecting P1->farEnd: slot(%s) port(%s[%lu]) id(%d) (%s) repl sz(%d)\n",
+                    p1->slot->name,
+                    p1->role()->name,
+                    index1,
+                    p1->role()->id,
+                    p1->role()->protocol,
+                    p1->role()->numFarEnd);
+        }
+        if (p2 == NULL)
+        {
+            BDEBUG(BD_CONNECT, "              P2 NULL\n");
+        }
+        else if (p2->unbound)
+        {
+            BDEBUG(BD_CONNECT, "              P2 UNBOUND\n");
+        }
+        else
+        {
+            BDEBUG(BD_CONNECT, "              P2 slot(%s) port(%s[%lu]) id(%d) (%s) repl sz(%d)\n",
+                    p2->slot->name,
+                    p2->role()->name,
+                    index2,
+                    p2->role()->id,
+                    p2->role()->protocol,
+                    p2->role()->numFarEnd);
+        }
+        p1->farEnds[index1].port = p2->unbound ? NULL : p2;
+        p1->farEnds[index1].farEndIndex = p2->unbound ? 0 : index2;
+        if ((p2 != NULL) && (!p2->unbound))
+        {
+            if (index2 > p2->numFarEnd)
+            {
+                FATAL("slot %s port %s p1 %s[%d] p2 %s[%d] p2 index exceeds p2->numFarEnd(%d)",
+                        p1->slot->name, p1->role()->name, index1, p2->role()->name, index2, p2->numFarEnd);
+            }
+            p2->farEnds[index2].port = p1;
+            p2->farEnds[index2].farEndIndex = index1;
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::connectRelayPort ( const UMLRTCommsPort * relayPort, size_t relayIndex, const UMLRTCommsPort * destPort, size_t destIndex )
+{
+    // Assumes global RTS lock already acquired.
+
+    BDEBUG(BD_CONNECT, "connectRelayPort: ");
+    if (relayPort == NULL)
+    {
+        BDEBUG(BD_CONNECT, "P1 NULL");
+    }
+    else if (relayPort->unbound)
+    {
+        BDEBUG(BD_CONNECT, "P1 UNBOUND");
+    }
+    else
+    {
+        relayPort->relay = true;
+
+        BDEBUG(BD_CONNECT, "P1 slot(%s) port(%s[%lu]) id(%d) (%s) repl sz(%d)\n",
+                relayPort->slot->name,
+                relayPort->role()->name,
+                relayIndex,
+                relayPort->role()->id,
+                relayPort->role()->protocol,
+                relayPort->role()->numFarEnd);
+
+        size_t original_index1 = relayIndex;
+        relayIndex = relayPort->farEnds[relayIndex].farEndIndex;
+        relayPort = relayPort->farEnds[original_index1].port;
+        if (relayPort == NULL)
+        {
+            BDEBUG(BD_CONNECT, "              *** connecting P1->farEnd: NULL - will leave p2 'as is'\n");
+        }
+        else
+        {
+            BDEBUG(BD_CONNECT, "              *** connecting P1->farEnd: slot(%s) port(%s[%lu]) id(%d) (%s) repl sz(%d)\n",
+                relayPort->slot->name,
+                relayPort->role()->name,
+                relayIndex,
+                relayPort->role()->id,
+                relayPort->role()->protocol,
+                relayPort->role()->numFarEnd);
+        }
+        if ((relayPort != NULL) && (destPort != NULL))
+        {
+            BDEBUG(BD_CONNECT, "              P2 slot(%s) port(%s[%lu]) id(%d) (%s) repl sz(%d)\n",
+                    destPort->slot->name,
+                    destPort->role()->name,
+                    destIndex,
+                    destPort->role()->id,
+                    destPort->role()->protocol,
+                    destPort->role()->numFarEnd);
+            destPort->farEnds[destIndex].port = relayPort;
+            destPort->farEnds[destIndex].farEndIndex = relayIndex;
+            relayPort->farEnds[relayIndex].port = destPort;
+            relayPort->farEnds[relayIndex].farEndIndex = destIndex;
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::controllerDeport ( UMLRTSlot * slot, bool synchronous, bool lockAcquired )
+{
+    // Get lock if we don't have it.
+    if (!lockAcquired)
+    {
+        rtsLock();
+    }
+    if (slot == NULL)
+    {
+        FATAL("Attempt deport from NULL slot.");
+    }
+    else if ((slot->capsule == NULL) && !synchronous)
+    {
+        // Must have received the deport request 'late'. Just ignore it.
+        BDEBUG(BD_IMPORT, "Received 'late' deport request for slot %s. Ignoring it.\n", slot->name);
+    }
+    else if (slot->slotToBorderMap == NULL)
+    {
+        FATAL("Attempt to deport from slot %s but slotToBorderMap was NULL.", slot->name);
+    }
+    else  if (!slot->role()->plugin)
+    {
+        FATAL("Attempt to deport from slot %s but slot was not a plugin slot.", slot->name);
+    }
+    else
+    {
+        const UMLRTCommsPort * * borderPorts = slot->capsule->getBorderPorts();
+
+        controllerDeportUnbind(slot, borderPorts);
+
+        delete[] slot->slotToBorderMap;
+        slot->slotToBorderMap = NULL;
+
+        slot->capsuleClass = slot->role()->capsuleClass; // restore the original capsuleClass
+        slot->capsule = NULL; // Removes record of this instance, but the instance lives on in its original optional slot.
+    }
+    // Get lock if we don't have it.
+    if (!lockAcquired)
+    {
+        rtsUnlock();
+    }
+}
+
+void UMLRTFrameService::controllerDeportUnbind ( UMLRTSlot * slot, const UMLRTCommsPort * * borderPorts )
+{
+    // Assumes global RTS lock already acquired.
+
+    // Examine the capsule's class slotToBorderMap to see if any of the capsules border ports were mapped to this slot.
+    for (size_t slot_i = 0; slot_i < slot->capsule->getSlot()->role()->capsuleClass->numPortRolesBorder; ++slot_i)
+    {
+        int border_i = slot->slotToBorderMap[slot_i];
+
+        if (border_i != -1)
+        {
+            // This capsule border port slot had bindings on this slot port - notify the capsule about the unbinds from this slot.
+            if (borderPorts[border_i] == &slot->ports[slot_i])
+            {
+                // Capsule has a border port mapped directly to the slot port.
+                BDEBUG(BD_BIND, "capsule %s (class %s) unbind entire slot port %d during deport\n", slot->name, slot->capsuleClass->name, border_i);
+
+                for (size_t j = 0; j < slot->ports[slot_i].numFarEnd; ++j)
+                {
+                    if (slot->ports[slot_i].farEnds[j].port != NULL)
+                    {
+                        // Notify the capsule.
+                        slot->capsule->unbindPort(true/*isBorder*/, slot_i, j);
+
+                        // Connect the slot port far-ends back to the slot.
+                        connectPorts(&slot->ports[slot_i], j, &slot->ports[slot_i], j);
+                    }
+                }
+            }
+            else
+            {
+                // This is a proxy port with individual instances that would have been bound during import binding.
+                if (!borderPorts[border_i]->proxy)
+                {
+                    FATAL("Unbinding capsule %s from slot %s and mapped slot port[%d] != border port[%d] and port was not a proxy?",
+                            slot->capsule->getSlot()->name, slot->name, slot_i, border_i );
+                }
+                // slotToBorderMap[border_i] should be -1 for unbound ports.
+                if (borderPorts[border_i]->unbound)
+                {
+                    FATAL("Unbinding capsule %s from slot %s and mapped slot port[%d] != border port[%d] and port was unbound ?",
+                            slot->capsule->getSlot()->name, slot->name, slot_i, border_i );
+                }
+                for (size_t j = 0; j < slot->ports[slot_i].numFarEnd; ++j)
+                {
+                    if (slot->ports[slot_i].farEnds[j].port != NULL)
+                    {
+                        int instance_i;
+
+                        if ((instance_i = findFarEndInstance(slot->ports[slot_i].farEnds[j].port, slot->ports[slot_i].farEnds[j].farEndIndex, borderPorts[border_i])) < 0)
+                        {
+                            FATAL("slot %s deport of capsule %s port %s bound to far end %s not found on border proxy port id(%d)",
+                                    slot->name, slot->capsule->getName(), slot->ports[slot_i].role()->name, slot->ports[slot_i].farEnds[j].port->slot->name, border_i);
+                        }
+                        else
+                        {
+                            // Callback into the capsule instance for unbinding the border port.
+                            BDEBUG(BD_BIND, "capsule %s (class %s) unbind proxy port instance %d %d during deport\n", slot->name, slot->capsuleClass->name, border_i, instance_i);
+
+                            // Notify capsule.
+                            slot->capsule->unbindPort(true/*isBorder*/, border_i, instance_i);
+
+                            // Reconnect the slot port instance to itself - it's far-end gets connected to the slot.
+                            connectPorts( &slot->ports[slot_i], j, &slot->ports[slot_i], j);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::controllerDestroy ( UMLRTSlot * slot, bool isTopSlot, bool synchronous, bool lockAcquired )
+{
+    // Get RTS lock if we don't have it.
+    if (!lockAcquired)
+    {
+        rtsLock();
+    }
+    BDEBUG(BD_DESTROY, "Controller %s destroying slot %s. Capsule instance %s. The slot itself %s.\n",
+            slot->controller->getName(),
+            slot->name,
+            (slot->capsule != NULL) ? "will be deported or deleted" : "not present",
+            isTopSlot ? "will persist" : "will be destroyed");
+
+    if (slot->role() == NULL)
+    {
+        FATAL("Attempting to destroy a slot with no role. Destroying Top?");
+    }
+    if (slot->generated && !isTopSlot)
+    {
+        FATAL("Attempt to destroy a generated slot name(%d) class(%s) role(%s)",
+                slot->name, slot->capsuleClass->name, slot->role()->name);
+    }
+    if (isTopSlot)
+    {
+        // This is the top slot in a destruction. Special processing is required.
+        // The destruction of sub-slots of the top slot do not branch into this code.
+
+        // Mark all sub-slots as 'condemned' to cease signal activity on these.
+        condemnParts(slot);
+
+        if (slot->capsule != NULL)
+        {
+            // Send rtUnbound for top capsule ports.
+            sendBoundUnboundForCapsule(slot->capsule, false/*isBind*/);
+
+            // Reconnect the slot port far-ends with the slot ports.
+            for (size_t i = 0; i < slot->capsule->getClass()->numPortRolesBorder; ++i)
+            {
+                for (size_t j = 0; j < slot->ports[i].numFarEnd; ++j)
+                {
+                    // Purge any deferred messages owned by capsule being destroyed.
+                    slot->ports[i].purge();
+                    slot->ports[i].relay = false; // Empty slots have no relay ports regardless of slot capsule class.
+                    connectPorts( &slot->ports[i], j, &slot->ports[i], j );
+                }
+            }
+        }
+        // Recurse into sub-structure, either deporting or sending DEPORT Controller Commands.
+        deportParts(slot);
+
+        // Recurse into sub-structure, either destroying or sending DESTROY Controller Commands.
+        for (size_t i = 0; i < slot->numParts; ++i)
+        {
+            for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+            {
+                requestControllerDestroy(slot->parts[i].slots[j], false/*isTopSlot*/, true/*lockAcquired*/);
+            }
+        }
+    }
+    if (slot->capsule != NULL)
+    {
+        // If the slot had a running instance, delete it.
+
+        // Get a copy of the ports to destroy them here.
+        const UMLRTCommsPort * * borderPorts = slot->capsule->getBorderPorts();
+        const UMLRTCommsPort * internalPorts = slot->capsule->getInternalPorts();
+        const UMLRTCapsuleClass * capsuleClass = slot->capsule->getClass();
+
+        delete slot->capsule;
+        destroyPortList(capsuleClass->numPortRolesBorder, borderPorts);
+        destroyPorts(capsuleClass->numPortRolesInternal, internalPorts);
+
+        slot->capsule = NULL;
+        slot->capsuleClass = slot->role()->capsuleClass; // restore the original capsuleClass
+
+        // Destroy parts data-structures. The destroy requests have already been enqueued for sub-slots, but need to clean up this slot's part structures.
+        destroyPartsBookkeeping(slot->numParts, slot->parts);
+        slot->parts = NULL;
+        slot->numParts = 0;
+    }
+    else if ((slot->numParts != 0) || (slot->parts != NULL))
+    {
+        // Sanity check - slot didn't have a running instance, so there should be no bookkeeping.
+        FATAL("slot (%s) had no running instance, but had numParts(%d) != 0 or parts != NULL", slot->name, slot->numParts);
+    }
+    // If the slot ports were bound at run-time, there will be a map.
+    if (slot->slotToBorderMap != NULL)
+    {
+        delete[] slot->slotToBorderMap;
+        slot->slotToBorderMap = NULL;
+    }
+    // Delete messages bound for the slot and timers bound for the slot.
+    slot->controller->deallocateSlotResources( slot );
+
+    if (!isTopSlot)
+    {
+        // Is a sub-slot in a condemned sub-capsule structure - delete the slot itself.
+        destroyPorts(slot->numPorts, slot->ports);
+        free((void*)slot->name);
+        delete slot;
+    }
+    else
+    {
+        slot->condemned = false; // Top capsule slot no longer 'condemned' - it has no instance, but is not condemned.
+    }
+    // Unlock RTS if we locked it here.
+    if (!lockAcquired)
+    {
+        rtsUnlock();
+    }
+}
+
+// Import a capsule - run from the controller who owns the capsule instance being imported.
+/*static*/ bool UMLRTFrameService::controllerImport ( UMLRTSlot * slot, UMLRTCapsule * capsule, bool synchronous, bool lockAcquired )
+{
+    bool ok = false;
+
+    if (slot == NULL)
+    {
+        FATAL("attempt to import into NULL slot");
+    }
+    if (capsule == NULL)
+    {
+        FATAL("attempt to import NULL capsule into slot %s", slot->name);
+    }
+    BDEBUG(BD_IMPORT, "controller import capsule %s into slot %s.\n", capsule->getName(), slot->name);
+
+    if (slot->capsule)
+    {
+        if (synchronous)
+        {
+            // We're running this code from the initial import request thread - need to set the requestor's controller error code.
+            slot->controller->setError(UMLRTController::E_IMPORT_OCCUPIED);
+        }
+        else
+        {
+            // May occur if this was an IMPORT Controller Command and some previous command caused the slot to be occupied.
+            // SWERR for now. Whether this can actually happen is not known at this time.
+            BDEBUG(BD_SWERR, "slot(%s) import of capsule(%s) slot is occupied by capsule %s", slot->name, capsule->getName(), slot->capsule->getName());
+        }
+    }
+    else
+    {
+        if (!lockAcquired)
+        {
+            rtsLock();
+        }
+        const UMLRTCommsPort * * borderPorts = NULL; // Returned ports are not used - just used as an indication of the binding success.
+
+        if ((borderPorts = bindPorts(slot, capsule, capsule->getSlot()->capsuleClass, slot->role()->capsuleClass, capsule->getBorderPorts(), true/*bind*/, true/*import*/)) == NULL)
+        {
+            // Failed compatibility check.
+            if (synchronous)
+            {
+                // Need to set the requestor's error code.
+                slot->controller->setError(UMLRTController::E_IMPORT_COMPAT);
+            }
+            else
+            {
+                // May occur if this was an IMPORT Controller Command and some previous previous activity made the slot incompatible?
+                // SWERR for now.
+                BDEBUG(BD_SWERR, "Controller bind of ports during import failed into slot %s - capsule's original slot %s.", slot->name, capsule->getName());
+            }
+        }
+        else
+        {
+            // Import succeeded.
+            delete[] borderPorts; // Do not need this copy for import - the capsule's border ports are updated.
+
+            // Update the capsule instance here and it's capsule class. They are restored during deport. This controller owns the slot now.
+            slot->controller = capsule->getSlot()->controller;
+            slot->capsule = capsule;
+            slot->capsuleClass = slot->capsule->getSlot()->capsuleClass;
+            ok = true;
+        }
+        if (!lockAcquired)
+        {
+            rtsUnlock();
+        }
+    }
+    return ok;
+}
+
+// Recurse into sub-structure requesting a destroy of the slot from the associated controller.
+/*static*/ void UMLRTFrameService::controllerIncarnate ( UMLRTCapsule * capsule, size_t sizeSerializedData, void * serializedData )
+{
+    // Can't acquire the RTS lock for this, since the capsule initialize signal can result in signal sends from the capsule.
+    if (capsule == NULL)
+    {
+        FATAL("attempt to initialize NULL capsule");
+    }
+    initializeCapsule(capsule, sizeSerializedData, serializedData);
+}
+
+/*static*/ char * UMLRTFrameService::createName ( const char * prefix, const char * suffix, size_t index, bool appendIndex )
+{
+    char ind[23]; // 18,446,744,073,709,551,615 is largest possible index in a 64-bit architecture.
+    if (appendIndex)
+    {
+        snprintf(ind, sizeof(ind), "[%lu]", index);
+    }
+    char * name = (char*)malloc(strlen(prefix) + strlen(suffix) + strlen(ind) + 2);
+
+    if (!name)
+    {
+        FATAL("could not allocate part name.");
+    }
+    strcpy(name, prefix);
+    strcat(name, ".");
+    strcat(name, suffix);
+    if (appendIndex)
+    {
+        strcat(name, ind);
+    }
+    return name;
+}
+
+/*static*/ UMLRTCapsulePart * UMLRTFrameService::createParts ( const char * containerName, const UMLRTCapsuleClass * containerClass )
+{
+    UMLRTCapsulePart * parts = NULL;
+
+    if (containerClass->numSubcapsuleRoles)
+    {
+        parts = new UMLRTCapsulePart[containerClass->numSubcapsuleRoles];
+
+        for (size_t i = 0; i < containerClass->numSubcapsuleRoles; ++i)
+        {
+            const UMLRTCapsuleRole * role = &containerClass->subcapsuleRoles[i];
+            parts[i].containerClass = containerClass;
+            parts[i].numSlot = role->multiplicityUpper;
+            parts[i].slots = new UMLRTSlot * [role->multiplicityUpper];
+            parts[i].roleIndex = i;
+
+            for (size_t j = 0; j < role->multiplicityUpper; ++j)
+            {
+                // define the slot for this part
+                char * name = createName(containerName, role->name, j, (role->multiplicityUpper > 1)/*appendIndex*/);
+
+                const UMLRTCapsulePart * subcapsuleParts = createParts( name, role->capsuleClass );
+                UMLRTSlot templateSlot = {
+                        name,
+                        j, // capsuleIndex
+                        role->capsuleClass,
+                        containerClass,
+                        i,
+                        NULL, // capsule,
+                        NULL, // controller
+                        role->capsuleClass->numSubcapsuleRoles, // numParts
+                        subcapsuleParts,
+                        role->capsuleClass->numPortRolesBorder,
+                        NULL, // ports
+                        NULL, // slotToBorderMap
+                        0, // generated
+                        0, // condemned
+                };
+                parts[i].slots[j] = new UMLRTSlot(templateSlot);
+                parts[i].slots[j]->ports = createPorts( parts[i].slots[j], role->capsuleClass, role->capsuleClass->numPortRolesBorder, role->capsuleClass->portRolesBorder, true/*border*/);
+            }
+        }
+    }
+    return parts;
+}
+
+/*static*/ const UMLRTCommsPort * UMLRTFrameService::createPorts ( UMLRTSlot * slot, const UMLRTCapsuleClass * capsuleClass, size_t numPortRoles, const UMLRTCommsPortRole portRoles[],
+        bool border, bool importProxy, int roleIndexOffset, bool isUnbound )
+{
+    UMLRTCommsPort * ports = new UMLRTCommsPort[numPortRoles];
+
+    for (size_t i = 0; i < numPortRoles; ++i)
+    {
+        ports[i].containerClass = capsuleClass;
+        ports[i].roleIndex = i + roleIndexOffset;
+        ports[i].slot = slot;
+        ports[i].numFarEnd = isUnbound ? 0 : portRoles[i].numFarEnd;
+
+        ports[i].automatic = portRoles[i].automatic;
+        ports[i].border = border;
+        ports[i].generated = false;
+        ports[i].locked = portRoles[i].locked;
+        ports[i].notification = portRoles[i].notification;
+        ports[i].proxy = importProxy;
+        ports[i].relay = false; // Set true during port binding, if appropriate.
+        ports[i].sap = portRoles[i].sap;
+        ports[i].spp = portRoles[i].spp;
+        ports[i].unbound = isUnbound;
+        ports[i].wired = portRoles[i].wired;
+
+        if (portRoles[i].registeredName != NULL)
+        {
+            ports[i].registeredName = strdup(portRoles[i].registeredName);
+        }
+        else
+        {
+            ports[i].registeredName = NULL;
+        }
+        ports[i].generated = false;
+        if (ports[i].numFarEnd == 0)
+        {
+            ports[i].farEnds = NULL;
+            ports[i].deferQueue = NULL;
+        }
+        else
+        {
+            ports[i].farEnds = new UMLRTCommsPortFarEnd[portRoles[i].numFarEnd];
+            ports[i].deferQueue = new UMLRTMessageQueue();
+        }
+        // Leave all ports disconnected for now. We connect them after the structure is built.
+        for (size_t j = 0; j < ports[i].numFarEnd; ++j)
+        {
+            ports[i].farEnds[j].farEndIndex = 0;
+            ports[i].farEnds[j].port = NULL;
+        }
+    }
+    return ports;
+}
+
+/*static*/ const UMLRTCommsPort * * UMLRTFrameService::createBorderPorts ( UMLRTSlot * slot, size_t numPorts )
+{
+    const UMLRTCommsPort * * borderPorts = new const UMLRTCommsPort * [numPorts];
+
+    for (size_t i = 0; i < numPorts; ++i)
+    {
+        borderPorts[i] = &slot->ports[i];
+    }
+    return borderPorts;
+}
+
+/*static*/ void UMLRTFrameService::defineSlotControllers ( UMLRTSlot * slot, const UMLRTCapsulePart * part, const UMLRTCapsuleClass * capsuleClass,
+        const char * logThread, UMLRTController * assignedController, UMLRTController *defaultController, int index )
+{
+    // Use the logical thread name, controller instance, or the default controller to determine the assigned controller.
+    slot->controller = getCapsuleController(slot, part, logThread, assignedController, defaultController, index);
+
+    if (slot->controller == NULL)
+    {
+        FATAL("slot %s controller NULL", slot->name);
+    }
+    // Recurse into sub-structure
+    for (size_t i = 0; i < slot->numParts; ++i)
+    {
+        for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+        {
+            defineSlotControllers(slot->parts->slots[j],
+                    &slot->parts[i],
+                    slot->parts->slots[j]->capsuleClass,
+                    logThread,
+                    assignedController,
+                    slot->controller,
+                    j);
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::deportParts ( UMLRTSlot * slot )
+{
+    // Assumes global RTS lock already acquired.
+
+    requestControllerDeport(slot, true/*lockAcquired*/);
+
+    for (size_t i = 0; i < slot->numParts; ++i)
+    {
+        for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+        {
+            // set 'condemned' on sub-structure.
+            deportParts(slot->parts[i].slots[j]);
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::destroyPartsBookkeeping ( size_t numParts, const UMLRTCapsulePart * parts )
+{
+    // Assumes global RTS lock already acquired.
+
+    // Deletes the array of slot pointers, but the not the slots themselves.
+    for (size_t i = 0; i < numParts; ++i)
+    {
+        delete[] parts[i].slots;
+    }
+    delete[] parts;
+}
+
+/*static*/ void UMLRTFrameService::destroyPorts ( const size_t numPorts, const UMLRTCommsPort * ports )
+{
+    // Assumes global RTS lock already acquired.
+
+    if (ports != NULL)
+    {
+        for (size_t i = 0; i < numPorts; ++i)
+        {
+            if (ports[i].spp)
+            {
+                UMLRTProtocol::deregisterSppPort(&ports[i]);
+            }
+            else if (ports[i].sap)
+            {
+                UMLRTProtocol::deregisterSapPort(&ports[i]);
+            }
+            if (ports[i].generated)
+            {
+                FATAL("trying to destroy a static slot %s port %s", ports[i].slot, ports[i].role()->name);
+            }
+            if (ports[i].numFarEnd > 0)
+            {
+                delete[] ports[i].farEnds;
+            }
+            if (ports[i].deferQueue)
+            {
+                ports[i].purge();
+                delete ports[i].deferQueue;
+            }
+            if (ports[i].registeredName != NULL)
+            {
+                free(ports[i].registeredName);
+            }
+        }
+        delete[] ports;
+    }
+}
+
+/*static*/ void UMLRTFrameService::destroyPortList ( size_t numPorts, const UMLRTCommsPort * * ports )
+{
+    // Assumes global RTS lock already acquired.
+
+    if (ports != NULL)
+    {
+        for (size_t i = 0; i < numPorts; ++i)
+        {
+            if (ports[i])
+            {
+                if (ports[i]->proxy)
+                {
+                    destroyPorts(1, ports[i]);
+                }
+            }
+        }
+        delete[] ports;
+    }
+}
+
+/*static*/ void UMLRTFrameService::disconnectPort ( const UMLRTCommsPort * port, int index )
+{
+    // Assumes global RTS lock already acquired.
+
+    if (port)
+    {
+        if (!port->unbound)
+        {
+            if (port->farEnds[index].port != NULL)
+            {
+                port->farEnds[index].port = NULL;
+                port->farEnds[index].farEndIndex = 0;
+            }
+        }
+    }
+}
+
+// Count the number of free far-ends on a port.
+/*static*/ size_t UMLRTFrameService::freeFarEndsCount ( const UMLRTCommsPort * port )
+{
+    size_t count = 0;
+
+    if (port != NULL)
+    {
+        for (size_t i = 0; i < port->numFarEnd; ++i)
+        {
+            if (port->farEnds[i].port == NULL)
+            {
+                ++count;
+            }
+        }
+    }
+    return count;
+}
+
+
+/*static*/ int UMLRTFrameService::findFarEndInstance ( const UMLRTCommsPort * farEnd, size_t farEndIndex, const UMLRTCommsPort * port )
+{
+    // Assumes global RTS lock already acquired.
+
+    int instance_i = -1;
+
+    if (farEnd)
+    {
+        if (!port->unbound)
+        {
+            for (size_t i = 0; (i < port->role()->numFarEnd) && (instance_i == -1); ++i)
+            {
+                if ((farEnd == port->farEnds[i].port) && (farEndIndex == port->farEnds[i].farEndIndex))
+                {
+                    instance_i = i;
+                }
+            }
+        }
+    }
+    return instance_i;
+}
+
+// Assumes AT MOST one of 'logThread' or 'assignedController' is non-NULL. (Both may be NULL.)
+/*static*/ UMLRTController * UMLRTFrameService::getCapsuleController ( const UMLRTSlot * slot, const UMLRTCapsulePart * part, const char * logThread,
+                                UMLRTController * assignedController, UMLRTController * defaultController, int slotIndex )
+{
+    UMLRTController * capsuleController = NULL;
+
+    if ((logThread != NULL) && (assignedController != NULL))
+    {
+        FATAL("Only one of logThread and controller may be non-NULL when assigning a controller to capsule %s.",
+                part->slots[slotIndex]->name);
+    }
+    else if (defaultController == NULL)
+    {
+        FATAL("Default controller NULL assigning a controller to capsule %s.",
+                part->slots[slotIndex]->name);
+    }
+    else if ((capsuleController = UMLRTCapsuleToControllerMap::getControllerForCapsule(part->slots[slotIndex]->name, slot->capsuleClass)) == NULL)
+    {
+        if ((logThread == NULL) && (assignedController == NULL))
+        {
+            capsuleController = defaultController; // Default to current controller.
+        }
+        else if (logThread != NULL)
+        {
+            if ((capsuleController = UMLRTCapsuleToControllerMap::getControllerFromName(logThread)) == NULL)
+            {
+                capsuleController = defaultController; // Default to current controller.
+            }
+        }
+        else if ((capsuleController = assignedController) == NULL)
+        {
+            capsuleController = defaultController;  // Default to current controller.
+        }
+    }
+    BDEBUG(BD_CONTROLLER, "getCapsuleController capsule %s (index %d) input controller(%s) logThread(%s) assigned to %s\n",
+                    part->slots[slotIndex]->name,
+                    slotIndex,
+                    assignedController == NULL ? "NULL" : assignedController->getName(),
+                    logThread == NULL ? "NULL" : logThread, capsuleController->getName());
+
+    return capsuleController;
+}
+
+// Get the next free capsule slot - return -1 if there's none.
+/*static*/ int UMLRTFrameService::getNextFreeCapsuleSlot ( const UMLRTCapsulePart * part )
+{
+    int nextFree = -1;
+
+    // Look for a slot with no controller assigned.
+
+    for (size_t i = 0; (i < part->numSlot) && (nextFree == -1); ++i)
+    {
+        if (part->slots[i]->capsule == NULL)
+        {
+            nextFree = i;
+        }
+    }
+    return nextFree;
+}
+
+/*static*/ const UMLRTRtsInterface * UMLRTFrameService::getRtsInterface ( )
+{
+    return &rtsifUmlrt;
+}
+
+
+/*static*/ bool UMLRTFrameService::importCapsule ( const UMLRTCommsPort * srcPort, UMLRTCapsule * capsule, const UMLRTCapsulePart * destPart, int index )
+{
+    bool ok = false;
+
+    //const UMLRTSlot * srcSlot = capsule->getSlot();
+
+    if (!destPart->role()->plugin)
+    {
+        // Returned 'ok' will be false.
+        srcPort->slot->controller->setError(UMLRTController::E_IMPORT_NONPLUG);
+    }
+    // Validate the index if it was explicitly set.
+    else if ((index < -1) || (index >= (int)destPart->numSlot))
+    {
+        // Returned 'ok' will be false.
+        srcPort->slot->controller->setError(UMLRTController::E_IMPORT_INV_IDX);
+    }
+    else
+    {
+        if (index < 0)
+        {
+            index = getNextFreeCapsuleSlot(destPart);
+        }
+        if (index < 0)
+        {
+            // Returned 'ok' will be false.
+            srcPort->slot->controller->setError(UMLRTController::E_IMPORT_NO_FREE_SLOT);
+        }
+        else if (index >= (int)destPart->numSlot)
+        {
+            FATAL("internal error obtaining next free capsule index(%d) max(%d)", index, destPart->numSlot);
+        }
+        else
+        {
+            // Obtain RTS lock.
+            rtsLock();
+
+            UMLRTSlot * destSlot = destPart->slots[index];
+
+            const UMLRTCommsPort * * borderPorts = NULL; // Not used to modify capsule instance - only used to check binding.
+
+            bool compatible = true; // Assume we're compatible unless we've proven otherwise.
+
+            if (destSlot->capsule != NULL)
+            {
+                srcPort->slot->controller->setError(UMLRTController::E_IMPORT_OCCUPIED);
+                compatible = false;
+            }
+            else if (!capsule->getSlot()->controller->isMyThread())
+            {
+                // We are not running in the context of the controller that owns the capsule, all we'll do is check compatibility.
+                // We check the binding, but don't actually bind - that's done in the context of the slot's controller.
+
+                if ((borderPorts = bindPorts(destSlot, capsule, capsule->getSlot()->capsuleClass, destPart->role()->capsuleClass, capsule->getBorderPorts(), false/*bind*/, true/*import*/)) == NULL)
+                {
+                    // Requested capsule type does not have port-compatibility.
+                    srcPort->slot->controller->setError(UMLRTController::E_IMPORT_COMPAT);
+                    compatible = false;
+                }
+            }
+            if (compatible)
+            {
+                // Either we're running in the context of the controller that owns the capsule (and port binding has not been verified,
+                // and the error code will be set by the following if it fails), or we're running in another thread, in which case the binding
+                // has been checked and is ok.
+                ok = requestControllerImport(destSlot, capsule, true/*lockAcquired*/);
+            }
+
+            // Unlock RTS
+            rtsUnlock();
+
+            // We don't need this copy of the border ports - it was used to check port binding success only.
+            if (borderPorts != NULL)
+            {
+                delete[] borderPorts;
+            }
+        }
+    }
+    return ok;
+}
+
+/*static*/ const UMLRTCapsuleId UMLRTFrameService::incarnateCapsule ( const UMLRTCommsPort * srcPort, const UMLRTCapsulePart * part, const UMLRTCapsuleClass * capsuleClass,
+                                            const void * userData, const UMLRTObject_class * type, const char * logThread, UMLRTController * assignedController, int index )
+{
+    UMLRTCapsuleId id(NULL);
+
+    // Default to part's capsuleClass.
+    if (capsuleClass == NULL)
+    {
+        capsuleClass = part->role()->capsuleClass;
+    }
+    // Verify type supplied if data supplied.
+    if ((userData) && (!type))
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_INC_DATATYPE);
+    }
+    // Validate the index if it was explicitly set.
+    else if ((index < -1) || (index >= (int)part->numSlot))
+    {
+        // Returned id will be the 'invalid capsule id'.
+        srcPort->slot->controller->setError(UMLRTController::E_INC_INV_IDX);
+    }
+    else if (!part->role()->optional)
+    {
+        // Attempting to incarnate into a non-optional slot.
+        srcPort->slot->controller->setError(UMLRTController::E_INC_NOT_OPT);
+    }
+    else
+    {
+        if (index < 0)
+        {
+            index = getNextFreeCapsuleSlot(part);
+        }
+        if (index < 0)
+        {
+            // Returned id will be the 'invalid capsule id'.
+            srcPort->slot->controller->setError(UMLRTController::E_INC_NO_FREE_SLOT);
+        }
+        else if (index >= (int)part->numSlot)
+        {
+            FATAL("internal error obtaining next free capsule index(%d) max(%d)", index, part->numSlot);
+        }
+        else
+        {
+            // Obtain global RTS lock
+            rtsLock();
+
+            UMLRTSlot * slot = part->slots[index];
+
+            const UMLRTCommsPort * * borderPorts = NULL; // Defines the border port mapping.
+
+            bool compatible = false;
+
+            if (slot == NULL)
+            {
+                FATAL("slot %s has NULL part slot[%d]", srcPort->slot->name, index);
+            }
+            if (slot->capsule != NULL)
+            {
+                srcPort->slot->controller->setError(UMLRTController::E_INC_SLOT_OCC);
+            }
+            else if (slot->parts != NULL)
+            {
+                srcPort->slot->controller->setError(UMLRTController::E_INC_PARTS_ERROR);
+            }
+            else if (slot->capsuleClass == capsuleClass)
+            {
+                compatible = true; // The border ports are the slot ports.
+                borderPorts = createBorderPorts(slot, capsuleClass->numPortRolesBorder);
+            }
+            else if ((borderPorts  = bindPorts(slot, NULL, capsuleClass, part->role()->capsuleClass, NULL /*borderPorts*/, true/*bind*/, false/*import*/)) != NULL)
+            {
+                // Bound OK - and the capsule's borderPorts are defined.
+                compatible = true;
+            }
+            else
+            {
+                srcPort->slot->controller->setError(UMLRTController::E_INC_COMPAT);
+            }
+            if (!compatible)
+            {
+                // Error already set - occupied, parts error, requested capsule type does not have port-compatibility.
+                if (borderPorts)
+                {
+                    delete[] borderPorts;
+                }
+            }
+            else
+            {
+               // Over-write with occupier's type.
+                slot->capsuleClass = capsuleClass;
+
+                // Recurse into sub-structure creating parts.
+                slot->parts = createParts(slot->name, capsuleClass);
+                slot->numParts = capsuleClass->numSubcapsuleRoles;
+
+                // Recurse into sub-structure assigning the controllers to the capsule and parts.
+                defineSlotControllers(slot, part, capsuleClass, logThread, assignedController, srcPort->slot->controller, index);
+
+                BDEBUG(BD_INSTANTIATE, "instantiate capsule class %s into slot %s\n", slot->capsuleClass->name, slot->name);
+
+                slot->capsuleClass->instantiate(&rtsifUmlrt, slot, borderPorts);
+
+                if (slot->capsule)
+                {
+                    // Recurse into sub-structure requesting the associated controllers to send the capsule initialize messages.
+                    requestControllerIncarnate(slot, userData, type);
+                }
+                // Send rtBound to slot far-ends that are not relay ports.
+                incarnateSendBoundSlotFarEnd(slot);
+                id = UMLRTCapsuleId(slot->capsule);
+            }
+            rtsUnlock();
+        }
+    }
+    return id;
+}
+
+/*static*/ void UMLRTFrameService::incarnateSendBoundSlotFarEnd ( UMLRTSlot * slot )
+{
+    // Assumes global RTS lock already acquired.
+    const UMLRTCommsPort * * borderPorts = slot->capsule->getBorderPorts();
+
+    // Examine the capsule's class slotToBorderMap to see if any of the capsules border ports were mapped to this slot.
+    for (size_t slot_i = 0; (borderPorts != NULL) && (slot_i < slot->capsule->getSlot()->role()->capsuleClass->numPortRolesBorder); ++slot_i)
+    {
+        int border_i = slot->slotToBorderMap[slot_i];
+
+        if (border_i != -1)
+        {
+            // This capsule border port slot had bindings on this slot port - notify those far-ends of the rtBound.
+            if (borderPorts[border_i] == &slot->ports[slot_i])
+            {
+                // Capsule has a border port mapped directly to the slot port.
+                for (size_t j = 0; !borderPorts[border_i]->relay && (j < slot->ports[slot_i].numFarEnd); ++j)
+                {
+                    // If port is non-relay, notify the far-end of rtBound.
+                    if ((slot->ports[slot_i].farEnds[j].port != NULL) && !slot->ports[slot_i].relay)
+                    {
+                        // Send rtBound to far-end.
+                        sendBoundUnbound( slot->ports[slot_i].farEnds[j].port, slot->ports[slot_i].farEnds[j].farEndIndex,
+                                &slot->ports[slot_i], slot_i, true/*isBind*/);
+                    }
+                }
+            }
+            // slotToBorderMap[border_i] should be -1 for unbound ports.
+            else if (borderPorts[border_i]->unbound)
+            {
+                FATAL("Sending rtBound to slot far end. slot %s and mapped slot port[%d] != border port[%d] and port was unbound ?",
+                        slot->name, slot_i, border_i );
+            }
+            else
+            {
+                for (size_t j = 0; !borderPorts[border_i]->relay && (j < slot->ports[slot_i].numFarEnd); ++j)
+                {
+                    // Non relay port.
+                    if (slot->ports[slot_i].farEnds[j].port != NULL)
+                    {
+                        int instance_i;
+                        // This slot port instance has a far-end.
+                        if ((instance_i = findFarEndInstance(slot->ports[slot_i].farEnds[j].port, slot->ports[slot_i].farEnds[j].farEndIndex, borderPorts[border_i])) < 0)
+                        {
+                            FATAL("slot %s port %s bound to far end %s not found on border proxy port id(%d)",
+                                    slot->name, slot->ports[slot_i].role()->name, slot->ports[slot_i].farEnds[j].port->slot->name, border_i);
+                        }
+                        else
+                        {
+                            // Send rtUnbound to slot port far-end - the local port (as seen from the far-end) remains the slot port instance.
+                            sendBoundUnbound( slot->ports[slot_i].farEnds[j].port, slot->ports[slot_i].farEnds[j].farEndIndex, &slot->ports[slot_i], slot_i, true/*isBind*/);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::initializeCapsule ( UMLRTCapsule * capsule, size_t sizeSerializedData, void * serializedData )
+{
+    // Assumes rts lock not acquired. capsule->initialize() may send messages.
+
+    BDEBUG(BD_INSTANTIATE, "initialize capsule %s\n", capsule->getName());
+
+    UMLRTMessage initializeMsg;
+
+    initializeMsg.signal.initialize(sizeSerializedData);
+
+    // Put the data in the signal.
+    memcpy(initializeMsg.signal.getPayload(), serializedData, sizeSerializedData);
+
+    // Deallocate serialized data - it was allocated immediately prior to the call to this method and is deallcoated here.
+    if (serializedData != NULL)
+    {
+        free(serializedData);
+    }
+    // Register automatic SAPs and SPPs.
+    initializePorts(capsule);
+
+    // Send rtBound/rtUnbound for capsule ports - far-ends not handled here.
+    sendBoundUnboundForCapsule(capsule, true/*isBind*/);
+
+    // Initialize the capsule, sending the initial message.
+    capsule->initialize(initializeMsg);
+}
+
+/*static*/ void UMLRTFrameService::initializePorts ( UMLRTCapsule * capsule )
+{
+    // Assume RTS lock not acquired, but acquires it for this.
+    rtsLock();
+
+    const UMLRTCommsPort * * borderPorts = capsule->getBorderPorts();
+    if (borderPorts != NULL)
+    {
+        for (size_t i = 0; i < capsule->getClass()->numPortRolesBorder; ++i)
+        {
+            if (borderPorts[i])
+            {
+                // Create defer queue for appropriate ports.
+                if ((borderPorts[i]->deferQueue == NULL) && !borderPorts[i]->unbound && (borderPorts[i]->wired || borderPorts[i]->sap || borderPorts[i]->spp))
+                {
+                    borderPorts[i]->deferQueue = new UMLRTMessageQueue();
+                }
+                // Handle automatic service port registration.
+                if (borderPorts[i]->sap && (borderPorts[i]->registeredName != NULL) && (borderPorts[i]->automatic))
+                {
+                    UMLRTProtocol::registerSapPort(borderPorts[i], borderPorts[i]->registeredName);
+                }
+                else if (borderPorts[i]->spp && (borderPorts[i]->registeredName != NULL) && (borderPorts[i]->automatic))
+                {
+                    UMLRTProtocol::registerSppPort(borderPorts[i], borderPorts[i]->registeredName);
+                }
+            }
+        }
+    }
+    const UMLRTCommsPort * internalPorts = capsule->getInternalPorts();
+    if (internalPorts != NULL)
+    {
+        for (size_t i = 0; i < capsule->getClass()->numPortRolesInternal; ++i)
+        {
+            // Create defer queue for appropriate ports.
+            if ((internalPorts[i].deferQueue == NULL) && !internalPorts[i].unbound && (internalPorts[i].wired || internalPorts[i].sap || internalPorts[i].spp))
+            {
+                internalPorts[i].deferQueue = new UMLRTMessageQueue();
+            }
+            if (internalPorts[i].sap && (internalPorts[i].registeredName != NULL) && (internalPorts[i].automatic))
+            {
+                UMLRTProtocol::registerSapPort(&internalPorts[i], internalPorts[i].registeredName);
+            }
+            else if (internalPorts[i].spp && (internalPorts[i].registeredName != NULL) && (internalPorts[i].automatic))
+            {
+                UMLRTProtocol::registerSppPort(&internalPorts[i], internalPorts[i].registeredName);
+            }
+        }
+    }
+    rtsUnlock();
+}
+
+/*static*/ void UMLRTFrameService::instantiate ( UMLRTSlot * slot, const UMLRTCapsuleClass * capsuleClass )
+{
+    // Utility method for generated code to instantiate a static sub-capsule whose border ports are the slot ports.
+
+    // Assumes RTS lock acquired.
+    capsuleClass->instantiate(&rtsifUmlrt, slot, createBorderPorts(slot, capsuleClass->numPortRolesBorder));
+}
+
+/*static*/ const UMLRTCommsPort * UMLRTFrameService::isBound ( const UMLRTCommsPort * port, int index, int * farEndIndexP )
+{
+    // Assumes local slot is occupied by a capsule instance.
+
+    const UMLRTCommsPort * farEndPort;
+
+    if (!port->unbound && ((farEndPort = port->farEnds[index].port) != NULL))
+    {
+        *farEndIndexP = port->farEnds[index].farEndIndex;
+
+        if (!farEndPort->slot->capsule)
+        {
+            // Far-end slot is not occupied.
+            farEndPort = NULL;
+            *farEndIndexP = 0;
+        }
+    }
+    return farEndPort;
+}
+
+// Request a deport.
+/*static*/ void UMLRTFrameService::requestControllerDeport ( UMLRTSlot * slot, bool lockAcquired )
+{
+    if (slot->role()->plugin && (slot->capsule != NULL))
+    {
+        if (slot->controller->isMyThread())
+        {
+            // We can perform the deport now because we're running in the context of the capsule's controller.
+            controllerDeport(slot, true/*synchronous*/, lockAcquired);
+        }
+        else
+        {
+            // We send a DEPORT Controller Command to have the capsule's controller execute the deport.
+            slot->controller->enqueueDeport(slot);
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::requestControllerDestroy ( UMLRTSlot * slot, bool isTopSlot, bool lockAcquired )
+{
+    if (slot->controller->isMyThread())
+    {
+        // We can perform the destroy now because we're running in the context of the destroyed capsule's controller.
+        controllerDestroy(slot, isTopSlot, true/*synchronous*/, lockAcquired);
+    }
+    else
+    {
+        // We send a DESTROY Controller Command to have the capsule's controller execute the destroy.
+        slot->controller->enqueueDestroy(slot, isTopSlot);
+    }
+    if (!isTopSlot)
+    {
+        // This is NOT the top-capsule in the destruction.
+        // Go ahead and recurse into sub-structure performing destroy requests (i.e capsules along with the slots themselves).
+        for (size_t i = 0; i < slot->numParts; ++i)
+        {
+             for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+             {
+                 requestControllerDestroy(slot->parts[i].slots[j], false/*isTopSlot*/, lockAcquired);
+             }
+        }
+    }
+}
+
+/*static*/ bool UMLRTFrameService::requestControllerImport ( UMLRTSlot * slot, UMLRTCapsule * capsule, bool lockAcquired )
+{
+    bool ok = true;
+
+    if (capsule->getSlot()->controller->isMyThread())
+    {
+        // The controller who owns the capsule being imported is running - the import can be performed directly now.
+        // The capsule instance being imported into the slot must run on the same controller it was originally incarnated on.
+
+        ok = controllerImport(slot, capsule, true/*synchronous*/, lockAcquired);
+    }
+    else
+    {
+        // The capsule's controller is not running - must send an IMPORT Controller Command. We've checked port binding once.
+        // We can reassign the slot to the capsule's controller and request an import to the controller.
+        slot->controller = capsule->getSlot()->controller;
+
+        slot->controller->enqueueImport(slot, capsule);
+    }
+    return ok;
+}
+
+/*static*/ void UMLRTFrameService::requestControllerIncarnate ( UMLRTSlot * slot, const void * userData, const UMLRTObject_class * type )
+{
+    // We've got the RTS lock - we must queue the initialize signals - even if the running controller is the capsule's controller.
+    if (slot->capsule != NULL)
+    {
+        // Must queue an INCARNATE Controller Command to send the initialize message.
+        slot->controller->enqueueIncarnate(slot->capsule, userData, type );
+    }
+    // Recurse into sub-structure, incarnating sub-slots where appropriate.
+    for (size_t i = 0; i < slot->numParts; ++i)
+    {
+        for (size_t j = 0; j < slot->parts[i].numSlot; ++j)
+        {
+            requestControllerIncarnate(slot->parts->slots[j], NULL, NULL);
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::rtsLock ( )
+{
+    BDEBUG(BD_LOCK,"rtsLock attempt\n");
+
+    // Outputting the instance model may take a long time - wait a minute and then die.
+    if (!rtsGlobalLock.take(60000))
+    {
+        FATAL("Failed to acquire global RTS lock after waiting a full minute.");
+    }
+    BDEBUG(BD_LOCK,"rtsLock acquired\n");
+}
+
+/*static*/ void UMLRTFrameService::rtsUnlock ( )
+{
+    BDEBUG(BD_LOCK,"rtsUnlock\n");
+
+    rtsGlobalLock.give();
+}
+
+/*static*/ void UMLRTFrameService::sendBoundUnbound( const UMLRTCommsPort * port, int index, const UMLRTCommsPort * farEndPort, int farEndIndex, bool isBind )
+{
+    if ((!port->unbound) && (!port->relay) && (port->slot->capsule != NULL) && (port->notification) && (!port->slot->condemned))
+    {
+        UMLRTSignal signal;
+        signal.initialize( isBind ? UMLRTSignal::rtBound : UMLRTSignal::rtUnbound, farEndPort);
+        port->slot->controller->deliver(port, signal, farEndIndex);
+
+        BDEBUG(BD_BIND,"send %s to slot %s port %s[%d] from slot %s port %s[%d]\n",
+                isBind ? "rtBound" : "rtUnbound", port->slot->name, port->role()->name, index,
+                farEndPort->slot->name, farEndPort->role()->name, farEndIndex );
+    }
+}
+
+/*static*/ void UMLRTFrameService::sendBoundUnboundForCapsule ( UMLRTCapsule * capsule, bool isBind )
+{
+    const UMLRTCommsPort * * borderPorts = capsule->getBorderPorts();
+
+    // Only do wired ports. Service port notifications are handled during registration/de-registration.
+
+    for (size_t port_i = 0; (borderPorts != NULL) && (port_i < capsule->getClass()->numPortRolesBorder); ++port_i)
+    {
+        for (size_t index = 0; (index < borderPorts[port_i]->numFarEnd) && !borderPorts[port_i]->relay && borderPorts[port_i]->wired; ++index)
+        {
+            const UMLRTCommsPort * farEndPort;
+            int farEndIndex;
+            if ((farEndPort = isBound(borderPorts[port_i], index, &farEndIndex)) != NULL)
+            {
+                if (isBind)
+                {
+                    // rtBound - is going to local port.
+                    sendBoundUnbound(borderPorts[port_i], index, farEndPort, farEndIndex, isBind);
+                }
+                else
+                {
+                    // rtUnbound - is going to far-end port.
+                    sendBoundUnbound(farEndPort, farEndIndex, borderPorts[port_i], index, isBind);
+                }
+            }
+        }
+    }
+    const UMLRTCommsPort * internalPorts = capsule->getInternalPorts();
+    for (size_t port_i = 0; (internalPorts != NULL) && (port_i < capsule->getClass()->numPortRolesInternal); ++port_i)
+    {
+        for (size_t index = 0; (index < internalPorts[port_i].numFarEnd) && !internalPorts[port_i].relay && internalPorts[port_i].wired; ++index)
+        {
+            const UMLRTCommsPort * farEndPort;
+            int farEndIndex;
+            if ((farEndPort = isBound(&internalPorts[port_i], index, &farEndIndex)) != NULL)
+            {
+                if (isBind)
+                {
+                    // rtBound - is going to local port.
+                    sendBoundUnbound(&internalPorts[port_i], index, farEndPort, farEndIndex, isBind);
+                }
+                else
+                {
+                    // rtUnbound - is going to far-end port.
+                    sendBoundUnbound(farEndPort, farEndIndex, &internalPorts[port_i], index, isBind);
+                }
+            }
+        }
+    }
+}
+
+/*static*/ void UMLRTFrameService::unbindSubcapsulePort ( bool isBorder, UMLRTCapsule * subcapsule, int portIndex, int farEndIndex )
+{
+    if (subcapsule != NULL)
+    {
+        BDEBUG(BD_CONNECT, "unbind subcapsule %s portIndex %d fei %d\n", subcapsule->getName(), portIndex, farEndIndex);
+
+        subcapsule->unbindPort(isBorder, portIndex, farEndIndex);
+    }
+}
+
+/*static*/ bool UMLRTFrameService::unbindServicePort ( const UMLRTCommsPort * sapPort, const UMLRTCommsPort * sppPort )
+{
+    bool ok = false;
+
+    if (sapPort && sppPort)
+    {
+        if (sapPort->numFarEnd == 1)
+        {
+            if (sapPort->farEnds[0].port != NULL)
+            {
+                for (size_t i = 0; (i < sppPort->numFarEnd) && !ok; ++i)
+                {
+                    if (sppPort->farEnds[i].port == sapPort)
+                    {
+                        sendBoundUnbound(sapPort, 0, sppPort, i, false/*isBind*/);
+                        sendBoundUnbound(sppPort, i, sapPort, 0, false/*isBind*/);
+                        disconnectPort(sapPort, 0);
+                        disconnectPort(sppPort, i);
+                        ok = true;
+                    }
+                }
+            }
+        }
+    }
+    return ok;
+}
+
diff --git a/rts/umlrt/umlrthashmap.cc b/rts/umlrt/umlrthashmap.cc
new file mode 100644
index 0000000..e0189ea
--- /dev/null
+++ b/rts/umlrt/umlrthashmap.cc
@@ -0,0 +1,290 @@
+// umlrthashmap.hh
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrthashmap.hh"
+#include "umlrtguard.hh"
+#include "basefatal.hh"
+#include <stdlib.h>
+#include <string.h>
+
+UMLRTHashMap::~UMLRTHashMap()
+{
+    mutex.take();
+
+    for (int i = 0; i < mapSize; ++i)
+    {
+        if (map[i].object != NULL)
+        {
+            free( (void *)map[i].object );
+        }
+    }
+    if (mapSize)
+    {
+        free( map );
+    }
+}
+
+/*static*/ int UMLRTHashMap::compareString( const void * k1, const void * k2 )
+{
+    if ((k1 == NULL) && (k2 != NULL))
+    {
+        return -1;
+    }
+    else if ((k1 != NULL) && (k2 == NULL))
+    {
+        return 1;
+    }
+    else if ((k1 == NULL) && (k2 == NULL))
+    {
+        return 0;
+    }
+    return strcmp((const char *)k1, (const char *)k2);
+}
+
+/*static*/ int UMLRTHashMap::compareValue( const void * k1, const void * k2 )
+{
+    return (char *)k1 - (char *)k2;
+}
+
+UMLRTHashMap::MapEntry * UMLRTHashMap::getEntry( const void * key ) const
+{
+    // Assumes mutex is taken.
+    MapEntry * entry = NULL;
+
+    int location = locate(key);
+
+    if ((location >= 0) && (location < mapSize))
+    {
+        if (compare(map[location].key, key) == 0)
+        {
+            entry = &map[location];
+        }
+    }
+    return entry;
+}
+
+void * UMLRTHashMap::getFirstObject() const
+{
+    // Return object associated with key. Return NULL if entry not found.
+    UMLRTGuard g(mutex);
+
+    void * object = NULL;
+    if (mapSize > 0)
+    {
+        object = map[0].object;
+    }
+    return object;
+}
+
+void * UMLRTHashMap::getObject( const void * key ) const
+{
+    // Return object associated with key. Return NULL if entry not found.
+    UMLRTGuard g(mutex);
+
+    void * object = NULL;
+    MapEntry * entry = getEntry(key);
+
+    if (entry != NULL)
+    {
+        object = entry->object;
+    }
+    return object;
+}
+
+const void * UMLRTHashMap::getKey( int location ) const
+{
+    // Return key associated with entry at location.
+    UMLRTGuard g(mutex);
+
+    const void * key = NULL;
+
+    if ((location >= 0) && (location < mapSize))
+    {
+        key = map[location].key;
+    }
+    return key;
+}
+
+void * UMLRTHashMap::getObject( int location ) const
+{
+    // Return key associated with entry at location.
+    UMLRTGuard g(mutex);
+
+    void * object = NULL;
+
+    if ((location >= 0) && (location < mapSize))
+    {
+        object = map[location].object;
+    }
+    return object;
+}
+
+void UMLRTHashMap::insert( const void * key, void * object )
+{
+    UMLRTGuard g(mutex);
+
+    MapEntry * entry = getEntry(key);
+    if (entry)
+    {
+        entry->object = object;
+    }
+    else
+    {
+        // Entry not find. Insert it.
+         int location = locate(key);
+
+         if (mapSize == 0)
+         {
+             map = (MapEntry *)malloc(sizeof(MapEntry));
+         }
+         else
+         {
+             map = (MapEntry *)realloc(map, (mapSize + 1) * sizeof(MapEntry));
+             memmove(&map[location + 1], &map[location], (mapSize - location) * sizeof(MapEntry));
+         }
+         ++mapSize;
+         map[location].key = key;
+         map[location].object = object;
+    }
+}
+
+int UMLRTHashMap::locate( const void * key ) const
+{
+    // Assumes mutex is taken.
+    // Returns either location of entry holding 'key' or the location where 'key' belongs (first entry where entry->key > input key).
+    int min, max, mid;
+    int location = -1;
+
+    min = 0;
+    max = mapSize - 1;
+
+    while (location == -1)
+    {
+        if (min > max)
+        {
+            // Zeroed in on location. It's 'min' or the one after.
+            location = min;
+            if (min < (mapSize-1))
+            {
+                if (compare(map[min].key, key) < 0)
+                {
+                    // 'min' was one before location we want.
+                    location = min + 1;
+                }
+            }
+        }
+        else
+        {
+            mid = (min + max) / 2;
+            if (compare(map[mid].key, key) == 0)
+            {
+                // located it
+                location = mid;
+            }
+            else if (compare(map[mid].key, key) < 0)
+            {
+                // location must be after 'mid'.
+                if ((min = (mid + 1)) >= mapSize)
+                {
+                    // location falls after last item
+                    location = mapSize;
+                }
+            }
+            else if ((max = (mid - 1)) < 0)
+            {
+                // location falls before first item
+                location = 0;
+            }
+        }
+    }
+    return location;
+}
+
+const void * UMLRTHashMap::remove( const void * key )
+{
+    UMLRTGuard g(mutex);
+
+    int location = locate(key);
+    const void * keyRemoved = NULL;
+
+    if (mapSize)
+    {
+        if (location < mapSize)
+        {
+            if (compare(map[location].key, key) == 0)
+            {
+                keyRemoved = map[location].key;
+                memmove(&map[location], &map[location + 1], (mapSize - location) * sizeof(MapEntry));
+                if ((--mapSize) == 0)
+                {
+                    free(map);
+                    map = NULL;
+                }
+            }
+        }
+    }
+    return keyRemoved;
+}
+
+UMLRTHashMap::Iterator UMLRTHashMap::getIterator() const
+{
+    if (!mapSize)
+    {
+        return Iterator(this, -1);
+    }
+    return Iterator(this, 0);
+}
+
+UMLRTHashMap::Iterator UMLRTHashMap::Iterator::end() const
+{
+    return Iterator(map, -1);
+}
+
+UMLRTHashMap::Iterator UMLRTHashMap::Iterator::next() const
+{
+    if (index == -1)
+    {
+        return end();
+    }
+    else if (map->isEmpty())
+    {
+        return end();
+    }
+    else if (index == (map->getSize() - 1))
+    {
+        return end();
+    }
+    return Iterator(map, index + 1);
+}
+
+const void * UMLRTHashMap::Iterator::getKey() const
+{
+    const void * key = NULL;
+
+    if (index != -1)
+    {
+        key = map->getKey(index);
+    }
+    return key;
+}
+
+void * UMLRTHashMap::Iterator::getObject() const
+{
+    void * object = NULL;
+
+    if (index != -1)
+    {
+        if (map->getSize() > 0)
+        {
+            object = map->getObject(index);
+        }
+    }
+    return object;
+}
diff --git a/rts/umlrt/umlrtinsignal.cc b/rts/umlrt/umlrtinsignal.cc
new file mode 100644
index 0000000..5142eb3
--- /dev/null
+++ b/rts/umlrt/umlrtinsignal.cc
@@ -0,0 +1,139 @@
+// umlrtinsignal.cc
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtinsignal.hh"
+#include "basefatal.hh"
+
+UMLRTInSignal::UMLRTInSignal()
+{
+
+}
+
+UMLRTInSignal::UMLRTInSignal(const UMLRTInSignal &signal)
+{
+
+}
+
+UMLRTInSignal& UMLRTInSignal::operator=(const UMLRTInSignal &signal)
+{
+    UMLRTSignal::operator = (signal);
+    return *this;
+}
+
+UMLRTInSignal::~UMLRTInSignal()
+{
+
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTInSignal::decode( void * * decodeInfo, void * data, const UMLRTObject_class * desc, int arraySize ) const
+{
+    if (!element)
+    {
+        FATAL("decode attempted on invalid signal.");
+    }
+    element->decode(decodeInfo, desc, data, arraySize);
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTInSignal::decode( void * * decodeInfo, int ptrIndirection, void * data, const UMLRTObject_class * desc, int arraySize ) const
+{
+    FATAL("encode ptr indirection not supported");
+}
+
+int UMLRTInSignal::purge()
+{
+    int count = 0;
+    if (element == NULL)
+    {
+        FATAL("purge element is NULL");
+    }
+    const UMLRTCommsPort * srcPort = element->getSrcPort();
+    if (srcPort != NULL)
+    {
+        count = srcPort->purge(-1/*index*/, element->getId());
+    }
+    return count;
+}
+
+int UMLRTInSignal::purgeAt( int index )
+{
+    int count = 0;
+    if (element == NULL)
+    {
+        FATAL("purge element is NULL");
+    }
+    const UMLRTCommsPort * srcPort = element->getSrcPort();
+    if ((srcPort != NULL) && (index >= 0) && (index < (int)srcPort->numFarEnd))
+    {
+        count = srcPort->purge(index, element->getId());
+    }
+    return count;
+}
+
+int UMLRTInSignal::recall( bool front )
+{
+    int count = 0;
+    if (element == NULL)
+    {
+        FATAL("purge element is NULL");
+    }
+    const UMLRTCommsPort * srcPort = element->getSrcPort();
+    if (srcPort != NULL)
+    {
+        count = srcPort->recall(-1/*index*/, front, true/*one*/, element->getId());
+    }
+    return count;
+}
+
+int UMLRTInSignal::recallAll( bool front )
+{
+    int count = 0;
+    if (element == NULL)
+    {
+        FATAL("purge element is NULL");
+    }
+    const UMLRTCommsPort * srcPort = element->getSrcPort();
+    if (srcPort != NULL)
+    {
+        count = srcPort->recall(-1/*index*/, front, false/*one*/, element->getId());
+    }
+    return count;
+}
+
+int UMLRTInSignal::recallAllAt( int index, bool front )
+{
+    int count = 0;
+    if (element == NULL)
+    {
+        FATAL("purge element is NULL");
+    }
+    const UMLRTCommsPort * srcPort = element->getSrcPort();
+    if ((srcPort != NULL) && (index >= 0) && (index < (int)srcPort->numFarEnd))
+    {
+        count = srcPort->recall(index, front, false/*one*/, element->getId());
+    }
+    return count;
+}
+
+int UMLRTInSignal::recallAt( int index, bool front )
+{
+    int count = 0;
+    if (element == NULL)
+    {
+        FATAL("purge element is NULL");
+    }
+    const UMLRTCommsPort * srcPort = element->getSrcPort();
+    if ((srcPort != NULL) && (index >= 0) && (index < (int)srcPort->numFarEnd))
+    {
+         count = srcPort->recall(index, front, true/*one*/, element->getId());
+    }
+    return count;
+}
diff --git a/rts/umlrt/umlrtlogprotocol.cc b/rts/umlrt/umlrtlogprotocol.cc
new file mode 100644
index 0000000..dc9c738
--- /dev/null
+++ b/rts/umlrt/umlrtlogprotocol.cc
@@ -0,0 +1,541 @@
+// umlrtlogprotocol.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtobjectclass.hh"
+#include "umlrtlogprotocol.hh"
+#include "umlrtmutex.hh"
+
+// Avoid concurrent output stdout and stderr. The application is responsible for mutual exclusion all other streams.
+/*static*/ UMLRTMutex UMLRTLogProtocol_baserole::stdoutMutex;
+/*static*/ UMLRTMutex UMLRTLogProtocol_baserole::stderrMutex;
+
+// Gain exclusive access to stdout or stderr - return NULL if stream is not one of these two.
+UMLRTMutex * UMLRTLogProtocol_baserole::takeMutex() const
+{
+    UMLRTMutex * mutex = NULL;
+    if (ostream)
+    {
+        if (ostream == stdout)
+        {
+            UMLRTLogProtocol_baserole::stdoutMutex.take();
+            mutex = &UMLRTLogProtocol_baserole::stdoutMutex;
+        }
+        else if (ostream == stderr)
+        {
+            UMLRTLogProtocol_baserole::stderrMutex.take();
+            mutex = &UMLRTLogProtocol_baserole::stderrMutex;
+        }
+    }
+    return mutex;
+}
+
+void UMLRTLogProtocol_baserole::giveMutex ( UMLRTMutex * mutex ) const
+{
+    if (mutex != NULL)
+    {
+        mutex->give();
+    }
+}
+
+// Output data with the new-line appended.
+int UMLRTLogProtocol_baserole::log ( const char * fmt, ... ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        va_list ap;
+        va_start(ap, fmt);
+        UMLRTMutex * mutex = takeMutex();
+        nchar = vfprintf(ostream, fmt, ap);
+        nchar += fprintf(ostream, "\n");
+        giveMutex(mutex);
+        va_end(ap);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( char c ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%c\n", c);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( short s ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%d\n", s);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( int i ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%d\n", i);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( long l ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%ld\n", l);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( long long ll ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%lld\n", ll);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( unsigned char uc ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%c\n", uc);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( unsigned short us ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%u\n", us);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( unsigned int ui ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%u\n", ui);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( unsigned long ul ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%lu\n", ul);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( unsigned long long ull ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%llu\n", ull);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( float f ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%f\n", f);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( double d ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%f\n", d);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( const void * userData, const UMLRTObject_class * type ) const
+{
+    int nchar;
+
+    nchar = show(userData, type);
+    nchar += log("");
+
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::log ( const UMLRTTypedValue & value ) const
+{
+    return log( value.data, value.type );
+}
+
+// Output data with no new-line appended.
+int UMLRTLogProtocol_baserole::show ( const char * fmt, ... ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        va_list ap;
+        va_start(ap, fmt);
+        UMLRTMutex * mutex = takeMutex();
+        nchar = vfprintf(ostream, fmt, ap);
+        giveMutex(mutex);
+        va_end(ap);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( char c ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%c", c);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( short s ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%d", s);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( int i ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%d", i);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( long l ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%ld", l);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( long long ll ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%lld", ll);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( unsigned char uc ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%c", uc);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( unsigned short us ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%u", us);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( unsigned int ui ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%u", ui);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( unsigned long ul ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%lu", ul);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( unsigned long long ull ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%llu", ull);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( float f ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%f", f);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( double d ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "%f", d);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( const void * userData, const UMLRTObject_class * type ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = UMLRTObject_fprintf(ostream, type, userData);
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::show ( const UMLRTTypedValue & value ) const
+{
+    return show( value.data, value.type );
+}
+
+int UMLRTLogProtocol_baserole::cr ( int numCr ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        while (numCr > 0)
+        {
+            nchar += fprintf(ostream, "\n");
+            --numCr;
+        }
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::crtab ( int numTab ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        nchar = fprintf(ostream, "\n");
+        while (numTab > 0)
+        {
+            nchar += fprintf(ostream, "\t");
+            --numTab;
+        }
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::space ( int numSpace ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        while (numSpace > 0)
+        {
+            nchar = fprintf(ostream, " ");
+            --numSpace;
+        }
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::tab ( int numTab ) const
+{
+    int nchar = 0;
+
+    if (ostream != NULL)
+    {
+        UMLRTMutex * mutex = takeMutex();
+        while (numTab > 0)
+        {
+            nchar += fprintf(ostream, "\t");
+            --numTab;
+        }
+        giveMutex(mutex);
+    }
+    return nchar;
+}
+
+int UMLRTLogProtocol_baserole::commit ( ) const
+{
+    if (ostream != NULL)
+    {
+        fflush(ostream);
+    }
+    return 0;
+}
+
+// Redirect logging output - closes previous output stream if it was opened via redirect(fname). Returns false if error.
+bool UMLRTLogProtocol_baserole::redirect ( FILE * ostream_ ) const
+{
+    if (isOpenFile)
+    {
+        fclose(ostream);
+        isOpenFile = false;
+    }
+    ostream = ostream_;
+    return true;
+}
+
+// Redirect to a file by name - removes previous output stream(s). Returns false if error.
+bool UMLRTLogProtocol_baserole::redirect ( const char * fname ) const
+{
+    bool ok = false;
+    if (isOpenFile)
+    {
+        fclose(ostream);
+        isOpenFile = false;
+    }
+    if (fname)
+    {
+        if ((ostream = fopen(fname, "w")) == NULL)
+        {
+            // Redirect to stderr in case file open fails.
+            ostream = stderr;
+        }
+        else
+        {
+            isOpenFile = true;
+            ok = true;
+        }
+    }
+    return ok;
+}
+
diff --git a/rts/umlrt/umlrtmain.cc b/rts/umlrt/umlrtmain.cc
new file mode 100644
index 0000000..998902a
--- /dev/null
+++ b/rts/umlrt/umlrtmain.cc
@@ -0,0 +1,335 @@
+// umlrtmain.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <stdio.h>
+#include "umlrtmain.hh"
+#include "basefatal.hh"
+#include "basedebug.hh"
+#include "umlrtcapsuletocontrollermap.hh"
+#include "umlrtcontroller.hh"
+
+// See umlrtmain.hh for documentation.
+
+// This set of argc, argv only contain user-arguments and do not contain arguments
+// intended for the RTS-library.
+int UMLRTMain::argc = 0;
+const char * * UMLRTMain::argv = NULL;
+bool UMLRTMain::argsDefined = false;
+
+typedef struct {
+
+    const char * const longopt;
+    const char   shortopt;
+    const char * const value;
+    const char * const help;
+
+} t_usage_option_help;
+
+// Help text for usage output
+static t_usage_option_help optionhelp[] = {
+
+        { "General RTS options", 0, "", "" },
+        { "help",           'h', "",            "Print usage and exit." },
+        { "userargs",       'u', "",            "Marks the start of application options." },
+        { "controllers",    'c', "<controllers-file>", "Specify a capsule-to-controller map file." },
+        { "Debug feature enable options", 0, "", "" },
+        { "debug",          'D', "0/1",         "Overall debug log enable." },
+        { "debugcolor",     'C', "0/1",         "Disable/enable terminal text color escape sequences." },
+        { "debugsummary",   's', "",            "Output debug summary." },
+        { "debugtypeon",    'T', "<types>",     "Enable debug types. See <types> below." },
+        { "debugtypeoff",   't', "<types>",     "Disable debug types. See <types> below." },
+        { "debugmodel",     'M', "",            "Output instance UML-RT model after startup. (Usually also requires '-T model')" },
+        { "Enabling invidual log message components", 0, "", "" },
+        { "debugtime",      'S', "0/1",         "Disable/enable log time-stamp." },
+        { "debugname",      'N', "0/1",         "Disable/enable log type name." },
+        { "debugfile",      'F', "0/1",         "Disable/enable log file-name." },
+        { "debugline",      'L', "0/1",         "Disable/enable log file line #." },
+        { "debugthread",    'n', "0/1",         "Disable/enable log thread name (or id)." },
+        { "debugmethod",    'r', "0/1",         "Disable/enable log method name." },
+        { "debugmsg",       'm', "0/1",         "Disable/enable log application message." },
+        { NULL, 0, NULL, NULL } // MUST BE LAST to terminate loop
+};
+
+// Output usage information and exit
+/*static*/ void UMLRTMain::usage( const char * const program )
+{
+    // Compute field widths for column-aligned output
+    int maxlongoptlen = 0;
+    int maxvaluelen = 0;
+    for (int i = 0; optionhelp[i].longopt; ++i)
+    {
+        int len;
+        if (optionhelp[i].shortopt == 0)
+        {
+            // Is a title for a group of options. Length doesn't apply.
+        }
+        else
+        {
+            if ((len = strlen(optionhelp[i].longopt)) > maxlongoptlen)
+            {
+                maxlongoptlen = len;
+            }
+            if ((len = strlen(optionhelp[i].value)) > maxvaluelen)
+            {
+                maxvaluelen = len;
+            }
+        }
+    }
+    // Terminal colour - must be reset at end.
+    base::debugColourBrightRed();
+
+    // Summary usage line
+    printf("usage:\n");
+    printf("  %s ", program);
+    for (int i = 0; optionhelp[i].longopt; ++i)
+    {
+        if (optionhelp[i].shortopt == 0)
+        {
+            // Is not an option, but contains a title for a group of options.
+        }
+        else if (optionhelp[i].value[0] == '\0')
+        {
+            printf("[-%c] ", optionhelp[i].shortopt);
+        }
+        else
+        {
+            printf("[-%c%s] ", optionhelp[i].shortopt, optionhelp[i].value);
+        }
+    }
+    printf("\n");
+
+    // Option summary
+    for (int i = 0; optionhelp[i].longopt; ++i)
+    {
+        int sofar;
+        if (optionhelp[i].shortopt == 0)
+        {
+            printf("\n%s:\n", optionhelp[i].longopt);
+        }
+        else
+        {
+            if (optionhelp[i].value[0] == '\0')
+            {
+                sofar = printf("[-%c]", optionhelp[i].shortopt);
+            }
+            else
+            {
+                sofar = printf("[-%c %s]", optionhelp[i].shortopt, optionhelp[i].value);
+            }
+            for (int j = sofar; j < (maxvaluelen + 6); ++j)
+            {
+                printf(" ");
+            }
+            if (optionhelp[i].value[0] == '\0')
+            {
+                sofar = printf(" or [--%s]", optionhelp[i].longopt);
+            }
+            else
+            {
+                sofar = printf(" or [--%s=%s]", optionhelp[i].longopt, optionhelp[i].value);
+            }
+            for (int j = sofar; j < (maxlongoptlen + maxvaluelen + 10); ++j)
+            {
+                printf(" ");
+            }
+            printf("%s\n", optionhelp[i].help);
+        }
+    }
+    printf("\n<types> is a string containing one or more debug-types.\n"
+           "Current types are ");
+    base::debugTypeSummary();
+    printf("\n");
+    base::debugColourReset();
+
+    exit(EXIT_FAILURE);
+}
+
+// Extract user arguments and define argument list and count for user.
+// Currently doesn't do anything with arguments specified before '--userargs'.
+/*static*/ void UMLRTMain::setArgs( int argc_, char * const * argv_ )
+{
+   static struct option options[] = {
+            { "help",               no_argument,       NULL, 'h' },
+            { "controllers",        required_argument, NULL, 'c' },
+            { "debug",              required_argument, NULL, 'D' },
+            { "debugcolor",         required_argument, NULL, 'C' },
+            { "debugtypeon",        required_argument, NULL, 'T' },
+            { "debugtypeoff",       required_argument, NULL, 't' },
+            { "debugname",          required_argument, NULL, 'N' },
+            { "debugtime",          required_argument, NULL, 'S' },
+            { "debugthread",        required_argument, NULL, 'n' },
+            { "debugfile",          required_argument, NULL, 'F' },
+            { "debugline",          required_argument, NULL, 'L' },
+            { "debugmethod",        required_argument, NULL, 'f' },
+            { "debugmsg",           required_argument, NULL, 'm' },
+            { "debugsummary",       no_argument,       NULL, 's' },
+            { "debugmodel",         no_argument,       NULL, 'M' },
+            { "userargs",           no_argument,       NULL, 'u' },
+    };
+
+    int userargstart = argc_; // No user arguments unless '--userargs' is found.
+    bool userargsfound = false;
+    int opti = 1; // getopt_long skips program name.
+    int optchar;
+
+    bool debugsummary = false;
+    bool displayusage = false;
+    bool displaymodel = false;
+    char * controllerfile = NULL;
+    int longindex = 0;
+
+    while (((optchar = getopt_long( argc_, argv_, "hc:D:C:T:t:N:S:n:F:L:f:m:Msu", options, &longindex)) != -1) && !userargsfound)
+    {
+        switch(optchar)
+        {
+        case 'h':
+            displayusage = true;
+            break;
+        case 'c':
+            controllerfile = optarg;
+            break;
+        case 'D':
+            base::debugEnableSet(atoi(optarg) != 0);
+            break;
+        case 'C':
+            base::debugEnableColorSet(atoi(optarg) != 0);
+            break;
+        case 'T':
+            if (!base::debugEnableTypeMaskSpecSet(optarg, true /*will enable*/))
+            {
+                usage(argv_[0]);
+            }
+           break;
+        case 't':
+           if (!base::debugEnableTypeMaskSpecSet(optarg, false /*will disable*/))
+           {
+               usage(argv_[0]);
+           }
+           break;
+        case 'N':
+            base::debugEnableTypeNameDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'S':
+            base::debugEnableTimeDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'n':
+            base::debugEnableThreadDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'F':
+            base::debugEnableFilenameDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'L':
+            base::debugEnableLineNumberDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'f':
+            base::debugEnableMethodDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'm':
+            base::debugEnableUserMsgDisplaySet(atoi(optarg) != 0);
+            break;
+        case 'M':
+            displaymodel = true;
+            break;
+        case 's':
+            debugsummary = true;
+            break;
+        case 'u':
+            userargsfound = true;
+            userargstart = opti + 1;
+            break;
+        default:
+            usage(argv_[0]);
+        }
+        opti++;
+    }
+    if (!userargsfound && (optind < argc_))
+    {
+        printf("ERROR: Command-line argument '%s' not recognized.\n", argv_[optind]);
+        usage(argv_[0]);
+    }
+    if (controllerfile)
+    {
+        // If user is reassigning the capsule controllers with a file...
+        if (!UMLRTCapsuleToControllerMap::readCapsuleControllerMap(controllerfile))
+        {
+            printf("ERROR: failed to create capsule-to-controller map. Exiting.\n");
+            usage(argv_[0]);
+        }
+        UMLRTCapsuleToControllerMap::debugOutputCaspuleToControllerMap();
+    }
+
+    // If user requested debug options summary...
+    if (debugsummary)
+    {
+        base::debugOptionSummary();
+    }
+    // If the user requested help, print usage (exit)
+    if (displayusage)
+    {
+        usage(argv_[0]);
+    }
+    if (displaymodel)
+    {
+        if ((base::debugGetEnabledTypes() & (1 << BD_MODEL)) == 0)
+        {
+            printf("WARNING: specified -M (--debugmodel) and '-T model' is not enabled.\n");
+        }
+        else
+        {
+            UMLRTController * controller = (UMLRTController *)UMLRTCapsuleToControllerMap::getFirstController();
+            if (controller == NULL)
+            {
+                printf("WARNING: no controllers instantiated?\n");
+            }
+            else
+            {
+                // Controllers are not actually running yet - use the synchronous output to capture the model before any run-time activity.
+                controller->debugOutputModel();
+            }
+        }
+    }
+    argc = argc_ - userargstart;
+    if (userargstart < argc_)
+    {
+        argv = new const char *[argc];
+    }
+    for (int i = 0, j = userargstart; userargsfound && (j < argc_); ++j)
+    {
+        argv[i++] = argv_[j];
+    }
+    argsDefined = true; // Sanity checking on user fetching of arguments.
+}
+
+// Get the number of user command-line arguments.
+/*static*/ int UMLRTMain::getArgCount()
+{
+    if (!argsDefined)
+    {
+        FATAL("getArgCount() called before setArgs()");
+    }
+    return argc;
+}
+
+// Get the i-th command-line argument.
+/*static*/ const char * UMLRTMain::getArg( int index )
+{
+    if (!argsDefined)
+    {
+        FATAL("getArg(%d) called before setArgs()", index);
+    }
+    if ((index < 0) || (index > (argc-1)))
+    {
+        FATAL("getArg(%d) called but max index is %d", index, (argc-1));
+    }
+    return argv[index];
+}
diff --git a/rts/umlrt/umlrtmainloop.cc b/rts/umlrt/umlrtmainloop.cc
new file mode 100644
index 0000000..2865b71
--- /dev/null
+++ b/rts/umlrt/umlrtmainloop.cc
@@ -0,0 +1,22 @@
+// umlrtmainloop.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtmain.hh"
+
+// See umlrtmain.hh for documentation.
+
+// mainLoop - a method that can be overridden by the user to implement a main thread.
+//
+// return 'false' to skip waiting for controllers to run-to-completion and call targetShutdown() immediately.
+// return 'true' to cause application to wait for controllers to complete before calling targetShutdown().
+/*static*/ bool UMLRTMain::mainLoop()
+{
+     return true; // By default, we wait for controllers to run-to-completion.
+}
diff --git a/rts/umlrt/umlrtmaintargetshutdown.cc b/rts/umlrt/umlrtmaintargetshutdown.cc
new file mode 100644
index 0000000..f5ecf36
--- /dev/null
+++ b/rts/umlrt/umlrtmaintargetshutdown.cc
@@ -0,0 +1,24 @@
+// umlrtmaintargetshutdown.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include <stdlib.h>
+#include "umlrtmain.hh"
+
+// See umlrtmain.hh for documentation.
+
+// targetShutdown - a method that can be overridden by the user to shutdown the execution platform.
+//
+// The input parameter is the return value of the mainLoop().
+//
+// Returns the 'exit status' of the application. This default version does nothing and returns EXIT_SUCCESS.
+/*static*/ int UMLRTMain::targetShutdown( bool mainLoopReturnValue )
+{
+     return EXIT_SUCCESS; // By default, we return 'ok' and application will spawn the controllers.
+}
diff --git a/rts/umlrt/umlrtmaintargetstartup.cc b/rts/umlrt/umlrtmaintargetstartup.cc
new file mode 100644
index 0000000..33b2141
--- /dev/null
+++ b/rts/umlrt/umlrtmaintargetstartup.cc
@@ -0,0 +1,22 @@
+// umlrtmaintargetstartup.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtmain.hh"
+
+// See umlrtmain.hh for documentation.
+
+// targetStartup - a method that can be overridden by the user to initialize prior to controllers starting.
+//
+// return 'false' to exit the application with a failure indication.
+// return 'true' to cause application to start controllers.
+/*static*/ bool UMLRTMain::targetStartup()
+{
+     return true; // By default, we return 'ok' and application will spawn the controllers.
+}
diff --git a/rts/umlrt/umlrtmessage.cc b/rts/umlrt/umlrtmessage.cc
new file mode 100644
index 0000000..3590940
--- /dev/null
+++ b/rts/umlrt/umlrtmessage.cc
@@ -0,0 +1,42 @@
+// umlrtmessage.cc
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtapi.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtmessage.hh"
+#include "umlrtqueue.hh"
+
+// See umlrtmessagequeue.hh for documentation.
+
+bool UMLRTMessage::defer() const
+{
+    bool ok = false;
+
+    UMLRTMessage * msg = umlrt::MessageGetFromPool();
+    if (msg == NULL)
+    {
+        destPort->slot->controller->setError(UMLRTController::E_DEFER_ALLOC);
+    }
+    else
+    {
+        msg->srcPortIndex = srcPortIndex;
+        msg->sapIndex0 = sapIndex0;
+        msg->destPort = destPort;
+        msg->destSlot = destSlot;
+        msg->signal = signal; // This copy causes the reference count on signal to increment.
+        msg->isCommand = isCommand;
+
+        // Append to defer queue.
+        destPort->deferQueue->enqueue(msg);
+        ok = true;
+    }
+    return ok;
+}
+
diff --git a/rts/umlrt/umlrtmessagepool.cc b/rts/umlrt/umlrtmessagepool.cc
new file mode 100644
index 0000000..5a1b07f
--- /dev/null
+++ b/rts/umlrt/umlrtmessagepool.cc
@@ -0,0 +1,49 @@
+// umlrtmessagepool.cc
+
+/*******************************************************************************
+ * Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+// See umlrtmessagepool.hh for documentation.
+#include <stdlib.h>
+#include "basefatal.hh"
+#include "umlrtmessagepool.hh"
+#include "umlrtguard.hh"
+
+UMLRTMessagePool::UMLRTMessagePool(UMLRTMessage messages[], size_t arraySize, size_t incrementSize) : UMLRTPool(incrementSize)
+{
+    UMLRTGuard g(mutex);
+
+    if (arraySize && messages != NULL)
+    {
+        for (size_t i = arraySize - 1; i > 0; --i)
+        {
+            messages[i - 1].next = &messages[i];
+            messages[i - 1].qid = qid++;
+        }
+        head = &messages[0];
+    }
+}
+
+UMLRTMessagePool::UMLRTMessagePool(size_t incrementSize) : UMLRTPool(incrementSize)
+{
+
+}
+
+void UMLRTMessagePool::grow()
+{
+    UMLRTMessage * newElements = new UMLRTMessage[increment]();
+
+    for (size_t i = increment - 1; i > 0; --i)
+    {
+        newElements[i - 1].next = &newElements[i];
+        newElements[i - 1].qid = qid++;
+    }
+    newElements[increment - 1].next = head;
+    head = &newElements[0];
+}
+
diff --git a/rts/umlrt/umlrtmessagequeue.cc b/rts/umlrt/umlrtmessagequeue.cc
new file mode 100644
index 0000000..a6feda0
--- /dev/null
+++ b/rts/umlrt/umlrtmessagequeue.cc
@@ -0,0 +1,16 @@
+// umlrtmessagequeue.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtmessagequeue.hh"
+
+// See umlrtmessagequeue.hh for documentation.
+
+UMLRTMessageQueue::UMLRTMessageQueue() { }
+
diff --git a/rts/umlrt/umlrtmutex.cc b/rts/umlrt/umlrtmutex.cc
new file mode 100644
index 0000000..5a7ccd0
--- /dev/null
+++ b/rts/umlrt/umlrtmutex.cc
@@ -0,0 +1,79 @@
+// umlrtmutex.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+
+#include <errno.h>
+#include <time.h>
+#include "basefatal.hh"
+#include "umlrtmutex.hh"
+#include "umlrttimespec.hh"
+
+// UMLRTMutex is platform-independent mutual-exclusion.
+
+// Bug 32 tracks the move of this implementation to +/os/linux/osmutex.cc
+
+UMLRTMutex::UMLRTMutex()
+{
+    pthread_mutex_init(&mutex, NULL);
+}
+
+// Can create a mutex which starts life as taken already.
+UMLRTMutex::UMLRTMutex( bool taken )
+{
+    if (taken)
+    {
+        take();
+    }
+}
+
+UMLRTMutex::~UMLRTMutex()
+{
+    pthread_mutex_destroy(&mutex);
+}
+// Wait forever for mutex.
+void UMLRTMutex::take()
+{
+    if (pthread_mutex_lock(&mutex) < 0)
+    {
+        FATAL_ERRNO("pthread_mutex_lock");
+    }
+}
+
+// Timed - returns non-zero for success, zero for timeout.
+int UMLRTMutex::take( uint32_t msec )
+{
+    struct timespec timeout;
+    int success = !0;
+
+    UMLRTTimespec::timespecAbsAddMsec( &timeout, msec );
+    if (pthread_mutex_timedlock(&mutex, &timeout) < 0)
+    {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+        int errno_ = errno;
+#pragma GCC diagnostic pop
+        if (errno_ != ETIMEDOUT)
+        {
+            FATAL_ERRNO("pthread_mutex_timedlock");
+        }
+        success = 0;
+    }
+    return success;
+}
+
+// Give mutex back.
+void UMLRTMutex::give()
+{
+    if (pthread_mutex_unlock(&mutex) < 0)
+    {
+        FATAL_ERRNO("pthread_mutex_unlock");
+    }
+}
+
diff --git a/rts/umlrt/umlrtobjectclass.cc b/rts/umlrt/umlrtobjectclass.cc
new file mode 100644
index 0000000..7bb3294
--- /dev/null
+++ b/rts/umlrt/umlrtobjectclass.cc
@@ -0,0 +1,519 @@
+// umlrtobjectclass.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtobjectclass.hh"
+#include "basedebugtype.hh"
+#include "basedebug.hh"
+#include <stdlib.h>
+
+// Type descriptor used for encoding/decoding data of a given type.
+// A number of UMLRTType_xxx descriptors are pre-defined by the library.
+
+// Default initializer - zeros the data and returns a pointer to next byte.
+
+void * UMLRTObject_initialize( const UMLRTObject_class * desc, void * data )
+{
+    uint8_t * s = (uint8_t *)data;
+
+    if (desc->fields == NULL)
+    {
+        memset(s, 0, desc->size);
+        s += desc->size;
+    }
+    else
+    {
+        for (size_t i = 0; i < desc->size; ++i)
+        {
+            desc->fields[i].desc->initialize(desc->fields[i].desc, s + desc->fields[i].offset);
+        }
+    }
+    return (void *)s;
+}
+
+// Default copy - copies the data and returns a pointer to the byte following the src data.
+// The return value is the byte following the last byte copied to the destination.
+void * UMLRTObject_copy( const UMLRTObject_class * desc, const void * src, void * dst )
+{
+    uint8_t * s = (uint8_t *)src;
+    uint8_t * end_p = (uint8_t *)dst;
+    uint8_t * d = (uint8_t *)dst;
+
+    if (desc->fields == NULL)
+    {
+        memcpy(d, s, desc->size);
+        end_p += desc->size;
+    }
+    else
+    {
+        for (size_t i = 0; i < desc->size; ++i)
+        {
+            // overwrite end_p here - the return value for the last field is the one that is relevant.
+            end_p = (uint8_t *)desc->fields[i].desc->copy(desc->fields[i].desc, s + desc->fields[i].offset, d + desc->fields[i].offset);
+        }
+    }
+    return (void *)end_p;
+}
+
+// Default decode is a copy (returns a pointer to the byte after the src data).
+// For now, we'll use the return value of the copy (a value relative to dst) to compute what the return value should be.
+size_t UMLRTObject_getSize( const UMLRTObject_class * desc )
+{
+    size_t size = desc->size;
+
+    if (desc->fields != NULL)
+    {
+        size = desc->fields[desc->size - 1].offset +
+                desc->fields[desc->size - 1].desc->getSize(desc->fields[desc->size - 1].desc);
+    }
+    return size;
+}
+
+void * UMLRTObject_decode( const UMLRTObject_class * desc, const void * src, void * dst )
+{
+    desc->copy(desc, src, dst); // ignore return value.
+
+    return (void *)((uint8_t *)src + UMLRTObject_getSize(desc));
+}
+
+// Default encode is a copy (returns a pointer to the byte after the dst data).
+void * UMLRTObject_encode(  const UMLRTObject_class * desc, const void * src, void * dst )
+{
+    return desc->copy(desc, src, dst);
+}
+
+// Default destroy does nothing (but returns a pointer to the byte after the data).
+void * UMLRTObject_destroy(  const UMLRTObject_class * desc, void * data )
+{
+    uint8_t * s = (uint8_t *)data;
+    uint8_t * end_p = (uint8_t *)data;
+
+    if (desc->fields != NULL)
+    {
+        for (size_t i = 0; i < desc->size; ++i)
+        {
+            end_p = (uint8_t *)desc->fields[i].desc->destroy(desc->fields[i].desc, s + desc->fields[i].offset);
+        }
+    }
+    else
+    {
+        end_p += desc->size;
+    }
+    return (void *)end_p;
+}
+
+int UMLRTObject_fprintf( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    uint8_t * s = (uint8_t *)data;
+
+    if (desc->fields != NULL)
+    {
+        nchar += fprintf(ostream, "{%s:", desc->name);
+
+        for (size_t i = 0; i < desc->size; ++i)
+        {
+            nchar += fprintf(ostream, "{%s:", desc->fields[i].name);
+            nchar += UMLRTObject_fprintf(ostream, desc->fields[i].desc, s + desc->fields[i].offset);
+            nchar += fprintf(ostream, "}");
+        }
+        nchar += fprintf(ostream, "}");
+    }
+    else if (desc->fprintf != 0)
+    {
+        nchar += desc->fprintf(ostream, desc, data);
+    }
+    else
+    {
+        nchar += fprintf(ostream, "{%s: (unable to print)}", desc->name);
+    }
+    return nchar;
+}
+
+int UMLRTObject_fprintf_bool( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    bool b;
+    desc->copy(desc, data, &b);
+    nchar += fprintf(ostream, "{bool %s}", b ? "true" : "false");
+    return nchar;
+}
+
+int UMLRTObject_fprintf_char( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    char c;
+    desc->copy(desc, data, &c);
+    nchar += fprintf(ostream, "{char %c}", c);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_double( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    double d;
+    desc->copy(desc, data, &d);
+    nchar += fprintf(ostream, "{double %f}", d);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_float( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    float f;
+    desc->copy(desc, data, &f);
+    nchar += fprintf(ostream, "{float %f}", f);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_int( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    int i;
+    desc->copy(desc, data, &i);
+    nchar += fprintf(ostream, "{int %d}", i);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_long( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    long l;
+    desc->copy(desc, data, &l);
+    nchar += fprintf(ostream, "{long %ld}", l);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_longlong( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    long long ll;
+    desc->copy(desc, data, &ll);
+    nchar += fprintf(ostream, "{longlong %lld}", ll);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_ptr( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    void * p;
+    desc->copy(desc, data, &p);
+    // Pointer de-referencing tracked by Bug 97.
+    nchar += fprintf(ostream, "{ptr %p}", p);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_short( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    short sh;
+    desc->copy(desc, data, &sh);
+    nchar += fprintf(ostream, "{short %d}", sh);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_uchar( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    unsigned char c;
+    desc->copy(desc, data, &c);
+    nchar += fprintf(ostream, "{char %u}", c);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_uint( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    unsigned int i;
+    desc->copy(desc, data, &i);
+    nchar += fprintf(ostream, "{uint %u}", i);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_ulong( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    unsigned long l;
+    desc->copy(desc, data, &l);
+    nchar += fprintf(ostream, "{ulong %lu}", l);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_ulonglong( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    unsigned long long ll;
+    desc->copy(desc, data, &ll);
+    nchar += fprintf(ostream, "{ulonglong %llu}", ll);
+    return nchar;
+}
+
+int UMLRTObject_fprintf_ushort( FILE *ostream, const UMLRTObject_class * desc, const void * data )
+{
+    int nchar = 0;
+    unsigned short sh;
+    desc->copy(desc, data, &sh);
+    nchar += fprintf(ostream, "{ushort %u}", sh);
+    return nchar;
+}
+
+const UMLRTObject_class UMLRTType_bool_
+= {
+        "bool",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_bool,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(bool),
+        NULL // fields
+};
+
+
+const UMLRTObject_class UMLRTType_char_
+= {
+        "char",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_char,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(char),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_double_
+= {
+        "double",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_double,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(double),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_float_
+= {
+        "float",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_float,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(float),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_int_
+= {
+        "int",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_int,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(int),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_long_
+= {
+        "long",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_long,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(long),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_longlong_
+= {
+        "longlong",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_longlong,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(long long),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_ptr_
+= {
+        "ptr",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_ptr,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(void *),
+        NULL // fields
+};
+
+const UMLRTObject_class UMLRTType_short_
+= {
+        "short",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_short,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(short),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_uchar_
+= {
+        "uchar",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_uchar,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(unsigned char),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_uint_
+= {
+        "uint",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_uint,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(unsigned int),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_ulong_
+= {
+        "ulong",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_ulong,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(unsigned long),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_ulonglong_
+= {
+        "ulonglong",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_ulonglong,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(unsigned long long),
+        NULL, // fields
+};
+
+const UMLRTObject_class UMLRTType_ushort_
+= {
+        "ushort",
+        UMLRTObject_initialize,
+        UMLRTObject_copy,
+        UMLRTObject_decode,
+        UMLRTObject_encode,
+        UMLRTObject_destroy,
+        UMLRTObject_getSize,
+        UMLRTObject_fprintf_ushort,
+        NULL, // super
+        UMLRTOBJECTCLASS_DEFAULT_VERSION, // version
+        UMLRTOBJECTCLASS_DEFAULT_BACKWARDS, // backwards
+        sizeof(unsigned short),
+        NULL, // fields
+};
+
+const UMLRTObject_class * const UMLRTType_bool = &UMLRTType_bool_;
+const UMLRTObject_class * const UMLRTType_char = &UMLRTType_char_;
+const UMLRTObject_class * const UMLRTType_double = &UMLRTType_double_;
+const UMLRTObject_class * const UMLRTType_float = &UMLRTType_float_;
+const UMLRTObject_class * const UMLRTType_int = &UMLRTType_int_;
+const UMLRTObject_class * const UMLRTType_long = &UMLRTType_long_;
+const UMLRTObject_class * const UMLRTType_longlong = &UMLRTType_longlong_;
+const UMLRTObject_class * const UMLRTType_ptr = &UMLRTType_ptr_;
+const UMLRTObject_class * const UMLRTType_short = &UMLRTType_short_;
+const UMLRTObject_class * const UMLRTType_uchar = &UMLRTType_uchar_;
+const UMLRTObject_class * const UMLRTType_uint = &UMLRTType_uint_;
+const UMLRTObject_class * const UMLRTType_ulong = &UMLRTType_ulong_;
+const UMLRTObject_class * const UMLRTType_ulonglong = &UMLRTType_ulonglong_;
+const UMLRTObject_class * const UMLRTType_ushort = &UMLRTType_ushort_;
+
diff --git a/rts/umlrt/umlrtoutsignal.cc b/rts/umlrt/umlrtoutsignal.cc
new file mode 100644
index 0000000..9a25c22
--- /dev/null
+++ b/rts/umlrt/umlrtoutsignal.cc
@@ -0,0 +1,211 @@
+// umlrtoutsignal.cc
+
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportfarend.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtoutsignal.hh"
+#include "umlrtframeservice.hh"
+#include "umlrtslot.hh"
+#include "basefatal.hh"
+#include "basedebugtype.hh"
+#include "basedebug.hh"
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+UMLRTOutSignal::UMLRTOutSignal()
+{
+
+}
+
+UMLRTOutSignal::UMLRTOutSignal(const UMLRTOutSignal &signal)
+{
+
+}
+
+UMLRTOutSignal& UMLRTOutSignal::operator=(const UMLRTOutSignal &signal)
+{
+    UMLRTSignal::operator = (signal);
+    return *this;
+}
+
+UMLRTOutSignal::~UMLRTOutSignal()
+{
+
+}
+
+
+// See documentation in UMLRTSignal.
+void UMLRTOutSignal::encode( const void * data, const UMLRTObject_class * desc, int arraySize )
+{
+    if (!element)
+    {
+        FATAL("encode attempted on invalid signal.");
+    }
+    element->encode(desc, data, arraySize);
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTOutSignal::encode( int ptrIndirection, void * data, const UMLRTObject_class * desc, int arraySize )
+{
+    FATAL("encode ptr indirection not supported");
+}
+
+
+// Synchronous send out all port instances. Returns the number of replies (0 if fail).
+int UMLRTOutSignal::invoke( UMLRTMessage * replyMsgs )
+{
+    FATAL("invoke not implemented");
+    return 0;
+}
+
+// Synchronous send out a specific port instance. Returns the number of replies (0 or 1).
+int UMLRTOutSignal::invokeAt( int index, UMLRTMessage * replyMsg )
+{
+    FATAL("invokeAt not implemented");
+    return 0;
+}
+
+// Reply to a synchronous message. Return true if success.
+bool UMLRTOutSignal::reply()
+{
+    FATAL("reply not implemented");
+    return false;
+}
+
+bool UMLRTOutSignal::send( UMLRTSignalElement::Priority priority ) const
+{
+    int ok = false;
+
+    if (!element)
+    {
+        BDEBUG(BD_SWERR, "WARNING: attempt to send an invalid signal. Capsule and port information are not known.\n");
+    }
+    else
+    {
+        const UMLRTCommsPort * srcPort = element->getSrcPort();
+
+        if (!srcPort)
+        {
+            FATAL("No srcPort when sending a signal. Should be the unbound port at least.");
+        }
+        else if (srcPort->unbound)
+        {
+            srcPort->slot->controller->setError(UMLRTController::E_SEND_UNBOUND);
+        }
+        else
+        {
+            // Set priority here.
+            if ((priority < UMLRTSignalElement::PRIORITY_BACKGROUND) || (priority > UMLRTSignalElement::PRIORITY_PANIC))
+            {
+                srcPort->slot->controller->setError(UMLRTController::E_SEND_PRIORITY);
+            }
+            else
+            {
+                element->setPriority(priority);
+
+                // Attempt all sends regardless of errors - one successful send will mean overall success.
+                for (size_t i = 0; (i < srcPort->numFarEnd); ++i)
+                {
+                    ok |= signalDeliver(srcPort, i);
+                }
+                if (ok)
+                {
+                    // If one succeeds, we'll return success - and remove error code from controller.
+                    srcPort->slot->controller->setError(UMLRTController::E_OK);
+                }
+            }
+       }
+   }
+   return ok;
+}
+
+// Send the signal to one far end port. See umlrtsignal.hh for documentation.
+bool UMLRTOutSignal::sendAt( size_t  portIndex, UMLRTSignalElement::Priority priority ) const
+{
+    bool ok = false;
+
+    if (!element)
+    {
+        BDEBUG(BD_SEND, "WARNING: attempt to send an invalid signal. Capsule and port information are not known.\n");
+    }
+    else
+    {
+        const UMLRTCommsPort * srcPort = element->getSrcPort();
+
+        if (!srcPort)
+        {
+            FATAL("No srcPort when sending a signal. Should be the unbound port at least.");
+        }
+        else if (srcPort->unbound)
+        {
+            srcPort->slot->controller->setError(UMLRTController::E_SEND_UNBOUND);
+        }
+        else if ((priority < UMLRTSignalElement::PRIORITY_BACKGROUND) || (priority > UMLRTSignalElement::PRIORITY_PANIC))
+        {
+            srcPort->slot->controller->setError(UMLRTController::E_SEND_PRIORITY);
+        }
+        else
+        {
+            // Set priority here.
+            element->setPriority(priority);
+
+            ok = signalDeliver(srcPort, portIndex);
+        }
+    }
+    return ok;
+}
+
+// Deliver the signal to a destination.
+bool UMLRTOutSignal::signalDeliver( const UMLRTCommsPort * srcPort, size_t portIndex ) const
+{
+    bool ok = false;
+
+    // Lock the RTS
+    UMLRTFrameService::rtsLock();
+
+    const UMLRTCommsPort * destPort;
+
+    if (srcPort->slot->condemned)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SEND_FROM_DSTR);
+    }
+    else if (portIndex >= srcPort->numFarEnd)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SEND_NO_PORT_INST);
+    }
+    else if ((destPort = srcPort->farEnds[portIndex].port) == NULL)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SEND_PRT_NOT_CON);
+    }
+    else if (destPort->slot->condemned)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SEND_TO_DSTR);
+    }
+    else if (destPort->slot->capsule == NULL)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SEND_NO_CAP_INST);
+    }
+    else if (destPort->slot->controller == NULL)
+    {
+        FATAL("Destination slot %s has no controller when sending from capsule %s via port %s[%d].",
+                destPort->slot,
+                srcPort->slot->name,
+                srcPort->role()->name,
+                portIndex);
+    }
+    else
+    {
+        ok = destPort->slot->controller->deliver( destPort, *this, portIndex );
+        // Error code set by 'deliver' if an error occurred.
+    }
+    // Unlock the RTS
+    UMLRTFrameService::rtsUnlock();
+
+    return ok;
+}
diff --git a/rts/umlrt/umlrtpool.cc b/rts/umlrt/umlrtpool.cc
new file mode 100644
index 0000000..2fd996f
--- /dev/null
+++ b/rts/umlrt/umlrtpool.cc
@@ -0,0 +1,55 @@
+// umlrtpool.cc
+
+/*******************************************************************************
+ * Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+#include <stdlib.h>
+#include "basefatal.hh"
+#include "basedebug.hh"
+#include "umlrtguard.hh"
+#include "umlrtpool.hh"
+#include "umlrtqueueelement.hh"
+#include "umlrtuserconfig.hh"
+
+// See umlrtqueue.hh for documentation.
+
+// Create an empty queue.
+UMLRTPool::UMLRTPool(size_t incrementSize) :
+        head(0), increment(incrementSize), qid(0)
+{
+}
+
+UMLRTPool::~UMLRTPool()
+{
+}
+
+// Remove the first element on the pool.
+// Grow the list if it is empty
+const UMLRTQueueElement * UMLRTPool::get()
+{
+    UMLRTGuard g(mutex);
+
+    if (head == NULL)
+    {
+        grow();
+    }
+    const UMLRTQueueElement * element = head;
+    head = element->next;
+    return element;
+}
+
+// Add element back to pool (at front).
+void UMLRTPool::put(const UMLRTQueueElement * element)
+{
+    UMLRTGuard g(mutex);
+    if (element)
+    {
+        element->next = head;
+        head = element;
+    }
+}
diff --git a/rts/umlrt/umlrtprioritymessagequeue.cc b/rts/umlrt/umlrtprioritymessagequeue.cc
new file mode 100644
index 0000000..f49ee11
--- /dev/null
+++ b/rts/umlrt/umlrtprioritymessagequeue.cc
@@ -0,0 +1,269 @@
+// umlrtprioritymessagequeue.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "basedebug.hh"
+#include "basedebugtype.hh"
+#include "basefatal.hh"
+#include "umlrtapi.hh"
+#include "umlrtslot.hh"
+#include "umlrtcommsportrole.hh"
+#include "umlrtprioritymessagequeue.hh"
+#include "umlrtmessage.hh"
+#include "umlrttimer.hh"
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+// See umlrtprioritymessagequeue.hh for documentation.
+
+UMLRTPriorityMessageQueue::UMLRTPriorityMessageQueue( const char * owner_ ) : owner(owner_)
+{
+    // Appenders write the pipe. Controllers 'wait' on a select() on the pipe with
+    // a timeout associated with any running timer. A write on the pipe wakes the controller.
+    if (pipe(notifyFd) < 0)
+    {
+        FATAL_ERRNO("pipe");
+    }
+    // Bytes available in the pipe wake up the controller as 'notify'. The controller
+    // has to be able to clean out the pipe (read) without blocking.
+    int flags = fcntl(notifyFd[0], F_GETFL, 0);
+    if (flags < 0)
+    {
+        FATAL_ERRNO("fcntl F_GETFL");
+    }
+    if (fcntl(notifyFd[0], F_SETFL, flags | O_NONBLOCK) < 0)
+    {
+        FATAL_ERRNO("fcntl F_SETFL");
+    }
+}
+
+// Return the queue associated with a priority.
+UMLRTMessageQueue & UMLRTPriorityMessageQueue::getQueue( UMLRTSignalElement::Priority priority )
+{
+    return queue[priority];
+}
+
+// Used to transfer all messages from each priority queue to
+// their associated priority-queue
+
+void UMLRTPriorityMessageQueue::moveAll( UMLRTPriorityMessageQueue & fromQueue )
+{
+    for (UMLRTSignalElement::Priority priority = 0; priority < UMLRTSignalElement::PRIORITY_MAX; ++priority)
+    {
+        const UMLRTQueueElement * last; // These are UMLRTMessage's.
+        const UMLRTQueueElement * all = fromQueue.getQueue(priority).dequeueAll(&last);
+
+        queue[priority].enqueueAll(all, last);
+    }
+}
+
+// Get all expired timers from the timer-queue and enqueue these to this the capsule priority message queue.
+// The 'incomingQueue' is also a priority queue, but timers are never queued to the incomingQueue instance.
+void UMLRTPriorityMessageQueue::queueTimerMessages( UMLRTTimerQueue * timerQueue )
+{
+    UMLRTTimer * timer = timerQueue->dequeue();
+
+    while (timer != NULL)
+    {
+        if (!timer->allocated)
+        {
+            FATAL("%s:timer (%p) obtained from timer-queue is not allocated.", owner, timer);
+        }
+        UMLRTMessage * msg = umlrt::MessageGetFromPool();
+
+        if (!msg)
+        {
+            FATAL("message allocation failed during timout message creation.");
+        }
+        msg->signal = timer->signal;
+        msg->destPort = timer->destPort;
+        msg->destSlot = timer->destSlot;
+        msg->srcPortIndex = 0; // Timer ports are not replicated.
+        msg->isCommand = false;
+
+        char tmbuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+        BDEBUG(BD_TIMER, "%s: queue timer msg signal id(%d) to %s(%s) isInterval(%d) due(%s)\n",
+                owner, msg->signal.getId(), msg->destPort->slot->name, msg->destPort->role()->name, timer->isInterval,
+                timer->isInterval ?  timer->due.toStringRelative(tmbuf, sizeof(tmbuf)): timer->due.toString(tmbuf, sizeof(tmbuf)));
+
+        enqueue(msg);
+
+        if (timer->isInterval)
+        {
+            // This is an interval timer. Adjust it's due-time and requeue it.
+            timer->due += timer->interval;
+            timerQueue->enqueue(timer);
+        }
+        else
+        {
+            // This timer can be put back on the system pool.
+            umlrt::TimerPutToPool(timer);
+        }
+
+        // See if there's another one expired.
+        timer = timerQueue->dequeue();
+    }
+}
+
+// Get the highest priority message from the collection of queues.
+
+UMLRTMessage * UMLRTPriorityMessageQueue::dequeueHighestPriority()
+{
+    UMLRTMessage * msg = 0;
+
+    for (UMLRTSignalElement::Priority priority = (UMLRTSignalElement::PRIORITY_MAX-1);
+            (priority >= UMLRTSignalElement::PRIORITY_BACKGROUND) && (priority < (UMLRTSignalElement::PRIORITY_MAX)) && !msg; --priority)
+    {
+        msg = (UMLRTMessage *)queue[priority].dequeue();
+
+    }
+    if (msg != NULL)
+    {
+        // Source port may no longer exist.
+        BDEBUG(BD_MSG, "%s: msg dequeued priority(%d) -> %s %s[%d] signal id(%d) payloadSz(%d)\n",
+                owner,
+                msg->signal.getPriority(),
+                msg->isCommand ? "" : msg->destPort->slot->name,
+                msg->isCommand ? "isCommand" : msg->destPort->role()->name,
+                msg->isCommand ? 0 : msg->sapIndex0,
+                msg->signal.getId(),
+                msg->signal.getPayloadSize());
+    }
+    return msg;
+}
+
+// Put the message into its appropriate priority-queue.
+void UMLRTPriorityMessageQueue::enqueue( UMLRTMessage * msg, bool front )
+{
+    UMLRTSignalElement::Priority priority = msg->signal.getPriority();
+
+    if ((priority < 0) || (priority >= UMLRTSignalElement::PRIORITY_MAX))
+    {
+        FATAL("enqueue with bad priority (%d)", priority);
+    }
+    if (!msg->isCommand && msg->destPort == NULL)
+    {
+        FATAL("enqueuing a message with no destination port");
+    }
+    // Source port may no longer exist.
+    BDEBUG(BD_MSG, "%s: msg enqueued priority(%d) -> %s[%d] signal id(%d) payloadSz(%d)\n",
+            owner,
+            msg->signal.getPriority(),
+            msg->isCommand ? "isCommand" : msg->destPort->role()->name,
+            msg->isCommand ? 0 : msg->sapIndex0,
+            msg->signal.getId(),
+            msg->signal.getPayloadSize());
+
+    queue[priority].enqueue(msg, front);
+
+    sendNotification();
+}
+
+// See umlrtprioritymessagequeue.hh for documentation.
+void UMLRTPriorityMessageQueue::sendNotification()
+{
+    bool already_notified = true;
+    int bytes_ready;
+
+    if (ioctl(notifyFd[0], FIONREAD, &bytes_ready) < 0)
+    {
+        FATAL_ERRNO("ioctl");
+    }
+    if (!bytes_ready)
+    {
+        already_notified = false;
+
+        // Write a byte to the notification-pipe as a notification of a pending message.
+        uint8_t notifyByte = 0;
+
+        if (write(notifyFd[1], &notifyByte, 1) < 0)
+        {
+            FATAL_ERRNO("write");
+        }
+    }
+    BDEBUG(BD_CONTROLLER, "%s: send notification (%s)\n", owner, already_notified ? "notification already pending" : "added notify byte");
+}
+
+// See umlrtprioritymessagequeue.hh for documentation.
+void UMLRTPriorityMessageQueue::clearNotifyFd()
+{
+    uint8_t ignore;
+    int bytes;
+    if ((bytes = read(notifyFd[0], &ignore, 1)) < 0)
+    {
+        FATAL_ERRNO("initial read - synchronization mechanism implies a byte is waiting");
+    }
+    else if (!bytes)
+    {
+        // Indicates synchronization logic error. Should always get at least one byte.
+        FATAL("Should never find pipe empty when clearing a notification.");
+    }
+    // Clear out the notification-pipe.
+    // Can shrink this after notify is debugged.
+    bool done = false;
+    while (!done)
+    {
+        int bytes = read(notifyFd[0], &ignore, 1);
+        if (bytes < 0)
+        {
+            if (errno != EAGAIN)
+            {
+                FATAL_ERRNO("read");
+            }
+            else
+            {
+                done = true;
+            }
+        }
+        if (bytes > 0)
+        {
+            // BDEBUG(0, "read returned bytes(%d)\n", bytes);
+        }
+        else
+        {
+            done = true;
+        }
+    }
+}
+
+// See umlrtprioritymessagequeue.hh for documentation.
+int UMLRTPriorityMessageQueue::getNotifyFd()
+{
+    return notifyFd[0];
+}
+
+
+// See umlrtprioritymessagequeue.hh for documentation.
+bool UMLRTPriorityMessageQueue::isEmpty()
+{
+    bool isempty = true;
+
+    for (UMLRTSignalElement::Priority priority = (UMLRTSignalElement::PRIORITY_MAX-1);
+            (priority >= UMLRTSignalElement::PRIORITY_BACKGROUND) && (priority < (UMLRTSignalElement::PRIORITY_MAX)) && isempty; --priority)
+    {
+        if (!queue[priority].isEmpty())
+        {
+            isempty = false;
+        }
+    }
+    return isempty;
+}
+
+void UMLRTPriorityMessageQueue::remove( UMLRTQueue::match_compare_t callback, UMLRTQueue::match_notify_t notify, void * userData )
+{
+    for (UMLRTSignalElement::Priority priority = (UMLRTSignalElement::PRIORITY_MAX-1);
+            (priority >= UMLRTSignalElement::PRIORITY_BACKGROUND) && (priority < (UMLRTSignalElement::PRIORITY_MAX)); --priority)
+    {
+        queue[priority].remove(callback, notify, userData);
+    }
+}
+
diff --git a/rts/umlrt/umlrtprotocol.cc b/rts/umlrt/umlrtprotocol.cc
new file mode 100644
index 0000000..47faa2c
--- /dev/null
+++ b/rts/umlrt/umlrtprotocol.cc
@@ -0,0 +1,720 @@
+// umlrtprotocol.cc
+
+/*******************************************************************************
+ * Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportfarend.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtframeservice.hh"
+#include "umlrthashmap.hh"
+#include "umlrtprotocol.hh"
+#include "basefatal.hh"
+#include "basedebugtype.hh"
+#include "basedebug.hh"
+#include <string.h>
+
+/*static*/ UMLRTHashMap * UMLRTProtocol::portToName; // key and object are associated with the port - not allocated/deallocated.
+/*static*/ UMLRTHashMap * UMLRTProtocol::nameToSppPort; // key and object are associated with the port - not allocated/deallocated.
+/*static*/ UMLRTHashMap * UMLRTProtocol::nameToUnboundSapPorts; // key and object are both allocated and must be deallocated.
+
+/*static*/ void UMLRTProtocol::addSapToQueue( const char * service, const UMLRTCommsPort * sapPort )
+{
+    // Assumes RTS lock obtained.
+    UMLRTQueue * unboundSapPorts;
+    if ((unboundSapPorts = (UMLRTQueue *)getNameToUnboundSapPortsMap()->getObject(service)) == NULL)
+    {
+        // This service had no SAP queue - create it.
+        unboundSapPorts = new UMLRTQueue();
+
+        // Both key and object (queue) must be deallocated when we remove it from the map.
+        getNameToUnboundSapPortsMap()->insert(strdup(service), unboundSapPorts);
+    }
+    // Queue elements must be deleted when they are removed from the queue.
+    UnboundSapPort * element = new UnboundSapPort(sapPort);
+
+    BDEBUG(BD_SAP,"add slot %s port %s to SPP %s pending queue - ENQUEUE\n", sapPort->slot->name, sapPort->role()->name, service);
+    unboundSapPorts->enqueue(element);
+}
+
+void UMLRTProtocol::bindingNotification( bool on )
+{
+    srcPort->notification = on;
+}
+
+bool UMLRTProtocol::bindingNotificatioRequested() const
+{
+    return srcPort->notification;
+}
+
+/*static*/ void UMLRTProtocol::bindQueuedSapsToSpp( const UMLRTCommsPort * sppPort )
+{
+    // Assumes RTS lock obtained.
+    int freeFarEnds = UMLRTFrameService::freeFarEndsCount(sppPort);
+
+    // Get queue of waiting SAP ports.
+    UMLRTQueue * unboundSapPorts = (UMLRTQueue *)getNameToUnboundSapPortsMap()->getObject(sppPort->registeredName);
+
+    for (size_t i = 0; (unboundSapPorts != NULL) && (i < sppPort->numFarEnd) && (freeFarEnds > 0); ++i)
+    {
+        // Get next waiting SAP port.
+        UnboundSapPort * element;
+        if ((element = (UnboundSapPort *)unboundSapPorts->dequeue()) != NULL)
+        {
+            // Bind the next SAP.
+            UMLRTFrameService::bindServicePort(element->port, sppPort);
+            delete element;
+            // One less free port on SPP.
+            --freeFarEnds;
+        }
+    }
+    if (unboundSapPorts != NULL)
+    {
+        if (unboundSapPorts->isEmpty())
+        {
+            // No more queued SAP ports for this SPP - remove the queue from the unbound-map.
+            // Both the key and the object (queue) must be deallocated.
+            const void * key = getNameToUnboundSapPortsMap()->remove(sppPort->registeredName);
+            if (key != NULL)
+            {
+                free((void *)key);
+            }
+            delete unboundSapPorts;
+        }
+    }
+}
+
+/*static*/ void UMLRTProtocol::completeRegistration( const UMLRTCommsPort * port, const char * service )
+{
+    // Assumes RTS lock obtained.
+    if (port->registeredName == NULL)
+    {
+        port->registeredName = strdup(service);
+    }
+    if (strcmp(port->registeredName, service))
+    {
+        if (!port->generated)
+        {
+            free((void *)port->registeredName);
+        }
+        port->registeredName = strdup(service);
+    }
+    // Memory for key/object in portToNameMap not managed with map.
+    getPortToNameMap()->insert(port, port->registeredName);
+}
+
+/*static*/ void UMLRTProtocol::completeDeregistration( const UMLRTCommsPort * port )
+{
+    // Assumes RTS lock obtained.
+    // Memory for key/object in portToNameMap not managed with map.
+    getPortToNameMap()->remove(port);
+    if (port->registeredName != NULL)
+    {
+        if (!port->generated)
+        {
+            free((void *)port->registeredName);
+            port->registeredName = NULL;
+        }
+    }
+}
+
+/*static*/ bool UMLRTProtocol::deregisterSapPort( const UMLRTCommsPort * sapPort )
+{
+    bool ok = false;
+    if (!sapPort->sap)
+    {
+        sapPort->slot->controller->setError(UMLRTController::E_SAPDREG_NOT_SAP);
+    }
+    else if (sapPort->registeredName == NULL)
+    {
+        ok = true; // Wasn't registered.
+    }
+    else
+    {
+        const char * service;
+        if ((service = (const char *)getPortToNameMap()->getObject(sapPort)) != NULL)
+        {
+            // Was registered. Remove this SAP if it was queued for the SPP.
+            removeSapFromQueue(sapPort);
+
+            if (sapPort->numFarEnd > 0)
+            {
+                const UMLRTCommsPort * sppPort;
+                if ((sppPort = sapPort->farEnds[0].port) != NULL)
+                {
+                    // If this SAP was bound to the SPP, unbind it.
+                    UMLRTFrameService::unbindServicePort(sapPort, sppPort);
+
+                    // Go to pending SAP queue for this SPP and bind another SAP.
+                    bindQueuedSapsToSpp(sppPort);
+                }
+            }
+            completeDeregistration(sapPort);
+        }
+        ok = true;
+    }
+    BDEBUG(BD_SAP, "SAP de-register slot %s port %s %s %s\n", sapPort->slot->name, sapPort->role()->name, ok ? "ok" : "failed", ok ? "" : sapPort->slot->controller->strerror());
+    return ok;
+}
+
+bool UMLRTProtocol::deregisterSAP()
+{
+    bool ok = false;
+    if (srcPort->locked)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SAPDREG_SAP_LOCKED);
+    }
+    else
+    {
+        UMLRTFrameService::rtsLock();
+
+        ok = deregisterSapPort(srcPort);
+
+        UMLRTFrameService::rtsUnlock();
+    }
+    return ok;
+}
+
+/*static*/ bool UMLRTProtocol::deregisterSppPort( const UMLRTCommsPort * sppPort )
+{
+    bool ok = false;
+
+    if (!sppPort->spp)
+    {
+        sppPort->slot->controller->setError(UMLRTController::E_SPPDREG_NOT_SPP);
+    }
+    else
+    {
+        const char * service;
+        if ((service = (const char *)getPortToNameMap()->getObject(sppPort)) != NULL)
+        {
+            // For every currently bound SAP port, unbind it and queue for re-binding later.
+            for (size_t i = 0; i < sppPort->numFarEnd; ++i)
+            {
+                const UMLRTCommsPort * sapPort = sppPort->farEnds[i].port;
+                if (sapPort != NULL)
+                {
+                    // A SAP was bound on this port. Unbind it and queue it to the service.
+                    UMLRTFrameService::unbindServicePort(sapPort, sppPort);
+                    addSapToQueue(sppPort->registeredName, sapPort);
+                }
+            }
+            // This port no longer registered as an SPP. Memory is associated with the port.
+            getNameToSppPortMap()->remove(sppPort->registeredName);
+            completeDeregistration(sppPort);
+        }
+        ok = true;
+    }
+    BDEBUG(BD_SAP, "SPP de-register slot %s port %s %s %s\n", sppPort->slot->name, sppPort->role()->name, ok ? "ok" : "failed", ok ? "" : sppPort->slot->controller->strerror());
+    return ok;
+}
+
+bool UMLRTProtocol::deregisterSPP()
+{
+    bool ok = false;
+    if (srcPort->locked)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_SPPDREG_SPP_LOCKED);
+    }
+    else
+    {
+        UMLRTFrameService::rtsLock();
+
+        ok = deregisterSppPort(srcPort);
+
+        UMLRTFrameService::rtsUnlock();
+    }
+    return ok;
+}
+
+/*static*/ UMLRTHashMap * UMLRTProtocol::getPortToNameMap()
+{
+    if (portToName == NULL)
+    {
+        portToName = new UMLRTHashMap("portToName", UMLRTHashMap::compareValue);
+    }
+    return portToName;
+}
+
+/*static*/ UMLRTHashMap * UMLRTProtocol::getNameToSppPortMap()
+{
+    if (nameToSppPort == NULL)
+    {
+        nameToSppPort = new UMLRTHashMap("nameToSppPort", UMLRTHashMap::compareString);
+    }
+    return nameToSppPort;
+}
+
+/*static*/ UMLRTHashMap * UMLRTProtocol::getNameToUnboundSapPortsMap()
+{
+    if (nameToUnboundSapPorts == NULL)
+    {
+        nameToUnboundSapPorts = new UMLRTHashMap("nameToUnboundSapPorts", UMLRTHashMap::compareString);
+    }
+    return nameToUnboundSapPorts;
+}
+
+const char * UMLRTProtocol::getRegisteredName() const
+{
+    return srcPort->registeredName;
+}
+
+/*static*/ bool UMLRTProtocol::isRegistered( const UMLRTCommsPort * port )
+{
+    UMLRTFrameService::rtsLock();
+
+    bool registered = (getPortToNameMap()->getObject(port) != NULL);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return registered;
+}
+
+bool UMLRTProtocol::isRegistered() const
+{
+    return isRegistered(srcPort);
+}
+
+bool UMLRTProtocol::isBoundAt( int index ) const
+{
+    bool bound = false;
+
+    UMLRTFrameService::rtsLock();
+
+    if ((index >= 0) && (index < (int)srcPort->numFarEnd))
+    {
+        bound = (srcPort->farEnds[index].port != NULL);
+    }
+    UMLRTFrameService::rtsUnlock();
+
+    return bound;
+}
+
+int UMLRTProtocol::indexTo( const UMLRTCapsule * capsule ) const
+{
+    int index = -1;
+
+    UMLRTFrameService::rtsLock();
+
+    for (size_t i = 0; (i < srcPort->numFarEnd) && (index == -1); ++i)
+    {
+        if (srcPort->farEnds[i].port)
+        {
+            if (srcPort->farEnds[i].port->slot->capsule == capsule)
+            {
+                index = i;
+            }
+        }
+    }
+    UMLRTFrameService::rtsUnlock();
+
+    return index;
+}
+
+bool UMLRTProtocol::isIndexTo( int index, const UMLRTCapsule * capsule ) const
+{
+    bool isIndex = false;
+
+    UMLRTFrameService::rtsLock();
+
+    if ((index >= 0) && (index <= (int)srcPort->numFarEnd))
+    {
+        isIndex = (srcPort->farEnds[index].port->slot->capsule == capsule);
+    }
+    UMLRTFrameService::rtsUnlock();
+
+    return isIndex;
+}
+
+int UMLRTProtocol::purge()
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->purge();
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::purgeAt( int index )
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->purge(index);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::recall()
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->recall(-1/*index*/, false/*front*/, true/*one*/);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::recallAll()
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->recall(-1/*index*/, false/*front*/, false/*one*/);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::recallAllAt( int index, bool front )
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->recall(index, front, false/*one*/);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::recallAllFront()
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->recall(-1/*index*/, true/*front*/, false/*one*/);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::recallAt( int index, bool front )
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->recall(index, front, true/*one*/);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+int UMLRTProtocol::recallFront()
+{
+    int count;
+
+    UMLRTFrameService::rtsLock();
+
+    count = srcPort->recall(-1/*index*/, true/*front*/, true/*one*/);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return count;
+}
+
+/*static*/ bool UMLRTProtocol::registerSapPort( const UMLRTCommsPort * sapPort, const char * service )
+{
+    bool ok = false;
+
+    if (!sapPort->sap)
+    {
+        sapPort->slot->controller->setError(UMLRTController::E_SAPREG_NOT_SAP);
+    }
+    else
+    {
+        bool continueRegistration = false; // Set true if registration needs to be performed.
+
+        char * registeredName = (char *)getPortToNameMap()->getObject(sapPort);
+        if (registeredName != NULL)
+        {
+            // Already registered. See if it's registered to the same service.
+            if (strcmp(registeredName, service))
+            {
+                // Was registered to an another SPP - deregister it first, then continue.
+                deregisterSapPort(sapPort);
+                continueRegistration = true;
+            }
+            // else it was already registered to this service and we can skip the remainder of registration.
+        }
+        else
+        {
+            // Wasn't registered.
+            continueRegistration = true;
+        }
+        if (continueRegistration)
+        {
+            // Bind to SPP if possible.
+            const UMLRTCommsPort * sppPort = (const UMLRTCommsPort *)getNameToSppPortMap()->getObject(service);
+            bool bound = false;
+
+            if (sppPort != NULL)
+            {
+                // SPP found. Attempt to bind.
+                bound = UMLRTFrameService::bindServicePort(sapPort, sppPort);
+            }
+            if (!bound)
+            {
+                // SAP unable to bind to SPP. Queue for binding when an SPP port comes free.
+                addSapToQueue(service, sapPort);
+            }
+            completeRegistration(sapPort, service);
+        }
+        ok = true;
+    }
+    BDEBUG(BD_SAP, "SAP register slot %s port %s %s %s\n", sapPort->slot->name, sapPort->role()->name, ok ? "ok" : "failed", ok ? "" : sapPort->slot->controller->strerror());
+    return ok;
+}
+
+bool UMLRTProtocol::registerSAP( const char * service )
+{
+    UMLRTFrameService::rtsLock();
+
+    bool ok = registerSapPort(srcPort, service);
+
+    UMLRTFrameService::rtsUnlock();
+
+    return ok;
+}
+
+/*static*/ bool UMLRTProtocol::registerSppPort( const UMLRTCommsPort * sppPort, const char * service )
+{
+    bool ok = false;
+
+    if (!sppPort->spp)
+    {
+        sppPort->slot->controller->setError(UMLRTController::E_SPPREG_NOT_SPP);
+    }
+    else
+    {
+        // See if another port has this service registered already.
+        const UMLRTCommsPort * otherSpp = (const UMLRTCommsPort *)getNameToSppPortMap()->getObject(service);
+        if ((otherSpp != NULL) && (otherSpp != sppPort))
+        {
+            sppPort->slot->controller->setError(UMLRTController::E_SPPREG_PREVIOUS);
+        }
+        else if (otherSpp != NULL)
+        {
+            // This SPP was already registered under this service. Nothing more to do.
+            ok = true;
+        }
+        else
+        {
+            char * registeredName = (char *)getPortToNameMap()->getObject(sppPort);
+            if (registeredName != NULL)
+            {
+                // Already registered. See if it's registered to the same service.
+                if (strcmp(registeredName, service))
+                {
+                    // Registered to an another service - de-register it.
+                    deregisterSppPort(sppPort);
+                }
+            }
+            // Complete the registration and we'll use the port registeredName for the name-to-spp-port map.
+            completeRegistration(sppPort, service);
+
+            // Make this the SPP service provider. Memory associated with the port.
+            getNameToSppPortMap()->insert(sppPort->registeredName, (void *)sppPort);
+
+            // Bind any queued SAP port.
+            bindQueuedSapsToSpp(sppPort);
+
+            ok = true;
+        }
+    }
+    BDEBUG(BD_SAP, "SPP register slot %s port %s %s %s\n", sppPort->slot->name, sppPort->role()->name, ok ? "ok" : "failed", ok ? "" : sppPort->slot->controller->strerror());
+
+    return ok;
+}
+
+bool UMLRTProtocol::registerSPP( const char * service )
+{
+    UMLRTFrameService::rtsLock();
+
+    bool ok = registerSppPort( srcPort, service );
+
+    UMLRTFrameService::rtsUnlock();
+
+    return ok;
+}
+
+/*static*/ void UMLRTProtocol::removeSapFromQueue( const UMLRTCommsPort * sapPort )
+{
+    // Assumes RTS lock obtained.
+    UMLRTQueue * unboundSapPorts = (UMLRTQueue *)getNameToUnboundSapPortsMap()->getObject(sapPort->registeredName);
+    if (unboundSapPorts != NULL)
+    {
+        // This SPP had queued SAPs. Remove the de-registering SAP from the queue.
+        unboundSapPorts->remove((UMLRTQueue::match_compare_t)removeSapFromQueueMatchCompare, (UMLRTQueue::match_notify_t)removeSapFromQueueMatchNotify, (void *)sapPort, true/*one*/);
+        if (unboundSapPorts->isEmpty())
+        {
+            // If this was the last queued SAP, remove the queue and delete it. The name key has to be freed.
+            char * key = (char *)getNameToUnboundSapPortsMap()->remove(sapPort->registeredName);
+            if (key)
+            {
+                free(key);
+            }
+            delete unboundSapPorts;
+        }
+    }
+}
+
+/*static*/ bool UMLRTProtocol::removeSapFromQueueMatchCompare( UnboundSapPort * element, const UMLRTCommsPort * port )
+{
+    return element->port == port;
+}
+
+/*static*/ void UMLRTProtocol::removeSapFromQueueMatchNotify( UnboundSapPort * element, const UMLRTCommsPort * port )
+{
+    delete element;
+}
+
+/*static*/ void UMLRTProtocol::debugOutputPortToNameMap()
+{
+    // Assumes RTS lock obtained.
+    BDEBUG(BD_MODEL, "SAP/SPP Port to Service Name Registration: { <slot>, <port>, <service name>, <SAP/SPP>}\n");
+
+    UMLRTHashMap::Iterator iter = getPortToNameMap()->getIterator();
+
+    if (iter == iter.end())
+    {
+        BDEBUG(BD_MODEL, "    No registered SAP/SPP ports.\n");
+    }
+    else
+    {
+        while (iter != iter.end())
+        {
+            const UMLRTCommsPort * port = (const UMLRTCommsPort *)iter.getKey();
+            const char * service = (const char *)iter.getObject();
+            BDEBUG(BD_MODEL, "    { %s, %s, %s, %s }\n",
+                    port->slot->name,
+                    port->role()->name,
+                    port->registeredName == NULL ? "???" : port->registeredName,
+                    port->spp ? "SPP" : (port->sap ? "SAP" : "???"));
+
+            if (strcmp(service, port->registeredName))
+            {
+                FATAL("slot %s port %s registered name %s != port-to-name-map service %s",
+                        port->slot->name,
+                        port->role()->name,
+                        port->registeredName,
+                        service );
+            }
+            iter = iter.next();
+        }
+    }
+}
+
+/*static*/ void UMLRTProtocol::debugOutputNameToSppPortMap()
+{
+    // Assumes RTS lock obtained.
+    BDEBUG(BD_MODEL, "Service Name to SPP Port: { <service name>, <slot>, <port> }\n");
+
+    UMLRTHashMap::Iterator iter = getNameToSppPortMap()->getIterator();
+
+    if (iter == iter.end())
+    {
+        BDEBUG(BD_MODEL, "    No registered SPP ports.\n");
+    }
+    else
+    {
+        while (iter != iter.end())
+        {
+            const UMLRTCommsPort * port = (const UMLRTCommsPort *)iter.getObject();
+            const char * service = (const char *)iter.getKey();
+            BDEBUG(BD_MODEL, "    { %s, %s, %s }\n",
+                    service,
+                    port->slot->name,
+                    port->role()->name);
+            if (strcmp(service, port->registeredName))
+            {
+                FATAL("slot %s port %s registered name %s != name-to-spp-port-map service %s",
+                        port->slot->name,
+                        port->role()->name,
+                        port->registeredName,
+                        service );
+            }
+            iter = iter.next();
+        }
+    }
+}
+
+/*static*/ bool UMLRTProtocol::debugOutputQueuedSap( UnboundSapPort * unboundSapPort, const char * service )
+{
+    // Assumes RTS lock obtained.
+    const UMLRTCommsPort * port = unboundSapPort->port;
+
+    if (port == NULL)
+    {
+        FATAL("found NULL port in nameToUnboundSapPortsMap queue");
+    }
+
+    BDEBUG(BD_MODEL, "        { %s, %s }\n", port->slot->name, port->role()->name);
+
+    if (strcmp(service, port->registeredName))
+    {
+        FATAL("slot %s port %s registered name %s != unbound-sap-ports-map service %s",
+                port->slot->name,
+                port->role()->name,
+                port->registeredName,
+                service );
+    }
+    return false; // Never abort.
+}
+
+/*static*/ void UMLRTProtocol::debugOutputNameToUnboundSapPortsMap()
+{
+    // Assumes RTS lock obtained.
+    BDEBUG(BD_MODEL, "Service Name to unbound SAP Ports:\n");
+
+    UMLRTHashMap::Iterator iter = getNameToUnboundSapPortsMap()->getIterator();
+
+    if (iter == iter.end())
+    {
+        BDEBUG(BD_MODEL, "    No unbound SAP ports.\n");
+    }
+    else
+    {
+        while (iter != iter.end())
+        {
+            const char * service = (const char *)iter.getKey();
+            UMLRTQueue * unboundSapPorts = (UMLRTQueue *)iter.getObject();
+            BDEBUG(BD_MODEL, "    service '%s' queued SAP ports: { <slot>, <port> }\n", service );
+            if (!unboundSapPorts->walk((UMLRTQueue::walk_callback_t)debugOutputQueuedSap, (void *)service))
+            {
+                BDEBUG(BD_MODEL, "        No queued SAP ports.\n");
+            }
+            iter = iter.next();
+        }
+    }
+}
+
+/*static*/ void UMLRTProtocol::debugOutputServiceRegistration()
+{
+    // Assumes RTS lock obtained.
+    debugOutputPortToNameMap();
+    debugOutputNameToSppPortMap();
+    debugOutputNameToUnboundSapPortsMap();
+}
diff --git a/rts/umlrt/umlrtqueue.cc b/rts/umlrt/umlrtqueue.cc
new file mode 100644
index 0000000..c591959
--- /dev/null
+++ b/rts/umlrt/umlrtqueue.cc
@@ -0,0 +1,223 @@
+// umlrtqueue.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include "basefatal.hh"
+#include "basedebug.hh"
+#include "umlrtguard.hh"
+#include "umlrtqueue.hh"
+#include "umlrtqueueelement.hh"
+
+// See umlrtqueue.hh for documentation.
+
+// Create an empty queue.
+UMLRTQueue::UMLRTQueue() : head(0), tail(0), qid(0) {}
+
+// Queue creation can (optionally) add elements.
+UMLRTQueue::UMLRTQueue( UMLRTQueueElement * first, size_t arraySize, size_t elementSize) : head(0), tail(0), qid(0)
+{
+    if (arraySize)
+    {
+        head = first;
+
+        uint8_t * p = (uint8_t *)first;
+
+        tail = (UMLRTQueueElement *)(p + elementSize*(arraySize-1));
+
+        // Need to do pointer arithmetic to point to elements
+        UMLRTQueueElement * element = (UMLRTQueueElement *)p;
+        for (size_t i = 0; i < arraySize; ++i)
+        {
+            memset(p, 0, elementSize); // In case elements were not from BSS.
+            p += elementSize;
+            element->next = (UMLRTQueueElement *)p;
+            element->qid = qid++;
+            element = (UMLRTQueueElement *)p;
+
+        }
+        tail->next = NULL; // Above loop left tail->next pointing to first byte after pool.
+    }
+}
+
+// Remove the first element on the queue.
+const UMLRTQueueElement * UMLRTQueue::dequeue()
+{
+    UMLRTGuard g( mutex );
+    const UMLRTQueueElement * element = head;
+    if (element)
+    {
+        head = element->next;
+    }
+    return element;
+}
+
+// Add element on the tail of the queue.
+void UMLRTQueue::enqueue( const UMLRTQueueElement * element, bool front )
+{
+    UMLRTGuard g( mutex );
+
+    if (!front)
+    {
+        // Queue to tail.
+        element->next = NULL;
+        if (head == NULL)
+        {
+            // Queue was empty.
+            head = tail = element;
+        }
+        else
+        {
+            // Append to tail.
+            tail->next = element;
+            tail = element;
+        }
+    }
+    else
+    {
+        // Queue to front.
+        element->next = head;
+        if (head == NULL)
+        {
+            // Queue was empty.
+            tail = element;
+        }
+        head = element;
+    }
+}
+
+// Return all elements from the queue, still linked, and empty the queue.
+
+// Also returns the tail (as 'last') so the returned elements can be
+// efficiently appended to another queue.
+
+const UMLRTQueueElement * UMLRTQueue::dequeueAll( const UMLRTQueueElement * * last )
+{
+    UMLRTGuard g( mutex );
+
+    const UMLRTQueueElement * all = head;
+
+    *last = tail;
+
+    tail = head = NULL;
+
+    return( all );
+}
+
+// Append a list of elements (that are already linked together) to the queue.
+
+void UMLRTQueue::enqueueAll( const UMLRTQueueElement * all, const UMLRTQueueElement * last )
+{
+    UMLRTGuard g( mutex );
+
+    if (all)
+    {
+        if (!last)
+        {
+            FATAL("all != 0, last == 0");
+        }
+        if (!head)
+        {
+            // This queue was empty - input list is the new queue.
+            head = all;
+            tail = last;
+        }
+        else
+        {
+            // Append input list to the tail of this queue.
+            tail->next = all;
+            tail = last;
+        }
+    }
+}
+
+int UMLRTQueue::remove( match_compare_t compare, match_notify_t notify, void * userData, bool one )
+{
+    int count = 0;
+
+    UMLRTGuard g( mutex );
+
+    // Start at the head and delete until the head no longer needs deleting.
+    const UMLRTQueueElement * headcopy;
+    bool done = false;
+    bool notified = false;
+    while (((headcopy = head) != NULL) && !done)
+    {
+        if (compare(head, userData))
+        {
+            // This head has to go. Unlink it - we've remembered it for notify.
+            head = head->next;
+
+            notify(headcopy, userData);
+
+            notified = true;
+            ++count;
+            if (one)
+            {
+                done = true;
+            }
+        }
+        else
+        {
+            done = true;
+        }
+    }
+    // Head is either NULL or not to be purged (a 'keeper')- we've checked it above.
+    // Go through queue and potentially delete the ones after the last 'keeper'.
+    done = (one && notified);
+
+    if (head != NULL && !done)
+    {
+        const UMLRTQueueElement * keeper = head;
+        const UMLRTQueueElement * candidate;
+
+        while ((candidate = keeper->next) != NULL)
+        {
+            // See if this candidate needs removal.
+            if (compare(candidate, userData))
+            {
+                // Unlink candidate from queue.
+                keeper->next = candidate->next;
+
+                // Notify caller that we've removed it.
+                notify(candidate, userData);
+                ++count;
+                if (one)
+                {
+                    done = true;
+                }
+            }
+            else
+            {
+                // Didn't delete candidate. It's the next 'keeper'.
+                keeper = candidate;
+            }
+        }
+        tail = keeper;
+    }
+    return count;
+}
+
+int UMLRTQueue::walk( walk_callback_t callback, void * userData ) const
+{
+    UMLRTGuard g( mutex );
+
+    int count = 0;
+
+    const UMLRTQueueElement * element = head;
+
+    while (element != NULL)
+    {
+        callback( element, userData );
+        count++;
+        element = element->next;
+    }
+    return count;
+}
diff --git a/rts/umlrt/umlrtrtsinterfaceumlrt.cc b/rts/umlrt/umlrtrtsinterfaceumlrt.cc
new file mode 100644
index 0000000..a4773c5
--- /dev/null
+++ b/rts/umlrt/umlrtrtsinterfaceumlrt.cc
@@ -0,0 +1,57 @@
+// umlrtrtsinterfaceumlrt.cc
+
+/*******************************************************************************
+* Copyright (c) 2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportfarend.hh"
+#include "umlrtframeservice.hh"
+#include "umlrtrtsinterfaceumlrt.hh"
+
+void UMLRTRtsInterfaceUmlrt::connectPorts ( const UMLRTCommsPort * p1, size_t p1Index, const UMLRTCommsPort * p2, size_t p2Index ) const
+{
+    UMLRTFrameService::connectPorts(p1, p1Index, p2, p2Index);
+}
+
+void UMLRTRtsInterfaceUmlrt::connectRelayPort ( const UMLRTCommsPort * relayPort, size_t relayIndex, const UMLRTCommsPort * destPort, size_t destIndex ) const
+{
+    UMLRTFrameService::connectRelayPort(relayPort, relayIndex, destPort, destIndex);
+}
+
+const UMLRTCommsPort * * UMLRTRtsInterfaceUmlrt::createBorderPorts ( UMLRTSlot * slot, size_t numPorts ) const
+{
+    return UMLRTFrameService::createBorderPorts(slot, numPorts);
+}
+
+const UMLRTCommsPort * UMLRTRtsInterfaceUmlrt::createInternalPorts ( UMLRTSlot * slot, const UMLRTCapsuleClass * capsuleClass, size_t numPortRoles, const UMLRTCommsPortRole portRoles[] ) const
+{
+    return UMLRTFrameService::createPorts(slot, capsuleClass, numPortRoles, portRoles, false/*border*/);
+}
+
+void UMLRTRtsInterfaceUmlrt::bindPort ( const UMLRTCommsPort * port, int index ) const
+{
+    UMLRTFrameService::sendBoundUnbound(port, index, port->farEnds[index].port, port->farEnds[index].farEndIndex, true/*isBind*/);
+    UMLRTFrameService::sendBoundUnbound(port->farEnds[index].port, port->farEnds[index].farEndIndex, port, index, true/*isBind*/);
+}
+
+void UMLRTRtsInterfaceUmlrt::bindSubcapsulePort ( bool isBorder, UMLRTCapsule * subcapsule, int portIndex, int farEndIndex ) const
+{
+    UMLRTFrameService::bindSubcapsulePort(isBorder, subcapsule, portIndex, farEndIndex);
+}
+
+void UMLRTRtsInterfaceUmlrt::unbindPort ( const UMLRTCommsPort * port, int index ) const
+{
+    UMLRTFrameService::sendBoundUnbound(port, index, port->farEnds[index].port, port->farEnds[index].farEndIndex, false/*isBind*/);
+    UMLRTFrameService::sendBoundUnbound(port->farEnds[index].port, port->farEnds[index].farEndIndex, port, index, false/*isBind*/);
+    UMLRTFrameService::disconnectPort(port, index);
+}
+
+void UMLRTRtsInterfaceUmlrt::unbindSubcapsulePort ( bool isBorder, UMLRTCapsule * subcapsule, int portIndex, int farEndIndex ) const
+{
+    UMLRTFrameService::unbindSubcapsulePort(isBorder, subcapsule, portIndex, farEndIndex);
+}
diff --git a/rts/umlrt/umlrtsemaphore.cc b/rts/umlrt/umlrtsemaphore.cc
new file mode 100644
index 0000000..7768567
--- /dev/null
+++ b/rts/umlrt/umlrtsemaphore.cc
@@ -0,0 +1,77 @@
+// umlrtmutex.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+
+#include <errno.h>
+#include <stdio.h>
+#include "basefatal.hh"
+#include "umlrtsemaphore.hh"
+#include "umlrttimespec.hh"
+
+// UMLRTSemaphore is platform-independent semaphore.
+
+// Bug 32 tracks the move of this implementation to +/os/linux/ossemaphore.cc
+
+UMLRTSemaphore::UMLRTSemaphore( int value )
+{
+    if (sem_init(&sem, 0/*threads only*/, value) < 0)
+    {
+        FATAL_ERRNO("sem_init");
+    }
+}
+
+UMLRTSemaphore::~UMLRTSemaphore()
+{
+    if (sem_destroy(&sem) < 0)
+    {
+        FATAL_ERRNO("sem_destroy");
+    }
+}
+
+// Wait forever for mutex.
+void UMLRTSemaphore::wait()
+{
+    if (sem_wait(&sem) < 0)
+    {
+        FATAL_ERRNO("sem_wait");
+    }
+}
+
+// Timed - returns non-zero for success, zero for timeout.
+int UMLRTSemaphore::wait( uint32_t msec )
+{
+    struct timespec timeout;
+    int success = !0;
+
+    UMLRTTimespec::timespecAbsAddMsec( &timeout, msec );
+    if (sem_timedwait(&sem, &timeout) < 0)
+    {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+        int errno_ = errno;
+#pragma GCC diagnostic pop
+        if (errno_ != ETIMEDOUT)
+        {
+            perror("UMLRTSemaphore wait");
+            FATAL("sem_timedwait (had waited %d msec)", msec);
+        }
+        success = 0;
+    }
+    return success;
+}
+
+// Give mutex back.
+void UMLRTSemaphore::post()
+{
+    if (sem_post(&sem) < 0)
+    {
+        FATAL_ERRNO("sem_wait");
+    }
+}
diff --git a/rts/umlrt/umlrtsignal.cc b/rts/umlrt/umlrtsignal.cc
new file mode 100644
index 0000000..e874918
--- /dev/null
+++ b/rts/umlrt/umlrtsignal.cc
@@ -0,0 +1,169 @@
+// umlrtsignal.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include <stdlib.h>
+#include "umlrtapi.hh"
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportfarend.hh"
+#include "umlrtcontroller.hh"
+#include "umlrtframeservice.hh"
+#include "umlrtsignal.hh"
+#include "umlrtsignalelement.hh"
+#include "umlrtuserconfig.hh"
+#include "basefatal.hh"
+#include "basedebugtype.hh"
+#include "basedebug.hh"
+
+// See umlrtsignal.hh for documentation.
+
+// No signal element by default - equivalent to the 'invalid signal'.
+// An element is allocated when signal is 'initialized'.
+UMLRTSignal::UMLRTSignal() : element(NULL)
+{
+}
+
+UMLRTSignal::~UMLRTSignal()
+{
+    if (element)
+    {
+        element->decrementRefCount();
+    }
+}
+
+UMLRTSignal::UMLRTSignal( const UMLRTSignal &signal ) : element(signal.element)
+{
+    if (element)
+    {
+        element->incrementRefCount();
+    }
+}
+
+UMLRTSignal &UMLRTSignal::operator=( const UMLRTSignal &signal )
+{
+    if (&signal != this)
+    {
+        if (element)
+        {
+            element->decrementRefCount();
+        }
+        if (signal.element)
+        {
+            signal.element->incrementRefCount();
+        }
+        element = signal.element;
+    }
+    return *this;
+}
+
+bool UMLRTSignal::initialize( Id id, const UMLRTCommsPort * srcPort, size_t payloadSize, UMLRTSignalElement::Priority priority )
+{
+    BDEBUG(BD_SIGNAL, "initialize signal-qid[%d] id %d for slot %s port %s payloadSize %d\n",
+            getQid(),
+            id,
+            (srcPort != NULL) ? srcPort->slot->name : "(slot unknown)",
+            (srcPort != NULL) ? srcPort->role()->name : "(no source port)",
+            payloadSize);
+
+    // Initialize for a wired port. If the srcPort is 'the unbound port', there is no need for a signal element with a payload
+    // as nothing will be sent. The current protocol code pattern requires the element with a payload, so we allocate one.
+    // When Bug 231 is resolved, we can avoid allocating an element and payload when the srcPort is 'the unbound port'.
+    if (element)
+    {
+        FATAL("initializing signal that already has an element signal-qid[%d] allocated.", element->qid);
+    }
+    element = umlrt::SignalElementGetFromPool();
+
+    if (!element)
+    {
+        FATAL("failed to allocate signal element");
+    }
+    element->initialize( id, srcPort, payloadSize, priority );
+
+    if (srcPort == NULL)
+    {
+        FATAL("initializing a signal that has no srcPort - should at least be the 'unbound port'");
+    }
+    return !srcPort->unbound;
+}
+
+// Basic initialization. Currently used for initialize message to capsules.
+void UMLRTSignal::initialize( size_t payloadSize, UMLRTSignalElement::Priority priority )
+{
+    if (element)
+    {
+        FATAL("initializing signal that already has an element allocated.");
+    }
+    element = umlrt::SignalElementGetFromPool();
+
+    if (!element)
+    {
+        FATAL("failed to allocate signal element");
+    }
+    BDEBUG(BD_SIGNAL, "allocate no id, srcPort or payloadSize\n");
+
+    element->initialize( payloadSize, priority );
+}
+
+// Basic initialization. Currently used for in-signals.
+void UMLRTSignal::initialize( Id id, const UMLRTCommsPort * srcPort )
+{
+    if (element)
+    {
+        FATAL("initializing signal that already has an element allocated.");
+    }
+    element = umlrt::SignalElementGetFromPool();
+
+    if (!element)
+    {
+        FATAL("failed to allocate signal element");
+    }
+    BDEBUG(BD_SIGNAL, "allocate no id, srcPort or payloadSize\n");
+
+    element->initialize(id, srcPort);
+}
+
+
+// Get the payload buffer.
+uint8_t *UMLRTSignal::getPayload() const
+{
+    if (!element)
+    {
+        return NULL;
+    }
+    return element->getPayload();
+}
+
+// Get the payload buffer.
+size_t UMLRTSignal::getPayloadSize() const
+{
+    if (!element)
+    {
+        return 0;
+    }
+    return element->getPayloadSize();
+}
+
+const UMLRTCommsPort * UMLRTSignal::getSrcPort() const
+{
+    if (!element)
+    {
+        return NULL;
+    }
+    return element->getSrcPort();
+}
+
+UMLRTSignal::Id UMLRTSignal::getId() const
+{
+    if (!element)
+    {
+        return -1; // Another example of using '-1' when we don't have a signal id.
+    }
+    return element->getId();
+}
diff --git a/rts/umlrt/umlrtsignalelement.cc b/rts/umlrt/umlrtsignalelement.cc
new file mode 100644
index 0000000..3b4f879
--- /dev/null
+++ b/rts/umlrt/umlrtsignalelement.cc
@@ -0,0 +1,229 @@
+// umlrtsignalelement.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include <stdlib.h>
+#include "basedebug.hh"
+#include "basedebugtype.hh"
+#include "basefatal.hh"
+#include "umlrtapi.hh"
+#include "umlrtslot.hh"
+#include "umlrtcommsportrole.hh"
+#include "umlrtguard.hh"
+#include "umlrtobjectclass.hh"
+#include "umlrtsignalelement.hh"
+#include "umlrtuserconfig.hh"
+
+// See umlrtsignalelement.hh for documentation.
+
+UMLRTSignalElement::UMLRTSignalElement() : id(0), srcPort(0), defaultPayload(0), payload(0), priority(PRIORITY_NORMAL), appPayloadSize(0),
+            maxPayloadSize(USER_CONFIG_SIGNAL_DEFAULT_PAYLOAD_SIZE), nonDefaultPayload(false), allocated(false), refCount(0)
+{
+    // DEFAULT PAYLOAD SIZE IS A CONSTANT HERE, BUT HAS TO BE OBTAINED AT RUN-TIME.
+    if (!(defaultPayload = payload = (uint8_t*)malloc(USER_CONFIG_SIGNAL_DEFAULT_PAYLOAD_SIZE)))
+    {
+        FATAL("(%p) payload malloc(%d)",this, USER_CONFIG_SIGNAL_DEFAULT_PAYLOAD_SIZE);
+    }
+    BDEBUG(BD_SIGNALINIT, "(%p) signal element payload(%p)\n", this, payload);
+}
+
+// Initialize a signal from the pool and make sure the payload is large enough.
+
+void UMLRTSignalElement::initialize( size_t payloadSize_, Priority priority_ )
+{
+    BDEBUG(BD_SIGNAL, "[%p] initialize no id, srcPort or payloadSize\n", this);
+
+    srcPort = NULL; // No srcPort by default.
+
+    id = -1; // The signal id of '-1' used for 'uninitialized id value'.
+    priority = priority_;
+
+    if (refCount)
+    {
+        FATAL("(%p) signal element alloc refcount non-zero(%d)", this, refCount);
+    }
+    // If the user is requesting more space than is available in the
+    // default payload buffer, allocate it here.
+
+    // THIS CONSTANT MAY HAVE TO BE OBTAINED AT RUN-TIME FROM THE
+    // GENERATED USER-CONFIGURATION PARAMETERS, IF THE VALUES FROM umlrtapi.hh ARE NOT USED.
+    if (payloadSize_ > USER_CONFIG_SIGNAL_DEFAULT_PAYLOAD_SIZE)
+    {
+        if (!(payload = (uint8_t *)malloc(payloadSize_)))
+        {
+            FATAL("(%p) non-default payload malloc(%d)", this, payloadSize_ );
+        }
+        nonDefaultPayload = true;
+        maxPayloadSize = payloadSize_;
+    }
+    appPayloadSize = payloadSize_;
+
+    // Initialize encoding.
+    encodeInfo = payload;
+
+    incrementRefCount();
+}
+// Initialize a signal from the pool and make sure the payload is large enough.
+
+void UMLRTSignalElement::initialize( Id id_, const UMLRTCommsPort * srcPort_, size_t payloadSize_, Priority priority_ )
+{
+    if (!srcPort_)
+    {
+        SWERR("(%p) signal allocate src port == 0.", this);
+    }
+
+    initialize(payloadSize_); // Default initialization.
+
+    id = id_;
+    srcPort = srcPort_;
+    priority = priority_;
+    
+    BDEBUG(BD_SIGNAL, "[%p] initialize id(%d) %s(%s) appPayloadSize(%d) maxPayloadSize(%d)\n",
+            this, id,
+            (srcPort_ != NULL) ? srcPort->slot->name : "(NULL src port)",
+            (srcPort_ != NULL) ? srcPort->role()->name : "(NULL src port)",
+            appPayloadSize,
+            maxPayloadSize);
+}
+
+void UMLRTSignalElement::initialize( Id id_, const UMLRTCommsPort * srcPort_ )
+{
+    if (!srcPort_)
+    {
+        SWERR("(%p) signal allocate src port == 0.", this);
+    }
+
+    initialize(0); // Default initialization.
+
+    id = id_;
+    srcPort = srcPort_;
+
+    BDEBUG(BD_SIGNAL, "[%p] initialize id(%d) %s(%s) appPayloadSize(%d) maxPayloadSize(%d)\n",
+            this, id,
+            (srcPort_ != NULL) ? srcPort->slot->name : "(NULL src port)",
+            (srcPort_ != NULL) ? srcPort->role()->name : "(NULL src port)",
+            appPayloadSize,
+            maxPayloadSize);
+}
+
+// Free a signal element (return to the pool).
+
+/*static*/ void UMLRTSignalElement::dealloc( UMLRTSignalElement * element )
+{
+    if (!element)
+    {
+        FATAL("element NULL");
+    }
+    BDEBUG(BD_SIGNAL, "[%p] deallocate id(%d) srcPort(%s) appPayloadSize(%d) maxPayloadSize(%d)\n",
+            element, element->id, element->srcPort ? element->srcPort->role()->name : "NONE", element->appPayloadSize, element->maxPayloadSize);
+
+    if (element->refCount)
+    {
+        FATAL("(%p) signal element dealloc refcount non-zero(%d)", element, element->refCount);
+    }
+
+    if (element->nonDefaultPayload)
+    {
+        // Return non-default payload.
+        free(element->payload);
+
+        // Restore default payload.
+        element->payload = element->defaultPayload;
+        element->maxPayloadSize = USER_CONFIG_SIGNAL_DEFAULT_PAYLOAD_SIZE;
+        element->appPayloadSize = 0; // Should be unused while deallocated.
+    }
+    umlrt::SignalElementPutToPool(element);
+}
+
+void UMLRTSignalElement::incrementRefCount() const
+{
+    BDEBUG(BD_SIGNALREF, "(%p) signal element inc ref count(%d)\n", this, refCount);
+
+    UMLRTGuard g(refCountMutex);
+
+    ++refCount;
+}
+
+void UMLRTSignalElement::decrementRefCount() const
+{
+    BDEBUG(BD_SIGNALREF, "(%p) signal element dec ref count(%d)\n", this, refCount);
+
+    UMLRTGuard g(refCountMutex);
+    if (refCount <= 0)
+    {
+        FATAL("(%p) signal element dec ref count that is already zero id(%d)", this, id);
+    }
+    else if (!(--refCount))
+    {
+        BDEBUG(BD_SIGNALREF, "(%p) signal element dec ref count == 0 dealloc\n", this);
+
+        UMLRTSignalElement::dealloc(const_cast<UMLRTSignalElement *>(this));
+    }
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTSignalElement::encode( const UMLRTObject_class * desc, const void * data, int arraySize )
+{
+    // encodeInfo is intitialized to be 'payload' when the signal is initialized.
+    // It is moved forward during successive #encode calls.
+    for (int i = 0; i < arraySize; ++i)
+    {
+        encodeInfo = desc->encode(desc, data, encodeInfo);
+    }
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTSignalElement::encode( const UMLRTObject_class * desc, int ptrIndirection, const void * data, int arraySize )
+{
+    FATAL("encode ptr indirection not implemented.");
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTSignalElement::decode( void * * decodeInfo, const UMLRTObject_class * desc, void * data, int arraySize )
+{
+    // decodeInfo is initialized to be NULL by a decoder - it is owned by the decoder and not by
+    // the signal (contrary to the encodeInfo, which can be owned by the signal, since there is always
+    // only ever one encoder).
+
+    if (!(*decodeInfo))
+    {
+        *decodeInfo = payload;
+    }
+    for (int i = 0; i < arraySize; ++i)
+    {
+        *decodeInfo = desc->decode(desc, *decodeInfo, data);
+    }
+}
+
+// See documentation in UMLRTSignal.
+void UMLRTSignalElement::decode( void * * decodeInfo, const UMLRTObject_class * desc, int ptrIndirection, void * data, int arraySize )
+{
+    FATAL("decode ptr indirection not implemented.");
+}
+
+void UMLRTSignalElement::setAllocated( bool allocated_ )
+{
+    if (allocated_)
+    {
+        if (allocated)
+        {
+            FATAL("signal-qid[%d] was already allocated", qid);
+        }
+        allocated = true;
+    }
+    else
+    {
+        if (!allocated)
+        {
+            FATAL("signal-qid[%d] was already deallocated", qid);
+        }
+        allocated = false;
+    }
+}
+
diff --git a/rts/umlrt/umlrtsignalelementpool.cc b/rts/umlrt/umlrtsignalelementpool.cc
new file mode 100644
index 0000000..cc6661e
--- /dev/null
+++ b/rts/umlrt/umlrtsignalelementpool.cc
@@ -0,0 +1,51 @@
+// umlrtsignalelementpool.cc
+
+/*******************************************************************************
+ * Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+// See umlrtsignalpool.hh for documentation.
+#include <stdlib.h>
+#include "basefatal.hh"
+#include "umlrtguard.hh"
+#include "umlrtsignalelementpool.hh"
+
+UMLRTSignalElementPool::UMLRTSignalElementPool(UMLRTSignalElement signalElements[],
+        size_t arraySize, size_t incrementSize) :
+        UMLRTPool(incrementSize)
+{
+    UMLRTGuard g(mutex);
+
+    if (arraySize && signalElements != NULL)
+    {
+        for (size_t i = arraySize - 1; i > 0; --i)
+        {
+            signalElements[i - 1].next = &signalElements[i];
+            signalElements[i - 1].qid = qid++;
+        }
+        head = &signalElements[0];
+    }
+}
+
+UMLRTSignalElementPool::UMLRTSignalElementPool(size_t incrementSize) :
+        UMLRTPool(incrementSize)
+{
+
+}
+
+void UMLRTSignalElementPool::grow()
+{
+    UMLRTSignalElement * newElements = new UMLRTSignalElement[increment]();
+
+    for (size_t i = increment - 1; i > 0; --i)
+    {
+        newElements[i - 1].next = &newElements[i];
+    }
+    newElements[increment - 1].next = head;
+    head = &newElements[0];
+}
+
diff --git a/rts/umlrt/umlrttimerid.cc b/rts/umlrt/umlrttimerid.cc
new file mode 100644
index 0000000..ff414a9
--- /dev/null
+++ b/rts/umlrt/umlrttimerid.cc
@@ -0,0 +1,23 @@
+// umlrttimerid.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrttimer.hh"
+#include "umlrttimerid.hh"
+#include "basefatal.hh"
+
+// Must have previously confirmed the timer #isValid.
+const UMLRTTimer * UMLRTTimerId::getTimer() const
+{
+    if (!timer)
+    {
+        FATAL("timer is invalid");
+    }
+    return timer;
+}
diff --git a/rts/umlrt/umlrttimerpool.cc b/rts/umlrt/umlrttimerpool.cc
new file mode 100644
index 0000000..bf43bad
--- /dev/null
+++ b/rts/umlrt/umlrttimerpool.cc
@@ -0,0 +1,50 @@
+// umlrttimerpool.cc
+
+/*******************************************************************************
+ * Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *******************************************************************************/
+
+// See umlrttimer.hh for documentation.
+#include <stdlib.h>
+#include "basefatal.hh"
+#include "umlrttimerpool.hh"
+#include "umlrtguard.hh"
+
+UMLRTTimerPool::UMLRTTimerPool(UMLRTTimer timerElements[], size_t arraySize, size_t incrementSize) :
+        UMLRTPool(incrementSize)
+{
+    UMLRTGuard g(mutex);
+
+    if (arraySize && timerElements != NULL)
+    {
+        for (size_t i = arraySize - 1; i > 0; --i)
+        {
+            timerElements[i - 1].next = &timerElements[i];
+            timerElements[i - 1].qid = qid++;
+        }
+        head = &timerElements[0];
+    }
+}
+
+UMLRTTimerPool::UMLRTTimerPool(size_t incrementSize) :
+        UMLRTPool(incrementSize)
+{
+
+}
+
+void UMLRTTimerPool::grow()
+{
+    UMLRTTimer * newElements = new UMLRTTimer[increment]();
+
+    for (size_t i = increment - 1; i > 0; --i)
+    {
+        newElements[i - 1].next = &newElements[i];
+    }
+    newElements[increment - 1].next = head;
+    head = &newElements[0];
+}
+
diff --git a/rts/umlrt/umlrttimerprotocol.cc b/rts/umlrt/umlrttimerprotocol.cc
new file mode 100644
index 0000000..6c7e293
--- /dev/null
+++ b/rts/umlrt/umlrttimerprotocol.cc
@@ -0,0 +1,204 @@
+// umlrttimerprotocol.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrtslot.hh"
+#include "umlrtcommsport.hh"
+#include "umlrtcommsportrole.hh"
+#include "umlrtcontroller.hh"
+#include "umlrttimerprotocol.hh"
+#include "umlrttimer.hh"
+#include "umlrttimerid.hh"
+#include "umlrtapi.hh"
+#include "basefatal.hh"
+#include "basedebugtype.hh"
+#include "basedebug.hh"
+#include <stdlib.h>
+
+// Protocol implementation for timer ports.
+
+// Allocate a timer.
+/*static*/ UMLRTTimerId UMLRTTimerProtocol::allocateTimer( const UMLRTCommsPort * srcPort, bool isRelative, bool isInterval, const UMLRTTimespec & due,
+        UMLRTSignalElement::Priority priority, const void * userData, const UMLRTObject_class * type )
+{
+    UMLRTTimer * timer = umlrt::TimerGetFromPool();
+
+    if (!timer)
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_TIMER_GET);
+    }
+    else if (!timer->allocated)
+    {
+        FATAL("allocated timer not deemed allocated.");
+    }
+    else
+    {
+        if (isRelative)
+        {
+            UMLRTTimespec now;
+            UMLRTTimespec::getClock(&now);
+            timer->due = now + due;
+        }
+        else
+        {
+            timer->due = due;
+        }
+        timer->isInterval = isInterval;
+        if (isInterval)
+        {
+            timer->interval = due;
+        }
+        timer->destPort = srcPort;
+        timer->destSlot = srcPort->slot;
+
+        size_t payloadSize = 0;
+        if (userData)
+        {
+            if (!type)
+            {
+                FATAL("user data requires a type descriptor");
+            }
+            payloadSize = type->getSize(type);
+        }
+        timer->signal.initialize(UMLRTTimerProtocol::signal_timeout, srcPort, payloadSize, priority);
+
+        char buf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+
+        BDEBUG(BD_TIMER, "allocate timer(%p) destPort(%s) isInterval(%d) priority(%d) payloadSize(%d) due(%s)\n",
+                timer, timer->destPort->role()->name, timer->isInterval, timer->signal.getPriority(), timer->signal.getPayloadSize(),
+                timer->isInterval ? timer->due.toStringRelative(buf, sizeof(buf)) : timer->due.toString(buf, sizeof(buf)));
+
+        if (userData)
+        {
+            timer->signal.encode(userData, type);
+        }
+    }
+    return UMLRTTimerId(timer);
+}
+
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informAt( const UMLRTCommsPort * srcPort, const UMLRTTimespec & clockTime, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, false, false, clockTime, priority, NULL, NULL);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informAt( const UMLRTCommsPort * srcPort, const UMLRTTimespec & clockTime, const void * userData, const UMLRTObject_class * type, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, false, false, clockTime, priority, userData, type);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informAt( const UMLRTCommsPort * srcPort, const UMLRTTimespec & clockTime, const UMLRTTypedValue & typedValue, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, false, false, clockTime, priority, typedValue.data, typedValue.type);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informIn( const UMLRTCommsPort * srcPort, const UMLRTTimespec & relativeTime, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, true, false, relativeTime, priority, NULL, NULL);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informIn( const UMLRTCommsPort * srcPort, const UMLRTTimespec & relativeTime, void * userData, const UMLRTObject_class * type, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, true, false, relativeTime, priority, userData, type);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informIn( const UMLRTCommsPort * srcPort, const UMLRTTimespec & relativeTime, const UMLRTTypedValue & typedValue, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, true, false, relativeTime, priority, typedValue.data, typedValue.type);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informEvery( const UMLRTCommsPort * srcPort, const UMLRTTimespec & relativeTime, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, true, true, relativeTime, priority, NULL, NULL);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informEvery( const UMLRTCommsPort * srcPort, const UMLRTTimespec & relativeTime, void * userData, const UMLRTObject_class * type, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, true, true, relativeTime, priority, userData, type);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+const UMLRTTimerId UMLRTTimerProtocol::OutSignals::informEvery( const UMLRTCommsPort * srcPort, const UMLRTTimespec & relativeTime, const UMLRTTypedValue & typedValue, UMLRTSignalElement::Priority priority ) const
+{
+    UMLRTTimerId id = allocateTimer(srcPort, true, true, relativeTime, priority, typedValue.data, typedValue.type);
+
+    if (id.isValid())
+    {
+        // Pass the timer to the controller to monitor it.
+        srcPort->slot->controller->startTimer(id.getTimer());
+    }
+    return id;
+}
+
+bool UMLRTTimerProtocol::OutSignals::cancelTimer( const UMLRTCommsPort * srcPort, const UMLRTTimerId id ) const
+{
+    if (!id.isValid())
+    {
+        srcPort->slot->controller->setError(UMLRTController::E_TIMER_CANC_INV);
+        return false;
+    }
+    return srcPort->slot->controller->cancelTimer(id);
+}
+
+void UMLRTTimerProtocol::OutSignals::timeAdjustStart( const UMLRTCommsPort * srcPort ) const
+{
+    FATAL("timer adjust start not implemented");
+}
+void UMLRTTimerProtocol::OutSignals::timeAdjustComplete(const UMLRTCommsPort * srcPort, const UMLRTTimespec & delta ) const
+{
+    FATAL("timer adjust complete not implemented");
+}
diff --git a/rts/umlrt/umlrttimerqueue.cc b/rts/umlrt/umlrttimerqueue.cc
new file mode 100644
index 0000000..1160758
--- /dev/null
+++ b/rts/umlrt/umlrttimerqueue.cc
@@ -0,0 +1,273 @@
+// umlrttimerqueue.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "basefatal.hh"
+#include "basedebug.hh"
+#include "umlrtapi.hh"
+#include "umlrtguard.hh"
+#include "umlrttimer.hh"
+#include "umlrttimerqueue.hh"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+
+// See umlrttimerqueue.hh for documentation.
+
+UMLRTTimerQueue::UMLRTTimerQueue() : UMLRTQueue()
+{
+    // Appenders write the pipe. Controllers 'wait' on a select() on the pipe with
+    // a timeout associated with any running timer. A write on the pipe wakes the controller.
+    if (pipe(notifyFd) < 0)
+    {
+        FATAL_ERRNO("pipe");
+    }
+    // Bytes available in the pipe wake up the controller as 'notify'. The controller
+    // has to be able to clean out the pipe (read) without blocking.
+    int flags = fcntl(notifyFd[0], F_GETFL, 0);
+    if (flags < 0)
+    {
+        FATAL_ERRNO("fcntl F_GETFL");
+    }
+    if (fcntl(notifyFd[0], F_SETFL, flags | O_NONBLOCK) < 0)
+    {
+        FATAL_ERRNO("fcntl F_SETFL");
+    }
+}
+
+// Remove the first timer on the queue. Returns NULL if first timer has not yet expired.
+UMLRTTimer * UMLRTTimerQueue::dequeue()
+{
+    UMLRTGuard(getMutex());
+
+    UMLRTTimer * first = (UMLRTTimer *)head;
+
+    if (first)
+    {
+        UMLRTTimespec now;
+        UMLRTTimespec::getClock(&now);
+
+        if (now >= first->due)
+        {
+            // First timer is due - dequeue it and return it.
+            head = first->next;
+            if (head == NULL)
+            {
+                tail = NULL; // Not required, but cleaner.
+            }
+            BDEBUG(BD_TIMER, "this(%p) dequeue found first timer due.\n", this);
+        }
+        else
+        {
+            // First timer still running - leave it there.
+            first = NULL;
+            BDEBUG(BD_TIMER, "this(%p) dequeue found first timer still running.\n", this);
+        }
+    }
+    else
+    {
+        BDEBUG(BD_TIMER, "this(%p) dequeue found no timers.\n", this);
+    }
+    return first;
+}
+
+// Add a timer to the queue in the order of when they will expire.
+void UMLRTTimerQueue::enqueue( const UMLRTTimer * timer )
+{
+    UMLRTGuard(getMutex());
+
+    UMLRTTimer * next = (UMLRTTimer *)head;
+    UMLRTTimer * previous = NULL;
+
+    char tmbuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+    BDEBUG(BD_TIMER, "this(%p) timer-enqueue due(%s)\n", this, timer->due.toString(tmbuf,sizeof(tmbuf)));
+
+    timer->next = NULL; // Initialize as last-in-queue.
+
+    // Only need to notify the controller if the new timer ends up at the head of the queue.
+    // The wait mechanism is only interested in the time remaining for the timer at the head of the queue.
+    if (!head)
+    {
+        // List was empty. Put it in there as only element.
+        head = tail = timer;
+        sendNotification();
+    }
+    else
+    {
+        // Skip ahead until we meet a timer due after this one.
+        while (next && (next->due <= timer->due))
+        {
+            previous = next;
+            next = (UMLRTTimer *)next->next;
+        }
+        if (!next)
+        {
+            // We're appending this timer to the end of the queue.
+            tail->next = timer;
+            tail = timer;
+        }
+        else if (!previous)
+        {
+            // This timer is before the first element in the queue - prepend it.
+            timer->next = head;
+            head = timer;
+            sendNotification();
+        }
+        else
+        {
+            // This timer goes after 'previous' and before 'next'.
+            previous->next = timer;
+            timer->next = next;
+        }
+    }
+}
+
+// Calculate how much time left before timer on the head of the queue is due.
+UMLRTTimespec UMLRTTimerQueue::timeRemaining() const
+{
+    UMLRTGuard(getMutex());
+
+    // NOTE: Intended only for the consumer of the queue elements which has confirmed
+    // the queue was non-empty. An alternate implementation is required if an empty queue
+    // is possible.
+    if (isEmpty())
+    {
+        FATAL("timer queue was empty in timeRemaining()");
+    }
+    UMLRTTimespec now;
+    UMLRTTimespec::getClock(&now);
+
+    BDEBUG(BD_TIMER, "this(%p) head(%p) tail(%p)\n", this, head, tail);
+
+    UMLRTTimespec remain = ((UMLRTTimer*)head)->due - now;
+
+    char tmbuf[UMLRTTimespec::TIMESPEC_TOSTRING_SZ];
+    BDEBUG(BD_TIMER, "timeRemaining %s\n", remain.toStringRelative(tmbuf, sizeof(tmbuf)));
+
+    return remain;
+}
+
+// Add a timer to the queue in the order of when they will expire.
+bool UMLRTTimerQueue::cancel( UMLRTTimerId id )
+{
+    UMLRTGuard(getMutex());
+
+    bool ok = false;
+    UMLRTTimer * next = (UMLRTTimer *)head;
+    UMLRTTimer * previous = NULL;
+
+    while (next && (next != id.getTimer()))
+    {
+        previous = next;
+        next = (UMLRTTimer *)next->next;
+    }
+    // Only need to notify the controller if the cancelled timer was at the head of the queue.
+    if (next)
+    {
+        // Found the one to delete.
+        if (!previous)
+        {
+            // This timer was at the head of the queue.
+            head = (UMLRTTimer *)next->next;
+            if (head == NULL)
+            {
+                tail = NULL; // Not strictly required, but cleaner.
+            }
+            sendNotification();
+        }
+        else
+        {
+            // Unlink the timer being deallocated by setting next of previous to be
+            // the cancelled timer's next.
+            previous->next = next->next;
+
+            // If the timer was last in the queue, the tail has to be updated.
+            if (tail == next)
+            {
+                tail = previous;
+            }
+        }
+        // Return it to the pool.
+        umlrt::TimerPutToPool(next);
+
+        ok = true;
+    }
+    return ok;
+}
+
+void UMLRTTimerQueue::sendNotification()
+{
+    int bytes_ready;
+
+    if (ioctl(notifyFd[0], FIONREAD, &bytes_ready) < 0)
+    {
+        FATAL_ERRNO("ioctl");
+    }
+    if (!bytes_ready)
+    {
+        // Write a byte to the notification-pipe as a notification of a pending message.
+        uint8_t notifyByte = 0;
+
+        if (write(notifyFd[1], &notifyByte, 1) < 0)
+        {
+            FATAL_ERRNO("write");
+        }
+    }
+}
+
+// See umlrtprioritymessagequeue.hh for documentation.
+void UMLRTTimerQueue::clearNotifyFd()
+{
+    uint8_t ignore;
+    int bytes;
+    if ((bytes = read(notifyFd[0], &ignore, 1)) < 0)
+    {
+        FATAL_ERRNO("initial read - synchronization mechanism implies a byte is waiting");
+    }
+    else if (!bytes)
+    {
+        // Indicates synchronization logic error. Should always get at least one byte.
+        FATAL("Should never find pipe empty when clearing a notification.");
+    }
+    // Clear out the notification-pipe.
+    // Can shrink this after notify is debugged.
+    bool done = false;
+    while (!done)
+    {
+        int bytes = read(notifyFd[0], &ignore, 1);
+        if (bytes < 0)
+        {
+            if (errno != EAGAIN)
+            {
+                FATAL_ERRNO("read");
+            }
+            else
+            {
+                done = true;
+            }
+        }
+        if (bytes > 0)
+        {
+            // BDEBUG(0, "read returned bytes(%d)\n", bytes);
+        }
+        else
+        {
+            done = true;
+        }
+    }
+}
+
+// See umlrtprioritymessagequeue.hh for documentation.
+int UMLRTTimerQueue::getNotifyFd()
+{
+    return notifyFd[0];
+}
+
+
diff --git a/rts/umlrt/umlrttimespec.cc b/rts/umlrt/umlrttimespec.cc
new file mode 100644
index 0000000..9589b82
--- /dev/null
+++ b/rts/umlrt/umlrttimespec.cc
@@ -0,0 +1,205 @@
+// umlrttimerspec.cc
+
+/*******************************************************************************
+* Copyright (c) 2014-2015 Zeligsoft (2009) Limited  and others.
+* All rights reserved. This program and the accompanying materials
+* are made available under the terms of the Eclipse Public License v1.0
+* which accompanies this distribution, and is available at
+* http://www.eclipse.org/legal/epl-v10.html
+*******************************************************************************/
+
+#include "umlrttimespec.hh"
+#include "basefatal.hh"
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+UMLRTTimespec::UMLRTTimespec( const UMLRTTimespec & tm ) : tv_sec(tm.tv_sec), tv_nsec(tm.tv_nsec) { }
+
+UMLRTTimespec::UMLRTTimespec( long seconds, long nanoseconds ): tv_sec(seconds), tv_nsec(nanoseconds)
+{
+    timespecAdjust(this);
+}
+
+UMLRTTimespec::UMLRTTimespec() { UMLRTTimespec::getClock(this); }
+
+UMLRTTimespec & UMLRTTimespec::operator=( const UMLRTTimespec & tm )
+{
+    tv_sec = tm.tv_sec;
+    tv_nsec = tm.tv_nsec;
+
+    return *this;
+}
+
+bool UMLRTTimespec::operator==( const UMLRTTimespec & tm ) const
+{
+    return (tv_sec == tm.tv_sec) && (tv_nsec == tm.tv_nsec);
+}
+
+bool UMLRTTimespec::operator!=( const UMLRTTimespec & tm ) const
+{
+    return (tv_sec != tm.tv_sec) || (tv_nsec != tm.tv_nsec);
+}
+
+bool UMLRTTimespec::operator<( const UMLRTTimespec & tm ) const
+{
+    if (tv_sec < tm.tv_sec)
+        return true;
+
+    else if (tv_sec == tm.tv_sec)
+        return (tv_nsec < tm.tv_nsec);
+
+    return false;
+}
+
+bool UMLRTTimespec::operator<=( const UMLRTTimespec & tm ) const
+{
+    if (tv_sec < tm.tv_sec)
+        return true;
+
+    else if (tv_sec == tm.tv_sec)
+        return (tv_nsec <= tm.tv_nsec);
+
+    return false;
+}
+
+bool UMLRTTimespec::operator>( const UMLRTTimespec & tm ) const
+{
+    if (tv_sec > tm.tv_sec)
+            return true;
+
+        else if (tv_sec == tm.tv_sec)
+            return (tv_nsec > tm.tv_nsec);
+
+        return false;
+}
+
+bool UMLRTTimespec::operator>=( const UMLRTTimespec & tm ) const
+{
+    if (tv_sec > tm.tv_sec)
+        return true;
+
+    else if (tv_sec == tm.tv_sec)
+        return (tv_nsec >= tm.tv_nsec);
+
+    return false;
+}
+
+// Ensure tv_nsec is always 0..999999999.
+/*static*/ void UMLRTTimespec::timespecAdjust( UMLRTTimespec * tm )
+{
+    // Times must be adjusted after a single add/subtract, so tv_nsec is assumed to be
+    // between -999999999 and 2*999999999 before it is adjusted.
+    // We do a sanity check after the adjustment to confirm our assumptions are correct.
+    if (tm->tv_nsec > ONE_BILLION)
+    {
+        tm->tv_sec += 1;
+        tm->tv_nsec -= ONE_BILLION;
+    }
+    if (tm->tv_nsec < 0)
+    {
+        tm->tv_sec -= 1;
+        tm->tv_nsec += ONE_BILLION;
+    }
+    // For now, we FATAL() if tm->tv_nsec was not sufficiently adjusted.
+    if (tm->tv_nsec > ONE_BILLION)
+    {
+        FATAL("time tv_nsec(%ld) > ONE_BILLION", tm->tv_nsec);
+    }
+    if (tm->tv_nsec < 0)
+    {
+        FATAL("time tv_nsec(%ld) < 0", tm->tv_nsec);
+    }
+}
+
+UMLRTTimespec UMLRTTimespec::operator+( const UMLRTTimespec & tm ) const
+{
+    return UMLRTTimespec(tv_sec + tm.tv_sec, tv_nsec + tm.tv_nsec);
+}
+
+UMLRTTimespec UMLRTTimespec::operator-( const UMLRTTimespec & tm ) const
+{
+    return UMLRTTimespec(tv_sec - tm.tv_sec, tv_nsec - tm.tv_nsec);
+}
+
+UMLRTTimespec & UMLRTTimespec::operator+=( const UMLRTTimespec & tm )
+{
+    tv_sec += tm.tv_sec;
+    tv_nsec += tm.tv_nsec;
+
+    timespecAdjust(this);
+
+    return *this;
+}
+
+UMLRTTimespec & UMLRTTimespec::operator-=( const UMLRTTimespec & tm )
+{
+    tv_sec -= tm.tv_sec;
+    tv_nsec -= tm.tv_nsec;
+
+    timespecAdjust(this);
+
+    return *this;
+}
+
+/*static*/ void UMLRTTimespec::getClock( UMLRTTimespec * tm )
+{
+    // Linux-specific for now.
+    struct timeval tv;
+
+    if (gettimeofday(&tv, NULL) < 0)
+    {
+        FATAL_ERRNO("gettimeofday");
+    }
+    tm->tv_sec = tv.tv_sec;
+    tm->tv_nsec = tv.tv_usec * 1000;
+}
+
+bool UMLRTTimespec::isZeroOrNegative() const
+{
+    return (tv_sec < 0) || ((tv_sec == 0) && (tv_nsec == 0));
+}
+
+char * UMLRTTimespec::toString( char * buffer, int size ) const
+{
+    struct tm from_localtime;
+    const time_t seconds = tv_sec;
+
+    localtime_r( &seconds, &from_localtime );
+
+    size_t length = strftime(buffer, size, "%Y-%m-%d:%H:%M:%S", &from_localtime);
+    long msec = tv_nsec / NANOSECONDS_PER_MILLISECOND;
+    snprintf( &buffer[length], size-length, ".%03ld", msec );
+
+    return buffer;
+}
+
+char * UMLRTTimespec::toStringRelative( char * buffer, int size ) const
+{
+    long int seconds = tv_sec;
+    long int days = seconds / SECONDS_PER_DAY;
+    seconds -= (days * SECONDS_PER_DAY);
+    long int hours = seconds / SECONDS_PER_HOUR;
+    seconds -= (hours * SECONDS_PER_HOUR);
+    long int minutes = seconds / SECONDS_PER_MINUTE;
+    seconds -= (minutes * SECONDS_PER_MINUTE);
+
+    long int msec = tv_nsec / NANOSECONDS_PER_MILLISECOND;
+
+    snprintf( buffer, size, "%ld:%02ld:%02ld:%02ld.%03ld", days, hours, minutes, seconds, msec );
+
+    return buffer;
+}
+
+/*static*/ void UMLRTTimespec::timespecAbsAddMsec( struct timespec * timeout, long msec )
+{
+    clock_gettime(CLOCK_REALTIME, timeout);
+    timeout->tv_sec += (msec / 1000);
+    timeout->tv_nsec += (msec % 1000) * ONE_BILLION;
+    if (timeout->tv_nsec >= ONE_BILLION)
+    {
+        timeout->tv_sec += 1;
+        timeout->tv_nsec -= ONE_BILLION;
+    }
+}