/* Copyright 2023 Stanford University, NVIDIA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "legion.h"
#include "legion/runtime.h"
#include "legion/legion_ops.h"
#include "legion/legion_tasks.h"
#include "legion/legion_trace.h"
#include "legion/legion_utilities.h"
#include "legion/region_tree.h"
#include "legion/legion_spy.h"
#include "legion/legion_profiling.h"
#include "legion/legion_instances.h"
#include "legion/legion_views.h"
#include "legion/legion_context.h"
#include "legion/mapper_manager.h"
#include "legion/garbage_collection.h"
#include "mappers/default_mapper.h"
#include "mappers/test_mapper.h"
#include "mappers/replay_mapper.h"
#include "mappers/debug_mapper.h"
#include "realm/cmdline.h"

#include <unistd.h> // sleep for warnings

#ifdef LEGION_MALLOC_INSTANCES
#include <sys/mman.h>
#ifdef LEGION_USE_CUDA
#include <cuda.h>
#endif
#ifdef LEGION_USE_HIP
#include <hip/hip_runtime.h>
#endif
#endif

#define REPORT_DUMMY_CONTEXT(message)                        \
  REPORT_LEGION_ERROR(ERROR_DUMMY_CONTEXT_OPERATION,  message)

namespace Legion {
  namespace Internal {

    // If you add a logger, update the LEGION_EXTERN_LOGGER_DECLARATIONS
    // macro in legion_types.h
    Realm::Logger log_run("runtime");
    Realm::Logger log_task("tasks");
    Realm::Logger log_index("index_spaces");
    Realm::Logger log_field("field_spaces");
    Realm::Logger log_region("regions");
    Realm::Logger log_inst("instances");
    Realm::Logger log_variant("variants");
    Realm::Logger log_allocation("allocation");
    Realm::Logger log_migration("migration");
    Realm::Logger log_prof("legion_prof");
    Realm::Logger log_garbage("legion_gc");
    Realm::Logger log_shutdown("shutdown");
    Realm::Logger log_tracing("tracing");
    namespace LegionSpy {
      Realm::Logger log_spy("legion_spy");
    };

    __thread TaskContext *implicit_context = NULL;
    __thread Runtime *implicit_runtime = NULL;
    __thread AutoLock *local_lock_list = NULL;
    __thread UniqueID implicit_provenance = 0;
    __thread unsigned inside_registration_callback = NO_REGISTRATION_CALLBACK;
    __thread ImplicitReferenceTracker *implicit_reference_tracker = NULL;

    const LgEvent LgEvent::NO_LG_EVENT = LgEvent();
    const ApEvent ApEvent::NO_AP_EVENT = ApEvent();
    const ApUserEvent ApUserEvent::NO_AP_USER_EVENT = ApUserEvent();
    const ApBarrier ApBarrier::NO_AP_BARRIER = ApBarrier();
    const RtEvent RtEvent::NO_RT_EVENT = RtEvent();
    const RtUserEvent RtUserEvent::NO_RT_USER_EVENT = RtUserEvent();
    const RtBarrier RtBarrier::NO_RT_BARRIER = RtBarrier();
    const PredEvent PredEvent::NO_PRED_EVENT = PredEvent();

    /////////////////////////////////////////////////////////////
    // Argument Map Impl
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    ArgumentMapImpl::ArgumentMapImpl(void)
      : Collectable(), runtime(implicit_runtime), 
        dependent_futures(0), equivalent(false)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    ArgumentMapImpl::ArgumentMapImpl(const FutureMap &rhs)
      : Collectable(), runtime(implicit_runtime),
        future_map(rhs), dependent_futures(0), equivalent(false)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    ArgumentMapImpl::ArgumentMapImpl(const ArgumentMapImpl &impl)
      : Collectable(), runtime(NULL)
    //--------------------------------------------------------------------------
    {
      // This should never ever be called
      assert(false);
    }
    
    //--------------------------------------------------------------------------
    ArgumentMapImpl::~ArgumentMapImpl(void)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    ArgumentMapImpl& ArgumentMapImpl::operator=(const ArgumentMapImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // This should never ever be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    bool ArgumentMapImpl::has_point(const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      if (future_map.impl != NULL)
        unfreeze();
      return (arguments.find(point) != arguments.end());
    }

    //--------------------------------------------------------------------------
    void ArgumentMapImpl::set_point(const DomainPoint &point, 
                                    const UntypedBuffer &arg, bool replace)
    //--------------------------------------------------------------------------
    {
      if (future_map.impl != NULL)
        unfreeze();
      std::map<DomainPoint,Future>::iterator finder = arguments.find(point);
      if (finder != arguments.end())
      {
        // If it already exists and we're not replacing it then we're done
        if (!replace)
          return;
        if (finder->second.impl->producer_op != NULL)
        {
#ifdef DEBUG_LEGION
          assert(dependent_futures > 0);
#endif
          dependent_futures--;
        }
        if (arg.get_size() > 0)
          finder->second = 
            Future::from_untyped_pointer(runtime->external,
                                         arg.get_ptr(), arg.get_size());
        else
          finder->second = Future();
      }
      else
      {
        if (arg.get_size() > 0)
          arguments[point] = 
            Future::from_untyped_pointer(runtime->external,
                                         arg.get_ptr(), arg.get_size());
        else
          arguments[point] = Future();
      }
      // If we modified things then they are no longer equivalent
      if (future_map.impl != NULL)
      {
        equivalent = false;
        future_map = FutureMap();
      }
    }

    //--------------------------------------------------------------------------
    void ArgumentMapImpl::set_point(const DomainPoint &point, 
                                    const Future &f, bool replace)
    //--------------------------------------------------------------------------
    {
      if (future_map.impl != NULL)
        unfreeze();
      std::map<DomainPoint,Future>::iterator finder = arguments.find(point);
      if (finder != arguments.end())
      {
        // If it already exists and we're not replacing it then we're done
        if (!replace)
          return;
        if (finder->second.impl->producer_op != NULL)
        {
#ifdef DEBUG_LEGION
          assert(dependent_futures > 0);
#endif
          dependent_futures--;
        }
        finder->second = f; 
        
      }
      else
        arguments[point] = f;
      if (f.impl->producer_op != NULL)
          dependent_futures++;
      // If we modified things then they are no longer equivalent
      if (future_map.impl != NULL)
      {
        equivalent = false;
        future_map = FutureMap();
      }
    }

    //--------------------------------------------------------------------------
    bool ArgumentMapImpl::remove_point(const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      if (future_map.impl != NULL)
        unfreeze();
      std::map<DomainPoint,Future>::iterator finder = arguments.find(point);
      if (finder != arguments.end())
      {
        if (finder->second.impl->producer_op != NULL)
        {
#ifdef DEBUG_LEGION
          assert(dependent_futures > 0);
#endif
          dependent_futures--;
        }
        arguments.erase(finder);
        // If we modified things then they are no longer equivalent
        if (future_map.impl != NULL)
        {
          equivalent = false;
          future_map = FutureMap();
        }
        return true;
      }
      return false;
    }

    //--------------------------------------------------------------------------
    UntypedBuffer ArgumentMapImpl::get_point(const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      if (future_map.impl != NULL)
        unfreeze();
      std::map<DomainPoint,Future>::const_iterator finder=arguments.find(point);
      if ((finder == arguments.end()) || (finder->second.impl == NULL))
        return UntypedBuffer();
      return UntypedBuffer(finder->second.impl->get_untyped_result(),
                           finder->second.impl->get_untyped_size());
    }

    //--------------------------------------------------------------------------
    FutureMap ArgumentMapImpl::freeze(TaskContext *ctx)
    //--------------------------------------------------------------------------
    {
      // If we already have a future map then we are good
      if (future_map.impl != NULL)
        return future_map;
      // If we have no futures then we can return an empty map
      if (arguments.empty())
        return FutureMap();
      // See if we have any dependent future points, if we do then we need
      // to launch an explicit creation operation to ensure we get the right
      // mapping dependences for this future map
      if (dependent_futures == 0)
      {
        // Otherwise we have to make a future map and set all the futures
        // We know that they are already completed 
        DistributedID did = runtime->get_available_distributed_id();
        future_map = FutureMap(new FutureMapImpl(ctx, runtime, did,
            runtime->address_space, RtEvent::NO_RT_EVENT));
        future_map.impl->set_all_futures(arguments);
      }
      else
        future_map = ctx->construct_future_map(Domain::NO_DOMAIN,
                                               arguments, true/*internal*/);
#ifdef DEBUG_LEGION
      for (std::map<DomainPoint,Future>::const_iterator it = 
            arguments.begin(); it != arguments.end(); it++)
        future_map.impl->add_valid_point(it->first);
#endif
      equivalent = true; // mark that these are equivalent
      dependent_futures = 0; // reset this for the next unpack 
      return future_map;
    }

    //--------------------------------------------------------------------------
    void ArgumentMapImpl::unfreeze(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(future_map.impl != NULL);
#endif
      // If they are already equivalent then we're done
      if (equivalent)
        return;
      // Otherwise we need to make them equivalent
      future_map.impl->get_all_futures(arguments);
      // Count how many dependent futures we have
#ifdef DEBUG_LEGION
      assert(dependent_futures == 0);
#endif
      for (std::map<DomainPoint,Future>::const_iterator it = 
            arguments.begin(); it != arguments.end(); it++)
        if (it->second.impl->producer_op != NULL)
          dependent_futures++;
      equivalent = true;
    }

    /////////////////////////////////////////////////////////////
    // Field Allocator Impl
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    FieldAllocatorImpl::FieldAllocatorImpl(FieldSpaceNode *n, TaskContext *ctx,
                                           RtEvent ready)
      : field_space(n->handle), node(n), context(ctx), ready_event(ready)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(node != NULL);
      assert(context != NULL);
#endif
      context->add_reference();
      node->add_base_resource_ref(FIELD_ALLOCATOR_REF);
    }

    //--------------------------------------------------------------------------
    FieldAllocatorImpl::FieldAllocatorImpl(const FieldAllocatorImpl &rhs)
      : field_space(rhs.field_space), node(rhs.node), context(rhs.context), 
        ready_event(rhs.ready_event)
    //--------------------------------------------------------------------------
    {
      // Should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    FieldAllocatorImpl::~FieldAllocatorImpl(void)
    //--------------------------------------------------------------------------
    {
      context->destroy_field_allocator(node);
      if (context->remove_reference())
        delete context;
      if (node->remove_base_resource_ref(FIELD_ALLOCATOR_REF))
        delete node;
    }

    //--------------------------------------------------------------------------
    FieldAllocatorImpl& FieldAllocatorImpl::operator=(
                                                  const FieldAllocatorImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // Should never be called
      assert(false);
      return *this;
    }
    
    //--------------------------------------------------------------------------
    FieldID FieldAllocatorImpl::allocate_field(size_t field_size,
                                               FieldID desired_fieldid,
                                               CustomSerdezID serdez_id, 
                                               bool local, const char *prov)
    //--------------------------------------------------------------------------
    {
      // Need to wait for this allocator to be ready
      if (ready_event.exists() && !ready_event.has_triggered())
        ready_event.wait();
      return context->allocate_field(field_space, field_size, desired_fieldid,
                                     local, serdez_id, prov);
    }

    //--------------------------------------------------------------------------
    FieldID FieldAllocatorImpl::allocate_field(const Future &field_size,
                                               FieldID desired_fieldid,
                                               CustomSerdezID serdez_id, 
                                               bool local, const char *prov)
    //--------------------------------------------------------------------------
    {
      // Need to wait for this allocator to be ready
      if (ready_event.exists() && !ready_event.has_triggered())
        ready_event.wait();
      return context->allocate_field(field_space, field_size, desired_fieldid, 
                                     local, serdez_id, prov);
    }

    //--------------------------------------------------------------------------
    void FieldAllocatorImpl::free_field(FieldID fid, const bool unordered,
                                        const char *provenance)
    //--------------------------------------------------------------------------
    {
      // Don't need to wait here since deletion operations catch
      // dependences on the allocator themselves
      context->free_field(this, field_space, fid, unordered, provenance);
    }

    //--------------------------------------------------------------------------
    void FieldAllocatorImpl::allocate_fields(
                                        const std::vector<size_t> &field_sizes,
                                        std::vector<FieldID> &resulting_fields,
                                        CustomSerdezID serdez_id, bool local,
                                        const char *provenance)
    //--------------------------------------------------------------------------
    {
      // Need to wait for this allocator to be ready
      if (ready_event.exists() && !ready_event.has_triggered())
        ready_event.wait();
      context->allocate_fields(field_space, field_sizes, resulting_fields,
                               local, serdez_id, provenance);
    }

    //--------------------------------------------------------------------------
    void FieldAllocatorImpl::allocate_fields(
                                        const std::vector<Future> &field_sizes,
                                        std::vector<FieldID> &resulting_fields,
                                        CustomSerdezID serdez_id, bool local,
                                        const char *provenance)
    //--------------------------------------------------------------------------
    {
      // Need to wait for this allocator to be ready
      if (ready_event.exists() && !ready_event.has_triggered())
        ready_event.wait();
      context->allocate_fields(field_space, field_sizes, resulting_fields, 
                               local, serdez_id, provenance);
    }

    //--------------------------------------------------------------------------
    void FieldAllocatorImpl::free_fields(const std::set<FieldID> &to_free,
                                   const bool unordered, const char *provenance)
    //--------------------------------------------------------------------------
    {
      // Don't need to wait here since deletion operations catch
      // dependences on the allocator themselves
      context->free_fields(this, field_space, to_free, unordered, provenance);
    }

    /////////////////////////////////////////////////////////////
    // Future Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    FutureImpl::FutureImpl(TaskContext *ctx, Runtime *rt, bool register_now, 
                           DistributedID did, AddressSpaceID own_space,
                           ApEvent complete, Operation *o /*= NULL*/)
      : DistributedCollectable(rt, 
          LEGION_DISTRIBUTED_HELP_ENCODE(did, FUTURE_DC), 
          own_space, register_now), context(ctx),
        producer_op(o), op_gen((o == NULL) ? 0 : o->get_generation()),
        producer_depth((o == NULL) ? -1 : o->get_context()->get_depth()),
#ifdef LEGION_SPY
        producer_uid((o == NULL) ? 0 : o->get_unique_op_id()),
#endif
        future_complete(complete), result(NULL), result_size(0), 
        result_set_space(local_space), callback_functor(NULL),
        own_callback_functor(false), empty(true), sampled(false)
    //--------------------------------------------------------------------------
    {
      if (producer_op != NULL)
        producer_op->add_mapping_reference(op_gen);
#ifdef LEGION_GC
      log_garbage.info("GC Future %lld %d", 
          LEGION_DISTRIBUTED_ID_FILTER(this->did), local_space);
#endif
    }

    //--------------------------------------------------------------------------
    FutureImpl::FutureImpl(const FutureImpl &rhs)
      : DistributedCollectable(NULL, 0, 0), context(NULL), producer_op(NULL),
        op_gen(0), producer_depth(0)
#ifdef LEGION_SPY
        , producer_uid(0)
#endif
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    FutureImpl::~FutureImpl(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!subscription_event.exists());
#endif
      // Remove the extra reference on a remote set future if there is one
      if (empty && (result_set_space != local_space))
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(did);
          rez.serialize<size_t>(0);
        }
        runtime->send_future_broadcast(result_set_space, rez);
      }
      if (result != NULL)
      {
        free(result);
        result = NULL;
        result_size = 0;
      }
      if (producer_op != NULL)
        producer_op->remove_mapping_reference(op_gen);
      if (callback_functor != NULL)
        callback_functor->callback_release_future();
      if (own_callback_functor)
        delete callback_functor;
    }

    //--------------------------------------------------------------------------
    FutureImpl& FutureImpl::operator=(const FutureImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void FutureImpl::wait(bool silence_warnings, const char *warning_string)
    //--------------------------------------------------------------------------
    {
      if (runtime->runtime_warnings && !silence_warnings && 
          (implicit_context != NULL))
      {
        if (!implicit_context->is_leaf_context())
          REPORT_LEGION_WARNING(LEGION_WARNING_WAITING_FUTURE_NONLEAF, 
             "Waiting on a future in non-leaf task %s "
             "(UID %lld) is a violation of Legion's deferred execution model "
             "best practices. You may notice a severe performance "
             "degradation. Warning string: %s",
             implicit_context->get_task_name(), 
             implicit_context->get_unique_id(),
             (warning_string == NULL) ? "" : warning_string)
      }
      if ((implicit_context != NULL) && !runtime->separate_runtime_instances)
        implicit_context->record_blocking_call();
      bool poisoned = false;
      if (!future_complete.has_triggered_faultaware(poisoned))
      {
        TaskContext *context = implicit_context;
        if (context != NULL)
        {
          context->begin_task_wait(false/*from runtime*/);
          future_complete.wait_faultaware(poisoned);
          context->end_task_wait();
        }
        else
          future_complete.wait_faultaware(poisoned);
      }
      if (poisoned)
        implicit_context->raise_poison_exception();
      mark_sampled();
    }
    
    //--------------------------------------------------------------------------
    void* FutureImpl::get_untyped_result(bool silence_warnings,
                                      const char *warning_string, bool internal, 
                                      bool check_size, size_t future_size)
    //--------------------------------------------------------------------------
    {
      if (!internal)
      {
        if (runtime->runtime_warnings && !silence_warnings && 
            (implicit_context != NULL))
        {
          if (!implicit_context->is_leaf_context())
            REPORT_LEGION_WARNING(LEGION_WARNING_WAITING_FUTURE_NONLEAF, 
               "Waiting on a future in non-leaf task %s "
               "(UID %lld) is a violation of Legion's deferred execution model "
               "best practices. You may notice a severe performance "
               "degradation. Warning string: %s",
               implicit_context->get_task_name(), 
               implicit_context->get_unique_id(),
               (warning_string == NULL) ? "" : warning_string)
        }
        if ((implicit_context != NULL) && !runtime->separate_runtime_instances)
          implicit_context->record_blocking_call();
      }
      const ApEvent ready_event = subscribe();
      bool poisoned = false;
      if (!ready_event.has_triggered_faultaware(poisoned))
      {
        TaskContext *context = implicit_context;
        if (context != NULL)
        {
          context->begin_task_wait(false/*from runtime*/);
          ready_event.wait_faultaware(poisoned);
          context->end_task_wait();
        }
        else
          ready_event.wait_faultaware(poisoned);
      }
      if (poisoned)
        implicit_context->raise_poison_exception();
      if (check_size)
      {
        if (empty)
          REPORT_LEGION_ERROR(ERROR_REQUEST_FOR_EMPTY_FUTURE, 
                              "Accessing empty future! (UID %lld)",
                              (producer_op == NULL) ? 0 :
                                producer_op->get_unique_op_id())
        else if (future_size != result_size)
          REPORT_LEGION_ERROR(ERROR_FUTURE_SIZE_MISMATCH,
              "Future size mismatch! Expected type of %zd bytes but "
              "requested type is %zd bytes. (UID %lld)", 
              result_size, future_size, (producer_op == NULL) ? 0 : 
              producer_op->get_unique_op_id())
      }
      mark_sampled();
      return result;
    }

    //--------------------------------------------------------------------------
    size_t FutureImpl::get_untyped_size(bool internal)
    //--------------------------------------------------------------------------
    {
      // Call this first to make sure the future is ready
      get_untyped_result(true, NULL, internal);
      return result_size;
    }

    //--------------------------------------------------------------------------
    bool FutureImpl::is_empty(bool block, bool silence_warnings,
                              const char *warning_string, bool internal)
    //--------------------------------------------------------------------------
    {
      if (!internal)
      {
        if (runtime->runtime_warnings && !silence_warnings && 
            (producer_op != NULL))
        {
          TaskContext *context = producer_op->get_context();
          if (!context->is_leaf_context())
            REPORT_LEGION_WARNING(LEGION_WARNING_BLOCKING_EMPTY, 
                "Performing a blocking is_empty test on a "
                "in non-leaf task %s (UID %lld) is a violation of Legion's "
                "deferred execution model best practices. You may notice a "
                "severe performance degradation. Warning string: %s", 
                context->get_task_name(), 
                context->get_unique_id(),
                (warning_string == NULL) ? "" : warning_string)
        }
        if (block && producer_op != NULL && Internal::implicit_context != NULL)
          Internal::implicit_context->record_blocking_call();
      }
      if (block)
      {
        const ApEvent ready_event = subscribe();
        bool poisoned = false;
        if (!ready_event.has_triggered_faultaware(poisoned))
        {
          TaskContext *context =
            (producer_op == NULL) ? NULL : producer_op->get_context();
          if (context != NULL)
          {
            context->begin_task_wait(false/*from runtime*/);
            ready_event.wait_faultaware(poisoned);
            context->end_task_wait();
          }
          else
            ready_event.wait_faultaware(poisoned);
        }
        if (poisoned)
          implicit_context->raise_poison_exception();
        mark_sampled();
      }
      return empty;
    }

    //--------------------------------------------------------------------------
    void FutureImpl::set_result(const void *args, size_t arglen, bool own)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(future_lock);
      if (!empty || (callback_functor != NULL))
        REPORT_LEGION_ERROR(ERROR_DUPLICATE_FUTURE_SET,
            "Duplicate future set! This can be either a runtime bug or a "
            "user error. If you have a must epoch launch in this program "
            "please check that all of the point tasks that it creates have "
            "unique index points. If your program has no must epoch launches "
            "then this is likely a runtime bug.")
      if (own)
      {
        result = const_cast<void*>(args);
        result_size = arglen;
      }
      else
      {
        result_size = arglen;
        result = malloc(result_size);
        memcpy(result,args,result_size);
      }
      finish_set_future();
    }

    //--------------------------------------------------------------------------
    void FutureImpl::set_result(FutureFunctor *functor, bool own,Processor proc)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(proc.kind() != Processor::UTIL_PROC);
#endif
      AutoLock f_lock(future_lock);
      if (!empty || (callback_functor != NULL))
        REPORT_LEGION_ERROR(ERROR_DUPLICATE_FUTURE_SET,
            "Duplicate future set! This can be either a runtime bug or a "
            "user error. If you have a must epoch launch in this program "
            "please check that all of the point tasks that it creates have "
            "unique index points. If your program has no must epoch launches "
            "then this is likely a runtime bug.")
      callback_functor = functor;
      own_callback_functor = own;
      callback_proc = proc;
      finish_set_future();
    }

    //--------------------------------------------------------------------------
    void FutureImpl::finish_set_future(void)
    //--------------------------------------------------------------------------
    {
      // must be called while we are already holding the lock
      empty = false; 
      if (!is_owner())
      {
        // Add an extra reference to prevent this from being collected
        // until the owner is also deleted, the owner will notify us
        // they are deleted with a broadcast of size 0 when they are deleted
        add_base_resource_ref(RUNTIME_REF);
        // If we're the first set then we need to tell the owner
        // that we are the ones with the value
        // This is literally an empty message
        Serializer rez;
        rez.serialize(did);
        runtime->send_future_notification(owner_space, rez); 
      }
      else if (!subscribers.empty())
        broadcast_result(subscribers, future_complete, false/*need lock*/);
      if (subscription_event.exists())
      {
        // Be very careful here, it might look like you can trigger the
        // subscription event immediately on the owner node but you can't
        // because we still rely on futures to propagate privileges when
        // return region tree types
        if (future_complete != subscription_event)
          Runtime::trigger_event(NULL, subscription_event, future_complete);
        else
          Runtime::trigger_event(NULL, subscription_event);
        subscription_event = ApUserEvent::NO_AP_USER_EVENT;
        if (remove_base_resource_ref(RUNTIME_REF))
          assert(false); // should always hold a reference from caller
      }
    }

    //--------------------------------------------------------------------------
    ApEvent FutureImpl::invoke_callback(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(callback_functor != NULL);
#endif
      if (!callback_ready.exists())
      {
        callback_ready = Runtime::create_ap_user_event(NULL);
        FutureCallbackArgs args(this);    
        runtime->issue_application_processor_task(args, 
            LG_LATENCY_WORK_PRIORITY, callback_proc);
      }
      return callback_ready;
    }

    //--------------------------------------------------------------------------
    void FutureImpl::perform_callback(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(callback_functor != NULL);
      assert(callback_ready.exists());
#endif
      result_size = callback_functor->callback_get_future_size();
      if (result_size > 0)
      {
        result = malloc(result_size);
        callback_functor->callback_pack_future(result, result_size);
      }
      callback_functor->callback_release_future();
      if (own_callback_functor)
        delete callback_functor;
      // Retake the lock and remove the guards
      AutoLock f_lock(future_lock);
      callback_functor = NULL;
      Runtime::trigger_event(NULL, callback_ready, future_complete);
      // Check for any subscribers that we need to tell about the result
      if (!subscribers.empty())
        broadcast_result(subscribers, future_complete, false/*need lock*/);
    }

    //--------------------------------------------------------------------------
    FutureImpl::FutureCallbackArgs::FutureCallbackArgs(FutureImpl *i)
      : LgTaskArgs<FutureCallbackArgs>(implicit_provenance), impl(i)
    //--------------------------------------------------------------------------
    {
      impl->add_base_gc_ref(DEFERRED_TASK_REF);
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureImpl::handle_callback(const void *args)
    //--------------------------------------------------------------------------
    {
      const FutureCallbackArgs *fargs = (const FutureCallbackArgs*)args;
      fargs->impl->perform_callback();
      if (fargs->impl->remove_base_gc_ref(DEFERRED_TASK_REF))
        delete fargs->impl;
    }

    //--------------------------------------------------------------------------
    void FutureImpl::unpack_future(Deserializer &derez)
    //-------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      AutoLock f_lock(future_lock);
#ifdef DEBUG_LEGION
      assert(empty);
      assert(subscription_event.exists());
#endif
      derez.deserialize(result_size);
      if (result_size > 0)
      {
        result = malloc(result_size);
        derez.deserialize(result,result_size);
      }
      empty = false;
      ApEvent complete;
      derez.deserialize(complete);
      Runtime::trigger_event(NULL, subscription_event, complete);
      subscription_event = ApUserEvent::NO_AP_USER_EVENT;
      if (is_owner())
      {
#ifdef DEBUG_LEGION
        assert(result_set_space != local_space);
#endif
        // Send a message to the result set space future to remove its
        // reference now that we no longer need it
        Serializer rez;
        {
          RezCheck z2(rez);
          rez.serialize(did);
          rez.serialize<size_t>(0);
        }
        runtime->send_future_broadcast(result_set_space, rez);
      }
    }

    //--------------------------------------------------------------------------
    bool FutureImpl::reset_future(void)
    //--------------------------------------------------------------------------
    {
      // TODO: update this for resilience
      assert(false);
      bool was_sampled = sampled;
      sampled = false;
      return was_sampled;
    }

    //--------------------------------------------------------------------------
    bool FutureImpl::get_boolean_value(bool &valid)
    //--------------------------------------------------------------------------
    {
      if (!empty)
      {
        bool poisoned = false;
        valid = future_complete.has_triggered_faultaware(poisoned);
        if (poisoned)
          implicit_context->raise_poison_exception();
#ifdef DEBUG_LEGION
        assert(callback_functor == NULL);
#endif
        return *((const bool*)result); 
      }
      valid = false;
      return false; 
    }

    //--------------------------------------------------------------------------
    ApEvent FutureImpl::subscribe(bool need_local_data)
    //--------------------------------------------------------------------------
    {
      if (!empty && (callback_functor == NULL))
        return future_complete;
      AutoLock f_lock(future_lock);
      // See if we lost the race
      if (empty)
      {
        if (!subscription_event.exists())
        {
          subscription_event = Runtime::create_ap_user_event(NULL);
          // Add a reference to prevent us from being collected
          // until we get the result of the subscription
          add_base_resource_ref(RUNTIME_REF);
          if (!is_owner())
          {
#ifdef DEBUG_LEGION
            assert(!future_complete.exists());
#endif
            future_complete = subscription_event;
            // Send a request to the owner node to subscribe
            Serializer rez;
            rez.serialize(did);
            runtime->send_future_subscription(owner_space, rez);
          }
          else
            record_subscription(local_space, false/*need lock*/);
        }
        return subscription_event;
      }
      else
      {
        if ((callback_functor != NULL) && need_local_data)
          return invoke_callback();
        return future_complete;
      }
    }

    //--------------------------------------------------------------------------
    void FutureImpl::notify_active(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // If we are not the owner, send a gc reference back to the owner
      if (!is_owner())
        send_remote_gc_increment(owner_space, mutator);
    }

    //--------------------------------------------------------------------------
    void FutureImpl::notify_valid(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    void FutureImpl::notify_invalid(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    void FutureImpl::notify_inactive(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // If we are not the owner, remove our gc reference
      if (!is_owner())
        send_remote_gc_decrement(owner_space, mutator);
    }

    //--------------------------------------------------------------------------
    void FutureImpl::register_dependence(Operation *consumer_op)
    //--------------------------------------------------------------------------
    {
      if (producer_op != NULL)
      {
        // Only record dependences on things from the same context
        // We know futures can never flow up the task tree so the
        // only way they have the same depth is if they are from 
        // the same parent context
        TaskContext *context = consumer_op->get_context();
        const int consumer_depth = context->get_depth();
#ifdef DEBUG_LEGION
        assert(consumer_depth >= producer_depth);
#endif
        if (consumer_depth == producer_depth)
        {
          consumer_op->register_dependence(producer_op, op_gen);
#ifdef LEGION_SPY
          LegionSpy::log_mapping_dependence(
              context->get_unique_id(), producer_uid, 0,
              consumer_op->get_unique_op_id(), 0, TRUE_DEPENDENCE);
#endif
        }
      }
#ifdef DEBUG_LEGION
      else
        assert(!empty); // better not be empty if it doesn't have an op
#endif
    }

    //--------------------------------------------------------------------------
    void FutureImpl::mark_sampled(void)
    //--------------------------------------------------------------------------
    {
      sampled = true;
    }

    //--------------------------------------------------------------------------
    void FutureImpl::broadcast_result(std::set<AddressSpaceID> &targets,
                                      ApEvent complete, const bool need_lock)
    //--------------------------------------------------------------------------
    {
      if (targets.empty())
        return;
      if (need_lock)
      {
        AutoLock f_lock(future_lock,1,false/*exclusive*/);
        broadcast_result(targets, complete, false/*need lock*/);
        return;
      }
#ifdef DEBUG_LEGION
      assert(!empty);
#endif
      if (callback_functor != NULL)
      {
        // Handle the special case where the only subscriber is the local
        // node so we can lazily defer this until later and the user
        // actually asks us for the result
        if (!targets.empty() && ((targets.size() > 1) ||
              (targets.find(local_space) == targets.end())))
        {
          // If we still have a callback to perform do
          // that now to get it in flight, it will send
          // out any updates to subscribers
          invoke_callback();
          // Make sure these targets are all in the set of subscribers
          // so that the callback will broadcast them later
          subscribers.insert(targets.begin(), targets.end());
        }
        return;
      }
      for (std::set<AddressSpaceID>::const_iterator it = 
            targets.begin(); it != targets.end(); it++)
      {
        if ((*it) == local_space)
          continue;
        Serializer rez;
        {
          rez.serialize(did);
          RezCheck z(rez);
          rez.serialize(result_size);
          if (result_size > 0)
            rez.serialize(result,result_size);
          rez.serialize(complete);
        }
        runtime->send_future_result(*it, rez);
      }
      targets.clear();
    }

    //--------------------------------------------------------------------------
    void FutureImpl::record_subscription(AddressSpaceID subscriber, 
                                         bool need_lock)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner());
#endif
      if (need_lock)
      {
        AutoLock f_lock(future_lock);
        record_subscription(subscriber, false/*need lock*/);
        return;
      }
      if (empty)
      {
        // See if we know who has the result
        if (result_set_space != local_space)
        {
          // We don't have the result, but we know who does so 
          // request that they send it out to the target
          Serializer rez;
          {
            RezCheck z(rez);
            rez.serialize(did);
            rez.serialize<size_t>(1); // size
            rez.serialize(subscriber);
            rez.serialize(future_complete);
          }
          runtime->send_future_broadcast(result_set_space, rez);
        }
        else
        {
          // We don't know yet, so save this for later
#ifdef DEBUG_LEGION
          assert(subscribers.find(subscriber) == subscribers.end());
#endif
          subscribers.insert(subscriber);
        }
      }
      else
      {
        if (callback_functor != NULL)
        {
          invoke_callback();
          // If we still have a callback to be done, make sure
          // it is in flight and that the subscriber is there
          // for it to be messaged when the callback is done
          subscribers.insert(subscriber);
          return;
        }
        // We've got the result so we can't send it back right away
        Serializer rez;
        {
          rez.serialize(did);
          RezCheck z(rez);
          rez.serialize(result_size);
          if (result_size > 0)
            rez.serialize(result,result_size);
          rez.serialize(future_complete);
        }
        runtime->send_future_result(subscriber, rez);
      }
    }

    //--------------------------------------------------------------------------
    void FutureImpl::notify_remote_set(AddressSpaceID remote_space)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(future_lock);
#ifdef DEBUG_LEGION
      assert(is_owner());
      assert(result_set_space == local_space);
      assert(result_set_space != remote_space);
#endif
      result_set_space = remote_space;
      if (!subscribers.empty())
      {
        // Pack these up and send them to the remote space
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(did);
          rez.serialize<size_t>(subscribers.size());
          for (std::set<AddressSpaceID>::const_iterator it = 
               subscribers.begin(); it != subscribers.end(); it++)
            rez.serialize(*it);
          rez.serialize(future_complete);
        }
        runtime->send_future_broadcast(remote_space, rez);
        subscribers.clear();
      }
    }

    //--------------------------------------------------------------------------
    void FutureImpl::record_future_registered(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // Similar to DistributedCollectable::register_with_runtime but
      // we don't actually need to do the registration since we know
      // it has already been done
#ifdef DEBUG_LEGION
      assert(!registered_with_runtime);
#endif
      registered_with_runtime = true;
      if (!is_owner())
      {
#ifdef DEBUG_LEGION
        assert(mutator != NULL);
#endif
        send_remote_registration(mutator);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureImpl::handle_future_result(Deserializer &derez,
                                                 Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      DistributedID did;
      derez.deserialize(did);
      DistributedCollectable *dc = runtime->find_distributed_collectable(did);
#ifdef DEBUG_LEGION
      FutureImpl *future = dynamic_cast<FutureImpl*>(dc);
      assert(future != NULL);
#else
      FutureImpl *future = static_cast<FutureImpl*>(dc);
#endif
      future->unpack_future(derez);
      // Now we can remove the reference that we added from before we
      // sent the subscription message
      if (future->remove_base_resource_ref(RUNTIME_REF))
        delete future;
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureImpl::handle_future_subscription(
                   Deserializer &derez, Runtime *runtime, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DistributedID did;
      derez.deserialize(did);
      DistributedCollectable *dc = runtime->find_distributed_collectable(did);
#ifdef DEBUG_LEGION
      FutureImpl *future = dynamic_cast<FutureImpl*>(dc);
      assert(future != NULL);
#else
      FutureImpl *future = static_cast<FutureImpl*>(dc);
#endif
      future->record_subscription(source, true/*need lock*/);
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureImpl::handle_future_notification(
                   Deserializer &derez, Runtime *runtime, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DistributedID did;
      derez.deserialize(did);
      DistributedCollectable *dc = runtime->find_distributed_collectable(did);
#ifdef DEBUG_LEGION
      FutureImpl *future = dynamic_cast<FutureImpl*>(dc);
      assert(future != NULL);
#else
      FutureImpl *future = static_cast<FutureImpl*>(dc);
#endif
      future->notify_remote_set(source);
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureImpl::handle_future_broadcast(
                                          Deserializer &derez, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      DistributedID did;
      derez.deserialize(did);
      DistributedCollectable *dc = runtime->find_distributed_collectable(did);
#ifdef DEBUG_LEGION
      FutureImpl *future = dynamic_cast<FutureImpl*>(dc);
      assert(future != NULL);
#else
      FutureImpl *future = static_cast<FutureImpl*>(dc);
#endif
      size_t num_subscribers;
      derez.deserialize(num_subscribers);
      // Special case for removing our final reference
      if (num_subscribers == 0)
      {
        if (future->remove_base_resource_ref(RUNTIME_REF))
          delete future;
        return;
      }
      std::set<AddressSpaceID> subscribers;
      for (unsigned idx = 0; idx < num_subscribers; idx++)
      {
        AddressSpaceID subscriber;
        derez.deserialize(subscriber);
        subscribers.insert(subscriber);
      }
      ApEvent complete_event;
      derez.deserialize(complete_event);
      future->broadcast_result(subscribers, complete_event, true/*need lock*/);
    }

    //--------------------------------------------------------------------------
    void FutureImpl::contribute_to_collective(const DynamicCollective &dc, 
                                              unsigned count)
    //--------------------------------------------------------------------------
    {
      const ApEvent ready = subscribe();
      if (!ready.has_triggered_faultignorant())
      {
        // If we're not done then defer the operation until we are triggerd
        // First add a garbage collection reference so we don't get
        // collected while we are waiting for the contribution task to run
        add_base_gc_ref(PENDING_COLLECTIVE_REF);
        ContributeCollectiveArgs args(this, dc, count);
        // Spawn the task dependent on the future being ready
        runtime->issue_runtime_meta_task(args, LG_LATENCY_WORK_PRIORITY,
                                         Runtime::protect_event(ready));
      }
      else // If we've already triggered, then we can do the arrival now
        Runtime::phase_barrier_arrive(dc, count, ApEvent::NO_AP_EVENT,
                                      result, result_size);
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureImpl::handle_contribute_to_collective(
                                                               const void *args)
    //--------------------------------------------------------------------------
    {
      const ContributeCollectiveArgs *cargs = (ContributeCollectiveArgs*)args;
      cargs->impl->contribute_to_collective(cargs->dc, cargs->count);
      // Now remote the garbage collection reference and see if we can 
      // reclaim the future
      if (cargs->impl->remove_base_gc_ref(PENDING_COLLECTIVE_REF))
        delete cargs->impl;
    }
      
    /////////////////////////////////////////////////////////////
    // Future Map Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    FutureMapImpl::FutureMapImpl(TaskContext *ctx, Operation *o, RtEvent ready,
                     Runtime *rt, DistributedID did, AddressSpaceID owner_space)
      : DistributedCollectable(rt, 
          LEGION_DISTRIBUTED_HELP_ENCODE(did, FUTURE_MAP_DC),  owner_space), 
        context(ctx), op(o), op_gen(o->get_generation()), 
        op_depth(o->get_context()->get_depth()),
#ifdef LEGION_SPY
        op_uid(o->get_unique_op_id()),
#endif
        ready_event(ready)
    //--------------------------------------------------------------------------
    {
#ifdef LEGION_GC
      log_garbage.info("GC Future Map %lld %d", 
          LEGION_DISTRIBUTED_ID_FILTER(this->did), local_space);
#endif
    }

    //--------------------------------------------------------------------------
    FutureMapImpl::FutureMapImpl(TaskContext *ctx, Runtime *rt,
                                 DistributedID did, AddressSpaceID owner_space,
                                 RtEvent ready, bool register_now)
      : DistributedCollectable(rt, 
          LEGION_DISTRIBUTED_HELP_ENCODE(did, FUTURE_MAP_DC), 
          owner_space, register_now), 
        context(ctx), op(NULL), op_gen(0), op_depth(0),
#ifdef LEGION_SPY
        op_uid(0),
#endif
        ready_event(ready)
    //--------------------------------------------------------------------------
    {
#ifdef LEGION_GC
      log_garbage.info("GC Future Map %lld %d", 
          LEGION_DISTRIBUTED_ID_FILTER(this->did), local_space);
#endif
    }

    //--------------------------------------------------------------------------
    FutureMapImpl::FutureMapImpl(const FutureMapImpl &rhs)
      : DistributedCollectable(rhs), context(NULL), op(NULL), op_gen(0), 
        op_depth(0)
#ifdef LEGION_SPY
        , op_uid(0)
#endif
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    FutureMapImpl::~FutureMapImpl(void)
    //--------------------------------------------------------------------------
    {
      futures.clear();
    }

    //--------------------------------------------------------------------------
    FutureMapImpl& FutureMapImpl::operator=(const FutureMapImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::notify_active(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // If we are not the owner, send a gc reference back to the owner
      if (!is_owner())
        send_remote_gc_increment(owner_space, mutator);
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::notify_valid(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::notify_invalid(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::notify_inactive(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // If we are not the owner, remove our gc reference
      if (!is_owner())
        send_remote_gc_decrement(owner_space, mutator);
    }

    //--------------------------------------------------------------------------
    Future FutureMapImpl::get_future(const DomainPoint &point, RtEvent *wait_on)
    //--------------------------------------------------------------------------
    {
      if (!is_owner())
      {
        // See if we already have it
        {
          AutoLock fm_lock(future_map_lock,1,false/*exlusive*/);
          std::map<DomainPoint,Future>::const_iterator finder = 
                                                futures.find(point);
          if (finder != futures.end())
            return finder->second;
        }
        // Make an event for when we have the answer
        RtUserEvent future_ready_event = Runtime::create_rt_user_event();
        // If not send a message to get it
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(did);
          rez.serialize(point);
          rez.serialize(future_ready_event);
        }
        runtime->send_future_map_request_future(owner_space, rez);
        if (wait_on != NULL)
        {
          *wait_on = future_ready_event;
          return Future();
        }
        future_ready_event.wait(); 
        // When we wake up it should be here
        AutoLock fm_lock(future_map_lock,1,false/*exlusive*/);
        std::map<DomainPoint,Future>::const_iterator finder = 
                                              futures.find(point);
#ifdef DEBUG_LEGION
        assert(finder != futures.end());
#endif
        return finder->second;
      }
      else
      {
#ifdef DEBUG_LEGION
#ifndef NDEBUG
        // Check to make sure we are asking for something in the domain
        if (valid_points.find(point) == valid_points.end())
        {
          bool is_valid_point = false;
          for (std::vector<Domain>::const_iterator it = 
                valid_domains.begin(); it != valid_domains.end(); it++)
          {
            if (it->contains(point))
            {
              is_valid_point = true;
              break;
            }
          }
          assert(is_valid_point);
        }
#endif
#endif
        AutoLock fm_lock(future_map_lock);
        // Check to see if we already have a future for the point
        std::map<DomainPoint,Future>::const_iterator finder = 
                                              futures.find(point);
        if (finder != futures.end())
          return finder->second;
        // Otherwise we need a future from the context to use for
        // the point that we will fill in later
        Future result = 
          runtime->help_create_future(context, ApEvent::NO_AP_EVENT, op);
        futures[point] = result;
        if (runtime->legion_spy_enabled)
          LegionSpy::log_future_creation(op->get_unique_op_id(),
                                   ApEvent::NO_AP_EVENT, point);
        return result;
      }
    }

    //--------------------------------------------------------------------------
    FutureImpl* FutureMapImpl::find_future(const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      AutoLock fm_lock(future_map_lock,1,false/*exclusive*/);
      std::map<DomainPoint,Future>::const_iterator finder = futures.find(point);
      if (finder != futures.end())
        return finder->second.impl;
      else
        return NULL;
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::set_future(const DomainPoint &point, FutureImpl *impl,
                                   ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!is_owner()); // should never be called on the owner node
#endif
      // Add the reference first and then set the future
      impl->add_base_gc_ref(FUTURE_HANDLE_REF, mutator);
      AutoLock fm_lock(future_map_lock);
      futures[point] = Future(impl, false/*need reference*/);
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::get_void_result(const DomainPoint &point,
                                        bool silence_warnings,
                                        const char *warning_string)
    //--------------------------------------------------------------------------
    {
      Future f = get_future(point);
      f.get_void_result(silence_warnings, warning_string);
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::wait_all_results(bool silence_warnings,
                                         const char *warning_string)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner());
#endif
      if (runtime->runtime_warnings && !silence_warnings && 
          (context != NULL) && !context->is_leaf_context())
        REPORT_LEGION_WARNING(LEGION_WARNING_WAITING_ALL_FUTURES, 
            "Waiting for all futures in a future map in "
            "non-leaf task %s (UID %lld) is a violation of Legion's deferred "
            "execution model best practices. You may notice a severe "
            "performance degredation. Warning string: %s", 
            context->get_task_name(),
            context->get_unique_id(),
            (warning_string == NULL) ? "" : warning_string)
      if ((op != NULL) && (Internal::implicit_context != NULL))
        Internal::implicit_context->record_blocking_call();
      // Wait on the event that indicates the entire task has finished
      if (!ready_event.has_triggered())
      {
        if (context != NULL)
        {
          context->begin_task_wait(false/*from runtime*/);
          ready_event.wait();
          context->end_task_wait();
        }
        else
          ready_event.wait();
      }
    }

    //--------------------------------------------------------------------------
    bool FutureMapImpl::reset_all_futures(RtEvent new_ready_event)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner());
#endif
      // TODO: send messages to all the remote copies of this
      assert(false);
      bool result = false;
      AutoLock fm_lock(future_map_lock);
      for (std::map<DomainPoint,Future>::const_iterator it = 
            futures.begin(); it != futures.end(); it++)
      {
        bool restart = runtime->help_reset_future(it->second);
        if (restart)
          result = true;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::get_all_futures(
                                     std::map<DomainPoint,Future> &others) const
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner());
#endif
      if (op != NULL && Internal::implicit_context != NULL)
        Internal::implicit_context->record_blocking_call();
      if (!ready_event.has_triggered())
      {
        if (context != NULL)
        {
          context->begin_task_wait(false/*from runtime*/);
          ready_event.wait();
          context->end_task_wait();
        }
        else
          ready_event.wait();
      }
      // No need for the lock since the map should be fixed at this point
      others = futures;
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::set_all_futures(
                                     const std::map<DomainPoint,Future> &others)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner());
#endif
      // No need for the lock here since we're initializing
      futures = others;
    }

#ifdef DEBUG_LEGION
    //--------------------------------------------------------------------------
    void FutureMapImpl::add_valid_domain(const Domain &d)
    //--------------------------------------------------------------------------
    {
      assert(is_owner());
      valid_domains.push_back(d);
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::add_valid_point(const DomainPoint &dp)
    //--------------------------------------------------------------------------
    {
      assert(is_owner());
      valid_points.insert(dp);
    }
#endif

    //--------------------------------------------------------------------------
    void FutureMapImpl::register_dependence(Operation *consumer_op)
    //--------------------------------------------------------------------------
    {
      if (op == NULL)
        return;
      // Only record dependences on things from the same context
      // We know futures can never flow up the task tree so the
      // only way they have the same depth is if they are from 
      // the same parent context
      TaskContext *context = consumer_op->get_context();
      const int consumer_depth = context->get_depth();
#ifdef DEBUG_LEGION
      assert(consumer_depth >= op_depth);
#endif
      if (consumer_depth == op_depth)
      {
        consumer_op->register_dependence(op, op_gen);
#ifdef LEGION_SPY
        LegionSpy::log_mapping_dependence(
            context->get_unique_id(), op_uid, 0,
            consumer_op->get_unique_op_id(), 0, TRUE_DEPENDENCE);
#endif
      }
    }

    //--------------------------------------------------------------------------
    void FutureMapImpl::record_future_map_registered(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // Similar to DistributedCollectable::register_with_runtime but
      // we don't actually need to do the registration since we know
      // it has already been done
#ifdef DEBUG_LEGION
      assert(!registered_with_runtime);
#endif
      registered_with_runtime = true;
      if (!is_owner())
        // Send the remote registration notice
        send_remote_registration(mutator);
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureMapImpl::handle_future_map_future_request(
                   Deserializer &derez, Runtime *runtime, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      DistributedID did;
      derez.deserialize(did);
      DomainPoint point;
      derez.deserialize(point);
      RtUserEvent done;
      derez.deserialize(done);
      
      // Should always find it since this is the owner node
      DistributedCollectable *dc = runtime->find_distributed_collectable(did);
#ifdef DEBUG_LEGION
      FutureMapImpl *impl = dynamic_cast<FutureMapImpl*>(dc);
      assert(impl != NULL);
#else
      FutureMapImpl *impl = static_cast<FutureMapImpl*>(dc);
#endif
      Future f = impl->get_future(point);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(did);
        rez.serialize(point);
        rez.serialize(f.impl->did);
        rez.serialize(done);
      }
      runtime->send_future_map_response_future(source, rez);
    }

    //--------------------------------------------------------------------------
    /*static*/ void FutureMapImpl::handle_future_map_future_response(
                                          Deserializer &derez, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      DistributedID did;
      derez.deserialize(did);
      DomainPoint point;
      derez.deserialize(point);
      DistributedID future_did;
      derez.deserialize(future_did);
      RtUserEvent done;
      derez.deserialize(done);
      
      // Should always find it since this is the source node
      DistributedCollectable *dc = runtime->find_distributed_collectable(did);
#ifdef DEBUG_LEGION
      FutureMapImpl *impl = dynamic_cast<FutureMapImpl*>(dc);
      assert(impl != NULL);
#else
      FutureMapImpl *impl = static_cast<FutureMapImpl*>(dc);
#endif
      std::set<RtEvent> done_events;
      WrapperReferenceMutator mutator(done_events);
      FutureImpl *future = runtime->find_or_create_future(future_did,
                            impl->context->get_unique_id(), &mutator);
      // Add it to the map
      impl->set_future(point, future, &mutator);
      // Trigger the done event
      if (!done_events.empty())
        Runtime::trigger_event(done, Runtime::merge_events(done_events));
      else
        Runtime::trigger_event(done);
    }

    /////////////////////////////////////////////////////////////
    // Physical Region Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    PhysicalRegionImpl::PhysicalRegionImpl(const RegionRequirement &r, 
      RtEvent mapped, ApEvent ready, ApUserEvent term, bool m, TaskContext *ctx, 
      MapperID mid, MappingTagID t, bool leaf, bool virt, Runtime *rt)
      : Collectable(), runtime(rt), context(ctx), map_id(mid), tag(t),
        leaf_region(leaf), virtual_mapped(virt), 
        replaying((ctx != NULL) ? ctx->owner_task->is_replaying() : false),
        req(r), mapped_event(mapped), ready_event(ready),
        termination_event(term), mapped(m), valid(false), made_accessor(false)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    PhysicalRegionImpl::~PhysicalRegionImpl(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!termination_event.exists());
#endif
      if (!references.empty() && !replaying)
      {
        if (leaf_region)
          references.remove_resource_references(PHYSICAL_REGION_REF);
        else
          references.remove_valid_references(PHYSICAL_REGION_REF, NULL/*mut*/);
      }
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::wait_until_valid(bool silence_warnings, 
                                              const char *warning_string,
                                              bool warn, const char *source)
    //--------------------------------------------------------------------------
    {
      if (context != NULL)
        context->record_blocking_call();
      if (runtime->runtime_warnings && !silence_warnings &&
          (context != NULL) && !context->is_leaf_context())
      {
        if (source != NULL)
          REPORT_LEGION_WARNING(LEGION_WARNING_WAITING_REGION, 
              "Waiting for a physical region to be valid "
              "for call %s in non-leaf task %s (UID %lld) is a violation of "
              "Legion's deferred execution model best practices. You may "
              "notice a severe performance degradation. Warning string: %s", 
              source, context->get_task_name(), context->get_unique_id(),
              (warning_string == NULL) ? "" : warning_string)
        else
          REPORT_LEGION_WARNING(LEGION_WARNING_WAITING_REGION, 
              "Waiting for a physical region to be valid "
              "in non-leaf task %s (UID %lld) is a violation of Legion's "
              "deferred execution model best practices. You may notice a "
              "severe performance degradation. Warning string: %s", 
              context->get_task_name(), context->get_unique_id(),
              (warning_string == NULL) ? "" : warning_string)
      }
      if (mapped_event.exists() && !mapped_event.has_triggered())
      {
        if (warn && !silence_warnings && (source != NULL))
          REPORT_LEGION_WARNING(LEGION_WARNING_MISSING_REGION_WAIT, 
              "Request for %s was performed on a "
              "physical region in task %s (ID %lld) without first waiting "
              "for the physical region to be valid. Legion is performing "
              "the wait for you. Warning string: %s", source, 
              context->get_task_name(), context->get_unique_id(),
              (warning_string == NULL) ? "" : warning_string)
        if (context != NULL)
          context->begin_task_wait(false/*from runtime*/);
        mapped_event.wait();
        if (context != NULL)
          context->end_task_wait();
      }
      // If we've already gone through this process we're good
      if (valid)
        return;
      // Now wait for the reference to be ready
      bool poisoned = false;
      if (!ready_event.has_triggered_faultaware(poisoned))
      {
        if (!poisoned)
        {
          if (context != NULL)
            context->begin_task_wait(false/*from runtime*/);
          ready_event.wait_faultaware(poisoned);
          if (context != NULL)
            context->end_task_wait();
        }
      }
      valid = true;
    }

    //--------------------------------------------------------------------------
    bool PhysicalRegionImpl::is_valid(void) const
    //--------------------------------------------------------------------------
    {
      if (valid)
        return true;
      if (!mapped_event.exists() || mapped_event.has_triggered())
      {
        bool poisoned = false;
        if (ready_event.has_triggered_faultaware(poisoned) && !poisoned)
          return true;
        if (poisoned)
          implicit_context->raise_poison_exception();
      }
      return valid;
    }

    //--------------------------------------------------------------------------
    bool PhysicalRegionImpl::is_mapped(void) const
    //--------------------------------------------------------------------------
    {
      return mapped;
    }

    //--------------------------------------------------------------------------
    LogicalRegion PhysicalRegionImpl::get_logical_region(void) const
    //--------------------------------------------------------------------------
    {
      return req.region;
    }

    //--------------------------------------------------------------------------
    PrivilegeMode PhysicalRegionImpl::get_privilege(void) const
    //--------------------------------------------------------------------------
    {
      return req.privilege;
    }

    //--------------------------------------------------------------------------
    LegionRuntime::Accessor::RegionAccessor<
      LegionRuntime::Accessor::AccessorType::Generic>
        PhysicalRegionImpl::get_accessor(bool silence_warnings)
    //--------------------------------------------------------------------------
    {
      if (context != NULL)
      {
        if (context->is_inner_context())
          REPORT_LEGION_ERROR(ERROR_INNER_TASK_VIOLATION, 
            "Illegal call to 'get_accessor' inside task "
            "%s (UID %lld) for a variant that was labeled as an 'inner' "
            "variant.", context->get_task_name(), context->get_unique_id())
        else if (runtime->runtime_warnings && !silence_warnings &&
                  !context->is_leaf_context())
          REPORT_LEGION_WARNING(LEGION_WARNING_NONLEAF_ACCESSOR, 
              "Call to 'get_accessor' in non-leaf task %s "
              "(UID %lld) is a blocking operation in violation of Legion's "
              "deferred execution model best practices. You may notice a "
              "severe performance degradation.", context->get_task_name(),
              context->get_unique_id())
      }
      // If this physical region isn't mapped, then we have to
      // map it before we can return an accessor
      if (!mapped)
      {
        if (virtual_mapped)
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_IMPLICIT_MAPPING, 
                        "Illegal implicit mapping of a virtual mapped region "
                        "in task %s (UID %lld)", context->get_task_name(),
                        context->get_unique_id())
        if (runtime->runtime_warnings && !silence_warnings)
          REPORT_LEGION_WARNING(LEGION_WARNING_UNMAPPED_ACCESSOR, 
                          "Request for 'get_accessor' was "
                          "performed on an unmapped region in task %s "
                          "(UID %lld). Legion is mapping it for you. "
                          "Please try to be more careful.",
                          context->get_task_name(), context->get_unique_id())
        runtime->remap_region(context, PhysicalRegion(this));
        // At this point we should have a new ready event
        // and be mapped
#ifdef DEBUG_LEGION
        assert(mapped);
#endif
      }
      // Wait until we are valid before returning the accessor
      wait_until_valid(silence_warnings, NULL, 
                       runtime->runtime_warnings, "get_accessor");
      // You can only legally invoke this method when you have one instance
      if (references.size() > 1)
        REPORT_LEGION_ERROR(ERROR_DEPRECATED_METHOD_USE, 
                      "Illegal invocation of deprecated 'get_accessor' method "
                      "in task %s (ID %lld) on a PhysicalRegion containing "
                      "multiple internal instances. Use of this deprecated "
                      "method is only supported if the PhysicalRegion contains "
                      "a single physical instance.", context->get_task_name(),
                      context->get_unique_id())
      made_accessor = true;
      const InstanceSet &instances = references;
#if defined(LEGION_PRIVILEGE_CHECKS) || defined(LEGION_BOUNDS_CHECKS)
      LegionRuntime::Accessor::RegionAccessor<
        LegionRuntime::Accessor::AccessorType::Generic>
          result = instances[0].get_accessor();
      result.set_region_untyped(this);
#ifdef LEGION_PRIVILEGE_CHECKS
      result.set_privileges_untyped(
          (LegionRuntime::AccessorPrivilege)req.get_accessor_privilege()); 
#endif
      return result;
#else // privilege or bounds checks
      return instances[0].get_accessor();
#endif
    }

    //--------------------------------------------------------------------------
    LegionRuntime::Accessor::RegionAccessor<
        LegionRuntime::Accessor::AccessorType::Generic>
          PhysicalRegionImpl::get_field_accessor(FieldID fid, 
                                                 bool silence_warnings)
    //--------------------------------------------------------------------------
    {
      if (context != NULL)
      {
        if (context->is_inner_context())
          REPORT_LEGION_ERROR(ERROR_INNER_TASK_VIOLATION, 
            "Illegal call to 'get_field_accessor' inside "
            "task %s (UID %lld) for a variant that was labeled as an 'inner' "
            "variant.", context->get_task_name(), context->get_unique_id())
        else if (runtime->runtime_warnings && !silence_warnings &&
                  !context->is_leaf_context())
          REPORT_LEGION_WARNING(LEGION_WARNING_NONLEAF_ACCESSOR, 
              "Call to 'get_field_accessor' in non-leaf "
              "task %s (UID %lld) is a blocking operation in violation of "
              "Legion's deferred execution model best practices. You may "
              "notice a severe performance degradation.", 
              context->get_task_name(), context->get_unique_id())
      }
      // If this physical region isn't mapped, then we have to
      // map it before we can return an accessor
      if (!mapped)
      {
        if (virtual_mapped)
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_IMPLICIT_MAPPING, 
                        "Illegal implicit mapping of a virtual mapped region "
                        "in task %s (UID %lld)", context->get_task_name(),
                        context->get_unique_id())
        if (runtime->runtime_warnings && !silence_warnings)
          REPORT_LEGION_WARNING(LEGION_WARNING_UNMAPPED_ACCESSOR, 
                          "Request for 'get_field_accessor' was "
                          "performed on an unmapped region in task %s "
                          "(UID %lld). Legion is mapping it for you. "
                          "Please try to be more careful.",
                          context->get_task_name(), context->get_unique_id())
        runtime->remap_region(context, PhysicalRegion(this));
        // At this point we should have a new ready event
        // and be mapped
#ifdef DEBUG_LEGION
        assert(mapped);
#endif 
      }
      // Wait until we are valid before returning the accessor
      wait_until_valid(silence_warnings, NULL, 
                       runtime->runtime_warnings, "get_field_acessor");
#ifdef DEBUG_LEGION
      if (req.privilege_fields.find(fid) == req.privilege_fields.end())
        REPORT_LEGION_ERROR(ERROR_INVALID_FIELD_PRIVILEGES, 
            "Requested field accessor for field %d without privileges!", fid)
#endif
      made_accessor = true;
      const InstanceSet &instances = references;
#if defined(LEGION_PRIVILEGE_CHECKS) || defined(LEGION_BOUNDS_CHECKS)
      LegionRuntime::Accessor::RegionAccessor<
        LegionRuntime::Accessor::AccessorType::Generic>
          result = instances.get_field_accessor(fid);
      result.set_region_untyped(this);
#ifdef LEGION_PRIVILEGE_CHECKS
      result.set_privileges_untyped(
          (LegionRuntime::AccessorPrivilege)req.get_accessor_privilege());
#endif
      return result;
#else // privilege or bounds checks
      return instances.get_field_accessor(fid);
#endif
    } 

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::unmap_region(void)
    //--------------------------------------------------------------------------
    {
      if (!mapped)
        return;
#ifdef DEBUG_LEGION
      assert(termination_event.exists());
#endif
      // trigger the termination event conditional upon the ready event
      Runtime::trigger_event(NULL, termination_event, ready_event);
#ifdef DEBUG_LEGION
      termination_event = ApUserEvent::NO_AP_USER_EVENT;
#endif
      // reset mapped and valid
      mapped = false;
      valid = false;
    }

    //--------------------------------------------------------------------------
    ApEvent PhysicalRegionImpl::remap_region(ApEvent new_ready)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!mapped);
      assert(!termination_event.exists());
#endif
      termination_event = Runtime::create_ap_user_event(NULL);
      ready_event = new_ready;
      mapped = true;
      return termination_event;
    }

    //--------------------------------------------------------------------------
    const RegionRequirement& PhysicalRegionImpl::get_requirement(void) const
    //--------------------------------------------------------------------------
    {
      return req;
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::add_padded_field(FieldID fid)
    //--------------------------------------------------------------------------
    {
      padded_fields.push_back(fid);
      // Resort to keep things in order
      if (padded_fields.size() > 1)
        std::sort(padded_fields.begin(), padded_fields.end());
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::set_reference(const InstanceRef &ref, bool safe)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(ref.has_ref());
      assert(references.empty());
      assert(safe || (mapped_event.exists() && !mapped_event.has_triggered()));
#endif
      references.add_instance(ref);
      if (!replaying)
      {
        if (leaf_region)
          ref.add_resource_reference(PHYSICAL_REGION_REF);
        else
          ref.add_valid_reference(PHYSICAL_REGION_REF, NULL/*mutator*/);
      }
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::set_references(const InstanceSet &refs, bool safe)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(references.empty());
      assert(safe || (mapped_event.exists() && !mapped_event.has_triggered()));
#endif
      references = refs;
      if (!references.empty() && !replaying)
      {
        if (leaf_region)
          references.add_resource_references(PHYSICAL_REGION_REF);
        else
          references.add_valid_references(PHYSICAL_REGION_REF, NULL/*mutator*/);
      }
    }

    //--------------------------------------------------------------------------
    bool PhysicalRegionImpl::has_references(void) const
    //--------------------------------------------------------------------------
    {
      return !references.empty();
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::get_references(InstanceSet &instances) const
    //--------------------------------------------------------------------------
    {
      if (mapped_event.exists() && !mapped_event.has_triggered())
        mapped_event.wait();
      instances = references;
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::get_memories(std::set<Memory>& memories,
                        bool silence_warnings, const char *warning_string) const
    //--------------------------------------------------------------------------
    {
      if (mapped_event.exists() && !mapped_event.has_triggered())
      {
        if (runtime->runtime_warnings && !silence_warnings)
          REPORT_LEGION_WARNING(LEGION_WARNING_MISSING_REGION_WAIT, 
              "Request for 'get_memories' was performed on a "
              "physical region in task %s (ID %lld) without first waiting "
              "for the physical region to be valid. Legion is performing "
              "the wait for you. Warning string: %s", context->get_task_name(), 
              context->get_unique_id(), (warning_string == NULL) ? 
              "" : warning_string)
        if (context != NULL)
          context->begin_task_wait(false/*from runtime*/);
        mapped_event.wait();
        if (context != NULL)
          context->end_task_wait();
      }
      const InstanceSet &instances = references;
      for (unsigned idx = 0; idx < instances.size(); idx++)
        memories.insert(instances[idx].get_memory());
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::get_fields(std::vector<FieldID>& fields) const
    //--------------------------------------------------------------------------
    {
      // Just get these from the region requirement
      fields.insert(fields.end(), req.privilege_fields.begin(),
                    req.privilege_fields.end());
    }


#if defined(LEGION_PRIVILEGE_CHECKS) || defined(LEGION_BOUNDS_CHECKS)
    //--------------------------------------------------------------------------
    const char* PhysicalRegionImpl::get_task_name(void) const
    //--------------------------------------------------------------------------
    {
      return context->get_task_name();
    }
#endif

#ifdef LEGION_BOUNDS_CHECKS 
    //--------------------------------------------------------------------------
    bool PhysicalRegionImpl::contains_ptr(ptr_t ptr)
    //--------------------------------------------------------------------------
    {
      if (!bounds.exists())
        bounds = runtime->forest->get_node(req.region.get_index_space())->
                    get_color_space_domain();
      DomainPoint dp(ptr.value);
      return bounds.contains(dp);
    }
    
    //--------------------------------------------------------------------------
    bool PhysicalRegionImpl::contains_point(const DomainPoint &dp)
    //--------------------------------------------------------------------------
    {
      if (!bounds.exists())
        bounds = runtime->forest->get_node(req.region.get_index_space())->
                    get_color_space_domain();
      return bounds.contains(dp);
    }
#endif

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::get_bounds(void *realm_is, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      runtime->get_index_space_domain(req.region.get_index_space(),
                                      realm_is, type_tag);
    }

    //--------------------------------------------------------------------------
    PieceIteratorImpl* PhysicalRegionImpl::get_piece_iterator(FieldID fid,
         bool privilege_only, bool silence_warnings, const char *warning_string)
    //--------------------------------------------------------------------------
    {
      if (req.privilege_fields.find(fid) == req.privilege_fields.end())
        REPORT_LEGION_ERROR(ERROR_INVALID_FIELD_PRIVILEGES, 
                       "Piece iterator construction in task %s on "
                       "PhysicalRegion that does not contain field %d!", 
                       context->get_task_name(), fid)
      if (mapped_event.exists() && !mapped_event.has_triggered())
      {
        if (runtime->runtime_warnings && !silence_warnings)
          REPORT_LEGION_WARNING(LEGION_WARNING_MISSING_REGION_WAIT, 
              "Request for 'get_piece_iterator' was performed on a "
              "physical region in task %s (ID %lld) without first waiting "
              "for the physical region to be valid. Legion is performing "
              "the wait for you. Warning string: %s", context->get_task_name(), 
              context->get_unique_id(), (warning_string == NULL) ? 
              "" : warning_string)
        if (context != NULL)
          context->begin_task_wait(false/*from runtime*/);
        mapped_event.wait();
        if (context != NULL)
          context->end_task_wait();
      }
      const InstanceSet &instances = references;
      for (unsigned idx = 0; idx < instances.size(); idx++)
      {
        const InstanceRef &ref = instances[idx];
        if (ref.is_field_set(fid))
        {
          PhysicalManager *manager = ref.get_physical_manager();
          if (privilege_only)
          {
            IndexSpaceNode *privilege_node =
              runtime->forest->get_node(req.region.get_index_space());
            return manager->create_piece_iterator(privilege_node);
          }
          else
            return manager->create_piece_iterator(NULL);
        }
      }
      assert(false);
      return NULL;
    }
    
    //--------------------------------------------------------------------------
    PhysicalInstance PhysicalRegionImpl::get_instance_info(PrivilegeMode mode, 
                                              FieldID fid, size_t field_size, 
                                              void *realm_is, TypeTag type_tag,
                                              const char *warning_string,
                                              bool silence_warnings, 
                                              bool generic_accessor,
                                              bool check_field_size,
                                              ReductionOpID redop)
    //--------------------------------------------------------------------------
    { 
      // Check the privilege mode first
      switch (mode)
      {
        case LEGION_READ_ONLY:
          {
            if (!(LEGION_READ_ONLY & req.privilege))
              REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                            "Error creating read-only field accessor without "
                            "read-only privileges on field %d in task %s",
                            fid, context->get_task_name())
            break;
          }
        case LEGION_READ_WRITE:
          {
            if (req.privilege == LEGION_WRITE_DISCARD)
            {
              if (!silence_warnings)
                REPORT_LEGION_WARNING(LEGION_WARNING_READ_DISCARD, 
                                "creating read-write accessor for "
                                "field %d in task %s which only has "
                                "WRITE_DISCARD privileges. You may be "
                                "accessing uninitialized data. "
                                "Warning string: %s",
                                fid, context->get_task_name(),
                                (warning_string == NULL) ? "" : warning_string)
            }
            else if (req.privilege != LEGION_READ_WRITE)
              REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                            "Error creating read-write field accessor without "
                            "read-write privileges on field %d in task %s",
                            fid, context->get_task_name())
            break;
          }
        case LEGION_WRITE_ONLY:
        case LEGION_WRITE_DISCARD:
          {
            if (!(LEGION_WRITE_DISCARD & req.privilege))
              REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                            "Error creating write-discard field accessor "
                            "without write privileges on field %d in task %s",
                            fid, context->get_task_name())
            break;
          }
        case LEGION_REDUCE:
          {
            if ((LEGION_REDUCE != req.privilege) || (redop != req.redop))
            {
              if (!(LEGION_REDUCE & req.privilege))
                REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                              "Error creating reduction field accessor "
                              "without reduction privileges on field %d in "
                              "task %s", fid, context->get_task_name())
              else if ((redop != req.redop) && 
                       (req.privilege != LEGION_READ_WRITE))
                REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                              "Error creating reduction field accessor "
                              "with mismatched reduction operators %d and %d "
                              "on field %d in task %s", redop, req.redop,
                              fid, context->get_task_name())
#ifdef DEBUG_LEGION
              assert(req.privilege == LEGION_READ_WRITE);
#endif
            }
            break;
          }
        default: // rest of the privileges don't matter
          break;
      }
      if (context != NULL)
      {
        if (context->is_inner_context())
          REPORT_LEGION_ERROR(ERROR_INNER_TASK_VIOLATION, 
            "Illegal accessor construction inside "
            "task %s (UID %lld) for a variant that was labeled as an 'inner' "
            "variant.", context->get_task_name(), context->get_unique_id())
        else if (runtime->runtime_warnings && !silence_warnings &&
                  !context->is_leaf_context())
          REPORT_LEGION_WARNING(LEGION_WARNING_NONLEAF_ACCESSOR, 
              "Accessor construction in non-leaf "
              "task %s (UID %lld) is a blocking operation in violation of "
              "Legion's deferred execution model best practices. You may "
              "notice a severe performance degradation. Warning string: %s",
              context->get_task_name(), context->get_unique_id(),
              (warning_string == NULL) ? "" : warning_string)
      }
      // If this physical region isn't mapped, then we have to
      // map it before we can return an accessor
      if (!mapped)
      {
        if (virtual_mapped)
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_IMPLICIT_MAPPING, 
                        "Illegal implicit mapping of a virtual mapped region "
                        "in task %s (UID %lld)", context->get_task_name(),
                        context->get_unique_id())
        if (runtime->runtime_warnings && !silence_warnings)
          REPORT_LEGION_WARNING(LEGION_WARNING_UNMAPPED_ACCESSOR, 
                          "Accessor construction was "
                          "performed on an unmapped region in task %s "
                          "(UID %lld). Legion is mapping it for you. "
                          "Please try to be more careful. Warning string: %s",
                          context->get_task_name(), context->get_unique_id(),
                          (warning_string == NULL) ? "" : warning_string)
        runtime->remap_region(context, PhysicalRegion(this));
        // At this point we should have a new ready event
        // and be mapped
#ifdef DEBUG_LEGION
        assert(mapped);
#endif 
      }
      if (req.privilege_fields.find(fid) == req.privilege_fields.end())
        REPORT_LEGION_ERROR(ERROR_INVALID_FIELD_PRIVILEGES, 
                       "Accessor construction for field %d in task %s "
                       "without privileges!", fid, context->get_task_name())
      if (generic_accessor && runtime->runtime_warnings && !silence_warnings)
        REPORT_LEGION_WARNING(LEGION_WARNING_GENERIC_ACCESSOR,
                              "Using a generic accessor for accessing a "
                              "physical instance of task %s (UID %lld). "
                              "Generic accessors are very slow and are "
                              "strongly discouraged for use in high "
                              "performance code. Warning string: %s", 
                              context->get_task_name(),
                              context->get_unique_id(),
                              (warning_string == NULL) ? "" : warning_string)
      // Get the index space to use for the accessor
      IndexSpaceNode *bounds = 
        runtime->forest->get_node(req.region.get_index_space());
      // Check to see if this is a padded field, if it is then we need to 
      // merge the padding into the resulting domain that is allowed
      // to be accessed by the accessor for bounds checks
      bool need_padded_bounds = false;
      if (!std::binary_search(padded_fields.begin(), padded_fields.end(), fid))
        bounds->get_index_space_domain(realm_is, type_tag);
      else
        need_padded_bounds = true;
      // Wait until we are valid before returning the accessor
      wait_until_valid(silence_warnings, warning_string,
                       runtime->runtime_warnings, "Accessor Construction");
      made_accessor = true;
      const InstanceSet &instances = references;
      for (unsigned idx = 0; idx < instances.size(); idx++)
      {
        const InstanceRef &ref = instances[idx];
        if (ref.is_field_set(fid))
        {
          PhysicalManager *manager = ref.get_physical_manager();
          if (check_field_size)
          {
            const size_t actual_size = 
              manager->field_space_node->get_field_size(fid);
            if (actual_size != field_size)
              REPORT_LEGION_ERROR(ERROR_ACCESSOR_FIELD_SIZE_CHECK,
                            "Error creating accessor for field %d with a "
                            "type of size %zd bytes when the field was "
                            "originally allocated with a size of %zd bytes "
                            "in task %s (UID %lld)",
                            fid, field_size, actual_size, 
                            context->get_task_name(), context->get_unique_id()) 
          }
          if (need_padded_bounds)
          {
            Domain domain;
            bounds->get_launch_space_domain(domain);
#ifdef DEBUG_LEGION
            assert(domain.dense());
#endif
            // Now we can compute the bounds on this instance
            const Domain &delta= 
              manager->layout->constraints->padding_constraint.delta;
#ifdef DEBUG_LEGION
            assert(domain.get_dim() == delta.get_dim());
#endif
            const Domain padded_bounds =
              Domain(domain.lo() - delta.lo(), domain.hi() + delta.hi());
            switch (domain.get_dim())
            {
#define DIMFUNC(DIM) \
              case DIM: \
                { \
                  RealmSpaceConverter<DIM,Realm::DIMTYPES>::convert_to( \
                      padded_bounds, realm_is, type_tag, "get_instance_info"); \
                  break; \
                }
              LEGION_FOREACH_N(DIMFUNC)
#undef DIMFUNC
              default:
                assert(false);
            }
          }
          return manager->get_instance(context->owner_task->index_point);
        }
      }
      // should never get here at worst there should have been an
      // error raised earlier in this function
      assert(false);
      return PhysicalInstance::NO_INST;
    } 

    //--------------------------------------------------------------------------
    PhysicalInstance PhysicalRegionImpl::get_padding_info(FieldID fid,
                              size_t field_size, Domain *inner, Domain &outer,
                              const char *warning_string, bool silence_warnings,
                              bool generic_accessor, bool check_field_size)
    //--------------------------------------------------------------------------
    {
      if (!std::binary_search(padded_fields.begin(), padded_fields.end(), fid))
        REPORT_LEGION_ERROR(ERROR_INVALID_PADDED_ACCESSOR,
            "Illegal request to create a padded accessor for field %d in "
            "parent task %s (UID %lld) which does not have padded privileges. "
            "You must record a layout constraint with an explicit for padding "
            "constraint when registering this task variant in order to be able "
            "to access the padded space on this instance.",
            fid, context->get_task_name(), context->get_unique_id())
      if (context != NULL)
      {
        if (context->is_inner_context())
          REPORT_LEGION_ERROR(ERROR_INNER_TASK_VIOLATION, 
            "Illegal padding accessor construction inside "
            "task %s (UID %lld) for a variant that was labeled as an 'inner' "
            "variant.", context->get_task_name(), context->get_unique_id())
        else if (runtime->runtime_warnings && !silence_warnings &&
                  !context->is_leaf_context())
          REPORT_LEGION_WARNING(LEGION_WARNING_NONLEAF_ACCESSOR, 
              "Padding ccessor construction in non-leaf "
              "task %s (UID %lld) is a blocking operation in violation of "
              "Legion's deferred execution model best practices. You may "
              "notice a severe performance degradation. Warning string: %s",
              context->get_task_name(), context->get_unique_id(),
              (warning_string == NULL) ? "" : warning_string)
      }
      if (req.privilege_fields.find(fid) == req.privilege_fields.end())
        REPORT_LEGION_ERROR(ERROR_INVALID_FIELD_PRIVILEGES, 
                       "Padding accessor construction for field %d in task %s "
                       "without privileges!", fid, context->get_task_name())
      if (generic_accessor && runtime->runtime_warnings && !silence_warnings)
        REPORT_LEGION_WARNING(LEGION_WARNING_GENERIC_ACCESSOR,
                              "Using a generic accessor for accessing a "
                              "physical instance of task %s (UID %lld). "
                              "Generic accessors are very slow and are "
                              "strongly discouraged for use in high "
                              "performance code. Warning string: %s", 
                              context->get_task_name(),
                              context->get_unique_id(),
                              (warning_string == NULL) ? "" : warning_string)
      const InstanceSet &instances = references;
      for (unsigned idx = 0; idx < instances.size(); idx++)
      {
        const InstanceRef &ref = instances[idx];
        if (ref.is_field_set(fid))
        {
          PhysicalManager *manager = ref.get_physical_manager();
          if (check_field_size)
          {
            const size_t actual_size = 
              manager->field_space_node->get_field_size(fid);
            if (actual_size != field_size)
              REPORT_LEGION_ERROR(ERROR_ACCESSOR_FIELD_SIZE_CHECK,
                            "Error creating accessor for field %d with a "
                            "type of size %zd bytes when the field was "
                            "originally allocated with a size of %zd bytes "
                            "in task %s (UID %lld)",
                            fid, field_size, actual_size, 
                            context->get_task_name(), context->get_unique_id()) 
          }
          // If this is a padded instance, then we know that this is an affine
          // instance so we can get it's index space expression and it should
          // be dense so then we can just add the offsets
          ApEvent dom_ready;
          Domain bounds = 
            manager->instance_domain->get_domain(dom_ready,true/*tight*/);
#ifdef DEBUG_LEGION
          assert(bounds.dense());
#endif
          if (inner != NULL)
            *inner = bounds;
          // Now we can compute the bounds on this instance
          const Domain &delta= 
            manager->layout->constraints->padding_constraint.delta;
#ifdef DEBUG_LEGION
          assert(bounds.get_dim() == delta.get_dim());
#endif
          outer = Domain(bounds.lo() - delta.lo(), bounds.hi() + delta.hi());
          return manager->get_instance(context->owner_task->index_point);
        }
      }
      // should never get here at worst there should have been an
      // error raised earlier in this function
      assert(false);
      return PhysicalInstance::NO_INST;
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::report_incompatible_accessor(
              const char *accessor_kind, PhysicalInstance instance, FieldID fid)
    //--------------------------------------------------------------------------
    {
      REPORT_LEGION_ERROR(ERROR_ACCESSOR_COMPATIBILITY_CHECK,
          "Unable to create Realm %s for field %d of instance %llx in task %s",
          accessor_kind, fid, instance.id, context->get_task_name())
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::report_incompatible_multi_accessor(unsigned index,
                    FieldID fid, PhysicalInstance inst1, PhysicalInstance inst2)
    //--------------------------------------------------------------------------
    {
      REPORT_LEGION_ERROR(ERROR_ACCESSOR_COMPATIBILITY_CHECK,
          "Unable to create multi-region accessor for field %d because "
          "instances " IDFMT " (index 0) and " IDFMT " (index %d) are "
          "differnt. Multi-region accessors must always be for region "
          "requirements with the same physical instance.", 
          fid, inst1.id, inst2.id, index)
    }

    //--------------------------------------------------------------------------
    void PhysicalRegionImpl::report_colocation_violation(
            const char *accessor_kind, FieldID fid, PhysicalInstance inst1,
            PhysicalInstance inst2, const PhysicalRegion &other, bool reduction)
    //--------------------------------------------------------------------------
    {
      REPORT_LEGION_ERROR(ERROR_COLOCATION_VIOLATION,
          "Unable to create co-location %s<%s> from multiple physical regions "
          "for field %d in task %s because regions have different physical "
          "instances " IDFMT " and  " IDFMT, reduction ? "ReductionAccessor" :
            "FieldAccessor", accessor_kind, fid, context->get_task_name(),
            inst1.id, inst2.id)
    }

    //--------------------------------------------------------------------------
    /*static*/ void PhysicalRegionImpl::empty_colocation_regions(
                         const char *accessor_kind, FieldID fid, bool reduction)
    //--------------------------------------------------------------------------
    {
      REPORT_LEGION_ERROR(ERROR_COLOCATION_VIOLATION,
          "Attempt to create colocation %s<%s> with no physical regions for "
          "field %d task %s. Must provide a non-empty set of regions.",
          reduction ? "ReductionAccessor" : "FieldAccessor", accessor_kind,
          fid, implicit_context->get_task_name())
    }

    //--------------------------------------------------------------------------
    /*static*/ void PhysicalRegionImpl::fail_bounds_check(DomainPoint p, 
                                    FieldID fid, PrivilegeMode mode, bool multi)
    //--------------------------------------------------------------------------
    {
      char point_string[128];
      sprintf(point_string," (");
      for (int d = 0; d < p.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", p[0]);
        else
          sprintf(buffer,",%lld", p[d]);
        strcat(point_string, buffer);
      }
      strcat(point_string,")");
      switch (mode)
      {
        case LEGION_READ_ONLY:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure reading point %s from "
                          "field %d in task %s%s\n", point_string, fid,
                          implicit_context->get_task_name(),
                          multi ? " for multi-region accessor" : "")
            break;
          }
        case LEGION_READ_WRITE:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure geting a reference to point %s "
                          "from field %d in task %s%s\n", point_string, fid,
                          implicit_context->get_task_name(),
                          multi ? " for multi-region accessor" : "")
            break;
          }
        case LEGION_WRITE_ONLY:
        case LEGION_WRITE_DISCARD:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure writing to point %s in "
                          "field %d in task %s%s\n", point_string, fid,
                          implicit_context->get_task_name(),
                          multi ? " for multi-region accessor" : "")
            break;
          }
        case LEGION_REDUCE:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure reducing to point %s in "
                          "field %d in task %s%s\n", point_string, fid,
                          implicit_context->get_task_name(),
                          multi ? " for multi-region accessor" : "")
            break;
          }
        default:
          assert(false);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void PhysicalRegionImpl::fail_bounds_check(Domain dom, 
                                    FieldID fid, PrivilegeMode mode, bool multi)
    //--------------------------------------------------------------------------
    {
      char rect_string[256];
      sprintf(rect_string," (");
      for (int d = 0; d < dom.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", dom.lo()[0]);
        else
          sprintf(buffer,",%lld", dom.lo()[d]);
        strcat(rect_string, buffer);
      }
      strcat(rect_string,") - (");
      for (int d = 0; d < dom.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", dom.hi()[0]);
        else
          sprintf(buffer,",%lld", dom.hi()[d]);
        strcat(rect_string, buffer);
      }
      strcat(rect_string,")");
      switch (mode)
      {
        case LEGION_READ_ONLY:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure getting a read-only reference "
                          "to rect %s from field %d in task %s%s\n", 
                          rect_string, fid, implicit_context->get_task_name(),
                          multi ? " for multi-region accessor" : "")
            break;
          }
        case LEGION_READ_WRITE:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure geting a reference to rect %s "
                          "from field %d in task %s%s\n", rect_string, fid,
                          implicit_context->get_task_name(),
                          multi ? " for multi-region accessor" : "")
            break;
          }
        default:
          assert(false);
      }
    } 

    //--------------------------------------------------------------------------
    /*static*/ void PhysicalRegionImpl::fail_privilege_check(DomainPoint p, 
                                                FieldID fid, PrivilegeMode mode)
    //--------------------------------------------------------------------------
    {
      char point_string[128];
      sprintf(point_string," (");
      for (int d = 0; d < p.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", p[0]);
        else
          sprintf(buffer,",%lld", p[d]);
        strcat(point_string, buffer);
      }
      strcat(point_string,")");
      switch (mode)
      {
        case LEGION_READ_ONLY:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                          "Privilege check failure reading point %s from "
                          "field %d in task %s\n", point_string, fid,
                          implicit_context->get_task_name())
            break;
          }
        case LEGION_READ_WRITE:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                          "Privilege check failure geting a reference to point "
                          "%s from field %d in task %s\n", point_string, fid,
                          implicit_context->get_task_name())
            break;
          }
        case LEGION_WRITE_ONLY:
        case LEGION_WRITE_DISCARD:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                          "Privilege check failure writing to point %s in "
                          "field %d in task %s\n", point_string, fid,
                          implicit_context->get_task_name())
            break;
          }
        case LEGION_REDUCE:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                          "Privilege check failure reducing to point %s in "
                          "field %d in task %s\n", point_string, fid,
                          implicit_context->get_task_name())
            break;
          }
        default:
          assert(false);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void PhysicalRegionImpl::fail_privilege_check(Domain dom, 
                                                FieldID fid, PrivilegeMode mode)
    //--------------------------------------------------------------------------
    {
      char rect_string[256];
      sprintf(rect_string," (");
      for (int d = 0; d < dom.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", dom.lo()[0]);
        else
          sprintf(buffer,",%lld", dom.lo()[d]);
        strcat(rect_string, buffer);
      }
      strcat(rect_string,") - (");
      for (int d = 0; d < dom.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", dom.hi()[0]);
        else
          sprintf(buffer,",%lld", dom.hi()[d]);
        strcat(rect_string, buffer);
      }
      strcat(rect_string,")");
      switch (mode)
      {
        case LEGION_READ_ONLY:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                          "Privilege check failure getting a read-only "
                          "reference to rect %s from field %d in task %s\n", 
                          rect_string, fid, implicit_context->get_task_name())
            break;
          }
        case LEGION_READ_WRITE:
          {
            REPORT_LEGION_ERROR(ERROR_ACCESSOR_PRIVILEGE_CHECK, 
                          "Privilege check failure geting a reference to rect "
                          "%s from field %d in task %s\n", rect_string, fid,
                          implicit_context->get_task_name())
            break;
          }
        default:
          assert(false);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void PhysicalRegionImpl::fail_padding_check(DomainPoint p,
                                                           FieldID fid)
    //--------------------------------------------------------------------------
    {
      char point_string[128];
      sprintf(point_string," (");
      for (int d = 0; d < p.get_dim(); d++)
      {
        char buffer[32];
        if (d == 0)
          sprintf(buffer,"%lld", p[0]);
        else
          sprintf(buffer,",%lld", p[d]);
        strcat(point_string, buffer);
      }
      strcat(point_string,")");
      REPORT_LEGION_ERROR(ERROR_ACCESSOR_BOUNDS_CHECK, 
                          "Bounds check failure accessing padded point %s from "
                          "field %d in task %s\n", point_string, fid,
                          implicit_context->get_task_name())
    }

    /////////////////////////////////////////////////////////////
    // ExternalResourcesImpl
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    ExternalResourcesImpl::ExternalResourcesImpl(InnerContext *ctx,
        size_t num_regions, RegionTreeNode *upper, IndexSpaceNode *launch,
        LogicalRegion par, const std::set<FieldID> &fields)
      : context(ctx), upper_bound(upper), launch_bounds(launch),
        privilege_fields(fields.begin(), fields.end()), parent(par),
        pid(0), detached(false)
    //--------------------------------------------------------------------------
    {
      regions.resize(num_regions);
      upper_bound->add_base_resource_ref(PHYSICAL_REGION_REF);
      launch_bounds->add_base_resource_ref(PHYSICAL_REGION_REF);
    }

    //--------------------------------------------------------------------------
    ExternalResourcesImpl::ExternalResourcesImpl(
                                               const ExternalResourcesImpl &rhs)
      : context(rhs.context), upper_bound(rhs.upper_bound),
        launch_bounds(rhs.launch_bounds), 
        privilege_fields(rhs.privilege_fields), parent(rhs.parent)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    ExternalResourcesImpl::~ExternalResourcesImpl(void)
    //--------------------------------------------------------------------------
    {
      if (upper_bound->remove_base_resource_ref(PHYSICAL_REGION_REF))
        delete upper_bound;
      if (launch_bounds->remove_base_resource_ref(PHYSICAL_REGION_REF))
        delete launch_bounds;
    }

    //--------------------------------------------------------------------------
    ExternalResourcesImpl& ExternalResourcesImpl::operator=(
                                               const ExternalResourcesImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    size_t ExternalResourcesImpl::size(void) const
    //--------------------------------------------------------------------------
    {
      return regions.size();
    }

    //--------------------------------------------------------------------------
    void ExternalResourcesImpl::set_region(unsigned index, 
                                           PhysicalRegionImpl *region)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(index < regions.size());
      assert(regions[index].impl == NULL);
#endif
      regions[index] = PhysicalRegion(region);
    }

    //--------------------------------------------------------------------------
    PhysicalRegion ExternalResourcesImpl::get_region(unsigned index) const
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(index < regions.size());
#endif
      return regions[index];
    }

    //--------------------------------------------------------------------------
    void ExternalResourcesImpl::set_projection(ProjectionID id)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(pid == 0);
#endif
      pid = id;
    }

    //--------------------------------------------------------------------------
    Future ExternalResourcesImpl::detach(InnerContext *ctx, IndexDetachOp *op,
                 const bool flush, const bool unordered, const char *provenance)
    //--------------------------------------------------------------------------
    {
      if (ctx != context)
        REPORT_LEGION_ERROR(ERROR_INDEX_SPACE_DETACH,
            "Attempted detach of external resources in context of task %s "
            "(UID %lld). Detach of external resources must always be performed "
            "in the the context of the task in which they are attached.",
            ctx->get_task_name(), ctx->get_unique_id())
      if (detached)
        REPORT_LEGION_ERROR(ERROR_INDEX_SPACE_DETACH,
            "Duplicate detach of external resources performed in task %s "
            "(UID %lld). External resources should only be detached once.",
            ctx->get_task_name(), ctx->get_unique_id())
      detached = true;
      // Unmap any mapped regions
      for (std::vector<PhysicalRegion>::iterator it =
            regions.begin(); it != regions.end(); it++)
      {
        if (!it->impl->is_mapped())
          continue;
        it->impl->unmap_region();
        ctx->unregister_inline_mapped_region(*it);
      }
      // Now initialize the detach operation
      return op->initialize_detach(ctx, parent, upper_bound, launch_bounds,
            this, privilege_fields, regions, flush, unordered, provenance);
    }

    /////////////////////////////////////////////////////////////
    // Grant Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    GrantImpl::GrantImpl(void)
      : acquired(false)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    GrantImpl::GrantImpl(const std::vector<ReservationRequest> &reqs)
      : requests(reqs), acquired(false)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    GrantImpl::GrantImpl(const GrantImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    GrantImpl::~GrantImpl(void)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    GrantImpl& GrantImpl::operator=(const GrantImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void GrantImpl::register_operation(ApEvent completion_event)
    //--------------------------------------------------------------------------
    {
      AutoLock g_lock(grant_lock);
      completion_events.insert(completion_event);
    }

    //--------------------------------------------------------------------------
    ApEvent GrantImpl::acquire_grant(void)
    //--------------------------------------------------------------------------
    {
      AutoLock g_lock(grant_lock);
      if (!acquired)
      {
        grant_event = ApEvent::NO_AP_EVENT;
        for (std::vector<ReservationRequest>::const_iterator it = 
              requests.begin(); it != requests.end(); it++)
        {
          grant_event = ApEvent(it->reservation.acquire(it->mode, 
                                                it->exclusive, grant_event));
        }
        acquired = true;
      }
      return grant_event;
    }

    //--------------------------------------------------------------------------
    void GrantImpl::release_grant(void)
    //--------------------------------------------------------------------------
    {
      AutoLock g_lock(grant_lock);
      ApEvent deferred_release = Runtime::merge_events(NULL, completion_events);
      for (std::vector<ReservationRequest>::const_iterator it = 
            requests.begin(); it != requests.end(); it++)
      {
        it->reservation.release(deferred_release);
      }
    }

    //--------------------------------------------------------------------------
    void GrantImpl::pack_grant(Serializer &rez)
    //--------------------------------------------------------------------------
    {
      ApEvent pack_event = acquire_grant();
      rez.serialize(pack_event);
    }

    //--------------------------------------------------------------------------
    void GrantImpl::unpack_grant(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      ApEvent unpack_event;
      derez.deserialize(unpack_event);
      AutoLock g_lock(grant_lock);
#ifdef DEBUG_LEGION
      assert(!acquired);
#endif
      grant_event = unpack_event;
      acquired = true;
    }

    /////////////////////////////////////////////////////////////
    // Legion Handshake Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    LegionHandshakeImpl::LegionHandshakeImpl(bool init_ext, int ext_parts,
                                                   int legion_parts)
      : init_in_ext(init_ext), ext_participants(ext_parts), 
        legion_participants(legion_parts)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    LegionHandshakeImpl::LegionHandshakeImpl(const LegionHandshakeImpl &rhs)
      : init_in_ext(false), ext_participants(-1), legion_participants(-1)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    LegionHandshakeImpl::~LegionHandshakeImpl(void)
    //--------------------------------------------------------------------------
    {
      ext_wait_barrier.get_barrier().destroy_barrier();
      legion_wait_barrier.get_barrier().destroy_barrier();
    }

    //--------------------------------------------------------------------------
    LegionHandshakeImpl& LegionHandshakeImpl::operator=(
                                                 const LegionHandshakeImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void LegionHandshakeImpl::initialize(void)
    //--------------------------------------------------------------------------
    {
      ext_wait_barrier = PhaseBarrier(ApBarrier(
            Realm::Barrier::create_barrier(legion_participants)));
      legion_wait_barrier = PhaseBarrier(ApBarrier(
            Realm::Barrier::create_barrier(ext_participants)));
      ext_arrive_barrier = legion_wait_barrier;
      legion_arrive_barrier = ext_wait_barrier;
      // Advance the two wait barriers
      Runtime::advance_barrier(ext_wait_barrier);
      Runtime::advance_barrier(legion_wait_barrier);
      // Whoever is waiting first, we have to advance their arrive barriers
      if (init_in_ext)
      {
        Runtime::phase_barrier_arrive(legion_arrive_barrier, legion_participants);
        Runtime::advance_barrier(ext_wait_barrier);
      }
      else
      {
        Runtime::phase_barrier_arrive(ext_arrive_barrier, ext_participants);
        Runtime::advance_barrier(legion_wait_barrier);
      }
    }

    //--------------------------------------------------------------------------
    void LegionHandshakeImpl::ext_handoff_to_legion(void)
    //--------------------------------------------------------------------------
    {
      // Just have to do our arrival
      Runtime::phase_barrier_arrive(ext_arrive_barrier, 1);
    }

    //--------------------------------------------------------------------------
    void LegionHandshakeImpl::ext_wait_on_legion(void)
    //--------------------------------------------------------------------------
    {
      // When we get this call, we know we have done 
      // all the arrivals so we can advance it
      Runtime::advance_barrier(ext_arrive_barrier);
      // Wait for ext  to be ready to run
      // Note we use the external wait to be sure 
      // we don't get drafted by the Realm runtime
      ApBarrier previous = Runtime::get_previous_phase(ext_wait_barrier);
      if (!previous.has_triggered_faultignorant())
      {
        // We can't call external wait directly on the barrier
        // right now, so as a work-around we'll make an event
        // and then wait on that
        ApUserEvent wait_on = Runtime::create_ap_user_event(NULL);
        Runtime::trigger_event(NULL, wait_on, previous);
        wait_on.external_wait();
      }
      // Now we can advance our wait barrier
      Runtime::advance_barrier(ext_wait_barrier);
    }

    //--------------------------------------------------------------------------
    void LegionHandshakeImpl::legion_handoff_to_ext(void)
    //--------------------------------------------------------------------------
    {
      // Just have to do our arrival
      Runtime::phase_barrier_arrive(legion_arrive_barrier, 1);
    }

    //--------------------------------------------------------------------------
    void LegionHandshakeImpl::legion_wait_on_ext(void)
    //--------------------------------------------------------------------------
    {
      Runtime::advance_barrier(legion_arrive_barrier);
      // Wait for Legion to be ready to run
      // No need to avoid being drafted by the
      // Realm runtime here
      legion_wait_barrier.wait();
      // Now we can advance our wait barrier
      Runtime::advance_barrier(legion_wait_barrier);
    }

    //--------------------------------------------------------------------------
    PhaseBarrier LegionHandshakeImpl::get_legion_wait_phase_barrier(void)
    //--------------------------------------------------------------------------
    {
      return legion_wait_barrier;
    }

    //--------------------------------------------------------------------------
    PhaseBarrier LegionHandshakeImpl::get_legion_arrive_phase_barrier(void)
    //--------------------------------------------------------------------------
    {
      return legion_arrive_barrier;
    }

    //--------------------------------------------------------------------------
    void LegionHandshakeImpl::advance_legion_handshake(void)
    //--------------------------------------------------------------------------
    {
      Runtime::advance_barrier(legion_wait_barrier);
      Runtime::advance_barrier(legion_arrive_barrier);
    }

    /////////////////////////////////////////////////////////////
    // MPI Rank Table
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    MPIRankTable::MPIRankTable(Runtime *rt)
      : runtime(rt), participating(int(runtime->address_space) <
         runtime->legion_collective_participating_spaces), done_triggered(false)
    //--------------------------------------------------------------------------
    {
      if (runtime->total_address_spaces > 1)
      {
        // We already have our contributions for each stage so
        // we can set the inditial participants to 1
        if (participating)
        {
          sent_stages.resize(runtime->legion_collective_stages, false);
#ifdef DEBUG_LEGION
          assert(runtime->legion_collective_stages > 0);
#endif
          stage_notifications.resize(runtime->legion_collective_stages, 1);
          // Stage 0 always starts with 0 notifications since we'll 
          // explictcly arrive on it
          stage_notifications[0] = 0;
        }
        done_event = Runtime::create_rt_user_event();
      }
      // Add ourselves to the set before any exchanges start
#ifdef DEBUG_LEGION
      assert(Runtime::mpi_rank >= 0);
#endif
      forward_mapping[Runtime::mpi_rank] = runtime->address_space;
    }
    
    //--------------------------------------------------------------------------
    MPIRankTable::MPIRankTable(const MPIRankTable &rhs)
      : runtime(NULL), participating(false)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    MPIRankTable::~MPIRankTable(void)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    MPIRankTable& MPIRankTable::operator=(const MPIRankTable &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void MPIRankTable::perform_rank_exchange(void)
    //--------------------------------------------------------------------------
    {
      // We can skip this part if there are not multiple nodes
      if (runtime->total_address_spaces > 1)
      {
        // See if we are participating node or not
        if (participating)
        {
          // We are a participating node
          // See if we are waiting for an initial notification
          // if not we can just send our message now
          if ((int(runtime->total_address_spaces) ==
                runtime->legion_collective_participating_spaces) ||
              (runtime->address_space >= (runtime->total_address_spaces -
                runtime->legion_collective_participating_spaces)))
          {
            const bool all_stages_done = initiate_exchange();
            if (all_stages_done)
              complete_exchange();
          }
        }
        else
        {
          // We are not a participating node
          // so we just have to send notification to one node
          send_remainder_stage();
        }
        // Wait for our done event to be ready
        done_event.wait();
      }
#ifdef DEBUG_LEGION
      assert(forward_mapping.size() == runtime->total_address_spaces);
#endif
      // Reverse the mapping
      for (std::map<int,AddressSpace>::const_iterator it = 
            forward_mapping.begin(); it != forward_mapping.end(); it++)
        reverse_mapping[it->second] = it->first;
    }

    //--------------------------------------------------------------------------
    bool MPIRankTable::initiate_exchange(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(participating); // should only get this for participating shards
#endif
      {
        AutoLock r_lock(reservation);
#ifdef DEBUG_LEGION
        assert(!sent_stages.empty());
        assert(!sent_stages[0]); // stage 0 shouldn't be sent yet
        assert(!stage_notifications.empty());
        if (runtime->legion_collective_stages == 1)
          assert(stage_notifications[0] < 
                  runtime->legion_collective_last_radix); 
        else
          assert(stage_notifications[0] < runtime->legion_collective_radix);
#endif
        stage_notifications[0]++;
      }
      return send_ready_stages(0/*start stage*/);
    }

    //--------------------------------------------------------------------------
    void MPIRankTable::send_remainder_stage(void)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(-1);
        AutoLock r_lock(reservation, 1, false/*exclusive*/);
        rez.serialize<size_t>(forward_mapping.size());
        for (std::map<int,AddressSpace>::const_iterator it = 
              forward_mapping.begin(); it != forward_mapping.end(); it++)
        {
          rez.serialize(it->first);
          rez.serialize(it->second);
        }
      }
      if (participating)
      {
        // Send back to the nodes that are not participating
        AddressSpaceID target = runtime->address_space +
          runtime->legion_collective_participating_spaces;
#ifdef DEBUG_LEGION
        assert(target < runtime->total_address_spaces);
#endif
        runtime->send_mpi_rank_exchange(target, rez);
      }
      else
      {
        // Sent to a node that is participating
        AddressSpaceID target = runtime->address_space % 
          runtime->legion_collective_participating_spaces;
        runtime->send_mpi_rank_exchange(target, rez);
      }
    }

    //--------------------------------------------------------------------------
    bool MPIRankTable::send_ready_stages(const int start_stage) 
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(participating);
#endif
      // Iterate through the stages and send any that are ready
      // Remember that stages have to be done in order
      for (int stage = start_stage; 
            stage < runtime->legion_collective_stages; stage++)
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(stage);
          AutoLock r_lock(reservation);
          // If this stage has already been sent then we can keep going
          if (sent_stages[stage])
            continue;
          // Check to see if we're sending this stage
          // We need all the notifications from the previous stage before
          // we can send this stage
          if ((stage > 0) && 
              (stage_notifications[stage-1] < runtime->legion_collective_radix))
            return false;
          // If we get here then we can send the stage
          sent_stages[stage] = true;
#ifdef DEBUG_LEGION
          {
            size_t expected_size = 1;
            for (int idx = 0; idx < stage; idx++)
              expected_size *= runtime->legion_collective_radix;
            assert(expected_size <= forward_mapping.size());
          }
#endif
          rez.serialize<size_t>(forward_mapping.size());
          for (std::map<int,AddressSpace>::const_iterator it = 
                forward_mapping.begin(); it != forward_mapping.end(); it++)
          {
            rez.serialize(it->first);
            rez.serialize(it->second);
          }
        }
        // Now we can do the send
        if (stage == (runtime->legion_collective_stages-1))
        {
          for (int r = 1; r < runtime->legion_collective_last_radix; r++)
          {
            AddressSpaceID target = runtime->address_space ^
              (r << (stage * runtime->legion_collective_log_radix));
#ifdef DEBUG_LEGION
            assert(int(target) < 
                    runtime->legion_collective_participating_spaces);
#endif
            runtime->send_mpi_rank_exchange(target, rez);
          }
        }
        else
        {
          for (int r = 1; r < runtime->legion_collective_radix; r++)
          {
            AddressSpaceID target = runtime->address_space ^
              (r << (stage * runtime->legion_collective_log_radix));
#ifdef DEBUG_LEGION
            assert(int(target) < 
                    runtime->legion_collective_participating_spaces);
#endif
            runtime->send_mpi_rank_exchange(target, rez);
          }
        }
      }
      // If we make it here, then we sent the last stage, check to see
      // if we've seen all the notifications for it
      AutoLock r_lock(reservation);
      if ((stage_notifications.back() == runtime->legion_collective_last_radix)
          && !done_triggered)
      {
        done_triggered = true;
        return true;
      }
      else
        return false;
    }

    //--------------------------------------------------------------------------
    void MPIRankTable::handle_mpi_rank_exchange(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      int stage;
      derez.deserialize(stage);
#ifdef DEBUG_LEGION
      assert(participating || (stage == -1));
#endif
      unpack_exchange(stage, derez);
      bool all_stages_done = false;
      if (stage == -1)
      {
        if (!participating)
          all_stages_done = true;
        else // we can now send our stage 0
          all_stages_done = initiate_exchange();
      }
      else
        all_stages_done = send_ready_stages();
      if (all_stages_done)
        complete_exchange();
    }

    //--------------------------------------------------------------------------
    void MPIRankTable::unpack_exchange(int stage, Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      size_t num_entries;
      derez.deserialize(num_entries);
      AutoLock r_lock(reservation);
      for (unsigned idx = 0; idx < num_entries; idx++)
      {
        int rank;
        derez.deserialize(rank);
	unsigned space;
	derez.deserialize(space);
#ifdef DEBUG_LEGION
	// Duplicates are possible because later messages aren't "held", but
	// they should be exact matches
	assert ((forward_mapping.count(rank) == 0) ||
		(forward_mapping[rank] == space));
#endif
	forward_mapping[rank] = space;
      }
      if (stage >= 0)
      {
#ifdef DEBUG_LEGION
	assert(stage < int(stage_notifications.size()));
        if (stage < (runtime->legion_collective_stages-1))
          assert(stage_notifications[stage] < 
                  runtime->legion_collective_radix);
        else
          assert(stage_notifications[stage] < 
                  runtime->legion_collective_last_radix);
#endif
        stage_notifications[stage]++;
      }
    }

    //--------------------------------------------------------------------------
    void MPIRankTable::complete_exchange(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(forward_mapping.size() == runtime->total_address_spaces);
#endif
      // See if we have to send a message back to a
      // non-participating node
      if ((int(runtime->total_address_spaces) > 
           runtime->legion_collective_participating_spaces) &&
          (int(runtime->address_space) < int(runtime->total_address_spaces -
            runtime->legion_collective_participating_spaces)))
        send_remainder_stage();
      // We are done
      Runtime::trigger_event(done_event);
    }

    /////////////////////////////////////////////////////////////
    // Processor Manager 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    ProcessorManager::ProcessorManager(Processor proc, Processor::Kind kind,
                                       Runtime *rt, unsigned def_mappers,
                                       bool no_steal, bool replay)
      : runtime(rt), local_proc(proc), proc_kind(kind), 
        stealing_disabled(no_steal), replay_execution(replay), 
        next_local_index(0), task_scheduler_enabled(false), 
        outstanding_task_scheduler(false),
        total_active_contexts(0), total_active_mappers(0)
    //--------------------------------------------------------------------------
    {
      context_states.resize(LEGION_DEFAULT_CONTEXTS);
      // Find our set of visible memories
      Machine::MemoryQuery vis_mems(runtime->machine);
      vis_mems.has_affinity_to(proc);
      for (Machine::MemoryQuery::iterator it = vis_mems.begin();
            it != vis_mems.end(); it++)
        visible_memories.insert(*it);
    }

    //--------------------------------------------------------------------------
    ProcessorManager::ProcessorManager(const ProcessorManager &rhs)
      : runtime(NULL), local_proc(Processor::NO_PROC),
        proc_kind(Processor::LOC_PROC), stealing_disabled(false), 
        replay_execution(false)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    ProcessorManager::~ProcessorManager(void)
    //--------------------------------------------------------------------------
    {
      mapper_states.clear();
    }

    //--------------------------------------------------------------------------
    ProcessorManager& ProcessorManager::operator=(const ProcessorManager &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::prepare_for_shutdown(void)
    //--------------------------------------------------------------------------
    {
      for (std::map<MapperID,std::pair<MapperManager*,bool> >::iterator it = 
            mappers.begin(); it != mappers.end(); it++)
      {
        if (it->second.second)
          delete it->second.first;
      }
      mappers.clear();
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::startup_mappers(void)
    //--------------------------------------------------------------------------
    {
      // No one can be modifying the mapper set here so 
      // there is no to hold the lock
      std::multimap<Processor,MapperID> stealing_targets;
      // See what if any stealing we should perform
      for (std::map<MapperID,std::pair<MapperManager*,bool> >::const_iterator
            it = mappers.begin(); it != mappers.end(); it++)
        it->second.first->perform_stealing(stealing_targets);
      if (!stealing_targets.empty())
        runtime->send_steal_request(stealing_targets, local_proc);
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::add_mapper(MapperID mid, MapperManager *m, 
                                      bool check, bool own, bool skip_replay)
    //--------------------------------------------------------------------------
    {
      // Don't do this if we are doing replay execution
      if (!skip_replay && replay_execution)
        return;
      log_run.spew("Adding mapper %d on processor " IDFMT "", 
                          mid, local_proc.id);
      if (check && (mid == 0))
        REPORT_LEGION_ERROR(ERROR_RESERVED_MAPPING_ID, 
                            "Invalid mapping ID. ID 0 is reserved.");
      if (check && !inside_registration_callback)
          REPORT_LEGION_WARNING(LEGION_WARNING_NON_CALLBACK_REGISTRATION,
            "Mapper %s (ID %d) was dynamically registered outside of a "
            "registration callback invocation. In the near future this will " 
            "become an error in order to support task subprocesses. Please "
            "use 'perform_registration_callback' to generate a callback "
            "where it will be safe to perform dynamic registrations.", 
            m->get_mapper_name(), mid)
      AutoLock m_lock(mapper_lock);
      std::map<MapperID,std::pair<MapperManager*,bool> >::iterator finder = 
        mappers.find(mid);
      if (finder != mappers.end())
      {
        if (finder->second.second)
          delete finder->second.first;
        finder->second = std::pair<MapperManager*,bool>(m, own);
      }
      else
      {
        mappers[mid] = std::pair<MapperManager*,bool>(m, own); 
        AutoLock q_lock(queue_lock);
        mapper_states[mid] = MapperState();
      }
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::replace_default_mapper(MapperManager *m, bool own)
    //--------------------------------------------------------------------------
    {
      // Don't do this if we are doing replay execution
      if (replay_execution)
        return;
      if (!inside_registration_callback)
          REPORT_LEGION_WARNING(LEGION_WARNING_NON_CALLBACK_REGISTRATION,
            "Replacing default mapper with %s was dynamically performed "
            "outside of a registration callback invocation. In the near "
            "future this will become an error in order to support task "
            "subprocesses. Please use 'perform_registration_callback' to "
            "generate a callback where it will be safe to perform dynamic " 
            "registrations.", m->get_mapper_name())
      AutoLock m_lock(mapper_lock);
      std::map<MapperID,std::pair<MapperManager*,bool> >::iterator finder = 
        mappers.find(0);
      if (finder != mappers.end())
      {
        if (finder->second.second)
          delete finder->second.first;
        finder->second = std::pair<MapperManager*,bool>(m, own);
      }
      else
      {
        mappers[0] = std::pair<MapperManager*,bool>(m, own);
        AutoLock q_lock(queue_lock);
        mapper_states[0] = MapperState();
      }
    }

    //--------------------------------------------------------------------------
    MapperManager* ProcessorManager::find_mapper(MapperID mid) const 
    //--------------------------------------------------------------------------
    {
      // Easy case if we are doing replay execution
      if (replay_execution)
      {
        std::map<MapperID,std::pair<MapperManager*,bool> >::const_iterator
          finder = mappers.find(0);
#ifdef DEBUG_LEGION
        assert(finder != mappers.end());
#endif
        return finder->second.first;
      }
      AutoLock m_lock(mapper_lock, 0/*mode*/, false/*exclusive*/);
      MapperManager *result = NULL;
      // We've got the lock, so do the operation
      std::map<MapperID,std::pair<MapperManager*,bool> >::const_iterator
        finder = mappers.find(mid);
      if (finder != mappers.end())
        result = finder->second.first;
      return result;
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::perform_scheduling(void)
    //--------------------------------------------------------------------------
    {
      perform_mapping_operations(); 
      // Now re-take the lock and re-check the condition to see 
      // if the next scheduling task should be launched
      AutoLock q_lock(queue_lock);
#ifdef DEBUG_LEGION
      assert(outstanding_task_scheduler);
#endif
      // If the task scheduler is enabled launch ourselves again
      if (task_scheduler_enabled)
      {
        SchedulerArgs sched_args(local_proc);
        runtime->issue_runtime_meta_task(sched_args, LG_LATENCY_WORK_PRIORITY);
      }
      else
        outstanding_task_scheduler = false;
    } 

    //--------------------------------------------------------------------------
    void ProcessorManager::launch_task_scheduler(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!outstanding_task_scheduler);
#endif
      outstanding_task_scheduler = true;
      SchedulerArgs sched_args(local_proc);
      runtime->issue_runtime_meta_task(sched_args, LG_LATENCY_WORK_PRIORITY);
    } 

    //--------------------------------------------------------------------------
    void ProcessorManager::notify_deferred_mapper(MapperID map_id,
                                                  RtEvent deferred_event)
    //--------------------------------------------------------------------------
    {
      AutoLock q_lock(queue_lock);
      MapperState &state = mapper_states[map_id];
      // Check to see if the deferral event matches the one that we have
      if (state.deferral_event == deferred_event)
      {
        // Now we can clear it
        state.deferral_event = RtEvent::NO_RT_EVENT;
        // And if we still have tasks, reactivate the mapper
        if (!state.ready_queue.empty())
          increment_active_mappers();
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void ProcessorManager::handle_defer_mapper(const void *args)
    //--------------------------------------------------------------------------
    {
      const DeferMapperSchedulerArgs *dargs = 
        (const DeferMapperSchedulerArgs*)args; 
      dargs->proxy_this->notify_deferred_mapper(dargs->map_id, 
                                                dargs->deferral_event);
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::activate_context(InnerContext *context)
    //--------------------------------------------------------------------------
    {
      ContextID ctx_id = context->get_context_id();
      AutoLock q_lock(queue_lock); 
      ContextState &state = context_states[ctx_id];
#ifdef DEBUG_LEGION
      assert(!state.active);
#endif
      state.active = true;
      if (state.owned_tasks > 0)
        increment_active_contexts();
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::deactivate_context(InnerContext *context)
    //--------------------------------------------------------------------------
    {
      ContextID ctx_id = context->get_context_id();
      // We can do this without holding the lock because we know
      // the size of this vector is fixed
      AutoLock q_lock(queue_lock); 
      ContextState &state = context_states[ctx_id];
#ifdef DEBUG_LEGION
      assert(state.active);
#endif
      state.active = false;
      if (state.owned_tasks > 0)
        decrement_active_contexts();
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::update_max_context_count(unsigned max_contexts)
    //--------------------------------------------------------------------------
    {
      AutoLock q_lock(queue_lock);
      context_states.resize(max_contexts);
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::increment_active_contexts(void)
    //--------------------------------------------------------------------------
    {
      // Better be called while holding the queue lock
      if (!task_scheduler_enabled && (total_active_contexts == 0) &&
          (total_active_mappers > 0))
      {
        task_scheduler_enabled = true;
        if (!outstanding_task_scheduler)
          launch_task_scheduler();
      }
      total_active_contexts++;
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::decrement_active_contexts(void)
    //--------------------------------------------------------------------------
    {
      // Better be called while holding the queue lock
#ifdef DEBUG_LEGION
      assert(total_active_contexts > 0);
#endif
      total_active_contexts--;
      if (total_active_contexts == 0)
        task_scheduler_enabled = false;
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::increment_active_mappers(void)
    //--------------------------------------------------------------------------
    {
      // Better be called while holding the queue lock
      if (!task_scheduler_enabled && (total_active_mappers == 0) &&
          (total_active_contexts > 0))
      {
        task_scheduler_enabled = true;
        if (!outstanding_task_scheduler)
          launch_task_scheduler();
      }
      total_active_mappers++;
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::decrement_active_mappers(void)
    //--------------------------------------------------------------------------
    {
      // Better be called while holding the queue lock
#ifdef DEBUG_LEGION
      assert(total_active_mappers > 0);
#endif
      total_active_mappers--;
      if (total_active_mappers == 0)
        task_scheduler_enabled = false;
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::process_steal_request(Processor thief,
                                           const std::vector<MapperID> &thieves)
    //--------------------------------------------------------------------------
    {
      log_run.spew("handling a steal request on processor " IDFMT " "
                         "from processor " IDFMT "", local_proc.id,thief.id);
      // Iterate over the task descriptions, asking the appropriate mapper
      // whether we can steal the task
      std::set<TaskOp*> stolen;
      std::vector<MapperID> successful_thiefs;
      for (std::vector<MapperID>::const_iterator steal_it = thieves.begin();
            steal_it != thieves.end(); steal_it++)
      {
        const MapperID stealer = *steal_it;
        // Handle a race condition here where some processors can 
        // issue steal requests to another processor before the mappers 
        // have been initialized on that processor.  There's no 
        // correctness problem for ignoring a steal request so just do that.
        MapperManager *mapper = find_mapper(stealer);
        if (mapper == NULL)
          continue;
        // Wait until we can exclusive access to the ready queue
        std::list<TaskOp*> queue_copy;
        RtEvent queue_copy_ready;
        // Pull out the current tasks for this mapping operation
        // Need to iterate until we get access to the queue
        do
        {
          if (queue_copy_ready.exists() && !queue_copy_ready.has_triggered())
          {
            queue_copy_ready.wait();
            queue_copy_ready = RtEvent::NO_RT_EVENT;
          }
          AutoLock q_lock(queue_lock);
          MapperState &map_state = mapper_states[*steal_it];
          if (!map_state.queue_guard)
          {
            // If we don't have a deferral event then grab our
            // ready queue of tasks so we can try to map them
            // this will also prevent them from being stolen
            if (!map_state.ready_queue.empty())
            {
              map_state.ready_queue.swap(queue_copy);
              // Set the queue guard so no one else tries to
              // read the ready queue while we've checked it out
              map_state.queue_guard = true;
            }
          }
          else
          {
            // Make an event if necessary
            if (!map_state.queue_waiter.exists())
              map_state.queue_waiter = Runtime::create_rt_user_event();
            // Record that we need to wait on it
            queue_copy_ready = map_state.queue_waiter;
          }
        } while (queue_copy_ready.exists());
        if (queue_copy.empty())
          continue;
        Mapper::StealRequestInput input;
        input.thief_proc = thief;
        for (std::list<TaskOp*>::const_iterator it = 
              queue_copy.begin(); it != queue_copy.end(); it++)
        {
          if ((*it)->is_stealable() && !(*it)->is_origin_mapped())
            input.stealable_tasks.push_back(*it);
        }
        Mapper::StealRequestOutput output;
        // Ask the mapper what it wants to allow be stolen
        if (!input.stealable_tasks.empty())
          mapper->invoke_permit_steal_request(&input, &output);
        // See which tasks we can succesfully steal
        std::vector<TaskOp*> local_stolen;
        if (!output.stolen_tasks.empty())
        {
          std::set<const Task*> to_steal(output.stolen_tasks.begin(), 
                                         output.stolen_tasks.end());
          // Remove any tasks that are going to be stolen
          for (std::list<TaskOp*>::iterator it = 
                queue_copy.begin(); it != queue_copy.end(); /*nothing*/)
          {
            if ((to_steal.find(*it) != to_steal.end()) && 
                (*it)->prepare_steal())
            {
              // Mark this as stolen and update the target processor
              (*it)->mark_stolen();
              local_stolen.push_back(*it);
              it = queue_copy.erase(it);
            }
            else
              it++;
          }
        }
        {
          // Retake the lock, put any tasks still in the ready queue
          // back into the queue and remove the queue guard
          AutoLock q_lock(queue_lock);
          MapperState &map_state = mapper_states[*steal_it];
#ifdef DEBUG_LEGION
          assert(map_state.queue_guard);
#endif
          std::list<TaskOp*> &rqueue = map_state.ready_queue;
          if (!queue_copy.empty())
          {
            // Put any new items on the back of the queue
            if (!rqueue.empty())
            {
              for (std::list<TaskOp*>::const_iterator it = 
                    rqueue.begin(); it != rqueue.end(); it++)
                queue_copy.push_back(*it);
            }
            rqueue.swap(queue_copy);
          }
          else if (rqueue.empty())
          {
            if (map_state.deferral_event.exists())
              map_state.deferral_event = RtEvent::NO_RT_EVENT;
            else
              decrement_active_mappers();
          }
          if (!local_stolen.empty())
          {
            for (std::vector<TaskOp*>::const_iterator it = 
                  local_stolen.begin(); it != local_stolen.end(); it++)
            {
              // Wait until we are no longer holding the lock
              // to mark that this is no longer an outstanding task
              ContextID ctx_id = (*it)->get_context()->get_context_id();
              ContextState &state = context_states[ctx_id];
#ifdef DEBUG_LEGION
              assert(state.owned_tasks > 0);
#endif
              state.owned_tasks--;
              if (state.active && (state.owned_tasks == 0))
                decrement_active_contexts();
            }
          }
          // Remove the queue guard
          map_state.queue_guard = false;
          if (map_state.queue_waiter.exists())
          {
            Runtime::trigger_event(map_state.queue_waiter);
            map_state.queue_waiter = RtUserEvent::NO_RT_USER_EVENT;
          }
        }
        if (!local_stolen.empty())
        {
          successful_thiefs.push_back(stealer);
          for (std::vector<TaskOp*>::const_iterator it = 
                local_stolen.begin(); it != local_stolen.end(); it++)
          {
            (*it)->deactivate_outstanding_task();
            stolen.insert(*it);
          }
        }
        else
          mapper->process_failed_steal(thief);
      }
      if (!stolen.empty())
      {
#ifdef DEBUG_LEGION
        for (std::set<TaskOp*>::const_iterator it = stolen.begin();
              it != stolen.end(); it++)
        {
          log_task.debug("task %s (ID %lld) stolen from processor " IDFMT
                         " by processor " IDFMT "", (*it)->get_task_name(), 
                         (*it)->get_unique_id(), local_proc.id, thief.id);
        }
#endif
        runtime->send_tasks(thief, stolen);
        // Also have to send advertisements to the mappers that 
        // successfully stole so they know that they can try again
        std::set<Processor> thief_set;
        thief_set.insert(thief);
        for (std::vector<MapperID>::const_iterator it = 
              successful_thiefs.begin(); it != successful_thiefs.end(); it++)
          runtime->send_advertisements(thief_set, *it, local_proc);
      }
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::process_advertisement(Processor advertiser,
                                                 MapperID mid)
    //--------------------------------------------------------------------------
    {
      MapperManager *mapper = find_mapper(mid);
      mapper->process_advertisement(advertiser);
      // See if this mapper would like to try stealing again
      std::multimap<Processor,MapperID> stealing_targets;
      mapper->perform_stealing(stealing_targets);
      if (!stealing_targets.empty())
        runtime->send_steal_request(stealing_targets, local_proc);
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::add_to_ready_queue(TaskOp *task)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(task != NULL);
#endif
      // have to do this when we are not holding the lock
      task->activate_outstanding_task();
      // We can do this without holding the lock because the
      // vector is of a fixed size
      ContextID ctx_id = task->get_context()->get_context_id();
      AutoLock q_lock(queue_lock);
#ifdef DEBUG_LEGION
      assert(mapper_states.find(task->map_id) != mapper_states.end());
#endif
      // Update the state for the context
      ContextState &state = context_states[ctx_id];
      if (state.active && (state.owned_tasks == 0))
        increment_active_contexts();
      state.owned_tasks++;
      // Also update the queue for the mapper
      MapperState &map_state = mapper_states[task->map_id];
      if (map_state.ready_queue.empty() || map_state.deferral_event.exists())
      {
        // Clear our deferral event since we are changing state
        map_state.deferral_event = RtEvent::NO_RT_EVENT;
        increment_active_mappers();
      }
      map_state.ready_queue.push_back(task);
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::perform_mapping_operations(void)
    //--------------------------------------------------------------------------
    {
      std::multimap<Processor,MapperID> stealing_targets;
      std::vector<MapperID> mappers_with_stealable_work;
      std::vector<std::pair<MapperID,MapperManager*> > current_mappers;
      // Take a snapshot of our current mappers
      {
        AutoLock m_lock(mapper_lock,1,false/*exclusive*/);
        // Fast path for no deferred mappers
        current_mappers.resize(mappers.size());
        unsigned idx = 0;
        for (std::map<MapperID,std::pair<MapperManager*,bool> >::
              const_iterator it = mappers.begin(); it != 
              mappers.end(); it++, idx++)
          current_mappers[idx] = 
            std::pair<MapperID,MapperManager*>(it->first, it->second.first);
      }
      for (std::vector<std::pair<MapperID,MapperManager*> >::const_iterator
            it = current_mappers.begin(); it != current_mappers.end(); it++)
      {
        const MapperID map_id = it->first;
        MapperManager *const mapper = it->second;
        std::list<TaskOp*> queue_copy;
        RtEvent queue_copy_ready;
        // Pull out the current tasks for this mapping operation
        // Need to iterate until we get access to the queue
        do
        {
          if (queue_copy_ready.exists() && !queue_copy_ready.has_triggered())
          {
            queue_copy_ready.wait();
            queue_copy_ready = RtEvent::NO_RT_EVENT;
          }
          AutoLock q_lock(queue_lock);
          MapperState &map_state = mapper_states[map_id];
          if (!map_state.queue_guard)
          {
            // If we don't have a deferral event then grab our
            // ready queue of tasks so we can try to map them
            // this will also prevent them from being stolen
            if (!map_state.deferral_event.exists() &&
                !map_state.ready_queue.empty())
            {
              map_state.ready_queue.swap(queue_copy);
              // Set the queue guard so no one else tries to
              // read the ready queue while we've checked it out
              map_state.queue_guard = true;
            }
          }
          else
          {
            // Make an event if necessary
            if (!map_state.queue_waiter.exists())
              map_state.queue_waiter = Runtime::create_rt_user_event();
            // Record that we need to wait on it
            queue_copy_ready = map_state.queue_waiter;
          }
        } while (queue_copy_ready.exists());
        // Do this before anything else in case we don't have any tasks
        if (!stealing_disabled)
          mapper->perform_stealing(stealing_targets);
        // Nothing to do if there are no tasks on the queue
        if (queue_copy.empty())
          continue;
        // Ask the mapper which tasks it would like to schedule
        Mapper::SelectMappingInput input;
        Mapper::SelectMappingOutput output;
        for (std::list<TaskOp*>::const_iterator it = 
              queue_copy.begin(); it != queue_copy.end(); it++)
          input.ready_tasks.push_back(*it);
        mapper->invoke_select_tasks_to_map(&input, &output);
        // If we had no entry then we better have gotten a mapper event
        std::vector<TaskOp*> to_trigger;
        if (output.map_tasks.empty() && output.relocate_tasks.empty())
        {
          const RtEvent wait_on = output.deferral_event.impl;
          if (wait_on.exists())
          {
            // Put this on the list of the deferred mappers
            AutoLock q_lock(queue_lock);
            MapperState &map_state = mapper_states[map_id];
            // We have to check to see if any new tasks were added to 
            // the ready queue while we were doing our mapper call, if 
            // they were then we need to invoke select_tasks_to_map again
            if (map_state.ready_queue.empty())
            {
#ifdef DEBUG_LEGION
              assert(!map_state.deferral_event.exists());
              assert(map_state.queue_guard);
#endif
              map_state.deferral_event = wait_on;
              // Decrement the number of active mappers
              decrement_active_mappers();
              // Put our tasks back on the queue
              map_state.ready_queue.swap(queue_copy);
              // Clear the queue guard
              map_state.queue_guard = false;
              if (map_state.queue_waiter.exists())
              {
                Runtime::trigger_event(map_state.queue_waiter);
                map_state.queue_waiter = RtUserEvent::NO_RT_USER_EVENT;
              }
              // Launch a task to remove the deferred mapper 
              // event when it triggers
              DeferMapperSchedulerArgs args(this, map_id, wait_on);
              runtime->issue_runtime_meta_task(args, 
                  LG_LATENCY_DEFERRED_PRIORITY, wait_on);
              // We can continue because there is nothing 
              // left to do for this mapper
              continue;
            }
            // Otherwise we fall through to put our tasks back on the queue 
            // which will lead to select_tasks_to_map being called again
          }
          else // Very bad, error message
            REPORT_LEGION_ERROR(ERROR_INVALID_MAPPER_OUTPUT,
                          "Mapper %s failed to specify an output MapperEvent "
                          "when returning from a call to 'select_tasks_to_map' "
                          "that performed no other actions. Specifying a "
                          "MapperEvent in such situation is necessary to avoid "
                          "livelock conditions. Please return a "
                          "'deferral_event' in the 'output' struct.",
                          mapper->get_mapper_name())
        }
        else
        {
          // Figure out which tasks are to be triggered
          std::set<const Task*> selected;
          if (!output.map_tasks.empty())
            selected.insert(output.map_tasks.begin(), output.map_tasks.end());
          if (!output.relocate_tasks.empty())
          {
            for (std::map<const Task*,Processor>::const_iterator it = 
                  output.relocate_tasks.begin(); it != 
                  output.relocate_tasks.end(); it++)
            {
              if (it->second.kind() == Processor::UTIL_PROC)
                REPORT_LEGION_ERROR(ERROR_INVALID_MAPPER_OUTPUT,
                    "Invalid mapper output. Mapper %s requested that task %s "
                    "(UID %lld) be relocated to a utility processor in "
                    "'select_tasks_to_map.' Only application processor kinds "
                    "are permitted to be the target processor for tasks.",
                    mapper->get_mapper_name(), it->first->get_task_name(),
                    it->first->get_unique_id())
              selected.insert(it->first);
            }
          }
          // Remove any tasks that are going to be triggered
          for (std::list<TaskOp*>::iterator it = 
                queue_copy.begin(); it != queue_copy.end(); /*nothing*/)
          {
            if (selected.find(*it) != selected.end())
            {
              to_trigger.push_back(*it);
              it = queue_copy.erase(it);
            }
            else
              it++;
          }
        }
        {
          // Retake the lock, put any tasks that the mapper didn't select
          // back on the queue and update the context states for any
          // that were selected 
          AutoLock q_lock(queue_lock);
          MapperState &map_state = mapper_states[map_id];
#ifdef DEBUG_LEGION
          assert(map_state.queue_guard);
#endif
          std::list<TaskOp*> &rqueue = map_state.ready_queue;
          if (!queue_copy.empty())
          {
            // Put any new items on the back of the queue
            if (!rqueue.empty())
            {
              for (std::list<TaskOp*>::const_iterator it = 
                    rqueue.begin(); it != rqueue.end(); it++)
                queue_copy.push_back(*it);
            }
            rqueue.swap(queue_copy);
          }
          else if (rqueue.empty())
          {
            if (map_state.deferral_event.exists())
              map_state.deferral_event = RtEvent::NO_RT_EVENT;
            else
              decrement_active_mappers();
          }
          if (!to_trigger.empty())
          {
            for (std::vector<TaskOp*>::const_iterator it = 
                  to_trigger.begin(); it != to_trigger.end(); it++)
            {
              ContextID ctx_id = (*it)->get_context()->get_context_id(); 
              ContextState &state = context_states[ctx_id];
#ifdef DEBUG_LEGION
              assert(state.owned_tasks > 0);
#endif
              state.owned_tasks--;
              if (state.active && (state.owned_tasks == 0))
                decrement_active_contexts();
            }
          }
          if (!stealing_disabled && !rqueue.empty())
          {
            for (std::list<TaskOp*>::const_iterator it =
                  rqueue.begin(); it != rqueue.end(); it++)
            {
              if ((*it)->is_stealable())
              {
                mappers_with_stealable_work.push_back(map_id);
                break;
              }
            }
          }
          // Remove the queue guard
          map_state.queue_guard = false;
          if (map_state.queue_waiter.exists())
          {
            Runtime::trigger_event(map_state.queue_waiter);
            map_state.queue_waiter = RtUserEvent::NO_RT_USER_EVENT;
          }
        }
        // Now we can trigger our tasks that the mapper selected
        for (std::vector<TaskOp*>::const_iterator it = 
              to_trigger.begin(); it != to_trigger.end(); it++)
        {
          // Update the target processor for this task if necessary
          std::map<const Task*,Processor>::const_iterator finder = 
            output.relocate_tasks.find(*it);
          const bool send_remotely = (finder != output.relocate_tasks.end());
          if (send_remotely)
            (*it)->set_target_proc(finder->second);
          // Mark that this task is no longer outstanding
          (*it)->deactivate_outstanding_task();
          TaskOp::TriggerTaskArgs trigger_args(*it);
          runtime->issue_runtime_meta_task(trigger_args,
                                           LG_THROUGHPUT_WORK_PRIORITY);
        }
      }

      // Advertise any work that we have
      if (!stealing_disabled && !mappers_with_stealable_work.empty())
      {
        for (std::vector<MapperID>::const_iterator it = 
              mappers_with_stealable_work.begin(); it !=
              mappers_with_stealable_work.end(); it++)
          issue_advertisements(*it);
      }

      // Finally issue any steal requeusts
      if (!stealing_disabled && !stealing_targets.empty())
        runtime->send_steal_request(stealing_targets, local_proc);
    }

    //--------------------------------------------------------------------------
    void ProcessorManager::issue_advertisements(MapperID map_id)
    //--------------------------------------------------------------------------
    {
      // Create a clone of the processors we want to advertise so that
      // we don't call into the high level runtime holding a lock
      std::set<Processor> failed_waiters;
      MapperManager *mapper = find_mapper(map_id);
      mapper->perform_advertisements(failed_waiters);
      if (!failed_waiters.empty())
        runtime->send_advertisements(failed_waiters, map_id, local_proc);
    }

    /////////////////////////////////////////////////////////////
    // Memory Manager 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    MemoryManager::MemoryManager(Memory m, Runtime *rt)
      : memory(m), owner_space(m.address_space()), 
        is_owner(m.address_space() == rt->address_space),
        capacity(m.capacity()), remaining_capacity(capacity), runtime(rt)
    //--------------------------------------------------------------------------
    {
#if defined(LEGION_USE_CUDA) || defined(LEGION_USE_HIP)
      if ((memory.kind() == Memory::GPU_FB_MEM) || 
          (memory.kind() == Memory::GPU_MANAGED_MEM) ||
          (memory.kind() == Memory::GPU_DYNAMIC_MEM))
      {
        Machine::ProcessorQuery finder(runtime->machine);
        finder.best_affinity_to(memory);
        finder.only_kind(Processor::TOC_PROC);
        assert(finder.count() > 0);
        local_gpu = finder.first();
      }
      else if (memory.kind() == Memory::Z_COPY_MEM)
      {
        Machine::ProcessorQuery finder(runtime->machine);
        finder.has_affinity_to(memory);
        finder.only_kind(Processor::TOC_PROC);
        assert(finder.count() > 0);
        local_gpu = finder.first();
      }
#endif
    }

    //--------------------------------------------------------------------------
    MemoryManager::~MemoryManager(void)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    void MemoryManager::find_shutdown_preconditions(
                                               std::set<ApEvent> &preconditions)
    //--------------------------------------------------------------------------
    {
      // We only need to check this on the owner node instances and 
      // in fact it's only safe for us to do it on the owner node
      // instance because we only are guaranteed to have references
      // to the owner node objects
      if (!is_owner)
        return;
      std::vector<PhysicalManager*> to_check;
      {
        AutoLock m_lock(manager_lock,1,false/*exclusive*/);
        for (std::map<RegionTreeID,TreeInstances>::const_iterator cit = 
              current_instances.begin(); cit != current_instances.end(); cit++)
          for (TreeInstances::const_iterator it = 
                cit->second.begin(); it != cit->second.end(); it++)
          {
            it->first->add_base_resource_ref(MEMORY_MANAGER_REF);
            to_check.push_back(it->first);
          }
      }
      for (std::vector<PhysicalManager*>::const_iterator it = 
            to_check.begin(); it != to_check.end(); it++)
      {
        (*it)->find_shutdown_preconditions(preconditions);
        if ((*it)->remove_base_resource_ref(MEMORY_MANAGER_REF))
          delete (*it);
      }
    }

    //--------------------------------------------------------------------------
    void MemoryManager::prepare_for_shutdown(void)
    //--------------------------------------------------------------------------
    {
      // Only need to do things if we are the owner memory
      if (!is_owner)
        return;
      // This is a kind of deletion so make sure it is ordered
      AutoLock c_lock(collection_lock);
      // This a collection so make sure we're ordered with other collections
      std::vector<PhysicalManager*> to_delete, delete_now;
      {
        AutoLock m_lock(manager_lock);
        for (std::map<RegionTreeID,TreeInstances>::iterator cit = 
              current_instances.begin(); cit != 
              current_instances.end(); /*nothing*/)
        {
          for (TreeInstances::iterator it =
                cit->second.begin(); it != cit->second.end(); /*nothing*/)
          {
            if ((it->second == LEGION_GC_NEVER_PRIORITY) && 
                it->first->is_owner())
            {
              it->first->remove_base_valid_ref(NEVER_GC_REF);
              it->second = 0;
            }
            bool already_collected = false;
            if (it->first->can_collect(runtime->address_space,
                                       already_collected))
            {
              to_delete.push_back(it->first);
            }
            else if (already_collected)
            {
              delete_now.push_back(it->first);
              remove_collectable(it->second, it->first);
              TreeInstances::iterator delete_it = it++;
              cit->second.erase(delete_it);
              continue;
            }
            it++;
          }
          if (cit->second.empty())
          {
            std::map<RegionTreeID,TreeInstances>::iterator delete_it = cit++;
            current_instances.erase(delete_it);
          }
          else
            cit++;
        }
      }
      if (!to_delete.empty())
        check_instance_deletions(to_delete);
      for (std::vector<PhysicalManager*>::const_iterator it =
            delete_now.begin(); it != delete_now.end(); it++)
        if ((*it)->remove_base_resource_ref(MEMORY_MANAGER_REF))
          delete (*it);
    }

    //--------------------------------------------------------------------------
    void MemoryManager::check_instance_deletions(
                                 const std::vector<PhysicalManager*> &to_delete)
    //--------------------------------------------------------------------------
    {
      std::vector<PhysicalManager*> deleted;
      for (std::vector<PhysicalManager*>::const_iterator it =
            to_delete.begin(); it != to_delete.end(); it++)
      {
        RtEvent deletion_done;
        if (!(*it)->collect(deletion_done))
          continue;
        deleted.push_back(*it);
      }
      if (!deleted.empty())
      {
        AutoLock m_lock(manager_lock);
        for (std::vector<PhysicalManager*>::const_iterator it =
              deleted.begin(); it != deleted.end(); it++)
        {
          std::map<RegionTreeID,TreeInstances>::iterator tree_finder =
            current_instances.find((*it)->tree_id);
#ifdef DEBUG_LEGION
          assert(tree_finder != current_instances.end());
#endif
          TreeInstances::iterator finder = tree_finder->second.find(*it);
#ifdef DEBUG_LEGION
          assert(finder != tree_finder->second.end());
#endif
          remove_collectable(finder->second, finder->first);
          tree_finder->second.erase(finder);
          if (tree_finder->second.empty())
            current_instances.erase(tree_finder);
          if ((*it)->remove_base_resource_ref(MEMORY_MANAGER_REF))
            delete (*it);
        }
      }
    }

    //--------------------------------------------------------------------------
    void MemoryManager::remove_collectable(GCPriority priority,
                                           PhysicalManager *manager)
    //--------------------------------------------------------------------------
    {
      if (priority != LEGION_GC_NEVER_PRIORITY)
      {
        std::map<GCPriority,std::set<PhysicalManager*> >::iterator finder =
          collectable_instances.find(priority);
        if (finder != collectable_instances.end())
        {
          finder->second.erase(manager);
          if (finder->second.empty())
            collectable_instances.erase(finder);
        }
      }
    }

    //--------------------------------------------------------------------------
    void MemoryManager::finalize(void)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
        return;
      // No need for the lock, no one should be doing anything at this point
      for (std::map<RegionTreeID,TreeInstances>::const_iterator cit = 
            current_instances.begin(); cit != current_instances.end(); cit++)
        for (TreeInstances::const_iterator it = 
              cit->second.begin(); it != cit->second.end(); it++)
          it->first->force_deletion();
      current_instances.clear();
#ifdef LEGION_MALLOC_INSTANCES
      for (std::map<RtEvent,uintptr_t>::const_iterator it = 
            pending_collectables.begin(); it != 
            pending_collectables.end(); it++)
        if (it->second > 0)
          free_legion_instance(it->first, it->second);
      pending_collectables.clear();
#endif
    }
    
    //--------------------------------------------------------------------------
    void MemoryManager::register_remote_instance(PhysicalManager *manager)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!is_owner);
#endif
      AutoLock m_lock(manager_lock);
      TreeInstances &insts = current_instances[manager->tree_id];
#ifdef DEBUG_LEGION
      assert(insts.find(manager) == insts.end());
#endif
      insts[manager] = LEGION_GC_NEVER_PRIORITY;
    }

    //--------------------------------------------------------------------------
    void MemoryManager::unregister_remote_instance(PhysicalManager *manager)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!is_owner);
#endif
      AutoLock m_lock(manager_lock);
      std::map<RegionTreeID,TreeInstances>::iterator finder = 
        current_instances.find(manager->tree_id);
 #ifdef DEBUG_LEGION
      assert(finder != current_instances.end());
      assert(finder->second.find(manager) != finder->second.end());
#endif     
      finder->second.erase(manager);
      if (finder->second.empty())
        current_instances.erase(finder);
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::create_physical_instance(
                                const LayoutConstraintSet &constraints,
                                const std::vector<LogicalRegion> &regions,
                                MappingInstance &result, MapperID mapper_id, 
                                Processor processor, bool acquire, 
                                GCPriority priority, bool tight_bounds,
                                LayoutConstraintKind *unsat_kind,
                                unsigned *unsat_index, size_t *footprint, 
                                CollectiveManager *target, DomainPoint *point,
                                UniqueID creator_id, bool remote)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
      {
        // Not the owner, send a meessage to the owner to request the creation
        Serializer rez;
        std::atomic<PhysicalManager*> remote_manager(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(CREATE_INSTANCE_CONSTRAINTS);
          rez.serialize(ready_event);
          rez.serialize<size_t>(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          if (target != NULL)
          {
            rez.serialize(target->did);
            rez.serialize(*point);
          }
          else
            rez.serialize<DistributedID>(0);
          constraints.serialize(rez);
          rez.serialize(mapper_id);
          rez.serialize(processor);
          rez.serialize(priority);
          rez.serialize<bool>(tight_bounds);
          rez.serialize(unsat_kind);
          rez.serialize(unsat_index);
          rez.serialize(footprint);
          rez.serialize(creator_id);
          rez.serialize(&remote_manager);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        PhysicalManager *manager = remote_manager.load();
        if (manager != NULL)
        {
          result = MappingInstance(manager);
          if (acquire)
          {
            LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
            const bool success =
#endif
            manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
            assert(success);
#else
            manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
            manager->send_remote_valid_decrement(owner_space, NULL,
                                             local_mutator.get_done_event());
          }
          else
            manager->send_remote_resource_decrement(owner_space);
          return true;
        }
        else
          return false;
      }
      else
      {
        // Create the builder and initialize it before getting
        // the allocation privilege to avoid deadlock scenario
        InstanceBuilder builder(regions, constraints, runtime, this,creator_id);
        builder.initialize(runtime->forest);
        // Acquire allocation privilege before doing anything
        const RtEvent wait_on = acquire_allocation_privilege();
        if (wait_on.exists())
          wait_on.wait();
        // Try to make the result
        PhysicalManager *manager = allocate_physical_instance(builder, 
            footprint, unsat_kind, unsat_index, target, point);
        bool success = false;
        if (manager != NULL)
        {
          if (runtime->legion_spy_enabled)
            manager->log_instance_creation(creator_id, processor, regions);
          // Do this first to add a resource reference
          result = MappingInstance(manager);
          record_created_instance(manager, acquire, mapper_id, processor,
                                  priority, remote);
          success = true;
        }
        // Release our allocation privilege after doing the record
        release_allocation_privilege();
        return success;
      }
    }
    
    //--------------------------------------------------------------------------
    bool MemoryManager::create_physical_instance(LayoutConstraints *constraints,
                                     const std::vector<LogicalRegion> &regions,
                                     MappingInstance &result,MapperID mapper_id,
                                     Processor processor, bool acquire, 
                                     GCPriority priority, bool tight_bounds,
                                     LayoutConstraintKind *unsat_kind,
                                     unsigned *unsat_index, size_t *footprint, 
                                     CollectiveManager *target, DomainPoint *p,
                                     UniqueID creator_id, bool remote)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
      {
        // Not the owner, send a meessage to the owner to request the creation
        Serializer rez;
        std::atomic<PhysicalManager*> remote_manager(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(CREATE_INSTANCE_LAYOUT);
          rez.serialize(ready_event);
          rez.serialize<size_t>(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          if (target != NULL)
          {
            rez.serialize(target->did);
            rez.serialize(*p);
          }
          else
            rez.serialize<DistributedID>(0);
          rez.serialize(constraints->layout_id);
          rez.serialize(mapper_id);
          rez.serialize(processor);
          rez.serialize(priority);
          rez.serialize<bool>(tight_bounds);
          rez.serialize(unsat_kind);
          rez.serialize(unsat_index);
          rez.serialize(footprint);
          rez.serialize(creator_id);
          rez.serialize(&remote_manager);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        PhysicalManager *manager = remote_manager.load();
        if (manager != NULL)
        {
          result = MappingInstance(manager);
          if (acquire)
          {
            LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
            const bool success =
#endif
            manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
            assert(success);
#else
            manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
            manager->send_remote_valid_decrement(owner_space, NULL,
                                             local_mutator.get_done_event());
          }
          else
            manager->send_remote_resource_decrement(owner_space);
          return true;
        }
        else
          return false;
      }
      else
      {
        // Create the builder and initialize it before getting
        // the allocation privilege to avoid deadlock scenario
        InstanceBuilder builder(regions,*constraints, runtime, this,creator_id);
        builder.initialize(runtime->forest);
        // Acquire allocation privilege before doing anything
        const RtEvent wait_on = acquire_allocation_privilege();
        if (wait_on.exists())
          wait_on.wait();
        // Try to make the instance
        PhysicalManager *manager = allocate_physical_instance(builder, 
            footprint, unsat_kind, unsat_index, target, p);
        bool success = false;
        if (manager != NULL)
        {
          if (runtime->legion_spy_enabled)
            manager->log_instance_creation(creator_id, processor, regions);
          // Do this first to add a resource reference
          result = MappingInstance(manager);
          record_created_instance(manager, acquire, mapper_id, processor,
                                  priority, remote);
          success = true;
        }
        // Release our allocation privilege after doing the record
        release_allocation_privilege();
        return success;
      }
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::find_or_create_physical_instance(
                                  const LayoutConstraintSet &constraints,
                                  const std::vector<LogicalRegion> &regions,
                                  MappingInstance &result, bool &created, 
                                  MapperID mapper_id, Processor processor,
                                  bool acquire, GCPriority priority,
                                  bool tight_region_bounds, 
                                  LayoutConstraintKind *unsat_kind,
                                  unsigned *unsat_index, size_t *footprint, 
                                  UniqueID creator_id, bool remote)
    //--------------------------------------------------------------------------
    {
      // Set created to default to false
      created = false;
      if (!is_owner)
      {
        // See if we can find a locally valid instance first
        if (find_valid_instance(constraints, regions, result, 
                                acquire, tight_region_bounds, remote))
          return true;
        // Not the owner, send a message to the owner to request creation
        Serializer rez;
        std::atomic<bool> remote_created(created);
        std::atomic<PhysicalManager*> remote_manager(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(FIND_OR_CREATE_CONSTRAINTS);
          rez.serialize(ready_event);
          rez.serialize<size_t>(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          constraints.serialize(rez);
          rez.serialize(mapper_id);
          rez.serialize(processor);
          rez.serialize(priority);
          rez.serialize<bool>(tight_region_bounds);
          rez.serialize(unsat_kind);
          rez.serialize(unsat_index);
          rez.serialize(footprint);
          rez.serialize(creator_id);
          rez.serialize(&remote_manager);
          rez.serialize(&remote_created);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        PhysicalManager *manager = remote_manager.load();
        if (manager != NULL)
        {
          result = MappingInstance(manager);
          created = remote_created.load();
          if (acquire)
          {
            LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
            const bool success =
#endif
            manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
            assert(success);
#else
            manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
            manager->send_remote_valid_decrement(owner_space, NULL,
                                             local_mutator.get_done_event());
          }
          else
            manager->send_remote_resource_decrement(owner_space);
          return true;
        }
        else
          return false;
      }
      else
      {
        // Create the builder and initialize it before getting
        // the allocation privilege to avoid deadlock scenario
        InstanceBuilder builder(regions, constraints, runtime, this,creator_id);
        builder.initialize(runtime->forest);
        // First get our allocation privileges so we're the only
        // one trying to do any allocations
        const RtEvent wait_on = acquire_allocation_privilege();
        if (wait_on.exists())
          wait_on.wait();
        // Since this is find or acquire, first see if we can find
        // an instance that has already been makde that satisfies 
        // our layout constraints
        bool success = find_satisfying_instance(constraints, regions, 
                         result, acquire, tight_region_bounds, remote);
        if (!success)
        {
          // If we couldn't find it, we have to make it
          PhysicalManager *manager = allocate_physical_instance(builder, 
              footprint, unsat_kind, unsat_index);
          if (manager != NULL)
          {
            success = true;
            if (runtime->legion_spy_enabled)
              manager->log_instance_creation(creator_id, processor, regions);
            // Do this first to add a resource reference
            result = MappingInstance(manager);
            record_created_instance(manager, acquire, mapper_id, processor,
                                    priority, remote);
            // We made this instance so mark that it was created
            created = true;
          }
        }
        else if (footprint != NULL)
          *footprint = result.get_instance_size();
        // Release our allocation privilege after doing the record
        release_allocation_privilege();
        return success;
      }
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::find_or_create_physical_instance(
                                LayoutConstraints *constraints, 
                                const std::vector<LogicalRegion> &regions,
                                MappingInstance &result, bool &created,
                                MapperID mapper_id, Processor processor,
                                bool acquire, GCPriority priority, 
                                bool tight_region_bounds, 
                                LayoutConstraintKind *unsat_kind,
                                unsigned *unsat_index, size_t *footprint, 
                                UniqueID creator_id, bool remote)
    //--------------------------------------------------------------------------
    {
      // Set created to false in case we fail
      created = false;
      if (!is_owner)
      {
        // See if we can find it locally
        if (find_valid_instance(*constraints, regions, result, 
                                acquire, tight_region_bounds, remote))
          return true;
        // Not the owner, send a message to the owner to request creation
        Serializer rez;
        std::atomic<bool> remote_created(created);
        std::atomic<PhysicalManager*> remote_manager(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(FIND_OR_CREATE_LAYOUT);
          rez.serialize(ready_event);
          rez.serialize<size_t>(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          rez.serialize(constraints->layout_id);
          rez.serialize(mapper_id);
          rez.serialize(processor);
          rez.serialize(priority);
          rez.serialize<bool>(tight_region_bounds);
          rez.serialize(unsat_kind);
          rez.serialize(unsat_index);
          rez.serialize(footprint);
          rez.serialize(creator_id);
          rez.serialize(&remote_manager);
          rez.serialize(&remote_created);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        PhysicalManager *manager = remote_manager.load();
        if (manager != NULL)
        {
          result = MappingInstance(manager);
          created = remote_created.load();
          if (acquire)
          {
            LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
            const bool success =
#endif
            manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
            assert(success);
#else
            manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
            manager->send_remote_valid_decrement(owner_space, NULL,
                                             local_mutator.get_done_event());
          }
          else
            manager->send_remote_resource_decrement(owner_space);
          return true;
        }
        else
          return false;
      }
      else
      {
        // Create the builder and initialize it before getting
        // the allocation privilege to avoid deadlock scenario
        InstanceBuilder builder(regions,*constraints, runtime, this,creator_id);
        builder.initialize(runtime->forest);
        // First get our allocation privileges so we're the only
        // one trying to do any allocations
        const RtEvent wait_on = acquire_allocation_privilege();
        if (wait_on.exists())
          wait_on.wait();
        // Since this is find or acquire, first see if we can find
        // an instance that has already been makde that satisfies 
        // our layout constraints
        // Try to find an instance first and then make one
        bool success = find_satisfying_instance(*constraints, regions, 
                        result, acquire, tight_region_bounds, remote);
        if (!success)
        {
          // If we couldn't find it, we have to make it
          PhysicalManager *manager = allocate_physical_instance(builder, 
              footprint, unsat_kind, unsat_index);
          if (manager != NULL)
          {
            success = true;
            if (runtime->legion_spy_enabled)
              manager->log_instance_creation(creator_id, processor, regions);
            // Do this first to add a resource reference
            result = MappingInstance(manager);
            record_created_instance(manager, acquire, mapper_id, processor,
                                    priority, remote);
            // We made this instance so mark that it was created
            created = true;
          }
        }
        else if (footprint != NULL)
          *footprint = result.get_instance_size();
        // Release our allocation privilege after doing the record
        release_allocation_privilege();
        return success;
      }
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::find_physical_instance(
                                     const LayoutConstraintSet &constraints,
                                     const std::vector<LogicalRegion> &regions,
                                     MappingInstance &result, bool acquire, 
                                     bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
      {
        // See if we can find it locally 
        if (find_valid_instance(constraints, regions, result, 
                                  acquire, tight_region_bounds, remote))
          return true;
        // Not the owner, send a message to the owner to try and find it
        Serializer rez;
        std::atomic<PhysicalManager*> remote_manager(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(FIND_ONLY_CONSTRAINTS);
          rez.serialize(ready_event);
          rez.serialize(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          constraints.serialize(rez);
          rez.serialize<bool>(tight_region_bounds);
          rez.serialize(&remote_manager);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        PhysicalManager *manager = remote_manager.load();
        if (manager != NULL)
        {
          if (acquire)
          {
            LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
            const bool success =
#endif
            manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
            assert(success);
#else
            manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
            manager->send_remote_valid_decrement(owner_space, NULL,
                                             local_mutator.get_done_event());
          }
          else
            manager->send_remote_resource_decrement(owner_space);
          return true;
        }
        else
          return false;
      }
      else
      {
        // Try to find an instance
        return find_satisfying_instance(constraints, regions, result, 
                                  acquire, tight_region_bounds, remote);
      }
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::find_physical_instance(LayoutConstraints *constraints,
                                      const std::vector<LogicalRegion> &regions,
                                      MappingInstance &result, bool acquire, 
                                      bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
      {
        // See if we can find a persistent instance
        if (find_valid_instance(*constraints, regions, result, 
                                  acquire, tight_region_bounds, remote))
          return true;
        Serializer rez;
        std::atomic<PhysicalManager*> remote_manager(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(FIND_ONLY_LAYOUT);
          rez.serialize(ready_event);
          rez.serialize<size_t>(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          rez.serialize(constraints->layout_id);
          rez.serialize<bool>(tight_region_bounds);
          rez.serialize(&remote_manager);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        PhysicalManager *manager = remote_manager.load();
        if (manager != NULL)
        {
          if (acquire)
          {
            LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
            const bool success =
#endif
            manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
            assert(success);
#else
            manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
            manager->send_remote_valid_decrement(owner_space, NULL,
                                             local_mutator.get_done_event());
          }
          else
            manager->send_remote_resource_decrement(owner_space);
          return true;
        }
        else
          return false;
      }
      else
      {
        // Try to find an instance
        return find_satisfying_instance(*constraints, regions, result,
                               acquire, tight_region_bounds, remote);
      }
    }

    //--------------------------------------------------------------------------
    void MemoryManager::find_physical_instances(
                            const LayoutConstraintSet &constraints,
                            const std::vector<LogicalRegion> &regions,
                            std::vector<MappingInstance> &results, 
                            bool acquire, bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
      {
        // Not the owner, send a message to the owner to try and find it
        Serializer rez;
        std::atomic<std::vector<PhysicalManager*>*> remote_managers(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(FIND_MANY_CONSTRAINTS);
          rez.serialize(ready_event);
          rez.serialize(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          constraints.serialize(rez);
          rez.serialize<bool>(tight_region_bounds);
          rez.serialize(&remote_managers);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        std::vector<PhysicalManager*> *managers = remote_managers.load();
        if (managers != NULL)
        {
          results.resize(managers->size());
          for (unsigned idx = 0; idx < results.size(); idx++)
          {
            PhysicalManager *manager = managers->at(idx);
#ifdef DEBUG_LEGION
            assert(manager != NULL);
#endif
            results[idx] = MappingInstance(manager);
            if (acquire)
            {
              LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
              const bool success =
#endif
              manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
              assert(success);
#else
              manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
              manager->send_remote_valid_decrement(owner_space, NULL,
                                               local_mutator.get_done_event());
            }
            else
              manager->send_remote_resource_decrement(owner_space);
          }
          delete managers;
        }
      }
      else
        find_satisfying_instances(constraints, regions, results,
                                  acquire, tight_region_bounds, remote);
    }

    //--------------------------------------------------------------------------
    void MemoryManager::find_physical_instances(LayoutConstraints *constraints,
                            const std::vector<LogicalRegion> &regions,
                            std::vector<MappingInstance> &results, 
                            bool acquire, bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      if (!is_owner)
      {
        Serializer rez;
        std::atomic<std::vector<PhysicalManager*>*> remote_managers(NULL);
        RtUserEvent ready_event = Runtime::create_rt_user_event();
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(FIND_MANY_LAYOUT);
          rez.serialize(ready_event);
          rez.serialize<size_t>(regions.size());
          for (unsigned idx = 0; idx < regions.size(); idx++)
            rez.serialize(regions[idx]);
          rez.serialize<bool>(acquire);
          rez.serialize(constraints->layout_id);
          rez.serialize<bool>(tight_region_bounds);
          rez.serialize(&remote_managers);
        }
        runtime->send_instance_request(owner_space, rez);
        ready_event.wait();
        std::vector<PhysicalManager*> *managers = remote_managers.load();
        if (managers != NULL)
        {
          results.resize(managers->size());
          for (unsigned idx = 0; idx < results.size(); idx++)
          {
            PhysicalManager *manager = managers->at(idx);
#ifdef DEBUG_LEGION
            assert(manager != NULL);
#endif
            results[idx] = MappingInstance(manager);
            if (acquire)
            {
              LocalReferenceMutator local_mutator;
#ifdef DEBUG_LEGION
#ifndef NDEBUG
              const bool success =
#endif
              manager->acquire_instance(MAPPING_ACQUIRE_REF, &local_mutator);
              assert(success);
#else
              manager->add_base_valid_ref(MAPPING_ACQUIRE_REF, &local_mutator);
#endif
              manager->send_remote_valid_decrement(owner_space, NULL,
                                               local_mutator.get_done_event());
            }
            else
              manager->send_remote_resource_decrement(owner_space);
          }
          delete managers;
        }
      }
      else
        find_satisfying_instances(*constraints, regions, results,
                                  acquire, tight_region_bounds, remote);
    }

    //--------------------------------------------------------------------------
    void MemoryManager::release_tree_instances(RegionTreeID tree_id)
    //--------------------------------------------------------------------------
    {
      // If we're not the owner, then there is nothing to do
      if (!is_owner)
        return;
      // Try to delete all the instances in the region tree
      // If any of them cannot be deleted yet, they'll have to 
      // wait until we do a garbage collection
      // This is a collection so we need to order it with respect to
      // to other collections
      AutoLock c_lock(collection_lock);
      std::vector<PhysicalManager*> to_delete, delete_now;
      {
        AutoLock m_lock(manager_lock);
        std::map<RegionTreeID,TreeInstances>::iterator finder = 
          current_instances.find(tree_id);
        if (finder != current_instances.end())
        {
          for (TreeInstances::iterator it =
                finder->second.begin(); it != finder->second.end(); /*nothing*/)
          {
            if ((it->second == LEGION_GC_NEVER_PRIORITY) && 
                it->first->is_owner())
            {
              it->first->remove_base_valid_ref(NEVER_GC_REF);
              it->second = 0;
            }
            bool already_collected = false;
            if (it->first->can_collect(runtime->address_space, 
                                       already_collected))
            {
              to_delete.push_back(it->first);
            }
            else if (already_collected)
            {
              delete_now.push_back(it->first);
              remove_collectable(it->second, it->first);
              TreeInstances::iterator delete_it = it++;
              finder->second.erase(delete_it);
              continue;
            }
            it++;
          }
          if (finder->second.empty())
            current_instances.erase(finder);
        }
      }
      if (!to_delete.empty())
        check_instance_deletions(to_delete);
      for (std::vector<PhysicalManager*>::const_iterator it =
            delete_now.begin(); it != delete_now.end(); it++)
        if ((*it)->remove_base_resource_ref(MEMORY_MANAGER_REF))
          delete (*it);
    }

    //--------------------------------------------------------------------------
    void MemoryManager::set_garbage_collection_priority(
                                  PhysicalManager *manager, GCPriority priority)
    //--------------------------------------------------------------------------
    { 
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      AutoLock c_lock(collection_lock);
      AutoLock m_lock(manager_lock);
      std::map<RegionTreeID,TreeInstances>::iterator tree_finder =
        current_instances.find(manager->tree_id);
#ifdef DEBUG_LEGION
      assert(tree_finder != current_instances.end());
#endif
      TreeInstances::iterator finder = tree_finder->second.find(manager);
#ifdef DEBUG_LEGION
      assert(finder != tree_finder->second.end());
#endif
      remove_collectable(finder->second, manager);
      finder->second = priority;
      if (priority != LEGION_GC_NEVER_PRIORITY)
        collectable_instances[priority].insert(manager);
    }

    //--------------------------------------------------------------------------
    void MemoryManager::process_instance_request(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      RequestKind kind;
      derez.deserialize(kind);
      RtUserEvent to_trigger;
      derez.deserialize(to_trigger);
      size_t num_regions;
      derez.deserialize(num_regions);
      std::vector<LogicalRegion> regions(num_regions);
      for (unsigned idx = 0; idx < num_regions; idx++)
        derez.deserialize(regions[idx]);
      bool acquire;
      derez.deserialize(acquire);
      switch (kind)
      {
        case CREATE_INSTANCE_CONSTRAINTS:
          {
            DistributedID collective_did;
            derez.deserialize(collective_did);
            RtEvent collective_ready;
            DomainPoint point;
            CollectiveManager *collective = NULL;
            if (collective_did > 0)
            {
              collective = static_cast<CollectiveManager*>(
                  runtime->find_or_request_instance_manager(collective_did, 
                                                            collective_ready));
              derez.deserialize(point);
            }
            LayoutConstraintSet constraints;
            constraints.deserialize(derez);
            MapperID mapper_id;
            derez.deserialize(mapper_id);
            Processor processor;
            derez.deserialize(processor);
            GCPriority priority;
            derez.deserialize(priority);
            bool tight_region_bounds;
            derez.deserialize<bool>(tight_region_bounds);
            LayoutConstraintKind *remote_kind;
            derez.deserialize(remote_kind);
            unsigned *remote_index;
            derez.deserialize(remote_index);
            size_t *remote_footprint; // warning: remote pointer
            derez.deserialize(remote_footprint);
            UniqueID creator_id;
            derez.deserialize(creator_id);
            std::atomic<PhysicalManager*> *remote_target;
            derez.deserialize(remote_target);
            MappingInstance result;
            size_t local_footprint;
            LayoutConstraintKind local_kind;
            unsigned local_index;
            if (collective_ready.exists() && !collective_ready.has_triggered())
              collective_ready.wait();
            bool success = create_physical_instance(constraints, regions, 
                                 result, mapper_id, processor, acquire, 
                                 priority, tight_region_bounds,
                                 &local_kind, &local_index, &local_footprint,
                                 collective, &point, creator_id,true/*remote*/);
            if (success || (remote_footprint != NULL) || 
                (remote_kind != NULL) || (remote_index != NULL))
            {
              // Send back the response starting with the instance
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(success);
                if (success)
                {
                  InstanceManager *manager = result.impl;
                  rez.serialize(manager->did);
                  rez.serialize(remote_target);
                }
                rez.serialize(kind);
                rez.serialize(remote_kind);
                rez.serialize(local_kind);
                rez.serialize(remote_index);
                rez.serialize(local_index);
                rez.serialize(remote_footprint);
                rez.serialize(local_footprint);
              }
              runtime->send_instance_response(source, rez);
            }
            else // we can just trigger the done event since we failed
              Runtime::trigger_event(to_trigger);
            break;
          }
        case CREATE_INSTANCE_LAYOUT:
          {
            DistributedID collective_did;
            derez.deserialize(collective_did);
            RtEvent collective_ready;
            CollectiveManager *collective = NULL;
            DomainPoint point;
            if (collective_did > 0)
            {
              collective = static_cast<CollectiveManager*>(
                  runtime->find_or_request_instance_manager(collective_did, 
                                                            collective_ready));
              derez.deserialize(point);
            }
            LayoutConstraintID layout_id;
            derez.deserialize(layout_id);
            MapperID mapper_id;
            derez.deserialize(mapper_id);
            Processor processor;
            derez.deserialize(processor);
            GCPriority priority;
            derez.deserialize(priority);
            bool tight_region_bounds;
            derez.deserialize<bool>(tight_region_bounds);
            LayoutConstraintKind *remote_kind;
            derez.deserialize(remote_kind);
            unsigned *remote_index;
            derez.deserialize(remote_index);
            size_t *remote_footprint; // warning: remote pointer
            derez.deserialize(remote_footprint);
            UniqueID creator_id;
            derez.deserialize(creator_id);
            std::atomic<PhysicalManager*> *remote_target;
            derez.deserialize(remote_target);
            LayoutConstraints *constraints = 
              runtime->find_layout_constraints(layout_id);
            MappingInstance result;
            size_t local_footprint;
            LayoutConstraintKind local_kind;
            unsigned local_index;
            if (collective_ready.exists() && !collective_ready.has_triggered())
              collective_ready.wait();
            bool success = create_physical_instance(constraints, regions, 
                                 result, mapper_id, processor, acquire, 
                                 priority, tight_region_bounds,
                                 &local_kind, &local_index, &local_footprint,
                                 collective, &point, creator_id,true/*remote*/);
            if (success || (remote_footprint != NULL) ||
                (remote_kind != NULL) || (remote_index != NULL))
            {
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(success);
                if (success)
                {
                  InstanceManager *manager = result.impl;
                  rez.serialize(manager->did);
                  rez.serialize(remote_target);
                }
                rez.serialize(kind);
                rez.serialize(remote_kind);
                rez.serialize(local_kind);
                rez.serialize(remote_index);
                rez.serialize(local_index);
                rez.serialize(remote_footprint);
                rez.serialize(local_footprint);
              }
              runtime->send_instance_response(source, rez);
            }
            else // if we failed, we can just trigger the response
              Runtime::trigger_event(to_trigger);
            break;
          }
        case FIND_OR_CREATE_CONSTRAINTS:
          {
            LayoutConstraintSet constraints;
            constraints.deserialize(derez);
            MapperID mapper_id;
            derez.deserialize(mapper_id);
            Processor processor;
            derez.deserialize(processor);
            GCPriority priority;
            derez.deserialize(priority);
            bool tight_bounds;
            derez.deserialize(tight_bounds);
            LayoutConstraintKind *remote_kind;
            derez.deserialize(remote_kind);
            unsigned *remote_index;
            derez.deserialize(remote_index);
            size_t *remote_footprint; // warning: remote pointer
            derez.deserialize(remote_footprint);
            UniqueID creator_id;
            derez.deserialize(creator_id);
            std::atomic<PhysicalManager*> *remote_target;
            derez.deserialize(remote_target);
            std::atomic<bool> *remote_created;
            derez.deserialize(remote_created);
            MappingInstance result;
            size_t local_footprint;
            LayoutConstraintKind local_kind;
            unsigned local_index;
            bool created;
            bool success = find_or_create_physical_instance(constraints, 
                                regions, result, created, mapper_id, 
                                processor, acquire, priority, tight_bounds,
                                &local_kind, &local_index,
                                &local_footprint, creator_id, true/*remote*/);
            if (success || (remote_footprint != NULL) ||
                (remote_kind != NULL) || (remote_index != NULL))
            {
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(success);
                if (success)
                {
                  InstanceManager *manager = result.impl;
                  rez.serialize(manager->did);
                  rez.serialize(remote_target);
                  rez.serialize(kind);
                  rez.serialize(remote_created);
                  rez.serialize<bool>(created);
                }
                else
                  rez.serialize(kind);
                rez.serialize(remote_kind);
                rez.serialize(local_kind);
                rez.serialize(remote_index);
                rez.serialize(local_index);
                rez.serialize(remote_footprint);
                rez.serialize(local_footprint);
              }
              runtime->send_instance_response(source, rez);
            }
            else // if we failed, we can just trigger the response
              Runtime::trigger_event(to_trigger);
            break;
          }
        case FIND_OR_CREATE_LAYOUT:
          {
            LayoutConstraintID layout_id;
            derez.deserialize(layout_id);
            MapperID mapper_id;
            derez.deserialize(mapper_id);
            Processor processor;
            derez.deserialize(processor);
            GCPriority priority;
            derez.deserialize(priority);
            bool tight_bounds;
            derez.deserialize(tight_bounds);
            LayoutConstraintKind *remote_kind;
            derez.deserialize(remote_kind);
            unsigned *remote_index;
            derez.deserialize(remote_index);
            size_t *remote_footprint; // warning: remote pointer
            derez.deserialize(remote_footprint);
            UniqueID creator_id;
            derez.deserialize(creator_id);
            std::atomic<PhysicalManager*> *remote_target;
            derez.deserialize(remote_target);
            std::atomic<bool> *remote_created;
            derez.deserialize(remote_created);
            LayoutConstraints *constraints = 
              runtime->find_layout_constraints(layout_id);
            MappingInstance result;
            size_t local_footprint;
            LayoutConstraintKind local_kind;
            unsigned local_index;
            bool created;
            bool success = find_or_create_physical_instance(constraints, 
                                 regions, result, created, mapper_id, 
                                 processor, acquire, priority, tight_bounds,
                                 &local_kind, &local_index,
                                 &local_footprint, creator_id, true/*remote*/);
            if (success || (remote_footprint != NULL) ||
                (remote_kind != NULL) || (remote_index != NULL))
            {
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(success);
                if (success)
                {
                  InstanceManager *manager = result.impl;
                  rez.serialize(manager->did);
                  rez.serialize(remote_target);
                  rez.serialize(kind);
                  rez.serialize(remote_created);
                  rez.serialize<bool>(created);
                }
                else
                  rez.serialize(kind);
                rez.serialize(remote_kind);
                rez.serialize(local_kind);
                rez.serialize(remote_index);
                rez.serialize(local_index);
                rez.serialize(remote_footprint);
                rez.serialize(local_footprint);
              }
              runtime->send_instance_response(source, rez);
            }
            else // we failed so just trigger the response
              Runtime::trigger_event(to_trigger);
            break;
          }
        case FIND_ONLY_CONSTRAINTS:
          {
            LayoutConstraintSet constraints; 
            constraints.deserialize(derez);
            bool tight_bounds;
            derez.deserialize(tight_bounds);
            std::atomic<PhysicalManager*> *remote_target;
            derez.deserialize(remote_target);
            MappingInstance result;
            bool success = find_physical_instance(constraints, regions,
                        result, acquire, tight_bounds, true/*remote*/);
            if (success)
            {
              InstanceManager *manager = result.impl;
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(true); // success
                rez.serialize(manager->did);
                rez.serialize(remote_target);
                rez.serialize(kind);
                // No things for us to pass back here
                rez.serialize<LayoutConstraintKind*>(NULL);
                rez.serialize(LEGION_SPECIALIZED_CONSTRAINT);
                rez.serialize<unsigned*>(NULL);
                rez.serialize<unsigned>(0);
                rez.serialize<size_t*>(NULL);
                rez.serialize<size_t>(0);
              }
              runtime->send_instance_response(source, rez);
            }
            else // we failed so we can just trigger the response
              Runtime::trigger_event(to_trigger);
            break;
          }
        case FIND_ONLY_LAYOUT:
          {
            LayoutConstraintID layout_id;
            derez.deserialize(layout_id);
            bool tight_bounds;
            derez.deserialize(tight_bounds);
            std::atomic<PhysicalManager*> *remote_target;
            derez.deserialize(remote_target);
            LayoutConstraints *constraints = 
              runtime->find_layout_constraints(layout_id);
            MappingInstance result;
            bool success = find_physical_instance(constraints, regions, 
                        result, acquire, tight_bounds, true/*remote*/);
            if (success)
            {
              InstanceManager *manager = result.impl;
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(true); // success
                rez.serialize(manager->did);
                rez.serialize(remote_target);
                rez.serialize(kind);
                // No things for us to pass back here
                rez.serialize<LayoutConstraintKind*>(NULL);
                rez.serialize(LEGION_SPECIALIZED_CONSTRAINT);
                rez.serialize<unsigned*>(NULL);
                rez.serialize<unsigned>(0);
                rez.serialize<size_t*>(NULL);
                rez.serialize<size_t>(0);
              }
              runtime->send_instance_response(source, rez);
            }
            else // we failed so just trigger
              Runtime::trigger_event(to_trigger);
            break;
          }
        case FIND_MANY_CONSTRAINTS:
          {
            LayoutConstraintSet constraints; 
            constraints.deserialize(derez);
            bool tight_bounds;
            derez.deserialize(tight_bounds);
            std::atomic<std::vector<PhysicalManager*>*> *remote_target;
            derez.deserialize(remote_target);
            std::vector<MappingInstance> results;
            find_physical_instances(constraints, regions, results, acquire, 
                                    tight_bounds, true/*remote*/);
            if (!results.empty())
            {
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(false); // success
                rez.serialize(kind);
                rez.serialize(remote_target);
                rez.serialize<size_t>(results.size());
                for (unsigned idx = 0; idx < results.size(); idx++)
                {
                  InstanceManager *manager = results[idx].impl;
                  rez.serialize(manager->did);
                }
                // No things for us to pass back here
                rez.serialize<LayoutConstraintKind*>(NULL);
                rez.serialize(LEGION_SPECIALIZED_CONSTRAINT);
                rez.serialize<unsigned*>(NULL);
                rez.serialize<unsigned>(0);
                rez.serialize<size_t*>(NULL);
                rez.serialize<size_t>(0);
              }
              runtime->send_instance_response(source, rez);
            }
            else // we failed so we can just trigger the response
              Runtime::trigger_event(to_trigger);
            break;
          }
        case FIND_MANY_LAYOUT:
          {
            LayoutConstraintID layout_id;
            derez.deserialize(layout_id);
            bool tight_bounds;
            derez.deserialize(tight_bounds);
            std::atomic<std::vector<PhysicalManager*>*> *remote_target;
            derez.deserialize(remote_target);
            LayoutConstraints *constraints = 
              runtime->find_layout_constraints(layout_id);
            std::vector<MappingInstance> results;
            find_physical_instances(constraints, regions, results, acquire, 
                                    tight_bounds, true/*remote*/);
            if (!results.empty())
            {
              Serializer rez;
              {
                RezCheck z(rez);
                rez.serialize(memory);
                rez.serialize(to_trigger);
                rez.serialize<bool>(false); // success
                rez.serialize(kind);
                rez.serialize(remote_target);
                rez.serialize<size_t>(results.size());
                for (unsigned idx = 0; idx < results.size(); idx++)
                {
                  InstanceManager *manager = results[idx].impl;
                  rez.serialize(manager->did);
                }
                // No things for us to pass back here
                rez.serialize<LayoutConstraintKind*>(NULL);
                rez.serialize(LEGION_SPECIALIZED_CONSTRAINT);
                rez.serialize<unsigned*>(NULL);
                rez.serialize<unsigned>(0);
                rez.serialize<size_t*>(NULL);
                rez.serialize<size_t>(0);
              }
              runtime->send_instance_response(source, rez);
            }
            else // we failed so just trigger
              Runtime::trigger_event(to_trigger);
            break;
          }
        default:
          assert(false);
      }
    }

    //--------------------------------------------------------------------------
    void MemoryManager::process_instance_response(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RtUserEvent to_trigger;
      derez.deserialize(to_trigger);
      bool success;
      derez.deserialize<bool>(success);
      std::vector<RtEvent> preconditions;
      if (success)
      {
        DistributedID did;
        derez.deserialize(did);
        std::atomic<PhysicalManager*> *target;
        derez.deserialize(target);
        RequestKind kind;
        derez.deserialize(kind);
#ifdef DEBUG_LEGION
        assert((CREATE_INSTANCE_CONSTRAINTS <= kind) &&
               (kind <= FIND_ONLY_LAYOUT));
#endif
        RtEvent manager_ready = RtEvent::NO_RT_EVENT;
        PhysicalManager *manager = 
          runtime->find_or_request_instance_manager(did, manager_ready);
        // If the manager isn't ready yet, then we need to wait for it
        if (manager_ready.exists())
          preconditions.push_back(manager_ready);
        target->store(manager);
        if ((kind == FIND_OR_CREATE_CONSTRAINTS) || 
            (kind == FIND_OR_CREATE_LAYOUT))
        {
          std::atomic<bool> *created_ptr;
          derez.deserialize(created_ptr);
          bool created;
          derez.deserialize(created);
          created_ptr->store(created);
        }
      }
      else
      {
        RequestKind kind;
        derez.deserialize(kind);
        if ((kind == FIND_MANY_CONSTRAINTS) || (kind == FIND_MANY_LAYOUT))
        {
          std::atomic<std::vector<PhysicalManager*>*> *target;
          derez.deserialize(target);
          size_t num_insts;
          derez.deserialize(num_insts);
          std::vector<PhysicalManager*> *results = 
            new std::vector<PhysicalManager*>();
          results->reserve(num_insts);
          for (unsigned idx = 0; idx < num_insts; idx++)
          {
            DistributedID did;
            derez.deserialize(did);
            RtEvent manager_ready = RtEvent::NO_RT_EVENT;
            PhysicalManager *manager = 
              runtime->find_or_request_instance_manager(did, manager_ready);
            // If the manager isn't ready yet, then we need to wait for it
            if (manager_ready.exists())
              preconditions.push_back(manager_ready);
            results->push_back(manager);
          }
          target->store(results);
        }
      }
      // Unpack the constraint responses
      LayoutConstraintKind *local_kind;
      derez.deserialize(local_kind);
      LayoutConstraintKind kind;
      derez.deserialize(kind);
      if (local_kind != NULL)
        *local_kind = kind;
      unsigned *local_index;
      derez.deserialize(local_index);
      unsigned index;
      derez.deserialize(index);
      if (local_index != NULL)
        *local_index = index;
      // Unpack the footprint and asign it if necessary
      size_t *local_footprint;
      derez.deserialize(local_footprint);
      size_t footprint;
      derez.deserialize(footprint);
      if (local_footprint != NULL)
        *local_footprint = footprint;
      // Trigger that we are done
      if (!preconditions.empty())
        Runtime::trigger_event(to_trigger,Runtime::merge_events(preconditions));
      else
        Runtime::trigger_event(to_trigger);
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::find_satisfying_instance(
                                const LayoutConstraintSet &constraints,
                                const std::vector<LogicalRegion> &regions,
                                MappingInstance &result, bool acquire, 
                                bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      RegionTreeID tree_id = 0;
      for (std::vector<LogicalRegion>::const_iterator it =
            regions.begin(); it != regions.end(); it++)
      {
        if (!it->exists())
          continue;
        tree_id = it->get_tree_id();
        break;
      }
      std::deque<PhysicalManager*> candidates;
      if (tree_id != 0)
      {
        // Hold the lock while searching here
        AutoLock m_lock(manager_lock, 1, false/*exclusive*/);
        std::map<RegionTreeID,TreeInstances>::const_iterator finder = 
          current_instances.find(tree_id);
        if (finder == current_instances.end())
          return false;
        for (TreeInstances::const_iterator it = 
              finder->second.begin(); it != finder->second.end(); it++)
        {
          it->first->add_base_resource_ref(MEMORY_MANAGER_REF);
          candidates.push_back(it->first);
        }
      }
      else
      {
        // Just get all the instances since we don't care about regions
        AutoLock m_lock(manager_lock, 1, false/*exclusive*/);
        for (std::map<RegionTreeID,TreeInstances>::const_iterator rit =
              current_instances.begin(); rit != current_instances.end(); rit++)
        {
          for (TreeInstances::const_iterator it =
                rit->second.begin(); it != rit->second.end(); it++)
          {
            it->first->add_base_resource_ref(MEMORY_MANAGER_REF);
            candidates.push_back(it->first);
          }
        }
      }
      // If we have any candidates check their constraints
      bool found = false;
      if (!candidates.empty())
      {
        if (tree_id != 0)
        {
          // If we need a padding constraint make sure we're
          // checking for tight region bounds
          if (constraints.padding_constraint.delta.get_dim() > 0)
            tight_region_bounds = true;
          std::set<IndexSpaceExpression*> region_exprs;
          RegionTreeForest *forest = runtime->forest;
          for (std::vector<LogicalRegion>::const_iterator it = 
                regions.begin(); it != regions.end(); it++)
          {
            // If the region tree IDs don't match that is bad
            if (tree_id != it->get_tree_id())
              return false;
            RegionNode *node = forest->get_node(*it);
            region_exprs.insert(node->row_source);
          }
          IndexSpaceExpression *space_expr = (region_exprs.size() == 1) ?
            *(region_exprs.begin()) : forest->union_index_spaces(region_exprs);
          for (std::deque<PhysicalManager*>::const_iterator it =
                candidates.begin(); it != candidates.end(); it++)
          {
            if (!(*it)->meets_expression(space_expr, tight_region_bounds))
              continue;
            if ((*it)->entails(constraints, DomainPoint(), NULL))
            {
              // Check to see if we need to acquire
              // If we fail to acquire then keep going
              if (acquire && !(*it)->acquire_instance(
                      remote ? REMOTE_DID_REF : MAPPING_ACQUIRE_REF, NULL))
                continue;
              // If we make it here, we succeeded
              result = MappingInstance(*it);
              found = true;
              break;
            }
          }
        }
        else
        {
          // No region constraints, just check the base constraints
          for (std::deque<PhysicalManager*>::const_iterator it =
                candidates.begin(); it != candidates.end(); it++)
          {
            if ((*it)->entails(constraints, DomainPoint(), NULL))
            {
              // Check to see if we need to acquire
              // If we fail to acquire then keep going
              if (acquire && !(*it)->acquire_instance(
                      remote ? REMOTE_DID_REF : MAPPING_ACQUIRE_REF, NULL))
                continue;
              // If we make it here, we succeeded
              result = MappingInstance(*it);
              found = true;
              break;
            }
          }
        }
        release_candidate_references(candidates);
      }
      return found;
    }

    //--------------------------------------------------------------------------
    void MemoryManager::find_satisfying_instances(
                            const LayoutConstraintSet &constraints,
                            const std::vector<LogicalRegion> &regions,
                            std::vector<MappingInstance> &results, 
                            bool acquire, bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      RegionTreeID tree_id = 0;
      for (std::vector<LogicalRegion>::const_iterator it =
            regions.begin(); it != regions.end(); it++)
      {
        if (!it->exists())
          continue;
        tree_id = it->get_tree_id();
        break;
      }
      std::deque<PhysicalManager*> candidates;
      if (tree_id != 0)
      {
        // Hold the lock while searching here
        AutoLock m_lock(manager_lock, 1, false/*exclusive*/);
        std::map<RegionTreeID,TreeInstances>::const_iterator finder = 
          current_instances.find(tree_id);
        if (finder == current_instances.end())
          return;
        for (TreeInstances::const_iterator it = 
              finder->second.begin(); it != finder->second.end(); it++)
        {
          it->first->add_base_resource_ref(MEMORY_MANAGER_REF);
          candidates.push_back(it->first);
        }
      }
      else
      {
        // Just get all the instances since we don't care about regions
        AutoLock m_lock(manager_lock, 1, false/*exclusive*/);
        for (std::map<RegionTreeID,TreeInstances>::const_iterator rit =
              current_instances.begin(); rit != current_instances.end(); rit++)
        {
          for (TreeInstances::const_iterator it =
                rit->second.begin(); it != rit->second.end(); it++)
          {
            it->first->add_base_resource_ref(MEMORY_MANAGER_REF);
            candidates.push_back(it->first);
          }
        }
      }
      // If we have any candidates check their constraints
      if (!candidates.empty())
      {
        if (tree_id != 0)
        {
          // If we need a padding constraint make sure we're
          // checking for tight region bounds
          if (constraints.padding_constraint.delta.get_dim() > 0)
            tight_region_bounds = true;
          std::set<IndexSpaceExpression*> region_exprs;
          RegionTreeForest *forest = runtime->forest;
          for (std::vector<LogicalRegion>::const_iterator it = 
                regions.begin(); it != regions.end(); it++)
          {
            // If the region tree IDs don't match that is bad
            if (tree_id != it->get_tree_id())
              return;
            RegionNode *node = forest->get_node(*it);
            region_exprs.insert(node->row_source);
          }
          IndexSpaceExpression *space_expr = (region_exprs.size() == 1) ?
            *(region_exprs.begin()) : forest->union_index_spaces(region_exprs);
          for (std::deque<PhysicalManager*>::const_iterator it = 
                candidates.begin(); it != candidates.end(); it++)
          {
            if (!(*it)->meets_expression(space_expr, tight_region_bounds))
              continue;
            if ((*it)->entails(constraints, DomainPoint(), NULL))
            {
              // Check to see if we need to acquire
              // If we fail to acquire then keep going
              if (acquire && !(*it)->acquire_instance(
                      remote ? REMOTE_DID_REF : MAPPING_ACQUIRE_REF, NULL))
                continue;
              // If we make it here, we succeeded
              results.push_back(MappingInstance(*it));
            }
          }
        }
        else
        {
          // No regions to care about here, just check constraints
          for (std::deque<PhysicalManager*>::const_iterator it = 
                candidates.begin(); it != candidates.end(); it++)
          {
            if ((*it)->entails(constraints, DomainPoint(), NULL))
            {
              // Check to see if we need to acquire
              // If we fail to acquire then keep going
              if (acquire && !(*it)->acquire_instance(
                      remote ? REMOTE_DID_REF : MAPPING_ACQUIRE_REF, NULL))
                continue;
              // If we make it here, we succeeded
              results.push_back(MappingInstance(*it));
            }
          }
        }
        release_candidate_references(candidates);
      }
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::find_valid_instance(
                                     const LayoutConstraintSet &constraints,
                                     const std::vector<LogicalRegion> &regions,
                                     MappingInstance &result, bool acquire, 
                                     bool tight_region_bounds, bool remote)
    //--------------------------------------------------------------------------
    {
      if (regions.empty())
        return false;
      RegionTreeID tree_id = 0;
      for (std::vector<LogicalRegion>::const_iterator it =
            regions.begin(); it != regions.end(); it++)
      {
        if (!it->exists())
          continue;
        tree_id = it->get_tree_id();
        break;
      }
      if (tree_id == 0)
        return false;
      std::deque<PhysicalManager*> candidates;
      {
        // Hold the lock while searching here
        AutoLock m_lock(manager_lock, 1, false/*exclusive*/);
        std::map<RegionTreeID,TreeInstances>::const_iterator finder = 
          current_instances.find(tree_id);
        if (finder == current_instances.end())
          return false;
        for (TreeInstances::const_iterator it = 
              finder->second.begin(); it != finder->second.end(); it++)
        {
          it->first->add_base_resource_ref(MEMORY_MANAGER_REF);
          candidates.push_back(it->first);
        }
      }
      // If we have any candidates check their constraints
      bool found = false;
      if (!candidates.empty())
      {
        // If we need a padding constraint make sure we're
        // checking for tight region bounds
        if (constraints.padding_constraint.delta.get_dim() > 0)
          tight_region_bounds = true;
        std::set<IndexSpaceExpression*> region_exprs;
        RegionTreeForest *forest = runtime->forest;
        for (std::vector<LogicalRegion>::const_iterator it = 
              regions.begin(); it != regions.end(); it++)
        {
          // If the region tree IDs don't match that is bad
          if (tree_id != it->get_tree_id())
            return false;
          RegionNode *node = forest->get_node(*it);
          region_exprs.insert(node->row_source);
        }
        IndexSpaceExpression *space_expr = (region_exprs.size() == 1) ?
          *(region_exprs.begin()) : forest->union_index_spaces(region_exprs);
        for (std::deque<PhysicalManager*>::const_iterator it = 
              candidates.begin(); it != candidates.end(); it++)
        {
          if (!(*it)->meets_expression(space_expr, tight_region_bounds))
            continue;
          if ((*it)->entails(constraints, DomainPoint(), NULL))
          {
            // Check to see if we need to acquire
            // If we fail to acquire then keep going
            if (acquire && !(*it)->acquire_instance(
                    remote ? REMOTE_DID_REF : MAPPING_ACQUIRE_REF, NULL))
              continue;
            // If we make it here, we succeeded
            result = MappingInstance(*it);
            found = true;
            break;
          }
        }
        release_candidate_references(candidates);
      }
      return found;
    }
    
    //--------------------------------------------------------------------------
    void MemoryManager::release_candidate_references(
                           const std::deque<PhysicalManager*> &candidates) const
    //--------------------------------------------------------------------------
    {
      for (std::deque<PhysicalManager*>::const_iterator it = 
            candidates.begin(); it != candidates.end(); it++)
      {
        if ((*it)->remove_base_resource_ref(MEMORY_MANAGER_REF))
          delete (*it);
      }
    }

    //--------------------------------------------------------------------------
    RtEvent MemoryManager::acquire_allocation_privilege(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner); // should only happen on the owner
#endif
      const RtUserEvent our_event = Runtime::create_rt_user_event();
      AutoLock m_lock(manager_lock);
      // Wait for the previous allocation if there is one
      const RtEvent wait_on = pending_allocation_attempts.empty() ? 
        RtEvent::NO_RT_EVENT : pending_allocation_attempts.back();
      pending_allocation_attempts.push_back(our_event);
      return wait_on;
    }

    //--------------------------------------------------------------------------
    void MemoryManager::release_allocation_privilege(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner); // should only happen on the owner
#endif
      RtUserEvent to_trigger;
      {
        AutoLock m_lock(manager_lock);
#ifdef DEBUG_LEGION
        assert(!pending_allocation_attempts.empty());
#endif
        to_trigger = pending_allocation_attempts.front();
        pending_allocation_attempts.pop_front();
      }
      Runtime::trigger_event(to_trigger);
    }

    //--------------------------------------------------------------------------
    PhysicalManager* MemoryManager::allocate_physical_instance(
                        InstanceBuilder &builder, size_t *footprint,
                        LayoutConstraintKind *unsat_kind, unsigned *unsat_index,
                        CollectiveManager *collective, DomainPoint *point)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      // First, just try to make the instance as is, if it works we are done 
      size_t needed_size;
      PhysicalManager *result = builder.create_physical_instance(
          runtime->forest,collective,point,unsat_kind,unsat_index,&needed_size);
      if (footprint != NULL)
        *footprint = needed_size;
      if ((result != NULL) || (needed_size == 0))
        return result;
      // Make sure that garbage collection is atomic and only one allocator
      // is attempting to delete instances at a time
      AutoLock c_lock(collection_lock);
      // Iterate over the lists of managers for each collection level
      for (std::map<GCPriority,std::set<PhysicalManager*>,
                    std::greater<GCPriority> >::iterator pit = 
            collectable_instances.begin(); pit != 
            collectable_instances.end(); /*nothing*/)
      {
        std::set<PhysicalManager*> deleted;
        std::vector<PhysicalManager*> small_holes;
        std::map<size_t,std::vector<PhysicalManager*> > large_holes;
        for (std::set<PhysicalManager*>::iterator it = 
              pit->second.begin(); it != pit->second.end(); /*nothing*/)
        {
          bool already_collected = false;
          if ((*it)->can_collect(runtime->address_space, already_collected))
          {
            if ((*it)->instance_footprint == needed_size)
            {
              // If we see another perfectly sized instance, try to 
              // collect it right now and hopefully realm will see the hole
              RtEvent collected;
              if ((*it)->collect(collected))
              {
                pit->second.erase(*it);
                deleted.insert(*it);
                result = builder.create_physical_instance(runtime->forest,
                   collective, point, unsat_kind, unsat_index, NULL, collected);
                if (result != NULL)
                  break;
              }
            }
            else if ((*it)->instance_footprint < needed_size)
              small_holes.push_back(*it);
            else
              large_holes[(*it)->instance_footprint].push_back(*it);
          }
          else if (already_collected)
          {
            deleted.insert(*it);
            std::set<PhysicalManager*>::iterator delete_it = it++;
            pit->second.erase(delete_it);
            continue;
          }
          it++;
        }
        // Try deleting the large holes first from the smallest to 
        // the largest to see if we can make a space
        if ((result == NULL) && !large_holes.empty())
        {
          for (std::map<size_t,std::vector<PhysicalManager*> >::const_iterator
                sit = large_holes.begin(); sit != large_holes.end(); sit++)
          {
            for (std::vector<PhysicalManager*>::const_reverse_iterator it =
                  sit->second.rbegin(); it != sit->second.rend(); it++)
            {
              RtEvent collected;
              if (!(*it)->collect(collected))
                continue;
              pit->second.erase(*it);
              deleted.insert(*it);
              result = builder.create_physical_instance(runtime->forest,
                  collective, point, unsat_kind, unsat_index, NULL, collected);
              if (result != NULL)
                break;
            }
            if (result != NULL)
              break;
          }
        }
        if ((result == NULL) && !small_holes.empty())
        {
          // If we still didn't delete anything then group the small
          // holes together into chunks that are either as big as 
          // possible or as big as the hole we need and try deleting them
          struct Range {
          public:
            Range(void) : size(0) { }
            Range(PhysicalManager *m) 
              : size(m->instance_footprint) { managers.insert(m); }
            std::set<PhysicalManager*> managers;
            size_t size;
          };
          std::map<uintptr_t,Range> ranges;
          for (std::vector<PhysicalManager*>::const_iterator sit =
                small_holes.begin(); sit != small_holes.end(); sit++)
          {
            // Get the instance pointer(s) for this memory
            std::vector<uintptr_t> pointers;
            (*sit)->get_instance_pointers(memory, pointers);
            for (std::vector<uintptr_t>::const_iterator
                  uit = pointers.begin(); uit != pointers.end(); uit++)
            {
              // Insert our range
              std::map<uintptr_t,Range>::iterator rit = 
                ranges.insert(std::make_pair(*uit, Range(*sit))).first;
              // Check if we can join it with the one before or after
              if (rit != ranges.begin())
              {
                std::map<uintptr_t,Range>::iterator prev = std::prev(rit);
                if ((prev->first + prev->second.size) == rit->first)
                {
                  // Merge rit into prev
                  prev->second.size += rit->second.size;
                  prev->second.managers.insert(
                      rit->second.managers.begin(), rit->second.managers.end());
                  ranges.erase(rit);
                  rit = prev;
                }
              }
              if (std::next(rit) != ranges.end())
              {
                std::map<uintptr_t,Range>::iterator next= std::next(rit);
                if ((rit->first + rit->second.size) == next->first)
                {
                  // Merge next into rit
                  rit->second.size += next->second.size;
                  rit->second.managers.insert(
                    next->second.managers.begin(), next->second.managers.end());
                  ranges.erase(next);
                }
              }
              // See if it is is big enough to try an allocation
              if (needed_size <= rit->second.size)
              {
                // Try deleting all the managers in the range
                std::vector<RtEvent> collected_events;
                for (std::set<PhysicalManager*>::const_iterator it =
                      rit->second.managers.begin(); it != 
                      rit->second.managers.end(); it++)
                {
                  RtEvent collected;
                  if (!(*it)->collect(collected))
                    continue;
                  pit->second.erase(*it);
                  deleted.insert(*it);
                  if (collected.exists())
                    collected_events.push_back(collected);
                }
                // We no longer need this range
                ranges.erase(rit);
                // Wait for the deletions to be done
                RtEvent collected;
                if (!collected_events.empty())
                  collected = Runtime::merge_events(collected_events);
                // Try to do another allocation
                result = builder.create_physical_instance(runtime->forest,
                   collective, point, unsat_kind, unsat_index, NULL, collected);
                if (result != NULL)
                  break;
              }
            }
            if (result != NULL)
              break;
          }
          if ((result == NULL) && !ranges.empty())
          {
            // At this point, things look pretty hopeless, so just
            // go through and start deleting ranges until we've freed
            // up enough memory for the needed size until we run out
            // of stuff to delete
            size_t freed_size = 0;
            std::vector<RtEvent> collected_events;
            for (std::map<uintptr_t,Range>::const_iterator rit =
                  ranges.begin(); rit != ranges.end(); rit++)
            {
              for (std::set<PhysicalManager*>::const_iterator it =
                    rit->second.managers.begin(); it != 
                    rit->second.managers.end(); it++)
              {
                RtEvent collected;
                if (!(*it)->collect(collected))
                  continue;
                pit->second.erase(*it);
                deleted.insert(*it);
                if (collected.exists())
                  collected_events.push_back(collected);
              }
              freed_size += rit->second.size;
              if (needed_size <= freed_size)
              {
                RtEvent collected;
                if (!collected_events.empty())
                  collected = Runtime::merge_events(collected_events);
                // Try to do another allocation
                result = builder.create_physical_instance(runtime->forest,
                   collective, point, unsat_kind, unsat_index, NULL, collected);
                if (result != NULL)
                  break;
                // Otherwise reset
                freed_size = 0;
                collected_events.clear();
              }
            }
            if ((result == NULL) && (freed_size > 0))
            {
              // One last shot in this priority generation
              RtEvent collected;
              if (!collected_events.empty())
                collected = Runtime::merge_events(collected_events);
              // Try to do another allocation
              result = builder.create_physical_instance(runtime->forest,
                 collective, point, unsat_kind, unsat_index, NULL, collected);
            }
          }
        }
        if (!deleted.empty())
        {
          AutoLock m_lock(manager_lock);
          for (std::set<PhysicalManager*>::const_iterator it =
                deleted.begin(); it != deleted.end(); it++)
          {
            std::map<RegionTreeID,TreeInstances>::iterator current_finder =
              current_instances.find((*it)->tree_id);
#ifdef DEBUG_LEGION
            assert(current_finder != current_instances.end());
#endif
            TreeInstances::iterator finder = current_finder->second.find(*it);
#ifdef DEBUG_LEGION
            assert(finder != current_finder->second.end());
#endif
            current_finder->second.erase(finder);
            if (current_finder->second.empty())
              current_instances.erase(current_finder);
            if ((*it)->remove_base_resource_ref(MEMORY_MANAGER_REF))
              delete (*it);
          }
        }
        if (pit->second.empty())
        {
          std::map<GCPriority,std::set<PhysicalManager*> >::iterator 
            delete_it = pit++;
          collectable_instances.erase(delete_it);
        }
        else
          pit++;
        if (result != NULL)
          break;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    void MemoryManager::record_created_instance(PhysicalManager *manager,
                           bool acquire, MapperID mapper_id, Processor p, 
                           GCPriority priority, bool remote)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      // Add references first to prevent races with collection
      if (acquire)
      {
#ifdef DEBUG_LEGION
#ifndef NDEBUG
        const bool result = 
#endif
#endif
        manager->acquire_instance(
            remote ? REMOTE_DID_REF : MAPPING_ACQUIRE_REF, NULL/*mutator*/);
#ifdef DEBUG_LEGION
        assert(result);
#endif
      }
      else if (remote)
        manager->add_base_resource_ref(REMOTE_DID_REF);
      // Since we're going to put this in the table add a reference
      manager->add_base_resource_ref(MEMORY_MANAGER_REF);
      // If we're setting the priority to min priority and this is the
      // owner then add the reference for the manager
      if ((priority == LEGION_GC_NEVER_PRIORITY) && manager->is_owner())
        manager->add_base_valid_ref(NEVER_GC_REF);
      // Record the manager here as being eligible for collection
      {
        AutoLock c_lock(collection_lock);
        AutoLock m_lock(manager_lock);
        TreeInstances &insts = current_instances[manager->tree_id];
#ifdef DEBUG_LEGION
        assert(insts.find(manager) == insts.end());
#endif
        insts[manager] = priority;
        if (priority != LEGION_GC_NEVER_PRIORITY)
          collectable_instances[priority].insert(manager);
      }
    }

    //--------------------------------------------------------------------------
    RtEvent MemoryManager::attach_external_instance(PhysicalManager *manager)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(manager->is_external_instance());
#endif
      if (!manager->is_owner())
      {
        // Send a message to the owner node to do the record
        RtUserEvent result = Runtime::create_rt_user_event();
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(manager->did);
          rez.serialize(result);
        }
        runtime->send_external_attach(manager->owner_space, rez);
        return result;
      }
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      // Since we're going to put this in the table add a reference
      manager->add_base_resource_ref(MEMORY_MANAGER_REF);
      {
        AutoLock m_lock(manager_lock);
        TreeInstances &insts = current_instances[manager->tree_id];
#ifdef DEBUG_LEGION
        assert(insts.find(manager) == insts.end());
#endif
        insts[manager] = LEGION_GC_NEVER_PRIORITY;
      }
      return RtEvent::NO_RT_EVENT;
    }

    //--------------------------------------------------------------------------
    RtEvent MemoryManager::detach_external_instance(PhysicalManager *manager)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(manager->is_external_instance());
#endif
      if (!manager->is_owner())
      {
        // Send a message to the owner node to do the deletion
        RtUserEvent result = Runtime::create_rt_user_event();
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(memory);
          rez.serialize(manager->did);
          rez.serialize(result);
        }
        runtime->send_external_detach(manager->owner_space, rez);
        return result;
      }
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      // Either delete the instance now or do a deferred deltion
      // that will delete the instance once all operations are
      // done using it
      {
        AutoLock m_lock(manager_lock);
        std::map<RegionTreeID,TreeInstances>::iterator tree_finder = 
          current_instances.find(manager->tree_id);
#ifdef DEBUG_LEGION
        assert(tree_finder != current_instances.end());
#endif
        TreeInstances::iterator finder = tree_finder->second.find(manager);
#ifdef DEBUG_LEGION
        assert(finder != tree_finder->second.end());
#endif
        // Reference will flow out
        tree_finder->second.erase(finder);
        if (tree_finder->second.empty())
          current_instances.erase(tree_finder);
      }
      // Perform the deletion contingent on references being removed
      const RtEvent result = manager->perform_deletion(runtime->address_space);
      if (manager->remove_base_resource_ref(MEMORY_MANAGER_REF))
        delete manager;
      return result;
    }

    //--------------------------------------------------------------------------
    bool MemoryManager::is_visible_memory(Memory other)
    //--------------------------------------------------------------------------
    {
      if (other == memory)
        return true;
      {
        AutoLock m_lock(manager_lock,1,false);
        if (!visible_memories.empty())
          return (visible_memories.find(other) != visible_memories.end());
      }
      // Do the query while not holding the lock
      Machine::MemoryQuery vis_mems(runtime->machine);
      vis_mems.has_affinity_to(memory);
      AutoLock m_lock(manager_lock);
      if (visible_memories.empty())
        for (Machine::MemoryQuery::iterator it = vis_mems.begin();
              it != vis_mems.end(); it++)
          visible_memories.insert(*it);
      return (visible_memories.find(other) != visible_memories.end());
    }

#ifdef LEGION_MALLOC_INSTANCES
    //--------------------------------------------------------------------------
    uintptr_t MemoryManager::allocate_legion_instance(size_t footprint,
                                                      bool needs_deferral)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
      assert(footprint > 0);
#endif
      uintptr_t result = 0;
      switch (memory.kind())
      {
        case SYSTEM_MEM:
        case SOCKET_MEM:
          {
            void *ptr = NULL;
            if (posix_memalign(&ptr, 32/*alignment*/, footprint))
              result = 0;
            else
              result = (uintptr_t)ptr;
            break;
          }
        case REGDMA_MEM:
          {
            void *ptr = NULL;
            if (posix_memalign(&ptr, 32/*alignment*/, footprint))
              result = 0;
            else
              result = (uintptr_t)ptr;
            mlock((void*)result, footprint);
            break;
          }
#ifdef LEGION_USE_CUDA
        case Z_COPY_MEM:
        case GPU_FB_MEM:
          {
            if (needs_deferral)
            {
              MallocInstanceArgs args(this, footprint, &result);
              const RtEvent wait_on = 
                runtime->issue_application_processor_task(args,
                  LG_LATENCY_WORK_PRIORITY, local_gpu);
              if (wait_on.exists() && !wait_on.has_triggered())
                wait_on.wait();
              return result;
            }
            else
            {
              // Use the driver API here to avoid the CUDA hijack
              if (memory.kind() == Memory::GPU_FB_MEM)
              {
                CUdeviceptr ptr;
                if (cuMemAlloc(&ptr, footprint) == CUDA_SUCCESS)
                  result = (uintptr_t)ptr;
                else
                  result = 0;
              }
              else
              {
                void *ptr = NULL;
                if (cuMemHostAlloc(&ptr, footprint, CU_MEMHOSTALLOC_PORTABLE |
                      CU_MEMHOSTALLOC_DEVICEMAP) == CUDA_SUCCESS)
                {
                  result = (uintptr_t)ptr;
                  // Check that the device pointer is the same as the host
                  CUdeviceptr gpuptr;
                  if (cuMemHostGetDevicePointer(&gpuptr,ptr,0) == CUDA_SUCCESS)
                  {
                    if (ptr != (void*)gpuptr)
                      result = 0;
                  }
                  else
                    result = 0;
                }
                else
                  result = 0;
              }
            }
            break;
          }
#endif
#ifdef LEGION_USE_HIP
        case Z_COPY_MEM:
        case GPU_FB_MEM:
          {
            if (needs_deferral)
            {
              MallocInstanceArgs args(this, footprint, &result);
              const RtEvent wait_on =
                runtime->issue_application_processor_task(args,
                  LG_LATENCY_WORK_PRIORITY, local_gpu);
              if (wait_on.exists() && !wait_on.has_triggered())
                wait_on.wait();
              return result;
            }
            else
            {
              // Use the driver API here to avoid the CUDA hijack
              if (memory.kind() == Memory::GPU_FB_MEM)
              {
                hipDeviceptr_t ptr;
                if (hipMalloc((void **)&ptr, footprint) == hipSuccess)
                  result = (uintptr_t)ptr;
                else
                  result = 0;
              }
              else
              {
                void *ptr = NULL;
                if (hipHostMalloc(&ptr, footprint, hipHostMallocPortable |
                      hipHostMallocMapped) == hipSuccess)
                {
                  result = (uintptr_t)ptr;
                  // Check that the device pointer is the same as the host
                  hipDeviceptr_t gpuptr;
                  if (hipHostGetDevicePointer((void **)&gpuptr,ptr,0)
                        == hipSuccess)
                  {
                    if (ptr != (void*)gpuptr)
                      result = 0;
                  }
                  else
                    result = 0;
                }
                else
                  result = 0;
              }
            }
            break;
          }
#endif
        default:
          REPORT_LEGION_FATAL(LEGION_FATAL_UNIMPLEMENTED_FEATURE,
              "Unsupported memory kind for LEGION_MALLOC_INSTANCES %d",
              memory.kind())
      }
      if (result > 0)
      {
        AutoLock m_lock(manager_lock);
#ifdef DEBUG_LEGION
        assert(allocations.find(result) == allocations.end());
#endif
        allocations[result] = footprint;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    void MemoryManager::record_legion_instance(InstanceManager *man,uintptr_t p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      AutoLock m_lock(manager_lock);
#ifdef DEBUG_LEGION
      assert(legion_instances.find(man) == legion_instances.end());
#endif
      legion_instances[man] = p;
    }

    //--------------------------------------------------------------------------
    void MemoryManager::free_legion_instance(InstanceManager *man,RtEvent defer)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      uintptr_t ptr;
      {
        AutoLock m_lock(manager_lock);
        std::map<InstanceManager*,uintptr_t>::iterator finder = 
          legion_instances.find(man);
#ifdef DEBUG_LEGION
        assert(finder != legion_instances.end());
#endif
        ptr = finder->second;
        legion_instances.erase(finder);
      }
      free_legion_instance(defer, ptr);
    }

    //--------------------------------------------------------------------------
    void MemoryManager::free_legion_instance(RtEvent defer, uintptr_t ptr,
                                             bool needs_defer)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(is_owner);
#endif
      if (ptr == 0)
        return;
      size_t size;
      {
        AutoLock m_lock(manager_lock);
        if (defer.exists() && !defer.has_triggered())
        {
          std::map<RtEvent,uintptr_t>::iterator finder = 
            pending_collectables.find(defer);
          if (finder == pending_collectables.end())
          {
            FreeInstanceArgs args(this, ptr);
#if defined(LEGION_USE_CUDA) || defined(LEGION_USE_HIP)
            if (local_gpu.exists())
              runtime->issue_application_processor_task(args, LG_LOW_PRIORITY, 
                                                        local_gpu, defer);
            else
              runtime->issue_runtime_meta_task(args, LG_LOW_PRIORITY, defer);
#else
            runtime->issue_runtime_meta_task(args, LG_LOW_PRIORITY, defer);
#endif
          }
          else
            finder->second = ptr;
          return;
        }
        std::map<uintptr_t,size_t>::iterator finder = allocations.find(ptr);
#ifdef DEBUG_LEGION
        assert(finder != allocations.end());
#endif
        size = finder->second;
        allocations.erase(finder);
      }
      switch (memory.kind())
      {
        case SYSTEM_MEM:
        case SOCKET_MEM:
          {
            free((void*)ptr);
            break;
          }
        case REGDMA_MEM:
          {
            munlock((void*)ptr, size);
            free((void*)ptr);
            break;
          }
        case Z_COPY_MEM:
        case GPU_FB_MEM:
          {
            if (needs_defer)
            {
              // Put the allocation back in for when we go to look
              // for it on the second pass
              {
                AutoLock m_lock(manager_lock);
#ifdef DEBUG_LEGION
                assert(allocations.find(ptr) == allocations.end());
#endif
                allocations[ptr] = size;
              }
              FreeInstanceArgs args(this, ptr);
              runtime->issue_application_processor_task(args, LG_LOW_PRIORITY, 
                                                        local_gpu, defer);
            }
            else
            {
#ifdef LEGION_USE_CUDA
#define CHECK_CUDART(cmd) do { \
  CUresult ret = (cmd); \
  if (ret != CUDA_SUCCESS) { \
    const char *name, *str; \
    cuGetErrorName(ret, &name); \
    cuGetErrorString(ret, &str); \
    fprintf(stderr, "CU: %s = %d (%s): %s\n", #cmd, ret, name, str); \
    abort(); \
  } \
} while (false)
              if (memory.kind() == Memory::GPU_FB_MEM)
                CHECK_CUDART( cuMemFree((CUdeviceptr)ptr) );
              else
                CHECK_CUDART( cuMemFreeHost((void*)ptr) );
#undef CHECK_CUDART
#endif
#ifdef LEGION_USE_HIP
#define CHECK_HIP(cmd) do { \
  hipError_t ret = (cmd); \
  if (ret != hipSuccess) { \
    const char *name, *str; \
    name = hipGetErrorName(ret); \
    str = hipGetErrorString(ret); \
    fprintf(stderr, "HIP: %s = %d (%s): %s\n", #cmd, ret, name, str); \
    abort(); \
  } \
} while (false)
              if (memory.kind() == Memory::GPU_FB_MEM)
                CHECK_HIP( hipFree((void*)ptr) );
              else
                CHECK_HIP( hipHostFree((void*)ptr) );
#undef CHECK_HIP
#endif
            }
            break;
          }
        default:
          REPORT_LEGION_FATAL(LEGION_FATAL_UNIMPLEMENTED_FEATURE,
              "Unsupported memory kind for LEGION_MALLOC_INSTANCES %d",
              memory.kind())
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void MemoryManager::handle_malloc_instance(const void *args)
    //--------------------------------------------------------------------------
    {
      const MallocInstanceArgs *margs = (const MallocInstanceArgs*)args;
      *(margs->ptr) = margs->manager->allocate_legion_instance(margs->size, 
                                                     false/*nneds defer*/);
    }

    //--------------------------------------------------------------------------
    /*static*/ void MemoryManager::handle_free_instance(const void *args)
    //--------------------------------------------------------------------------
    {
      const FreeInstanceArgs *fargs = (const FreeInstanceArgs*)args;
      fargs->manager->free_legion_instance(RtEvent::NO_RT_EVENT, fargs->ptr, 
                                                      false/*needs defer*/);
    }
#endif

    /////////////////////////////////////////////////////////////
    // Virtual Channel 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    VirtualChannel::VirtualChannel(VirtualChannelKind kind, 
        AddressSpaceID local_address_space, size_t max_message_size, 
        bool profile_outgoing, LegionProfiler *prof)
      : sending_buffer((char*)malloc(max_message_size)), 
        sending_buffer_size(max_message_size), 
        ordered_channel((kind != DEFAULT_VIRTUAL_CHANNEL) &&
                        (kind != THROUGHPUT_VIRTUAL_CHANNEL)), 
        profile_outgoing_messages(profile_outgoing),
        request_priority((kind == THROUGHPUT_VIRTUAL_CHANNEL) ?
            LG_THROUGHPUT_MESSAGE_PRIORITY : (kind == UPDATE_VIRTUAL_CHANNEL) ?
            LG_LATENCY_DEFERRED_PRIORITY : LG_LATENCY_MESSAGE_PRIORITY),
        response_priority((kind == THROUGHPUT_VIRTUAL_CHANNEL) ?
            LG_THROUGHPUT_RESPONSE_PRIORITY : (kind == UPDATE_VIRTUAL_CHANNEL) ?
            LG_LATENCY_MESSAGE_PRIORITY : LG_LATENCY_RESPONSE_PRIORITY),
        partial_messages(0), observed_recent(true), profiler(prof)
    //--------------------------------------------------------------------------
    //
    {
      receiving_buffer_size = max_message_size;
      receiving_buffer = (char*)legion_malloc(MESSAGE_BUFFER_ALLOC,
                                              receiving_buffer_size);
#ifdef DEBUG_LEGION
      assert(sending_buffer != NULL);
      assert(receiving_buffer != NULL);
#endif
      // Use a dummy implicit provenance at the front for the message
      // to comply with the requirements of the meta-task handler which
      // expects this before the task ID. We'll actually have individual
      // implicit provenances that will override this when handling the
      // messages so we can just set this to zero.
      *((UniqueID*)sending_buffer) = 0;
      sending_index = sizeof(UniqueID);
      // Set up the buffer for sending the first batch of messages
      // Only need to write the processor once
      *((LgTaskID*)(((char*)sending_buffer)+sending_index))= LG_MESSAGE_ID;
      sending_index += sizeof(LgTaskID);
      *((AddressSpaceID*)
          (((char*)sending_buffer)+sending_index)) = local_address_space;
      sending_index += sizeof(local_address_space);
      *((VirtualChannelKind*)
          (((char*)sending_buffer)+sending_index)) = kind;
      sending_index += sizeof(kind);
      header = FULL_MESSAGE;
      sending_index += sizeof(header);
      packaged_messages = 0;
      sending_index += sizeof(packaged_messages);
      last_message_event = RtEvent::NO_RT_EVENT;
      partial_message_id = 0;
      partial_assembly = NULL;
      partial = false;
      // Set up the receiving buffer
      received_messages = 0;
      receiving_index = 0;
    }

    //--------------------------------------------------------------------------
    VirtualChannel::VirtualChannel(const VirtualChannel &rhs)
      : sending_buffer(NULL), sending_buffer_size(0), 
        ordered_channel(false), profile_outgoing_messages(false),
        request_priority(rhs.request_priority),
        response_priority(rhs.response_priority), profiler(NULL)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    VirtualChannel::~VirtualChannel(void)
    //--------------------------------------------------------------------------
    {
      free(sending_buffer);
      free(receiving_buffer);
      receiving_buffer = NULL;
      receiving_buffer_size = 0;
      if (partial_assembly != NULL)
        delete partial_assembly;
    }

    //--------------------------------------------------------------------------
    void VirtualChannel::package_message(Serializer &rez, MessageKind k,
                         bool flush, RtEvent flush_precondition,
                         Runtime *runtime, Processor target, 
                         bool response, bool shutdown)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!flush_precondition.exists() || flush);
#endif
      // First check to see if the message fits in the current buffer    
      // including the overhead for the message: kind and size
      size_t buffer_size = rez.get_used_bytes();
      const char *buffer = (const char*)rez.get_buffer();
      const size_t header_size = 
        sizeof(k) + sizeof(implicit_provenance) + sizeof(buffer_size);
      // Need to hold the lock when manipulating the buffer
      AutoLock c_lock(channel_lock);
      if ((sending_index+header_size+buffer_size) > sending_buffer_size)
      {
        // Make sure we can at least get the meta-data into the buffer
        // Since there is no partial data we can fake the flush
        if ((sending_buffer_size - sending_index) <= header_size)
          send_message(true/*complete*/, runtime, target, k,
                       response, shutdown, flush_precondition);
        // Now can package up the meta data
        packaged_messages++;
        *((MessageKind*)(sending_buffer+sending_index)) = k;
        sending_index += sizeof(k);
        *((UniqueID*)(sending_buffer+sending_index)) = implicit_provenance;
        sending_index += sizeof(implicit_provenance);
        *((size_t*)(sending_buffer+sending_index)) = buffer_size;
        sending_index += sizeof(buffer_size);
        while (buffer_size > 0)
        {
          unsigned remaining = sending_buffer_size - sending_index;
          if (remaining == 0)
            send_message(false/*complete*/, runtime, target, k,
                         response, shutdown, flush_precondition);
          remaining = sending_buffer_size - sending_index;
#ifdef DEBUG_LEGION
          assert(remaining > 0); // should be space after the send
#endif
          // Figure out how much to copy into the buffer
          unsigned to_copy = (remaining < buffer_size) ? 
                                            remaining : buffer_size;
          memcpy(sending_buffer+sending_index,buffer,to_copy);
          buffer_size -= to_copy;
          buffer += to_copy;
          sending_index += to_copy;
        } 
      }
      else
      {
        packaged_messages++;
        // Package up the kind and the size first
        *((MessageKind*)(sending_buffer+sending_index)) = k;
        sending_index += sizeof(k);
        *((UniqueID*)(sending_buffer+sending_index)) = implicit_provenance;
        sending_index += sizeof(implicit_provenance);
        *((size_t*)(sending_buffer+sending_index)) = buffer_size;
        sending_index += sizeof(buffer_size);
        // Then copy over the buffer
        memcpy(sending_buffer+sending_index,buffer,buffer_size); 
        sending_index += buffer_size;
      }
      if (flush)
        send_message(true/*complete*/, runtime, target, k, 
                     response, shutdown, flush_precondition);
    }

    //--------------------------------------------------------------------------
    void VirtualChannel::send_message(bool complete, Runtime *runtime,
                                      Processor target, MessageKind kind,
                                      bool response, bool shutdown,
                                      RtEvent send_precondition)
    //--------------------------------------------------------------------------
    {
      // See if we need to switch the header file
      // and update the state of partial
      bool first_partial = false;
      if (!complete)
      {
        header = PARTIAL_MESSAGE;
        // If this is an unordered virtual channel, then embed our partial
        // message id in the high-order bits
        if (!ordered_channel)
          header = (MessageHeader)
            (((unsigned)header) | (partial_message_id << 2));
        if (!partial)
        {
          partial = true;
          first_partial = true;
        }
      }
      else if (partial)
      {
        header = FINAL_MESSAGE;
        // If this is an unordered virtual channel, then embed our partial
        // message id in the high-order bits
        if (!ordered_channel)
          // Also increment the partial message id for the next message
          // This can overflow safely since it's an unsigned integer
          header = (MessageHeader)
            (((unsigned)header) | (partial_message_id++ << 2));
        partial = false;
      }
      // Save the header and the number of messages into the buffer
      const size_t base_size = sizeof(UniqueID) + sizeof(LgTaskID) + 
        sizeof(AddressSpaceID) + sizeof(VirtualChannelKind);
      *((MessageHeader*)(sending_buffer + base_size)) = header;
      *((unsigned*)(sending_buffer + base_size + sizeof(header))) = 
                                                            packaged_messages;
      // Send the message directly there, don't go through the
      // runtime interface to avoid being counted, still include
      // a profiling request though if necessary in order to 
      // see waits on message handlers
      // Note that we don't profile on shutdown messages or we would 
      // never actually finish running
      if (profile_outgoing_messages && !shutdown)
      {
        Realm::ProfilingRequestSet requests;
        LegionProfiler::add_message_request(requests, kind, target);
        last_message_event = RtEvent(target.spawn(
#ifdef LEGION_SEPARATE_META_TASKS
              LG_TASK_ID + LG_MESSAGE_ID + kind,
#else
              LG_TASK_ID, 
#endif
              sending_buffer, sending_index, requests, 
              (ordered_channel || 
               ((header != FULL_MESSAGE) && !first_partial)) ?
                (send_precondition.exists() ? 
                  Runtime::merge_events(send_precondition, last_message_event) :
                  last_message_event) : send_precondition, 
              response ? response_priority : request_priority));
        if (!ordered_channel && (header != PARTIAL_MESSAGE))
        {
          unordered_events.insert(last_message_event);
          if (unordered_events.size() >= MAX_UNORDERED_EVENTS)
            filter_unordered_events();
        }
      }
      else
      {
        last_message_event = RtEvent(target.spawn(
#ifdef LEGION_SEPARATE_META_TASKS
                LG_TASK_ID + LG_MESSAGE_ID + kind,
#else
                LG_TASK_ID, 
#endif
                sending_buffer, sending_index, 
                (ordered_channel || 
                 ((header != FULL_MESSAGE) && !first_partial)) ?
                  (send_precondition.exists() ? 
                   Runtime::merge_events(send_precondition,last_message_event) :
                   last_message_event) : send_precondition, 
                response ? response_priority : request_priority));
        if (!ordered_channel && (header != PARTIAL_MESSAGE))
        {
          unordered_events.insert(last_message_event);
          if (unordered_events.size() >= MAX_UNORDERED_EVENTS)
            filter_unordered_events();
        }
      }
      // Reset the state of the buffer
      sending_index = base_size + sizeof(header) + sizeof(unsigned);
      if (partial)
        header = PARTIAL_MESSAGE;
      else
        header = FULL_MESSAGE;
      packaged_messages = 0;
    }

    //--------------------------------------------------------------------------
    void VirtualChannel::filter_unordered_events(void)
    //--------------------------------------------------------------------------
    {
      // Lock held from caller
#ifdef DEBUG_LEGION
      assert(!ordered_channel);
      assert(unordered_events.size() >= MAX_UNORDERED_EVENTS);
#endif
      // Prune out any triggered events
      for (std::set<RtEvent>::iterator it = unordered_events.begin();
            it != unordered_events.end(); /*nothing*/)
      {
        if (it->has_triggered())
        {
          std::set<RtEvent>::iterator to_delete = it++;
          unordered_events.erase(to_delete);
        }
        else
          it++;
      }
      // If we still have too many events, collapse them down
      if (unordered_events.size() >= MAX_UNORDERED_EVENTS)
      {
        const RtEvent summary = Runtime::merge_events(unordered_events);
        unordered_events.clear();
        unordered_events.insert(summary);
      }
    }

    //--------------------------------------------------------------------------
    void VirtualChannel::confirm_shutdown(ShutdownManager *shutdown_manager,
                                          bool phase_one)
    //--------------------------------------------------------------------------
    {
      AutoLock c_lock(channel_lock);
      if (phase_one)
      {
        if (packaged_messages > 0)
          shutdown_manager->record_recent_message();
        if (ordered_channel)
        {
          if (!last_message_event.has_triggered())
          {
            // Subscribe to make sure we see this trigger
            last_message_event.subscribe();
            // A little hack here for slow gasnet conduits
            // If the event didn't trigger yet, make sure its just
            // because we haven't gotten the return message yet
            usleep(1000);
            if (!last_message_event.has_triggered())
              shutdown_manager->record_pending_message(last_message_event);
            else
              observed_recent = false;
          }
          else
            observed_recent = false;
        }
        else
        {
          observed_recent = false;
          for (std::set<RtEvent>::const_iterator it = 
                unordered_events.begin(); it != unordered_events.end(); it++)
          {
            if (!it->has_triggered())
            {
              // Subscribe to make sure we see this trigger
              it->subscribe();
              // A little hack here for slow gasnet conduits
              // If the event didn't trigger yet, make sure its just
              // because we haven't gotten the return message yet
              usleep(1000);
              if (!it->has_triggered())
              {
                shutdown_manager->record_pending_message(*it); 
                observed_recent = true;
                break;
              }
            }
          }
        }
      }
      else
      {
        if (observed_recent || (packaged_messages > 0)) 
          shutdown_manager->record_recent_message(); 
        else
        {
          if (ordered_channel)
          {
            if (!last_message_event.has_triggered())
            {
              // Subscribe to make sure we see this trigger
              last_message_event.subscribe();
              // A little hack here for slow gasnet conduits
              // If the event didn't trigger yet, make sure its just
              // because we haven't gotten the return message yet
              usleep(1000);
              if (!last_message_event.has_triggered())
                shutdown_manager->record_recent_message();
            }
          }
          else
          {
            for (std::set<RtEvent>::const_iterator it = 
                  unordered_events.begin(); it != unordered_events.end(); it++)
            {
              if (!it->has_triggered())
              {
                // Subscribe to make sure we see this trigger
                it->subscribe();
                // A little hack here for slow gasnet conduits
                // If the event didn't trigger yet, make sure its just
                // because we haven't gotten the return message yet
                usleep(1000);
                if (!it->has_triggered())
                {
                  shutdown_manager->record_recent_message();
                  break;
                }
              }
            }
          }
        }
      }
    }

    //--------------------------------------------------------------------------
    void VirtualChannel::process_message(const void *args, size_t arglen,
                         Runtime *runtime, AddressSpaceID remote_address_space)
    //--------------------------------------------------------------------------
    {
      // If we have a profiler we need to increment our requests count
      if (profiler != NULL)
#ifdef DEBUG_LEGION
        profiler->increment_total_outstanding_requests(
                    LegionProfiler::LEGION_PROF_MESSAGE);
#else
        profiler->increment_total_outstanding_requests();
#endif
      // Strip off our header and the number of messages, the 
      // processor part was already stipped off by the Legion runtime
      const char *buffer = (const char*)args;
      MessageHeader head = *((const MessageHeader*)buffer);
      buffer += sizeof(head);
      arglen -= sizeof(head);
      unsigned num_messages = *((const unsigned*)buffer);
      buffer += sizeof(num_messages);
      arglen -= sizeof(num_messages);
      unsigned incoming_message_id = 0;
      if (!ordered_channel)
      {
        incoming_message_id = ((unsigned)head) >> 2; 
        head = (MessageHeader)(((unsigned)head) & 0x3);
      }
      switch (head)
      {
        case FULL_MESSAGE:
          {
            // Can handle these messages directly
            if (handle_messages(num_messages, runtime, 
                                remote_address_space, buffer, arglen) &&
                // If we had a shutdown message and a profiler then we
                // shouldn't have incremented the outstanding profiling
                // count because we don't actually do profiling requests
                // on any shutdown messages
                (profiler != NULL))
            {
#ifdef DEBUG_LEGION
              profiler->decrement_total_outstanding_requests(
                          LegionProfiler::LEGION_PROF_MESSAGE);
#else
              profiler->decrement_total_outstanding_requests();
#endif
            }
            break;
          }
        case PARTIAL_MESSAGE:
          {
            // Save these messages onto the receiving buffer
            // but do not handle them
            if (!ordered_channel)
            {
              AutoLock c_lock(channel_lock);
              if (partial_assembly == NULL)
                partial_assembly = new std::map<unsigned,PartialMessage>();
              PartialMessage &message = 
                (*partial_assembly)[incoming_message_id];
              // Allocate the buffer on the first pass
              if (message.buffer == NULL)
              {
                // Same as max message size
                message.size = sending_buffer_size;
                message.buffer = 
                  (char*)legion_malloc(MESSAGE_BUFFER_ALLOC, message.size);
              }
              buffer_messages(num_messages, buffer, arglen,
                              message.buffer, message.size,
                              message.index, message.messages, message.total);
            }
            else
              // Ordered channels don't need the lock
              buffer_messages(num_messages, buffer, arglen, receiving_buffer, 
                              receiving_buffer_size, receiving_index, 
                              received_messages, partial_messages);
            break;
          }
        case FINAL_MESSAGE:
          {
            // Save the remaining messages onto the receiving
            // buffer, then handle them and reset the state.
            char *final_buffer = NULL;
            size_t final_index = 0;
            unsigned final_messages = 0, final_total = 0;
            bool free_buffer = false;
            if (!ordered_channel)
            {
              AutoLock c_lock(channel_lock);
#ifdef DEBUG_LEGION
              assert(partial_assembly != NULL);
#endif
              std::map<unsigned,PartialMessage>::iterator finder = 
                partial_assembly->find(incoming_message_id);
#ifdef DEBUG_LEGION
              assert(finder != partial_assembly->end());
              assert(finder->second.buffer != NULL);
#endif
              buffer_messages(num_messages, buffer, arglen,
                              finder->second.buffer, finder->second.size,
                              finder->second.index, finder->second.messages,
                              finder->second.total);
              final_index = finder->second.index;
              final_buffer = finder->second.buffer;
              final_messages = finder->second.messages;
              final_total = finder->second.total;
              free_buffer = true;
              partial_assembly->erase(finder);
            }
            else
            {
              buffer_messages(num_messages, buffer, arglen, receiving_buffer,
                              receiving_buffer_size, receiving_index, 
                              received_messages, partial_messages);
              final_index = receiving_index;
              final_buffer = receiving_buffer;
              final_messages = received_messages;
              final_total = partial_messages;
              receiving_index = 0;
              received_messages = 0;
              partial_messages = 0;
            }
            if (handle_messages(final_messages, runtime, remote_address_space,
                                final_buffer, final_index) &&
                // If we had a shutdown message and a profiler then we
                // shouldn't have incremented the outstanding profiling
                // count because we don't actually do profiling requests
                // on any shutdown messages
                (profiler != NULL))
            {
#ifdef DEBUG_LEGION
              profiler->decrement_total_outstanding_requests(
                          LegionProfiler::LEGION_PROF_MESSAGE, final_total);
#else
              profiler->decrement_total_outstanding_requests(final_total);
#endif
            }
            if (free_buffer)
              free(final_buffer);
            break;
          }
        default:
          assert(false); // should never get here
      }
    }

    //--------------------------------------------------------------------------
    bool VirtualChannel::handle_messages(unsigned num_messages,
                                         Runtime *runtime,
                                         AddressSpaceID remote_address_space,
                                         const char *args, size_t arglen) const
    //--------------------------------------------------------------------------
    {
      bool has_shutdown = false;
      for (unsigned idx = 0; idx < num_messages; idx++)
      {
        // Pull off the message kind and the size of the message
#ifdef DEBUG_LEGION
        assert(arglen >= (sizeof(MessageKind)+sizeof(size_t)));
#endif
        MessageKind kind = *((const MessageKind*)args);
        // Any message that is not a shutdown message needs to be recorded
        if (!observed_recent && (kind != SEND_SHUTDOWN_NOTIFICATION) &&
            (kind != SEND_SHUTDOWN_RESPONSE))
          observed_recent = true;
        args += sizeof(kind);
        arglen -= sizeof(kind);
        implicit_provenance = *((const UniqueID*)args);
        args += sizeof(implicit_provenance);
        arglen -= sizeof(implicit_provenance);
        size_t message_size = *((const size_t*)args);
        args += sizeof(message_size);
        arglen -= sizeof(message_size);
#ifdef DEBUG_LEGION
        if (idx == (num_messages-1))
          assert(message_size == arglen);
#endif
        // Build the deserializer
        Deserializer derez(args,message_size);
        switch (kind)
        {
          case TASK_MESSAGE:
            {
              runtime->handle_task(derez);
              break;
            }
          case STEAL_MESSAGE:
            {
              runtime->handle_steal(derez);
              break;
            }
          case ADVERTISEMENT_MESSAGE:
            {
              runtime->handle_advertisement(derez);
              break;
            }
#ifdef LEGION_USE_LIBDL
          case SEND_REGISTRATION_CALLBACK:
            {
              runtime->handle_registration_callback(derez);
              break;
            }
#endif
          case SEND_REMOTE_TASK_REPLAY:
            {
              runtime->handle_remote_task_replay(derez);
              break;
            }
          case SEND_REMOTE_TASK_PROFILING_RESPONSE:
            {
              runtime->handle_remote_task_profiling_response(derez);
              break;
            }
          case SEND_SHARED_OWNERSHIP:
            {
              runtime->handle_shared_ownership(derez);
              break;
            }
          case SEND_INDEX_SPACE_REQUEST:
            {
              runtime->handle_index_space_request(derez, remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_RETURN:
            {
              runtime->handle_index_space_return(derez, remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_SET:
            {
              runtime->handle_index_space_set(derez, remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_CHILD_REQUEST:
            {
              runtime->handle_index_space_child_request(derez, 
                                                        remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_CHILD_RESPONSE:
            {
              runtime->handle_index_space_child_response(derez);
              break;
            }
          case SEND_INDEX_SPACE_COLORS_REQUEST:
            {
              runtime->handle_index_space_colors_request(derez,
                                                         remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_COLORS_RESPONSE:
            {
              runtime->handle_index_space_colors_response(derez);
              break;
            }
          case SEND_INDEX_SPACE_REMOTE_EXPRESSION_REQUEST:
            {
              runtime->handle_index_space_remote_expression_request(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_REMOTE_EXPRESSION_RESPONSE:
            {
              runtime->handle_index_space_remote_expression_response(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_GENERATE_COLOR_REQUEST:
            {
              runtime->handle_index_space_generate_color_request(derez,
                                                  remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_GENERATE_COLOR_RESPONSE:
            {
              runtime->handle_index_space_generate_color_response(derez);
              break;
            }
          case SEND_INDEX_SPACE_RELEASE_COLOR:
            {
              runtime->handle_index_space_release_color(derez);
              break;
            }
          case SEND_INDEX_PARTITION_NOTIFICATION:
            {
              runtime->handle_index_partition_notification(derez);
              break;
            }
          case SEND_INDEX_PARTITION_REQUEST:
            {
              runtime->handle_index_partition_request(derez, 
                                                      remote_address_space);
              break;
            }
          case SEND_INDEX_PARTITION_RETURN:
            {
              runtime->handle_index_partition_return(derez,
                                                     remote_address_space);
              break;
            }
          case SEND_INDEX_PARTITION_CHILD_REQUEST:
            {
              runtime->handle_index_partition_child_request(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_INDEX_PARTITION_CHILD_RESPONSE:
            {
              runtime->handle_index_partition_child_response(derez);
              break;
            }
          case SEND_INDEX_PARTITION_DISJOINT_UPDATE:
            {
              runtime->handle_index_partition_disjoint_update(derez);
              break;
            }
          case SEND_FIELD_SPACE_NODE:
            {
              runtime->handle_field_space_node(derez, remote_address_space);
              break;
            }
          case SEND_FIELD_SPACE_REQUEST:
            {
              runtime->handle_field_space_request(derez, remote_address_space);
              break;
            }
          case SEND_FIELD_SPACE_RETURN:
            {
              runtime->handle_field_space_return(derez);
              break;
            }
          case SEND_FIELD_SPACE_ALLOCATOR_REQUEST:
            {
              runtime->handle_field_space_allocator_request(derez,
                                            remote_address_space);
              break;
            }
          case SEND_FIELD_SPACE_ALLOCATOR_RESPONSE:
            {
              runtime->handle_field_space_allocator_response(derez);
              break;
            }
          case SEND_FIELD_SPACE_ALLOCATOR_INVALIDATION:
            {
              runtime->handle_field_space_allocator_invalidation(derez);
              break;
            }
          case SEND_FIELD_SPACE_ALLOCATOR_FLUSH:
            {
              runtime->handle_field_space_allocator_flush(derez);
              break;
            }
          case SEND_FIELD_SPACE_ALLOCATOR_FREE:
            {
              runtime->handle_field_space_allocator_free(derez, 
                                          remote_address_space);
              break;
            }
          case SEND_FIELD_SPACE_INFOS_REQUEST:
            {
              runtime->handle_field_space_infos_request(derez);
              break;
            }
          case SEND_FIELD_SPACE_INFOS_RESPONSE:
            {
              runtime->handle_field_space_infos_response(derez);
              break;
            }
          case SEND_FIELD_ALLOC_REQUEST:
            {
              runtime->handle_field_alloc_request(derez);
              break;
            }
          case SEND_FIELD_SIZE_UPDATE:
            {
              runtime->handle_field_size_update(derez, remote_address_space);
              break;
            }
          case SEND_FIELD_FREE:
            {
              runtime->handle_field_free(derez, remote_address_space);
              break;
            }
          case SEND_FIELD_FREE_INDEXES:
            {
              runtime->handle_field_free_indexes(derez);
              break;
            }
          case SEND_FIELD_SPACE_LAYOUT_INVALIDATION:
            {
              runtime->handle_field_space_layout_invalidation(derez,
                                              remote_address_space);
              break;
            }
          case SEND_LOCAL_FIELD_ALLOC_REQUEST:
            {
              runtime->handle_local_field_alloc_request(derez, 
                                                        remote_address_space);
              break;
            }
          case SEND_LOCAL_FIELD_ALLOC_RESPONSE:
            {
              runtime->handle_local_field_alloc_response(derez);
              break;
            }
          case SEND_LOCAL_FIELD_FREE:
            {
              runtime->handle_local_field_free(derez);
              break;
            }
          case SEND_LOCAL_FIELD_UPDATE:
            {
              runtime->handle_local_field_update(derez);
              break;
            }
          case SEND_TOP_LEVEL_REGION_REQUEST:
            {
              runtime->handle_top_level_region_request(derez, 
                                                       remote_address_space);
              break;
            }
          case SEND_TOP_LEVEL_REGION_RETURN:
            {
              runtime->handle_top_level_region_return(derez,
                                                      remote_address_space);
              break;
            }
          case INDEX_SPACE_DESTRUCTION_MESSAGE:
            {
              runtime->handle_index_space_destruction(derez,
                                                      remote_address_space);
              break;
            }
          case INDEX_PARTITION_DESTRUCTION_MESSAGE:
            {
              runtime->handle_index_partition_destruction(derez); 
              break;
            }
          case FIELD_SPACE_DESTRUCTION_MESSAGE:
            {
              runtime->handle_field_space_destruction(derez); 
              break;
            }
          case LOGICAL_REGION_DESTRUCTION_MESSAGE:
            {
              runtime->handle_logical_region_destruction(derez); 
              break;
            }
          case INDIVIDUAL_REMOTE_COMPLETE:
            {
              runtime->handle_individual_remote_complete(derez);
              break;
            }
          case INDIVIDUAL_REMOTE_COMMIT:
            {
              runtime->handle_individual_remote_commit(derez);
              break;
            }
          case SLICE_REMOTE_MAPPED:
            {
              runtime->handle_slice_remote_mapped(derez, remote_address_space);
              break;
            }
          case SLICE_REMOTE_COMPLETE:
            {
              runtime->handle_slice_remote_complete(derez);
              break;
            }
          case SLICE_REMOTE_COMMIT:
            {
              runtime->handle_slice_remote_commit(derez);
              break;
            }
          case SLICE_FIND_INTRA_DEP:
            {
              runtime->handle_slice_find_intra_dependence(derez);
              break;
            }
          case SLICE_RECORD_INTRA_DEP:
            {
              runtime->handle_slice_record_intra_dependence(derez);
              break;
            }
          case SLICE_COLLECTIVE_REQUEST:
            {
              runtime->handle_slice_collective_request(derez,
                                                       remote_address_space);
              break;
            }
          case SLICE_COLLECTIVE_RESPONSE:
            {
              runtime->handle_slice_collective_response(derez);
              break;
            }
          case DISTRIBUTED_REMOTE_REGISTRATION:
            {
              runtime->handle_did_remote_registration(derez, 
                                                      remote_address_space);
              break;
            }
          case DISTRIBUTED_VALID_UPDATE:
            {
              runtime->handle_did_remote_valid_update(derez);
              break;
            }
          case DISTRIBUTED_GC_UPDATE:
            {
              runtime->handle_did_remote_gc_update(derez); 
              break;
            }
          case DISTRIBUTED_RESOURCE_UPDATE:
            {
              runtime->handle_did_remote_resource_update(derez);
              break;
            }
          case DISTRIBUTED_CREATE_ADD:
            {
              runtime->handle_did_create_add(derez);
              break;
            }
          case DISTRIBUTED_CREATE_REMOVE:
            {
              runtime->handle_did_create_remove(derez);
              break;
            }
          case DISTRIBUTED_UNREGISTER:
            {
              runtime->handle_did_remote_unregister(derez);
              break;
            }
          case SEND_ATOMIC_RESERVATION_REQUEST:
            {
              runtime->handle_send_atomic_reservation_request(derez,
                                                      remote_address_space);
              break;
            }
          case SEND_ATOMIC_RESERVATION_RESPONSE:
            {
              runtime->handle_send_atomic_reservation_response(derez);
              break;
            }
          case SEND_PADDED_RESERVATION_REQUEST:
            {
              runtime->handle_send_padded_reservation_request(derez,
                                                      remote_address_space);
              break;
            }
          case SEND_PADDED_RESERVATION_RESPONSE:
            {
              runtime->handle_send_padded_reservation_response(derez);
              break;
            }
          case SEND_BACK_LOGICAL_STATE:
            {
              runtime->handle_send_back_logical_state(derez, 
                                                      remote_address_space);
              break;
            }
          case SEND_MATERIALIZED_VIEW:
            {
              runtime->handle_send_materialized_view(derez, 
                                                     remote_address_space);
              break;
            }
          case SEND_FILL_VIEW:
            {
              runtime->handle_send_fill_view(derez, remote_address_space);
              break;
            }
          case SEND_PHI_VIEW:
            {
              runtime->handle_send_phi_view(derez, remote_address_space);
              break;
            }
          case SEND_REDUCTION_VIEW:
            {
              runtime->handle_send_reduction_view(derez, remote_address_space);
              break;
            }
          case SEND_INSTANCE_MANAGER:
            {
              runtime->handle_send_instance_manager(derez, 
                                                    remote_address_space);
              break;
            }
          case SEND_COLLECTIVE_MANAGER:
            {
              runtime->handle_collective_instance_manager(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_COLLECTIVE_MESSAGE:
            {
              runtime->handle_collective_instance_message(derez);
              break;
            }
          case SEND_CREATE_TOP_VIEW_REQUEST:
            {
              runtime->handle_create_top_view_request(derez,
                                                      remote_address_space);
              break;
            }
          case SEND_CREATE_TOP_VIEW_RESPONSE:
            {
              runtime->handle_create_top_view_response(derez);
              break;
            }
          case SEND_VIEW_REQUEST:
            {
              runtime->handle_view_request(derez, remote_address_space);
              break;
            }
          case SEND_VIEW_REGISTER_USER:
            {
              runtime->handle_view_register_user(derez, remote_address_space);
              break;
            }
          case SEND_VIEW_FIND_COPY_PRE_REQUEST:
            {
              runtime->handle_view_copy_pre_request(derez,remote_address_space);
              break;
            }
          case SEND_VIEW_FIND_COPY_PRE_RESPONSE:
            {
              runtime->handle_view_copy_pre_response(derez,
                                                    remote_address_space);
              break;
            }
          case SEND_VIEW_ADD_COPY_USER:
            {
              runtime->handle_view_add_copy_user(derez, remote_address_space);
              break;
            }
#ifdef ENABLE_VIEW_REPLICATION
          case SEND_VIEW_REPLICATION_REQUEST:
            {
              runtime->handle_view_replication_request(derez, 
                                                       remote_address_space);
              break;
            }
          case SEND_VIEW_REPLICATION_RESPONSE:
            {
              runtime->handle_view_replication_response(derez);
              break;
            }
          case SEND_VIEW_REPLICATION_REMOVAL:
            {
              runtime->handle_view_replication_removal(derez, 
                                                       remote_address_space);
              break;
            }
#endif
          case SEND_MANAGER_REQUEST:
            {
              runtime->handle_manager_request(derez, remote_address_space);
              break;
            } 
          case SEND_FUTURE_RESULT:
            {
              runtime->handle_future_result(derez);
              break;
            }
          case SEND_FUTURE_SUBSCRIPTION:
            {
              runtime->handle_future_subscription(derez, remote_address_space);
              break;
            }
          case SEND_FUTURE_NOTIFICATION:
            {
              runtime->handle_future_notification(derez, remote_address_space);
              break;
            }
          case SEND_FUTURE_BROADCAST:
            {
              runtime->handle_future_broadcast(derez);
              break;
            }
          case SEND_FUTURE_MAP_REQUEST:
            {
              runtime->handle_future_map_future_request(derez, 
                                        remote_address_space);
              break;
            }
          case SEND_FUTURE_MAP_RESPONSE:
            {
              runtime->handle_future_map_future_response(derez);
              break;
            }
          case SEND_MAPPER_MESSAGE:
            {
              runtime->handle_mapper_message(derez);
              break;
            }
          case SEND_MAPPER_BROADCAST:
            {
              runtime->handle_mapper_broadcast(derez);
              break;
            }
          case SEND_TASK_IMPL_SEMANTIC_REQ:
            {
              runtime->handle_task_impl_semantic_request(derez, 
                                                        remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_SEMANTIC_REQ:
            {
              runtime->handle_index_space_semantic_request(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_INDEX_PARTITION_SEMANTIC_REQ:
            {
              runtime->handle_index_partition_semantic_request(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_FIELD_SPACE_SEMANTIC_REQ:
            {
              runtime->handle_field_space_semantic_request(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_FIELD_SEMANTIC_REQ:
            {
              runtime->handle_field_semantic_request(derez, 
                                                     remote_address_space);
              break;
            }
          case SEND_LOGICAL_REGION_SEMANTIC_REQ:
            {
              runtime->handle_logical_region_semantic_request(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_LOGICAL_PARTITION_SEMANTIC_REQ:
            {
              runtime->handle_logical_partition_semantic_request(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_TASK_IMPL_SEMANTIC_INFO:
            {
              runtime->handle_task_impl_semantic_info(derez,
                                                      remote_address_space);
              break;
            }
          case SEND_INDEX_SPACE_SEMANTIC_INFO:
            {
              runtime->handle_index_space_semantic_info(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_INDEX_PARTITION_SEMANTIC_INFO:
            {
              runtime->handle_index_partition_semantic_info(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_FIELD_SPACE_SEMANTIC_INFO:
            {
              runtime->handle_field_space_semantic_info(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_FIELD_SEMANTIC_INFO:
            {
              runtime->handle_field_semantic_info(derez, remote_address_space);
              break;
            }
          case SEND_LOGICAL_REGION_SEMANTIC_INFO:
            {
              runtime->handle_logical_region_semantic_info(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_LOGICAL_PARTITION_SEMANTIC_INFO:
            {
              runtime->handle_logical_partition_semantic_info(derez,
                                                          remote_address_space);
              break;
            }
          case SEND_REMOTE_CONTEXT_REQUEST:
            {
              runtime->handle_remote_context_request(derez, 
                                                     remote_address_space);
              break;
            }
          case SEND_REMOTE_CONTEXT_RESPONSE:
            {
              runtime->handle_remote_context_response(derez);
              break;
            }
          case SEND_REMOTE_CONTEXT_RELEASE:
            {
              runtime->handle_remote_context_release(derez);
              break;
            }
          case SEND_REMOTE_CONTEXT_FREE:
            {
              runtime->handle_remote_context_free(derez);
              break;
            }
          case SEND_REMOTE_CONTEXT_PHYSICAL_REQUEST:
            {
              runtime->handle_remote_context_physical_request(derez,
                                              remote_address_space);
              break;
            }
          case SEND_REMOTE_CONTEXT_PHYSICAL_RESPONSE:
            {
              runtime->handle_remote_context_physical_response(derez);
              break;
            }
          case SEND_COMPUTE_EQUIVALENCE_SETS_REQUEST: 
            {
              runtime->handle_compute_equivalence_sets_request(derez,
                                               remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REQUEST:
            {
              runtime->handle_equivalence_set_request(derez, 
                                      remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_RESPONSE:
            {
              runtime->handle_equivalence_set_response(derez,
                                                       remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_SUBSET_REQUEST:
            {
              runtime->handle_equivalence_set_subset_request(derez); 
              break;
            }
          case SEND_EQUIVALENCE_SET_SUBSET_RESPONSE:
            {
              runtime->handle_equivalence_set_subset_response(derez);
              break;
            }
          case SEND_EQUIVALENCE_SET_SUBSET_UPDATE:
            {
              runtime->handle_equivalence_set_subset_update(derez);
              break;
            }
          case SEND_EQUIVALENCE_SET_RAY_TRACE_REQUEST:
            {
              runtime->handle_equivalence_set_ray_trace_request(derez,
                                                remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_RAY_TRACE_RESPONSE:
            {
              runtime->handle_equivalence_set_ray_trace_response(derez);
              break;
            }
          case SEND_EQUIVALENCE_SET_MIGRATION:
            {
              runtime->handle_equivalence_set_migration(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_OWNER_UPDATE:
            {
              runtime->handle_equivalence_set_owner_update(derez);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_REFINEMENT:
            {
              runtime->handle_equivalence_set_remote_refinement(derez);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_REQUEST_INSTANCES:
            {
              runtime->handle_equivalence_set_remote_request_instances(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_REQUEST_INVALID:
            {
              runtime->handle_equivalence_set_remote_request_invalid(derez,
                                                        remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_UPDATES:
            {
              runtime->handle_equivalence_set_remote_updates(derez,
                                              remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_ACQUIRES:
            {
              runtime->handle_equivalence_set_remote_acquires(derez,
                                              remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_RELEASES:
            {
              runtime->handle_equivalence_set_remote_releases(derez,
                                              remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_COPIES_ACROSS:
            {
              runtime->handle_equivalence_set_remote_copies_across(derez,
                                                    remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_OVERWRITES:
            {
              runtime->handle_equivalence_set_remote_overwrites(derez,
                                                remote_address_space);
            break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_FILTERS:
            {
              runtime->handle_equivalence_set_remote_filters(derez,
                                              remote_address_space);
              break;
            }
          case SEND_EQUIVALENCE_SET_REMOTE_INSTANCES:
            {
              runtime->handle_equivalence_set_remote_instances(derez);
              break;
            }
          case SEND_EQUIVALENCE_SET_STALE_UPDATE:
            {
              runtime->handle_equivalence_set_stale_update(derez);
              break;
            }
          case SEND_INSTANCE_REQUEST:
            {
              runtime->handle_instance_request(derez, remote_address_space);
              break;
            }
          case SEND_INSTANCE_RESPONSE:
            {
              runtime->handle_instance_response(derez, remote_address_space);
              break;
            }
          case SEND_EXTERNAL_CREATE_REQUEST:
            {
              runtime->handle_external_create_request(derez, 
                                                      remote_address_space);
              break;
            }
          case SEND_EXTERNAL_CREATE_RESPONSE:
            {
              runtime->handle_external_create_response(derez);
              break;
            }
          case SEND_EXTERNAL_ATTACH:
            {
              runtime->handle_external_attach(derez);
              break;
            }
          case SEND_EXTERNAL_DETACH:
            {
              runtime->handle_external_detach(derez);
              break;
            }
          case SEND_GC_PRIORITY_UPDATE:
            {
              runtime->handle_gc_priority_update(derez, remote_address_space);
              break;
            }
          case SEND_GC_REQUEST:
            {
              runtime->handle_gc_request(derez, remote_address_space);
              break;
            }
          case SEND_GC_RESPONSE:
            {
              runtime->handle_gc_response(derez);
              break;
            }
          case SEND_GC_ACQUIRE:
            {
              runtime->handle_gc_acquire(derez, remote_address_space);
              break;
            }
          case SEND_GC_ACQUIRED:
            {
              runtime->handle_gc_acquired(derez);
              break;
            }
          case SEND_GC_DEBUG_REQUEST:
            {
              runtime->handle_gc_debug_request(derez, remote_address_space);
              break;
            }
          case SEND_GC_DEBUG_RESPONSE:
            {
              runtime->handle_gc_debug_response(derez);
              break;
            }
          case SEND_ACQUIRE_REQUEST:
            {
              runtime->handle_acquire_request(derez, remote_address_space);
              break;
            }
          case SEND_ACQUIRE_RESPONSE:
            {
              runtime->handle_acquire_response(derez, remote_address_space);
              break;
            }
          case SEND_VARIANT_BROADCAST:
            {
              runtime->handle_variant_broadcast(derez);
              break;
            }
          case SEND_CONSTRAINT_REQUEST:
            {
              runtime->handle_constraint_request(derez, remote_address_space);
              break;
            }
          case SEND_CONSTRAINT_RESPONSE:
            {
              runtime->handle_constraint_response(derez, remote_address_space);
              break;
            }
          case SEND_CONSTRAINT_RELEASE:
            {
              runtime->handle_constraint_release(derez);
              break;
            }
          case SEND_TOP_LEVEL_TASK_REQUEST:
            {
              runtime->handle_top_level_task_request(derez);
              break;
            }
          case SEND_TOP_LEVEL_TASK_COMPLETE:
            {
              runtime->handle_top_level_task_complete(derez);
              break;
            }
          case SEND_MPI_RANK_EXCHANGE:
            {
              runtime->handle_mpi_rank_exchange(derez);
              break;
            }
          case SEND_LIBRARY_MAPPER_REQUEST:
            {
              runtime->handle_library_mapper_request(derez, 
                                      remote_address_space);
              break;
            }
          case SEND_LIBRARY_MAPPER_RESPONSE:
            {
              runtime->handle_library_mapper_response(derez);
              break;
            }
          case SEND_LIBRARY_TRACE_REQUEST:
            {
              runtime->handle_library_trace_request(derez,remote_address_space);
              break;
            }
          case SEND_LIBRARY_TRACE_RESPONSE:
            {
              runtime->handle_library_trace_response(derez);
              break;
            }
          case SEND_LIBRARY_PROJECTION_REQUEST:
            {
              runtime->handle_library_projection_request(derez,
                                          remote_address_space);
              break;
            }
          case SEND_LIBRARY_PROJECTION_RESPONSE:
            {
              runtime->handle_library_projection_response(derez);
              break;
            }
          case SEND_LIBRARY_TASK_REQUEST:
            {
              runtime->handle_library_task_request(derez, remote_address_space);
              break;
            }
          case SEND_LIBRARY_TASK_RESPONSE:
            {
              runtime->handle_library_task_response(derez);
              break;
            }
          case SEND_LIBRARY_REDOP_REQUEST:
            {
              runtime->handle_library_redop_request(derez,remote_address_space);
              break;
            }
          case SEND_LIBRARY_REDOP_RESPONSE:
            {
              runtime->handle_library_redop_response(derez);
              break;
            }
          case SEND_LIBRARY_SERDEZ_REQUEST:
            {
              runtime->handle_library_serdez_request(derez,
                                      remote_address_space);
              break;
            }
          case SEND_LIBRARY_SERDEZ_RESPONSE:
            {
              runtime->handle_library_serdez_response(derez);
              break;
            }
          case SEND_REMOTE_OP_REPORT_UNINIT:
            {
              runtime->handle_remote_op_report_uninitialized(derez);
              break;
            }
          case SEND_REMOTE_OP_PROFILING_COUNT_UPDATE:
            {
              runtime->handle_remote_op_profiling_count_update(derez);
              break;
            }
          case SEND_REMOTE_TRACE_UPDATE:
            {
              runtime->handle_remote_tracing_update(derez,remote_address_space);
              break;
            }
          case SEND_REMOTE_TRACE_RESPONSE:
            {
              runtime->handle_remote_tracing_response(derez);
              break;
            }
          case SEND_REMOTE_TRACE_EQ_REQUEST:
            {
              runtime->handle_remote_tracing_eq_request(derez,
                                          remote_address_space);
              break;
            }
          case SEND_REMOTE_TRACE_EQ_RESPONSE:
            {
              runtime->handle_remote_tracing_eq_response(derez);
              break;
            }
          case SEND_SHUTDOWN_NOTIFICATION:
            {
#ifdef DEBUG_LEGION
              assert(!has_shutdown); // should only be one per message
#endif
              has_shutdown = true; 
              runtime->handle_shutdown_notification(derez,remote_address_space);
              break;
            }
          case SEND_SHUTDOWN_RESPONSE:
            {
#ifdef DEBUG_LEGION
              assert(!has_shutdown); // should only be one per message
#endif
              has_shutdown = true;
              runtime->handle_shutdown_response(derez);
              break;
            }
          default:
            assert(false); // should never get here
        }
        // Update the args and arglen
        args += message_size;
        arglen -= message_size;
      }
#ifdef DEBUG_LEGION
      assert(arglen == 0); // make sure we processed everything
#endif
      return has_shutdown;
    }

    //--------------------------------------------------------------------------
    /*static*/ void VirtualChannel::buffer_messages(unsigned num_messages,
                                         const void *args, size_t arglen,
                                         char *&receiving_buffer,
                                         size_t &receiving_buffer_size,
                                         size_t &receiving_index,
                                         unsigned &received_messages,
                                         unsigned &partial_messages)
    //--------------------------------------------------------------------------
    {
      received_messages += num_messages;
      partial_messages += 1; // up the number of partial messages received
      // Check to see if it fits
      if (receiving_buffer_size < (receiving_index+arglen))
      {
        // Figure out what the new size should be
        // Keep doubling until it's larger
        size_t new_buffer_size = receiving_buffer_size;
        while (new_buffer_size < (receiving_index+arglen))
          new_buffer_size *= 2;
#ifdef DEBUG_LEGION
        assert(new_buffer_size != 0); // would cause deallocation
#endif
        // Now realloc the memory
        void *new_ptr = legion_realloc(MESSAGE_BUFFER_ALLOC, receiving_buffer,
                                       receiving_buffer_size, new_buffer_size);
        receiving_buffer_size = new_buffer_size;
#ifdef DEBUG_LEGION
        assert(new_ptr != NULL);
#endif
        receiving_buffer = (char*)new_ptr;
      }
      // Copy the data in
      memcpy(receiving_buffer+receiving_index,args,arglen);
      receiving_index += arglen;
    }

    /////////////////////////////////////////////////////////////
    // Message Manager 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    MessageManager::MessageManager(AddressSpaceID remote,
                                   Runtime *rt, size_t max_message_size,
                                   const Processor remote_util_group)
      : channels((VirtualChannel*)
                  malloc(MAX_NUM_VIRTUAL_CHANNELS*sizeof(VirtualChannel))), 
        runtime(rt), remote_address_space(remote), target(remote_util_group), 
        always_flush(remote < rt->num_profiling_nodes)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(remote != runtime->address_space);
#endif
      // Initialize our virtual channels 
      for (unsigned idx = 0; idx < MAX_NUM_VIRTUAL_CHANNELS; idx++)
      {
        new (channels+idx) VirtualChannel((VirtualChannelKind)idx,
          rt->address_space, max_message_size, always_flush, runtime->profiler);
      }
    }

    //--------------------------------------------------------------------------
    MessageManager::MessageManager(const MessageManager &rhs)
      : channels(NULL), runtime(NULL), remote_address_space(0), 
        target(rhs.target), always_flush(false)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    MessageManager::~MessageManager(void)
    //--------------------------------------------------------------------------
    {
      for (unsigned idx = 0; idx < MAX_NUM_VIRTUAL_CHANNELS; idx++)
      {
        channels[idx].~VirtualChannel();
      }
      free(channels);
    }

    //--------------------------------------------------------------------------
    MessageManager& MessageManager::operator=(const MessageManager &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    template<MessageKind M>
    void MessageManager::send_message(Serializer &rez, bool flush,
        bool response, bool shutdown, RtEvent flush_precondition)
    //--------------------------------------------------------------------------
    {
      // Always flush for the profiler if we're doing that
      if (!flush && always_flush)
        flush = true;
      const VirtualChannelKind channel = find_message_vc(M);
      channels[channel].package_message(rez, M, flush, flush_precondition,
                                        runtime, target, response, shutdown);
    }

    //--------------------------------------------------------------------------
    void MessageManager::receive_message(const void *args, size_t arglen)
    //--------------------------------------------------------------------------
    {
      // Pull the channel off to do the receiving
      const char *buffer = (const char*)args;
      VirtualChannelKind channel = *((const VirtualChannelKind*)buffer);
      buffer += sizeof(channel);
      arglen -= sizeof(channel);
      channels[channel].process_message(buffer, arglen, runtime, 
                                        remote_address_space);
    }

    //--------------------------------------------------------------------------
    void MessageManager::confirm_shutdown(ShutdownManager *shutdown_manager, 
                                          bool phase_one)
    //--------------------------------------------------------------------------
    {
      for (unsigned idx = 0; idx < MAX_NUM_VIRTUAL_CHANNELS; idx++)
        channels[idx].confirm_shutdown(shutdown_manager, phase_one);
    }

    /////////////////////////////////////////////////////////////
    // Shutdown Manager 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    ShutdownManager::ShutdownManager(ShutdownPhase p, Runtime *rt, 
                                     AddressSpaceID s, unsigned r, 
                                     ShutdownManager *own)
      : phase(p), runtime(rt), source(s), radix(r), owner(own),
        needed_responses(0), return_code(rt->return_code), result(true)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    ShutdownManager::ShutdownManager(const ShutdownManager &rhs)
      : phase(rhs.phase), runtime(NULL), source(0), radix(0), owner(NULL)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    ShutdownManager::~ShutdownManager(void)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    ShutdownManager& ShutdownManager::operator=(const ShutdownManager &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    bool ShutdownManager::attempt_shutdown(void)
    //--------------------------------------------------------------------------
    {
      // Do the broadcast tree to the other nodes
      // Figure out who we have to send messages to
      std::vector<AddressSpaceID> targets;
      const AddressSpaceID local_space = runtime->address_space;
      const AddressSpaceID start = local_space * radix + 1;
      for (unsigned idx = 0; idx < radix; idx++)
      {
        AddressSpaceID next = start+idx;
        if (next < runtime->total_address_spaces)
          targets.push_back(next);
        else
          break;
      }
      
      if (!targets.empty())
      {
        // Set the number of needed_responses
        needed_responses = targets.size();
        Serializer rez;
        rez.serialize(this);
        rez.serialize(phase);
        for (std::vector<AddressSpaceID>::const_iterator it = 
              targets.begin(); it != targets.end(); it++)
          runtime->send_shutdown_notification(*it, rez); 
        return false;
      }
      else // no messages means we can finalize right now
      {
        finalize();
        return true;
      }
    }

    //--------------------------------------------------------------------------
    bool ShutdownManager::handle_response(int code, bool success,
                                          const std::set<RtEvent> &to_add)
    //--------------------------------------------------------------------------
    {
      bool done = false;
      {
        AutoLock s_lock(shutdown_lock);
        if ((return_code == 0) && (code != 0))
          return_code = code;
        if (result && !success)
          result = false;
        wait_for.insert(to_add.begin(), to_add.end()); 
#ifdef DEBUG_LEGION
        assert(needed_responses > 0);
#endif
        needed_responses--;
        done = (needed_responses == 0);
      }
      if (done)
      {
        finalize();
        return true;
      }
      return false;
    }

    //--------------------------------------------------------------------------
    void ShutdownManager::finalize(void)
    //--------------------------------------------------------------------------
    {
      // Do our local check
      runtime->confirm_runtime_shutdown(this, phase);
#ifdef DEBUG_SHUTDOWN_HANG
      if (!result)
      {
        LG_TASK_DESCRIPTIONS(task_descs);
        // Only need to see tasks less than this 
        for (unsigned idx = 0; idx < LG_BEGIN_SHUTDOWN_TASK_IDS; idx++)
        {
          if (runtime->outstanding_counts[idx].load() == 0)
            continue;
          log_shutdown.info("Meta-Task %s: %d outstanding",
                task_descs[idx], runtime->outstanding_counts[idx].load());
        }
      }
#endif
      if (result && (runtime->address_space == source))
      {
        log_shutdown.info("SHUTDOWN PHASE %d SUCCESS!", phase);
        if (phase != CONFIRM_SHUTDOWN)
        {
          if (phase == CONFIRM_TERMINATION)
            runtime->prepare_runtime_shutdown();
          // Do the next phase
          runtime->initiate_runtime_shutdown(source, (ShutdownPhase)(phase+1));
        }
        else
        {
          log_shutdown.info("SHUTDOWN SUCCEEDED!");
          runtime->finalize_runtime_shutdown(return_code);
        }
      }
      else if (runtime->address_space != source)
      {
#ifdef DEBUG_LEGION
        assert(owner != NULL);
#endif
        // Send the message back
        Serializer rez;
        rez.serialize(owner);
        rez.serialize(return_code);
        rez.serialize<bool>(result);
        rez.serialize<size_t>(wait_for.size());
        for (std::set<RtEvent>::const_iterator it = 
              wait_for.begin(); it != wait_for.end(); it++)
          rez.serialize(*it);
        runtime->send_shutdown_response(source, rez);
      }
      else
      {
#ifdef DEBUG_LEGION
        assert(!result);
#endif
        log_shutdown.info("FAILED SHUTDOWN PHASE %d! Trying again...", phase);
        RtEvent precondition;
        if (!wait_for.empty())
          precondition = Runtime::merge_events(wait_for);
        // If we failed an even phase we go back to the one before it
        RetryShutdownArgs args(((phase % 2) == 0) ?
            (ShutdownPhase)(phase-1) : phase);
        runtime->issue_runtime_meta_task(args, LG_LOW_PRIORITY,
                                         precondition);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_op_report_uninitialized(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      RemoteOp::handle_report_uninitialized(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_op_profiling_count_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      RemoteOp::handle_report_profiling_count_update(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_tracing_update(Deserializer &derez,
                                               AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RemoteTraceRecorder::handle_remote_update(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_tracing_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      RemoteTraceRecorder::handle_remote_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_tracing_eq_request(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RemoteMemoizable::handle_eq_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_tracing_eq_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      RemoteMemoizable::handle_eq_response(derez, this);
    }

    //--------------------------------------------------------------------------
    /*static*/ void ShutdownManager::handle_shutdown_notification(
                   Deserializer &derez, Runtime *runtime, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      ShutdownManager *owner;
      derez.deserialize(owner);
      ShutdownPhase phase;
      derez.deserialize(phase);
      runtime->initiate_runtime_shutdown(source, phase, owner);
    }

    //--------------------------------------------------------------------------
    /*static*/ void ShutdownManager::handle_shutdown_response(
                                                            Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      ShutdownManager *shutdown_manager;
      derez.deserialize(shutdown_manager);
      int return_code;
      derez.deserialize(return_code);
      bool success;
      derez.deserialize(success);
      size_t num_events;
      derez.deserialize(num_events);
      std::set<RtEvent> wait_for;
      for (unsigned idx = 0; idx < num_events; idx++)
      {
        RtEvent event;
        derez.deserialize(event);
        wait_for.insert(event);
      }
      if (shutdown_manager->handle_response(return_code, success, wait_for))
        delete shutdown_manager;
    }

    //--------------------------------------------------------------------------
    void ShutdownManager::record_outstanding_tasks(void)
    //--------------------------------------------------------------------------
    {
      // Instant death
      result = false;
      log_shutdown.info("Outstanding tasks on node %d", runtime->address_space);
    }

    //--------------------------------------------------------------------------
    void ShutdownManager::record_recent_message(void)
    //--------------------------------------------------------------------------
    {
      // Instant death
      result = false;
      log_shutdown.info("Outstanding message on node %d", 
                        runtime->address_space);
    }

    //--------------------------------------------------------------------------
    void ShutdownManager::record_pending_message(RtEvent pending_event)
    //--------------------------------------------------------------------------
    {
      // Instant death
      result = false;
      wait_for.insert(pending_event);
      log_shutdown.info("Pending message on node %d", runtime->address_space);
    }

    /////////////////////////////////////////////////////////////
    // Pending Registrations 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    PendingVariantRegistration::PendingVariantRegistration(VariantID v,
                                  size_t return_size, 
                                  const TaskVariantRegistrar &reg,
                                  const void *udata, size_t udata_size,
                                  const CodeDescriptor &realm, 
                                  const char *task_name)
      : vid(v), return_type_size(return_size), registrar(reg), 
        realm_desc(realm), logical_task_name(NULL)
    //--------------------------------------------------------------------------
    {
      // If we're doing a pending registration, this is a static
      // registration so we don't have to register it globally
      registrar.global_registration = false;
      // Make sure we own the task variant name
      if (reg.task_variant_name != NULL)
        registrar.task_variant_name = strdup(reg.task_variant_name);
      // We need to own the user data too
      if (udata != NULL)
      {
        user_data_size = udata_size;
        user_data = malloc(user_data_size);
        memcpy(user_data,udata,user_data_size);
      }
      else
      {
        user_data_size = 0;
        user_data = NULL;
      }
      if (task_name != NULL)
        logical_task_name = strdup(task_name);
    }

    //--------------------------------------------------------------------------
    PendingVariantRegistration::PendingVariantRegistration(
                                          const PendingVariantRegistration &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    PendingVariantRegistration::~PendingVariantRegistration(void)
    //--------------------------------------------------------------------------
    {
      if (registrar.task_variant_name != NULL)
        free(const_cast<char*>(registrar.task_variant_name));
      if (user_data != NULL)
        free(user_data);
      if (logical_task_name != NULL)
        free(logical_task_name);
    }

    //--------------------------------------------------------------------------
    PendingVariantRegistration& PendingVariantRegistration::operator=(
                                          const PendingVariantRegistration &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void PendingVariantRegistration::perform_registration(Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      // If we have a logical task name, attach the name info
      // Do this first before any logging for the variant
      if (logical_task_name != NULL)
        runtime->attach_semantic_information(registrar.task_id, 
                          LEGION_NAME_SEMANTIC_TAG, logical_task_name, 
                          strlen(logical_task_name)+1, 
                          false/*mutable*/, false/*send to owner*/);
      runtime->register_variant(registrar, user_data, user_data_size,
                    realm_desc, return_type_size, vid, false/*check task*/,
                    true/*check context*/, true/*preregistered*/);
    }

    /////////////////////////////////////////////////////////////
    // Task Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    TaskImpl::TaskImpl(TaskID tid, Runtime *rt, const char *name/*=NULL*/)
      : task_id(tid), runtime(rt), initial_name(static_cast<char*>(
          malloc(((name == NULL) ? 64 : strlen(name) + 1) * sizeof(char)))),
        all_idempotent(false)
    //--------------------------------------------------------------------------
    {
      // Always fill in semantic info 0 with a name for the task
      if (name != NULL)
      {
        const size_t name_size = strlen(name) + 1; // for \0
        char *name_copy = (char*)legion_malloc(SEMANTIC_INFO_ALLOC, name_size);
        memcpy(name_copy, name, name_size);
        semantic_infos[LEGION_NAME_SEMANTIC_TAG] = 
          SemanticInfo(name_copy, name_size, false/*mutable*/);
        if (runtime->legion_spy_enabled)
          LegionSpy::log_task_name(task_id, name);
        // Also set the initial name to be safe
        memcpy(initial_name, name, name_size);
        // Register this task with the profiler if necessary
        if (runtime->profiler != NULL)
          runtime->profiler->register_task_kind(task_id, name, false);
      }
      else // Just set the initial name
      {
        snprintf(initial_name,64,"unnamed_task_%d", task_id);
        // Register this task with the profiler if necessary
        if (runtime->profiler != NULL)
          runtime->profiler->register_task_kind(task_id, initial_name, false);
      }
    }

    //--------------------------------------------------------------------------
    TaskImpl::TaskImpl(const TaskImpl &rhs)
      : task_id(rhs.task_id), runtime(rhs.runtime), initial_name(NULL)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    TaskImpl::~TaskImpl(void)
    //-------------------------------------------------------------------------
    {
      for (std::map<SemanticTag,SemanticInfo>::const_iterator it = 
            semantic_infos.begin(); it != semantic_infos.end(); it++)
      {
        legion_free(SEMANTIC_INFO_ALLOC, it->second.buffer,
                    it->second.size);
      }
      semantic_infos.clear();
      free(initial_name);
    }

    //--------------------------------------------------------------------------
    TaskImpl& TaskImpl::operator=(const TaskImpl &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    VariantID TaskImpl::get_unique_variant_id(void)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(task_lock);
      // VariantIDs have to uniquely identify our node so start at our
      // current runtime name and stride by the number of nodes
      VariantID result = runtime->address_space;
      if (result == 0) // Never use VariantID 0
        result = runtime->runtime_stride;
      for ( ; result <= (UINT_MAX - runtime->runtime_stride); 
            result += runtime->runtime_stride)
      {
        if (variants.find(result) != variants.end())
          continue;
        if (pending_variants.find(result) != pending_variants.end())
          continue;
        pending_variants.insert(result);
        return result;
      }
      assert(false);
      return result;
    }

    //--------------------------------------------------------------------------
    void TaskImpl::add_variant(VariantImpl *impl)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(impl->owner == this);
#endif
      AutoLock t_lock(task_lock);
      if (!variants.empty())
      {
        if (all_idempotent != impl->is_idempotent())
          REPORT_LEGION_ERROR(ERROR_IDEMPOTENT_MISMATCH, 
                        "Variants of task %s (ID %d) have different idempotent "
                        "options.  All variants of the same task must "
                        "all be either idempotent or non-idempotent.",
                        get_name(false/*need lock*/), task_id)
      }
      else
        all_idempotent  = impl->is_idempotent();
      // Check to see if this variant has already been registered
      if (variants.find(impl->vid) != variants.end())
        REPORT_LEGION_ERROR(ERROR_DUPLICATE_VARIANT_REGISTRATION,
                      "Duplicate variant ID %d registered for task %s (ID %d)",
                      impl->vid, get_name(false/*need lock*/), task_id)
      variants[impl->vid] = impl;
      // Erase the pending VariantID if there is one
      pending_variants.erase(impl->vid);
    }

    //--------------------------------------------------------------------------
    VariantImpl* TaskImpl::find_variant_impl(VariantID variant_id,bool can_fail)
    //--------------------------------------------------------------------------
    {
      // See if we already have the variant
      {
        AutoLock t_lock(task_lock,1,false/*exclusive*/);
        std::map<VariantID,VariantImpl*>::const_iterator finder = 
          variants.find(variant_id);
        if (finder != variants.end())
          return finder->second;
      }
      if (!can_fail)
        REPORT_LEGION_ERROR(ERROR_UNREGISTERED_VARIANT, 
                            "Unable to find variant %d of task %s!",
                            variant_id, get_name())
      return NULL;
    }

    //--------------------------------------------------------------------------
    void TaskImpl::find_valid_variants(std::vector<VariantID> &valid_variants,
                                       Processor::Kind kind) const
    //--------------------------------------------------------------------------
    {
      if (kind == Processor::NO_KIND)
      {
        AutoLock t_lock(task_lock,1,false/*exclusive*/);
        valid_variants.resize(variants.size());
        unsigned idx = 0;
        for (std::map<VariantID,VariantImpl*>::const_iterator it = 
              variants.begin(); it != variants.end(); it++, idx++)
        {
          valid_variants[idx] = it->first; 
        }
      }
      else
      {
        AutoLock t_lock(task_lock,1,false/*exclusive*/);
        for (std::map<VariantID,VariantImpl*>::const_iterator it = 
              variants.begin(); it != variants.end(); it++)
        {
          if (it->second->can_use(kind, true/*warn*/))
            valid_variants.push_back(it->first);
        }
      }
    }

    //--------------------------------------------------------------------------
    const char* TaskImpl::get_name(bool needs_lock /*= true*/)
    //--------------------------------------------------------------------------
    {
      if (needs_lock)
      {
        // Do the request through the semantic information
        const void *ptr = NULL; size_t dummy_size;
        if (retrieve_semantic_information(LEGION_NAME_SEMANTIC_TAG, ptr, 
              dummy_size, true/*can fail*/, false/*wait until*/))
        {
          const char *result = NULL;
          static_assert(sizeof(result) == sizeof(ptr), "Fuck c++");
          memcpy(&result, &ptr, sizeof(result));
          return result;
        }
      }
      else
      {
        // If we're already holding the lock then we can just do
        // the local look-up regardless of if we're the owner or not
        std::map<SemanticTag,SemanticInfo>::const_iterator finder = 
          semantic_infos.find(LEGION_NAME_SEMANTIC_TAG);
        if (finder != semantic_infos.end())
        {
          const char *result = NULL;
          static_assert(sizeof(result) == 
              sizeof(finder->second.buffer), "Fuck c++");
          memcpy(&result, &finder->second.buffer, sizeof(result)); 
          return result;
        }
      }
      // Couldn't find it so use the initial name
      return initial_name;
    }

    //--------------------------------------------------------------------------
    void TaskImpl::attach_semantic_information(SemanticTag tag,
                                               AddressSpaceID source,
                                               const void *buffer, size_t size,
                                            bool is_mutable, bool send_to_owner)
    //--------------------------------------------------------------------------
    {
      if ((tag == LEGION_NAME_SEMANTIC_TAG) && (runtime->profiler != NULL))
        runtime->profiler->register_task_kind(task_id,(const char*)buffer,true);

      void *local = legion_malloc(SEMANTIC_INFO_ALLOC, size);
      memcpy(local, buffer, size);
      bool added = true;
      RtUserEvent to_trigger;
      {
        AutoLock t_lock(task_lock);
        std::map<SemanticTag,SemanticInfo>::iterator finder = 
          semantic_infos.find(tag);
        if (finder != semantic_infos.end())
        {
          // Check to see if it is valid
          if (finder->second.is_valid())
          {
            // See if it is mutable or not
            if (!finder->second.is_mutable)
            {
              // Note mutable so check to make sure that the bits are the same
              if (size != finder->second.size)
                REPORT_LEGION_ERROR(ERROR_INCONSISTENT_SEMANTIC_TAG,
                              "Inconsistent Semantic Tag value "
                              "for tag %ld with different sizes of %zd"
                              " and %zd for task impl", 
                              tag, size, finder->second.size)
              // Otherwise do a bitwise comparison
              {
                const char *orig = (const char*)finder->second.buffer;
                const char *next = (const char*)buffer;
                for (unsigned idx = 0; idx < size; idx++)
                {
                  char diff = orig[idx] ^ next[idx];
                  if (diff)
                    REPORT_LEGION_ERROR(ERROR_INCONSISTENT_SEMANTIC_TAG,
                         "Inconsistent Semantic Tag value "
                                     "for tag %ld with different values at"
                                     "byte %d for task impl, %x != %x",
                                     tag, idx, orig[idx], next[idx])
                }
              }
              added = false;
            }
            else
            {
              // It is mutable so just overwrite it
              legion_free(SEMANTIC_INFO_ALLOC, 
                          finder->second.buffer, finder->second.size);
              finder->second.buffer = local;
              finder->second.size = size;
              finder->second.ready_event = RtUserEvent::NO_RT_USER_EVENT;
              finder->second.is_mutable = is_mutable;
            }
          }
          else
          {
            finder->second.buffer = local;
            finder->second.size = size;
            to_trigger = finder->second.ready_event;
            finder->second.ready_event = RtUserEvent::NO_RT_USER_EVENT;
            finder->second.is_mutable = is_mutable;
          }
        }
        else
          semantic_infos[tag] = SemanticInfo(local, size, is_mutable);
      }
      if (to_trigger.exists())
        Runtime::trigger_event(to_trigger);
      if (added)
      {
        if (send_to_owner)
        {
          AddressSpaceID owner_space = get_owner_space();
          // if we are not the owner and the message didn't come
          // from the owner, then send it
          if ((owner_space != runtime->address_space) && 
              (source != owner_space))
          {
            if (tag == LEGION_NAME_SEMANTIC_TAG)
            {
              // Special case here for task names, the user can reasonably
              // expect all tasks to have an initial name so we have to 
              // guarantee that this update is propagated before continuing
              // because otherwise we can't distinguish the case where a 
              // name hasn't propagated from one where it was never set
              RtUserEvent wait_on = Runtime::create_rt_user_event();
              send_semantic_info(owner_space, tag, buffer, size, 
                                 is_mutable, wait_on);
              wait_on.wait();
            }
            else
              send_semantic_info(owner_space, tag, buffer, size, is_mutable);
          }
        }
      }
      else
        legion_free(SEMANTIC_INFO_ALLOC, local, size);
    }

    //--------------------------------------------------------------------------
    bool TaskImpl::retrieve_semantic_information(SemanticTag tag,
              const void *&result, size_t &size, bool can_fail, bool wait_until)
    //--------------------------------------------------------------------------
    {
      RtEvent wait_on;
      RtUserEvent request;
      const AddressSpaceID owner_space = get_owner_space();
      const bool is_remote = (owner_space != runtime->address_space);
      {
        AutoLock t_lock(task_lock);
        std::map<SemanticTag,SemanticInfo>::const_iterator finder = 
          semantic_infos.find(tag);
        if (finder != semantic_infos.end())
        {
          // Already have the data so we are done
          if (finder->second.is_valid())
          {
            result = finder->second.buffer;
            size = finder->second.size;
            return true;
          }
          else if (is_remote)
          {
            if (can_fail)
            {
              // Have to make our own event
              request = Runtime::create_rt_user_event();
              wait_on = request;
            }
            else // can use the canonical event
              wait_on = finder->second.ready_event; 
          }
          else if (wait_until) // local so use the canonical event
            wait_on = finder->second.ready_event;
        }
        else
        {
          // Otherwise we make an event to wait on
          if (!can_fail && wait_until)
          {
            // Make a canonical ready event
            request = Runtime::create_rt_user_event();
            semantic_infos[tag] = SemanticInfo(request);
            wait_on = request;
          }
          else if (is_remote)
          {
            // Make an event just for us to use
            request = Runtime::create_rt_user_event();
            wait_on = request;
          }
        }
      }
      // We didn't find it yet, see if we have something to wait on
      if (!wait_on.exists())
      {
        // Nothing to wait on so we have to do something
        if (can_fail)
          return false;
        REPORT_LEGION_ERROR(ERROR_INVALID_SEMANTIC_TAG, 
                      "Invalid semantic tag %ld for task implementation", tag)
      }
      else
      {
        // Send a request if necessary
        if (is_remote && request.exists())
          send_semantic_request(owner_space, tag, can_fail, wait_until,request);
        wait_on.wait();
      }
      // When we wake up, we should be able to find everything
      AutoLock t_lock(task_lock,1,false/*exclusive*/);
      std::map<SemanticTag,SemanticInfo>::const_iterator finder = 
        semantic_infos.find(tag);
      if (finder == semantic_infos.end())
      {
        if (can_fail)
          return false;
        REPORT_LEGION_ERROR(ERROR_INVALID_SEMANTIC_TAG, 
            "invalid semantic tag %ld for task implementation", tag)
      }
      result = finder->second.buffer;
      size = finder->second.size;
      return true;
    }

    //--------------------------------------------------------------------------
    void TaskImpl::send_semantic_info(AddressSpaceID target, SemanticTag tag,
                                      const void *buffer, size_t size, 
                                      bool is_mutable, RtUserEvent to_trigger)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(task_id);
        rez.serialize(tag);
        rez.serialize(size);
        rez.serialize(buffer, size);
        rez.serialize(is_mutable);
        rez.serialize(to_trigger);
      }
      runtime->send_task_impl_semantic_info(target, rez);
    }

    //--------------------------------------------------------------------------
    void TaskImpl::send_semantic_request(AddressSpaceID target, 
             SemanticTag tag, bool can_fail, bool wait_until, RtUserEvent ready)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(task_id);
        rez.serialize(tag);
        rez.serialize(can_fail);
        rez.serialize(wait_until);
        rez.serialize(ready);
      }
      runtime->send_task_impl_semantic_request(target, rez);
    }

    //--------------------------------------------------------------------------
    void TaskImpl::process_semantic_request(SemanticTag tag, 
       AddressSpaceID target, bool can_fail, bool wait_until, RtUserEvent ready)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(get_owner_space() == runtime->address_space);
#endif
      RtEvent precondition;
      void *result = NULL;
      size_t size = 0;
      bool is_mutable = false;
      {
        AutoLock t_lock(task_lock);
        // See if we already have the data
        std::map<SemanticTag,SemanticInfo>::iterator finder = 
          semantic_infos.find(tag);
        if (finder != semantic_infos.end())
        {
          if (finder->second.is_valid())
          {
            result = finder->second.buffer;
            size = finder->second.size;
            is_mutable = finder->second.is_mutable;
          }
          else if (!can_fail && wait_until)
            precondition = finder->second.ready_event;
        }
        else if (!can_fail && wait_until)
        {
          // Don't have it yet, make a condition and hope that one comes
          RtUserEvent ready_event = Runtime::create_rt_user_event();
          precondition = ready_event;
          semantic_infos[tag] = SemanticInfo(ready_event);
        }
      }
      if (result == NULL)
      {
        // this will cause a failure on the original node
        if (can_fail || !wait_until)
          Runtime::trigger_event(ready);  
        else
        {
          // Defer this until the semantic condition is ready
          SemanticRequestArgs args(this, tag, target);
          runtime->issue_runtime_meta_task(args, LG_LATENCY_WORK_PRIORITY, 
                                           precondition);
        }
      }
      else
        send_semantic_info(target, tag, result, size, is_mutable, ready);
    }

    //--------------------------------------------------------------------------
    /*static*/ void TaskImpl::handle_semantic_request(Runtime *runtime,
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      TaskID task_id;
      derez.deserialize(task_id);
      SemanticTag tag;
      derez.deserialize(tag);
      bool can_fail;
      derez.deserialize(can_fail);
      bool wait_until;
      derez.deserialize(wait_until);
      RtUserEvent ready;
      derez.deserialize(ready);
      TaskImpl *impl = runtime->find_or_create_task_impl(task_id);
      impl->process_semantic_request(tag, source, can_fail, wait_until, ready);
    }

    //--------------------------------------------------------------------------
    /*static*/ void TaskImpl::handle_semantic_info(Runtime *runtime,
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      TaskID task_id;
      derez.deserialize(task_id);
      SemanticTag tag;
      derez.deserialize(tag);
      size_t size;
      derez.deserialize(size);
      const void *buffer = derez.get_current_pointer();
      derez.advance_pointer(size);
      bool is_mutable;
      derez.deserialize(is_mutable);
      RtUserEvent to_trigger;
      derez.deserialize(to_trigger);
      TaskImpl *impl = runtime->find_or_create_task_impl(task_id);
      impl->attach_semantic_information(tag, source, buffer, size, 
                                        is_mutable, false/*send to owner*/);
      if (to_trigger.exists())
        Runtime::trigger_event(to_trigger);
    }

    //--------------------------------------------------------------------------
    /*static*/ AddressSpaceID TaskImpl::get_owner_space(TaskID task_id,
                                                        Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      return (task_id % runtime->runtime_stride);
    }

    /////////////////////////////////////////////////////////////
    // Variant Impl 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    VariantImpl::VariantImpl(Runtime *rt, VariantID v, TaskImpl *own, 
                           const TaskVariantRegistrar &registrar,
                           size_t return_size, const CodeDescriptor &realm,
                           const void *udata /*=NULL*/, size_t udata_size/*=0*/)
      : vid(v), owner(own), runtime(rt), global(registrar.global_registration),
        needs_padding(check_padding(rt, registrar.layout_constraints)),
        return_type_size(return_size),
        descriptor_id(runtime->get_unique_code_descriptor_id()),
        realm_descriptor(realm),
        execution_constraints(registrar.execution_constraints),
        layout_constraints(registrar.layout_constraints),
        user_data_size(udata_size), leaf_variant(registrar.leaf_variant), 
        inner_variant(registrar.inner_variant),
        idempotent_variant(registrar.idempotent_variant)
    //--------------------------------------------------------------------------
    { 
      if (udata != NULL)
      {
        user_data = malloc(user_data_size);
        memcpy(user_data, udata, user_data_size);
      }
      else
        user_data = NULL;
      // If we have a variant name, then record it
      if (registrar.task_variant_name == NULL)
      {
        variant_name = (char*)malloc(64*sizeof(char));
        snprintf(variant_name,64,"unnamed_variant_%d", vid);
      }
      else
        variant_name = strdup(registrar.task_variant_name);
      // If a global registration was requested, but the code descriptor
      // provided does not have portable implementations, try to make one
      // (if it fails, we'll complain below)
      if (global && !realm_descriptor.has_portable_implementations())
	realm_descriptor.create_portable_implementation();
      // Perform the registration, the normal case is not to have separate
      // runtime instances, but if we do have them, we only register on
      // the local processor
      if (!runtime->separate_runtime_instances)
      {
        Realm::ProfilingRequestSet profiling_requests;
        const ProcessorConstraint &proc_constraint = 
          execution_constraints.processor_constraint;
        if (proc_constraint.valid_kinds.empty())
        {
          REPORT_LEGION_WARNING(LEGION_WARNING_MISSING_PROC_CONSTRAINT, 
                     "NO PROCESSOR CONSTRAINT SPECIFIED FOR VARIANT"
                     " %s (ID %d) OF TASK %s (ID %d)! ASSUMING LOC_PROC!",
                     variant_name, vid, owner->get_name(false), owner->task_id)
          ready_event = ApEvent(Processor::register_task_by_kind(
                Processor::LOC_PROC, false/*global*/, descriptor_id, 
                realm_descriptor, profiling_requests, user_data, user_data_size));
        }
        else if (proc_constraint.valid_kinds.size() > 1)
        {
          std::set<ApEvent> ready_events;
          for (std::vector<Processor::Kind>::const_iterator it = 
                proc_constraint.valid_kinds.begin(); it !=
                proc_constraint.valid_kinds.end(); it++)
            ready_events.insert(ApEvent(Processor::register_task_by_kind(*it,
                false/*global*/, descriptor_id, realm_descriptor, 
                profiling_requests, user_data, user_data_size)));
          ready_event = Runtime::merge_events(NULL, ready_events);
        }
        else
          ready_event = ApEvent(Processor::register_task_by_kind(
              proc_constraint.valid_kinds[0], false/*global*/, descriptor_id, 
              realm_descriptor, profiling_requests, user_data, user_data_size));
      }
      else
      {
        // This is a debug case for when we have one runtime instance
        // for each processor
        std::set<Processor::Kind> handled_kinds;
        Machine::ProcessorQuery local_procs(runtime->machine);
        local_procs.local_address_space();
        std::set<ApEvent> ready_events;
        for (Machine::ProcessorQuery::iterator it = 
              local_procs.begin(); it != local_procs.end(); it++)
        {
          const Processor::Kind kind = it->kind();
          if (handled_kinds.find(kind) != handled_kinds.end())
            continue;
          Realm::ProfilingRequestSet profiling_requests;
          ready_events.insert(ApEvent(Processor::register_task_by_kind(kind,
                          false/*global*/, descriptor_id, realm_descriptor, 
                          profiling_requests, user_data, user_data_size)));
          handled_kinds.insert(kind);
        }
        if (!ready_events.empty())
          ready_event = Runtime::merge_events(NULL, ready_events);
      }
      // register this with the runtime profiler if we have to
      if (runtime->profiler != NULL)
        runtime->profiler->register_task_variant(own->task_id, vid,
            variant_name);
      // Check that global registration has portable implementations
      if (global && (!realm_descriptor.has_portable_implementations()))
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_GLOBAL_VARIANT_REGISTRATION, 
             "Variant %s requested global registration without "
                         "a portable implementation.", variant_name)
      if (leaf_variant && inner_variant)
        REPORT_LEGION_ERROR(ERROR_INNER_LEAF_MISMATCH, 
                      "Task variant %s (ID %d) of task %s (ID %d) is not "
                      "permitted to be both inner and leaf tasks "
                      "simultaneously.", variant_name, vid,
                      owner->get_name(), owner->task_id)
      if (runtime->record_registration)
        log_run.print("Task variant %s of task %s (ID %d) has Realm ID %ld",
              variant_name, owner->get_name(), owner->task_id, descriptor_id);
    }

    //--------------------------------------------------------------------------
    VariantImpl::~VariantImpl(void)
    //--------------------------------------------------------------------------
    {
      if (user_data != NULL)
        free(user_data);
      if (variant_name != NULL)
        free(variant_name);
    }

    //--------------------------------------------------------------------------
    bool VariantImpl::is_no_access_region(unsigned idx) const
    //--------------------------------------------------------------------------
    {
      bool result = false;
      for (std::multimap<unsigned,LayoutConstraintID>::const_iterator it = 
            layout_constraints.layouts.lower_bound(idx); it !=
            layout_constraints.layouts.upper_bound(idx); it++)
      {
        result = true;
        LayoutConstraints *constraints = 
          runtime->find_layout_constraints(it->second);
        if (!constraints->specialized_constraint.is_no_access())
        {
          result = false;
          break;
        }
      }
      return result;
    }

    //--------------------------------------------------------------------------
    ApEvent VariantImpl::dispatch_task(Processor target, SingleTask *task,
                                       TaskContext *ctx, ApEvent precondition,
                                       PredEvent predicate_guard, int priority, 
                                       Realm::ProfilingRequestSet &requests)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      // Either it is local or it is a group that we made
      assert(runtime->is_local(target) || runtime->separate_runtime_instances ||
              (target.kind() == Processor::PROC_GROUP));
#endif
      // Add any profiling requests
      if (runtime->profiler != NULL)
        runtime->profiler->add_task_request(requests, owner->task_id, vid,
                                            task->get_unique_op_id(), target);
      // Increment the number of outstanding tasks
#ifdef DEBUG_LEGION
      runtime->increment_total_outstanding_tasks(task->task_id, false/*meta*/);
#else
      runtime->increment_total_outstanding_tasks();
#endif
      DETAILED_PROFILER(runtime, REALM_SPAWN_TASK_CALL);
      // If our ready event hasn't triggered, include it in the precondition
      if (predicate_guard.exists())
      {
        // Merge in the predicate guard
        ApEvent pre = Runtime::merge_events(NULL, precondition, ready_event, 
                                            ApEvent(predicate_guard));
        // Have to protect the result in case it misspeculates
        return Runtime::ignorefaults(ApEvent(target.spawn(descriptor_id, 
                    &ctx, sizeof(ctx), requests, pre, priority)));
      }
      else
      {
        // No predicate guard
        if (ready_event.exists())
          return ApEvent(target.spawn(descriptor_id, &ctx, sizeof(ctx),requests,
             Runtime::merge_events(NULL, precondition, ready_event), priority));
        return ApEvent(target.spawn(descriptor_id, &ctx, sizeof(ctx), requests, 
                                    precondition, priority));
      }
    }

    //--------------------------------------------------------------------------
    void VariantImpl::dispatch_inline(Processor current, TaskContext *ctx)
    //--------------------------------------------------------------------------
    {
      const Realm::FunctionPointerImplementation *fp_impl = 
        realm_descriptor.find_impl<Realm::FunctionPointerImplementation>();
#ifdef DEBUG_LEGION
      assert(fp_impl != NULL);
      assert(implicit_context != NULL);
#endif
      // Save the implicit context here on the stack so we can restore it
      TaskContext *previous_context = implicit_context;
      RealmFnptr inline_ptr = fp_impl->get_impl<RealmFnptr>();
      (*inline_ptr)(&ctx, sizeof(ctx), user_data, user_data_size, current);
      // Restore the implicit context back to the previous context
      implicit_context = previous_context;
    }

    //--------------------------------------------------------------------------
    bool VariantImpl::can_use(Processor::Kind kind, bool warn) const
    //--------------------------------------------------------------------------
    {
      const ProcessorConstraint &constraint = 
                                  execution_constraints.processor_constraint;
      if (constraint.is_valid())
        return constraint.can_use(kind);
      if (warn)
        REPORT_LEGION_WARNING(LEGION_WARNING_MISSING_PROC_CONSTRAINT, 
           "NO PROCESSOR CONSTRAINT SPECIFIED FOR VARIANT"
                        " %s (ID %d) OF TASK %s (ID %d)! ASSUMING LOC_PROC!",
                      variant_name, vid, owner->get_name(false),owner->task_id)
      return (Processor::LOC_PROC == kind);
    }

    //--------------------------------------------------------------------------
    void VariantImpl::broadcast_variant(RtUserEvent done, AddressSpaceID origin,
                                        AddressSpaceID local)
    //--------------------------------------------------------------------------
    {
      std::vector<AddressSpaceID> targets;
      std::vector<AddressSpaceID> locals;
      const AddressSpaceID start = local * runtime->legion_collective_radix + 1;
      for (int idx = 0; idx < runtime->legion_collective_radix; idx++)
      {
        AddressSpaceID next = start+idx;
        if (next >= runtime->total_address_spaces)
          break;
        locals.push_back(next);
        // Convert from relative to actual address space
        AddressSpaceID actual = (origin + next) % runtime->total_address_spaces;
        targets.push_back(actual);
      }
      if (!targets.empty())
      {
        std::set<RtEvent> local_done;
        for (unsigned idx = 0; idx < targets.size(); idx++)
        {
          RtUserEvent next_done = Runtime::create_rt_user_event();
          Serializer rez;
          {
            RezCheck z(rez);
            // pack the code descriptors 
            Realm::Serialization::ByteCountSerializer counter;
            realm_descriptor.serialize(counter, true/*portable*/);
            const size_t impl_size = counter.bytes_used();
            rez.serialize(impl_size);
            {
              Realm::Serialization::FixedBufferSerializer 
                serializer(rez.reserve_bytes(impl_size), impl_size);
              realm_descriptor.serialize(serializer, true/*portable*/);
            }
            rez.serialize(owner->task_id);
            rez.serialize(vid);
            // Extra padding to fix a realm bug for now
            rez.serialize(vid);
            rez.serialize(next_done);
            rez.serialize(return_type_size);
            rez.serialize(user_data_size);
            if (user_data_size > 0)
              rez.serialize(user_data, user_data_size);
            rez.serialize(leaf_variant);
            rez.serialize(inner_variant);
            rez.serialize(idempotent_variant);
            size_t name_size = strlen(variant_name)+1;
            rez.serialize(variant_name, name_size);
            // Pack the constraints
            execution_constraints.serialize(rez);
            layout_constraints.serialize(rez);
            rez.serialize(origin);
            rez.serialize(locals[idx]);
          }
          runtime->send_variant_broadcast(targets[idx], rez);
          local_done.insert(next_done);
        }
        Runtime::trigger_event(done, Runtime::merge_events(local_done));
      }
      else
        Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void VariantImpl::find_padded_locks(SingleTask *task,
                        const std::vector<RegionRequirement> &regions,
                        const std::deque<InstanceSet> &physical_instances) const
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(needs_padding);
#endif
      for (std::multimap<unsigned,LayoutConstraintID>::const_iterator it = 
            layout_constraints.layouts.begin(); it != 
            layout_constraints.layouts.end(); it++)
      {
        const LayoutConstraints *layout =
          runtime->find_layout_constraints(it->second);
        if (layout->padding_constraint.delta.get_dim() == 0)
          continue;
#ifdef DEBUG_LEGION
        assert(it->first < regions.size());
        assert(it->first < physical_instances.size());
#endif
        const RegionRequirement &req = regions[it->first];
        const InstanceSet &instances = physical_instances[it->first];
        // Check to see if we have any explicit fields
        std::set<FieldID> padded_fields;
        if (!layout->field_constraint.field_set.empty())
        {
          for (std::vector<FieldID>::const_iterator fit =
                layout->field_constraint.field_set.begin(); fit !=
                layout->field_constraint.field_set.end(); fit++)
          {
#ifdef DEBUG_LEGION
            assert(req.privilege_fields.find(*fit) != 
                    req.privilege_fields.end());
#endif
            padded_fields.insert(*fit);
          }
        }
        else // Add all the fields for this region requirement
          padded_fields.insert(req.privilege_fields.begin(),
                               req.privilege_fields.end());
        FieldSpaceNode *fs = 
          runtime->forest->get_node(req.region.get_field_space());
        FieldMask padded_mask = fs->get_field_mask(padded_fields);
        for (unsigned idx = 0; idx < instances.size(); idx++)
        {
          const InstanceRef &ref = instances[idx];
          const FieldMask &overlap = padded_mask & ref.get_valid_fields();
          if (!overlap)
            continue;
          PhysicalManager *manager = ref.get_physical_manager();
          manager->find_padded_reservations(overlap, task, it->first);
          padded_mask -= overlap;
          if (!padded_mask)
            break;
        }
#ifdef DEBUG_LEGION
        assert(!padded_mask);
#endif
      }
    }

    //--------------------------------------------------------------------------
    void VariantImpl::record_padded_fields(
                      const std::vector<RegionRequirement> &regions,
                      const std::vector<PhysicalRegion> &physical_regions) const
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(needs_padding);
#endif
      for (std::multimap<unsigned,LayoutConstraintID>::const_iterator it = 
            layout_constraints.layouts.begin(); it != 
            layout_constraints.layouts.end(); it++)
      {
        const LayoutConstraints *layout =
          runtime->find_layout_constraints(it->second);
        if (layout->padding_constraint.delta.get_dim() == 0)
          continue;
#ifdef DEBUG_LEGION
        assert(it->first < regions.size());
        assert(it->first < physical_regions.size());
#endif
        const RegionRequirement &req = regions[it->first];
        const PhysicalRegion &region = physical_regions[it->first];
        // Check to see if we have any explicit fields
        if (layout->field_constraint.field_set.empty())
        {
          // Add all the fields for this region requirement
          for (std::set<FieldID>::const_iterator fit =
                req.privilege_fields.begin(); fit !=
                req.privilege_fields.end(); fit++)
            region.impl->add_padded_field(*fit);
        }
        else
        {
          // Only add the fields specified by the constraint
          for (std::vector<FieldID>::const_iterator fit =
                layout->field_constraint.field_set.begin(); fit !=
                layout->field_constraint.field_set.end(); fit++)
          {
#ifdef DEBUG_LEGION
            assert(req.privilege_fields.find(*fit) != 
                    req.privilege_fields.end());
#endif
            region.impl->add_padded_field(*fit);
          }
        }
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void VariantImpl::handle_variant_broadcast(Runtime *runtime,
                                                          Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t impl_size;
      derez.deserialize(impl_size);
      CodeDescriptor realm_desc;
      {
        // Realm's serializers assume properly aligned buffers, so
        // malloc a temporary buffer here and copy the data to ensure
        // alignment.
        void *impl_buffer = malloc(impl_size);
#ifdef DEBUG_LEGION
        assert(impl_buffer);
#endif
        memcpy(impl_buffer, derez.get_current_pointer(), impl_size);
        derez.advance_pointer(impl_size);
        Realm::Serialization::FixedBufferDeserializer
          deserializer(impl_buffer, impl_size);
#ifdef DEBUG_LEGION
#ifndef NDEBUG
        bool ok =
#endif
                  realm_desc.deserialize(deserializer);
        assert(ok);
#else
        realm_desc.deserialize(deserializer);
#endif
        free(impl_buffer);
      }
      TaskID task_id;
      derez.deserialize(task_id);
      TaskVariantRegistrar registrar(task_id, false/*global*/);
      VariantID variant_id;
      derez.deserialize(variant_id);
      // Extra padding to fix a realm bug for now
      derez.deserialize(variant_id); 
      RtUserEvent done;
      derez.deserialize(done);
      size_t return_type_size;
      derez.deserialize(return_type_size);
      size_t user_data_size;
      derez.deserialize(user_data_size);
      const void *user_data = derez.get_current_pointer();
      derez.advance_pointer(user_data_size);
      derez.deserialize(registrar.leaf_variant);
      derez.deserialize(registrar.inner_variant);
      derez.deserialize(registrar.idempotent_variant);
      // The last thing will be the name
      registrar.task_variant_name = (const char*)derez.get_current_pointer();
      size_t name_size = strlen(registrar.task_variant_name)+1;
      derez.advance_pointer(name_size);
      // Unpack the constraints
      registrar.execution_constraints.deserialize(derez);
      registrar.layout_constraints.deserialize(derez);
      // Ask the runtime to perform the registration 
      // Can lie about preregistration since the user would already have
      // gotten there error message on the owner node
      runtime->register_variant(registrar, user_data, user_data_size,
              realm_desc, return_type_size, variant_id, false/*check task*/,
              false/*check context*/, true/*preregistered*/);
      AddressSpaceID origin;
      derez.deserialize(origin);
      AddressSpaceID local;
      derez.deserialize(local);
      VariantImpl *impl = runtime->find_variant_impl(task_id, variant_id);
      impl->broadcast_variant(done, origin, local);
    }

    //--------------------------------------------------------------------------
    /*static*/ bool VariantImpl::check_padding(Runtime *runtime,
                                     const TaskLayoutConstraintSet &constraints)
    //--------------------------------------------------------------------------
    {
      for (std::multimap<unsigned,LayoutConstraintID>::const_iterator it = 
            constraints.layouts.begin(); it != constraints.layouts.end(); it++)
      {
        const LayoutConstraints *layout =
          runtime->find_layout_constraints(it->second);
        if (layout->padding_constraint.delta.get_dim() > 0)
          return true;
      }
      return false;
    }

    /////////////////////////////////////////////////////////////
    // Layout Constraints 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    LayoutConstraints::LayoutConstraints(LayoutConstraintID lay_id,FieldSpace h,
                                     Runtime *rt, bool inter, DistributedID did)
      : LayoutConstraintSet(), DistributedCollectable(rt, (did > 0) ? did : 
          rt->get_available_distributed_id(), get_owner_space(lay_id, rt), 
          false/*register*/), layout_id(lay_id), handle(h), internal(inter), 
        constraints_name(NULL)
    //--------------------------------------------------------------------------
    {
#ifdef LEGION_GC
      log_garbage.info("GC Constraints %lld %d", 
          LEGION_DISTRIBUTED_ID_FILTER(this->did), local_space);
#endif
    }

    //--------------------------------------------------------------------------
    LayoutConstraints::LayoutConstraints(LayoutConstraintID lay_id, Runtime *rt,
      const LayoutConstraintRegistrar &registrar, bool inter, DistributedID did)
      : LayoutConstraintSet(registrar.layout_constraints), 
        DistributedCollectable(rt, (did > 0) ? did : 
            rt->get_available_distributed_id(), get_owner_space(lay_id, rt),
            false/*register with runtime*/), 
        layout_id(lay_id), handle(registrar.handle), internal(inter)
    //--------------------------------------------------------------------------
    {
      if (registrar.layout_name == NULL)
      {
        constraints_name = (char*)malloc(64*sizeof(char));
        snprintf(constraints_name,64,"layout constraints %ld", layout_id);
      }
      else
        constraints_name = strdup(registrar.layout_name);
#ifdef LEGION_GC
      log_garbage.info("GC Constraints %lld %d", 
          LEGION_DISTRIBUTED_ID_FILTER(this->did), local_space);
#endif
    }

    //--------------------------------------------------------------------------
    LayoutConstraints::LayoutConstraints(LayoutConstraintID lay_id, Runtime *rt,
                                         const LayoutConstraintSet &cons,
                                         FieldSpace h, bool inter)
      : LayoutConstraintSet(cons), DistributedCollectable(rt,
          rt->get_available_distributed_id(), get_owner_space(lay_id, rt),
          false/*register with runtime*/), 
        layout_id(lay_id), handle(h), internal(inter)
    //--------------------------------------------------------------------------
    {
      constraints_name = (char*)malloc(64*sizeof(char));
      snprintf(constraints_name,64,"layout constraints %ld", layout_id);
#ifdef LEGION_GC
      log_garbage.info("GC Constraints %lld %d", 
          LEGION_DISTRIBUTED_ID_FILTER(this->did), local_space);
#endif
    }

    //--------------------------------------------------------------------------
    LayoutConstraints::LayoutConstraints(const LayoutConstraints &rhs)
      : LayoutConstraintSet(rhs), DistributedCollectable(NULL, 0, 0), 
        layout_id(rhs.layout_id), handle(rhs.handle), internal(false)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    LayoutConstraints::~LayoutConstraints(void)
    //--------------------------------------------------------------------------
    {
      if (constraints_name != NULL)
        free(constraints_name);
    }

    //--------------------------------------------------------------------------
    LayoutConstraints& LayoutConstraints::operator=(const LayoutConstraints &rh)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    bool LayoutConstraints::operator==(const LayoutConstraints &rhs) const
    //--------------------------------------------------------------------------
    {
      // We check equalities only on the members of LayoutConstraintSet
      return field_constraint == rhs.field_constraint
             && specialized_constraint == rhs.specialized_constraint
             && memory_constraint == rhs.memory_constraint
             && ordering_constraint == rhs.ordering_constraint
             && alignment_constraints == rhs.alignment_constraints
             && dimension_constraints == rhs.dimension_constraints
             && tiling_constraints == rhs.tiling_constraints
             && offset_constraints == rhs.offset_constraints
             && pointer_constraint == rhs.pointer_constraint;
    }

    //--------------------------------------------------------------------------
    bool LayoutConstraints::operator==(const LayoutConstraintSet &rhs) const
    //--------------------------------------------------------------------------
    {
      // We check equalities only on the members of LayoutConstraintSet
      return field_constraint == rhs.field_constraint
             && specialized_constraint == rhs.specialized_constraint
             && memory_constraint == rhs.memory_constraint
             && ordering_constraint == rhs.ordering_constraint
             && alignment_constraints == rhs.alignment_constraints
             && dimension_constraints == rhs.dimension_constraints
             && tiling_constraints == rhs.tiling_constraints
             && offset_constraints == rhs.offset_constraints
             && pointer_constraint == rhs.pointer_constraint;
    }

    //--------------------------------------------------------------------------
    void LayoutConstraints::notify_active(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // If we're not the owner add a remote reference
      if (!is_owner())
        send_remote_gc_increment(owner_space, mutator);
    }

    //--------------------------------------------------------------------------
    void LayoutConstraints::notify_inactive(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      if (is_owner())
        runtime->unregister_layout(layout_id);
      else
        send_remote_gc_decrement(owner_space, mutator);
    }

    //--------------------------------------------------------------------------
    void LayoutConstraints::notify_valid(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    void LayoutConstraints::notify_invalid(ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    void LayoutConstraints::send_constraint_response(AddressSpaceID target,
                                                     RtUserEvent done_event)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(layout_id);
        rez.serialize(did);
        rez.serialize(handle);
        rez.serialize<bool>(internal);
        size_t name_len = strlen(constraints_name)+1;
        rez.serialize(name_len);
        rez.serialize(constraints_name, name_len);
        // pack the constraints
        serialize(rez);   
        // pack the done events
        rez.serialize(done_event);
      }
      runtime->send_constraint_response(target, rez);
      update_remote_instances(target);
    }

    //--------------------------------------------------------------------------
    void LayoutConstraints::update_constraints(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(constraints_name == NULL);
#endif
      size_t name_len;
      derez.deserialize(name_len);
      constraints_name = (char*)malloc(name_len);
      derez.deserialize(constraints_name, name_len);
      // unpack the constraints
      deserialize(derez); 
    }

    //--------------------------------------------------------------------------
    bool LayoutConstraints::entails(LayoutConstraints *constraints,
                unsigned total_dims, const LayoutConstraint **failed_constraint,
                bool test_pointer)
    //--------------------------------------------------------------------------
    {
      const std::pair<LayoutConstraintID,unsigned> 
        key(constraints->layout_id, total_dims);
      // Check to see if the result is in the cache
      if (test_pointer)
      {
        AutoLock lay(layout_lock,1,false/*exclusive*/);
        std::map<std::pair<LayoutConstraintID,unsigned>,
                  const LayoutConstraint*>::const_iterator finder = 
            entailment_cache.find(key);
        if (finder != entailment_cache.end())
        {
          if (finder->second != NULL)
          {
            if (failed_constraint != NULL)
              *failed_constraint = finder->second;
            return false;
          }
          else
            return true;
        }
      }
      else
      {
        AutoLock lay(layout_lock,1,false/*exclusive*/);
        std::map<std::pair<LayoutConstraintID,unsigned>,
                  const LayoutConstraint*>::const_iterator finder = 
            no_pointer_entailment_cache.find(key);
        if (finder != no_pointer_entailment_cache.end())
        {
          if (finder->second != NULL)
          {
            if (failed_constraint != NULL)
              *failed_constraint = finder->second;
            return false;
          }
          else
            return true;
        }
      }
      // Didn't find it, so do the test for real
      const LayoutConstraint *result = NULL;
      const bool entailment = 
        entails(*constraints, total_dims, &result, test_pointer);
#ifdef DEBUG_LEGION
      assert(entailment ^ (result != NULL)); // only one should be true
#endif
      if (!entailment && (failed_constraint != NULL))
        *failed_constraint = result;
      // Save the result in the cache
      AutoLock lay(layout_lock);
      if (test_pointer)
        entailment_cache[key] = result;
      else
        no_pointer_entailment_cache[key] = result;
      return entailment;
    }

    //--------------------------------------------------------------------------
    bool LayoutConstraints::entails(const LayoutConstraintSet &other,
          unsigned total_dims, const LayoutConstraint **failed_constraint, 
          bool test_pointer) const
    //--------------------------------------------------------------------------
    {
      return LayoutConstraintSet::entails(other, total_dims, 
                                          failed_constraint, test_pointer);
    }

    //--------------------------------------------------------------------------
    bool LayoutConstraints::conflicts(LayoutConstraints *constraints,
              unsigned total_dims, const LayoutConstraint **conflict_constraint)
    //--------------------------------------------------------------------------
    {
      const std::pair<LayoutConstraintID,unsigned> 
        key(constraints->layout_id, total_dims);
      // Check to see if the result is in the cache
      {
        AutoLock lay(layout_lock,1,false/*exclusive*/);
        std::map<std::pair<LayoutConstraintID,unsigned>,
                  const LayoutConstraint*>::const_iterator finder = 
          conflict_cache.find(key);
        if (finder != conflict_cache.end())
        {
          if (finder->second != NULL)
          {
            if (conflict_constraint != NULL)
              *conflict_constraint = finder->second;
            return true;
          }
          else
            return false;
        }
      }
      // Didn't find it, so do the test for real
      const LayoutConstraint *result = NULL;
      const bool conflicted = conflicts(*constraints, total_dims, &result);
#ifdef DEBUG_LEGION
      assert(conflicted ^ (result == NULL)); // only one should be true
#endif
      // Save the result in the cache
      AutoLock lay(layout_lock);
      conflict_cache[key] = result;
      if (conflicted && (conflict_constraint != NULL))
        *conflict_constraint = result;
      return conflicted;
    }

    //--------------------------------------------------------------------------
    bool LayoutConstraints::conflicts(const LayoutConstraintSet &other,
        unsigned total_dims, const LayoutConstraint **conflict_constraint) const
    //--------------------------------------------------------------------------
    {
      return LayoutConstraintSet::conflicts(other, total_dims, 
                                            conflict_constraint);
    }

    //--------------------------------------------------------------------------
    /*static*/ AddressSpaceID LayoutConstraints::get_owner_space(
                            LayoutConstraintID layout_id, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      return (layout_id % runtime->runtime_stride);
    }

    //--------------------------------------------------------------------------
    /*static*/ void LayoutConstraints::process_request(Runtime *runtime,
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      LayoutConstraintID lay_id;
      derez.deserialize(lay_id);
      RtUserEvent done_event;
      derez.deserialize(done_event);
      bool can_fail;
      derez.deserialize(can_fail);
      LayoutConstraints *constraints = 
        runtime->find_layout_constraints(lay_id, can_fail);
      if (can_fail && (constraints == NULL))
        Runtime::trigger_event(done_event);
      else
        constraints->send_constraint_response(source, done_event);
    }

    //--------------------------------------------------------------------------
    /*static*/ void LayoutConstraints::process_response(
                   Runtime *runtime, Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      LayoutConstraintID lay_id;
      derez.deserialize(lay_id);
      DistributedID did;
      derez.deserialize(did);
      FieldSpace handle;
      derez.deserialize(handle);
      bool internal;
      derez.deserialize(internal);
      // Make it an unpack it, then try to register it 
      LayoutConstraints *new_constraints = 
        new LayoutConstraints(lay_id, handle, runtime, internal, did);
      new_constraints->update_constraints(derez);
      std::set<RtEvent> preconditions;
      WrapperReferenceMutator mutator(preconditions);
      // Now try to register this with the runtime
      if (!runtime->register_layout(new_constraints, &mutator))
        delete new_constraints;
      // Trigger our done event and then return it
      RtUserEvent done_event;
      derez.deserialize(done_event);
      if (!preconditions.empty())
        Runtime::trigger_event(done_event,Runtime::merge_events(preconditions));
      else
        Runtime::trigger_event(done_event);
    }

    /////////////////////////////////////////////////////////////
    // Identity Projection Functor
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    IdentityProjectionFunctor::IdentityProjectionFunctor(Legion::Runtime *rt)
      : ProjectionFunctor(rt)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    IdentityProjectionFunctor::~IdentityProjectionFunctor(void)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    LogicalRegion IdentityProjectionFunctor::project(const Mappable *mappable,
            unsigned index, LogicalRegion upper_bound, const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      return upper_bound;
    }
    
    //--------------------------------------------------------------------------
    LogicalRegion IdentityProjectionFunctor::project(const Mappable *mappable,
         unsigned index, LogicalPartition upper_bound, const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      return runtime->get_logical_subregion_by_color(upper_bound, point);
    }

    //--------------------------------------------------------------------------
    bool IdentityProjectionFunctor::is_exclusive(void) const
    //--------------------------------------------------------------------------
    {
      return true;
    }

    //--------------------------------------------------------------------------
    unsigned IdentityProjectionFunctor::get_depth(void) const
    //--------------------------------------------------------------------------
    {
      return 0;
    }

    /////////////////////////////////////////////////////////////
    // Projection Function 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    ProjectionFunction::ProjectionFunction(ProjectionID pid, 
                                           ProjectionFunctor *func)
      : depth(func->get_depth()), is_exclusive(func->is_exclusive()),
        is_invertible(func->is_invertible()), projection_id(pid), functor(func)
    //--------------------------------------------------------------------------
    {
    }

    //--------------------------------------------------------------------------
    ProjectionFunction::ProjectionFunction(const ProjectionFunction &rhs)
      : depth(rhs.depth), is_exclusive(rhs.is_exclusive), 
        is_invertible(rhs.is_invertible), projection_id(rhs.projection_id), 
        functor(rhs.functor)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    ProjectionFunction::~ProjectionFunction(void)
    //--------------------------------------------------------------------------
    {
      // These can be shared in the case of multiple runtime instances
      if (!implicit_runtime->separate_runtime_instances)
        delete functor;
    }

    //--------------------------------------------------------------------------
    LogicalRegion ProjectionFunction::project_point(Task *task, unsigned idx, 
                                     Runtime *runtime, const DomainPoint &point)
    //--------------------------------------------------------------------------
    {
      const RegionRequirement &req = task->regions[idx];
#ifdef DEBUG_LEGION
      assert(req.handle_type != LEGION_SINGULAR_PROJECTION);
#endif
      if (!is_exclusive)
      {
        AutoLock p_lock(projection_reservation);
        if (req.handle_type == LEGION_PARTITION_PROJECTION)
        {
          LogicalRegion result = functor->project(task, idx, 
                                                  req.partition, point); 
          check_projection_partition_result(req, task, idx, result, runtime);
          return result;
        }
        else
        {
          LogicalRegion result = functor->project(task, idx, req.region, point);
          check_projection_region_result(req, task, idx, result, runtime);
          return result;
        }
      }
      else
      {
        if (req.handle_type == LEGION_PARTITION_PROJECTION)
        {
          LogicalRegion result = functor->project(task, idx, 
                                                  req.partition, point);
          check_projection_partition_result(req, task, idx, result, runtime);
          return result;
        }
        else
        {
          LogicalRegion result = functor->project(task, idx, req.region, point);
          check_projection_region_result(req, task, idx, result, runtime);
          return result;
        }
      }
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::project_points(const RegionRequirement &req, 
                                    unsigned idx, Runtime *runtime, 
                                    const std::vector<PointTask*> &point_tasks,
                                    IndexSpaceNode *launch_space)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(req.handle_type != LEGION_SINGULAR_PROJECTION);
#endif
      std::map<LogicalRegion,std::vector<DomainPoint> > dependences;
      const bool find_dependences = is_invertible && IS_WRITE(req);
      Domain launch_domain;
      if (find_dependences)
        launch_space->get_launch_space_domain(launch_domain);
      if (!is_exclusive)
      {
        AutoLock p_lock(projection_reservation);
        if (req.handle_type == LEGION_PARTITION_PROJECTION)
        {
          for (std::vector<PointTask*>::const_iterator it = 
                point_tasks.begin(); it != point_tasks.end(); it++)
          {
            LogicalRegion result = functor->project(*it, idx, req.partition, 
                                                    (*it)->get_domain_point());
            check_projection_partition_result(req, static_cast<Task*>(*it), 
                                              idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result,req.partition,launch_domain,region_deps);
                check_inversion((*it), idx, region_deps);
              }
              else
                check_containment((*it), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
        else
        {
          for (std::vector<PointTask*>::const_iterator it = 
                point_tasks.begin(); it != point_tasks.end(); it++)
          {
            LogicalRegion result = functor->project(*it, idx, req.region, 
                                                    (*it)->get_domain_point());
            check_projection_region_result(req, static_cast<Task*>(*it), 
                                           idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result, req.region, launch_domain, region_deps);
                check_inversion((*it), idx, region_deps);
              }
              else
                check_containment((*it), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
      }
      else
      {
        if (req.handle_type == LEGION_PARTITION_PROJECTION)
        {
          for (std::vector<PointTask*>::const_iterator it = 
                point_tasks.begin(); it != point_tasks.end(); it++)
          {
            LogicalRegion result = functor->project(*it, idx, req.partition, 
                                                    (*it)->get_domain_point());
            check_projection_partition_result(req, static_cast<Task*>(*it), 
                                              idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result,req.partition,launch_domain,region_deps);
                check_inversion((*it), idx, region_deps);
              }
              else
                check_containment((*it), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
        else
        {
          for (std::vector<PointTask*>::const_iterator it = 
                point_tasks.begin(); it != point_tasks.end(); it++)
          {
            LogicalRegion result = functor->project(*it, idx, req.region, 
                                                    (*it)->get_domain_point());
            check_projection_region_result(req, static_cast<Task*>(*it), 
                                           idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result, req.region, launch_domain, region_deps);
                check_inversion((*it), idx, region_deps);
              }
              else
                check_containment((*it), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
      }
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::project_points(Operation *op, unsigned idx,
                         const RegionRequirement &req, Runtime *runtime, 
                         const std::vector<ProjectionPoint*> &points,
                         IndexSpaceNode *launch_space)
    //--------------------------------------------------------------------------
    {
      Mappable *mappable = op->get_mappable();
#ifdef DEBUG_LEGION
      assert(req.handle_type != LEGION_SINGULAR_PROJECTION);
      assert(mappable != NULL);
#endif
      const bool find_dependences = is_invertible && IS_WRITE(req);
      std::map<LogicalRegion,std::vector<DomainPoint> > dependences;
      Domain launch_domain;
      if (find_dependences)
        launch_space->get_launch_space_domain(launch_domain);
      if (!is_exclusive)
      {
        AutoLock p_lock(projection_reservation);
        if (req.handle_type == LEGION_PARTITION_PROJECTION)
        {
          for (std::vector<ProjectionPoint*>::const_iterator it = 
                points.begin(); it != points.end(); it++)
          {
            LogicalRegion result = functor->project(mappable, idx, 
                req.partition, (*it)->get_domain_point());
            check_projection_partition_result(req, op, idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result,req.partition,launch_domain,region_deps);
                check_inversion((*it)->as_mappable(), idx, region_deps);
              }
              else
                check_containment((*it)->as_mappable(), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
        else
        {
          for (std::vector<ProjectionPoint*>::const_iterator it = 
                points.begin(); it != points.end(); it++)
          {
            LogicalRegion result = functor->project(mappable, idx, req.region,
                                                    (*it)->get_domain_point());
            check_projection_region_result(req, op, idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result, req.region, launch_domain, region_deps);
                check_inversion((*it)->as_mappable(), idx, region_deps);
              }
              else
                check_containment((*it)->as_mappable(), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
      }
      else
      {
        if (req.handle_type == LEGION_PARTITION_PROJECTION)
        {
          for (std::vector<ProjectionPoint*>::const_iterator it = 
                points.begin(); it != points.end(); it++)
          {
            LogicalRegion result = functor->project(mappable, idx,
                req.partition, (*it)->get_domain_point());
            check_projection_partition_result(req, op, idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result,req.partition,launch_domain,region_deps);
                check_inversion((*it)->as_mappable(), idx, region_deps);
              }
              else
                check_containment((*it)->as_mappable(), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
        else
        {
          for (std::vector<ProjectionPoint*>::const_iterator it = 
                points.begin(); it != points.end(); it++)
          {
            LogicalRegion result = functor->project(mappable, idx, req.region,
                                                    (*it)->get_domain_point());
            check_projection_region_result(req, op, idx, result, runtime);
            (*it)->set_projection_result(idx, result);
            if (find_dependences)
            {
              std::vector<DomainPoint> &region_deps = dependences[result];
              if (region_deps.empty())
              {
                functor->invert(result, req.region, launch_domain, region_deps);
                check_inversion((*it)->as_mappable(), idx, region_deps);
              }
              else
                check_containment((*it)->as_mappable(), idx, region_deps);
              (*it)->record_intra_space_dependences(idx, region_deps);
            }
          }
        }
      }
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_projection_region_result(
        const RegionRequirement &req, const Task *task, unsigned idx,
        LogicalRegion result, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      // NO_REGION is always an acceptable answer
      if (result == LogicalRegion::NO_REGION)
        return;
      if (result.get_tree_id() != req.region.get_tree_id())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion of tree ID %d for region requirement %d "
            "of task %s (UID %lld) which is different from the upper "
            "bound node of tree ID %d", projection_id, 
            result.get_tree_id(), idx, task->get_task_name(), 
            task->get_unique_id(), req.region.get_tree_id())
#ifdef DEBUG_LEGION
      if (!runtime->forest->is_subregion(result, req.region))
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which is not a subregion of the "
            "upper bound region for region requirement %d of "
            "task %s (UID %lld)", projection_id, idx,
            task->get_task_name(), task->get_unique_id())
      const unsigned projection_depth = 
        runtime->forest->get_projection_depth(result, req.region);
      if (projection_depth != functor->get_depth())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which has projection depth %d which "
            "is different from stated projection depth of the functor "
            "which is %d for region requirement %d of task %s (ID %lld)",
            projection_id, projection_depth, functor->get_depth(),
            idx, task->get_task_name(), task->get_unique_id())
#endif
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_projection_partition_result(
        const RegionRequirement &req, const Task *task, unsigned idx,
        LogicalRegion result, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      // NO_REGION is always an acceptable answer
      if (result == LogicalRegion::NO_REGION)
        return;
      if (result.get_tree_id() != req.partition.get_tree_id())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion of tree ID %d for region requirement %d "
            "of task %s (UID %lld) which is different from the upper "
            "bound node of tree ID %d", projection_id, 
            result.get_tree_id(), idx, task->get_task_name(), 
            task->get_unique_id(), req.partition.get_tree_id())
#ifdef DEBUG_LEGION
      if (!runtime->forest->is_subregion(result, req.partition))
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which is not a subregion of the "
            "upper bound region for region requirement %d of "
            "task %s (UID %lld)", projection_id, idx,
            task->get_task_name(), task->get_unique_id())
      const unsigned projection_depth = 
        runtime->forest->get_projection_depth(result, req.partition);
      if (projection_depth != functor->get_depth())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which has projection depth %d which "
            "is different from stated projection depth of the functor "
            "which is %d for region requirement %d of task %s (ID %lld)",
            projection_id, projection_depth, functor->get_depth(),
            idx, task->get_task_name(), task->get_unique_id())
#endif
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_projection_region_result(
        const RegionRequirement &req, Operation *op, unsigned idx,
        LogicalRegion result, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      // NO_REGION is always an acceptable answer
      if (result == LogicalRegion::NO_REGION)
        return;
      if (result.get_tree_id() != req.region.get_tree_id())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion of tree ID %d for region requirement %d "
            "of operation %s (UID %lld) which is different from the upper "
            "bound node of tree ID %d", projection_id, 
            result.get_tree_id(), idx, op->get_logging_name(), 
            op->get_unique_op_id(), req.region.get_tree_id())
#ifdef DEBUG_LEGION
      if (!runtime->forest->is_subregion(result, req.region))
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which is not a subregion of the "
            "upper bound region for region requirement %d of "
            "operation %s (UID %lld)", projection_id, idx,
            op->get_logging_name(), op->get_unique_op_id())
      const unsigned projection_depth = 
        runtime->forest->get_projection_depth(result, req.region);
      if (projection_depth != functor->get_depth())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which has projection depth %d which "
            "is different from stated projection depth of the functor "
            "which is %d for region requirement %d of operation %s (ID %lld)",
            projection_id, projection_depth, functor->get_depth(),
            idx, op->get_logging_name(), op->get_unique_op_id())
#endif
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_projection_partition_result(
        const RegionRequirement &req, Operation *op, unsigned idx,
        LogicalRegion result, Runtime *runtime)
    //--------------------------------------------------------------------------
    {
      // NO_REGION is always an acceptable answer
      if (result == LogicalRegion::NO_REGION)
        return;
      if (result.get_tree_id() != req.partition.get_tree_id())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion of tree ID %d for region requirement %d "
            "of operation %s (UID %lld) which is different from the upper "
            "bound node of tree ID %d", projection_id, 
            result.get_tree_id(), idx, op->get_logging_name(), 
            op->get_unique_op_id(), req.partition.get_tree_id())
#ifdef DEBUG_LEGION
      if (!runtime->forest->is_subregion(result, req.partition))
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which is not a subregion of the "
            "upper bound region for region requirement %d of "
            "operation %s (UID %lld)", projection_id, idx,
            op->get_logging_name(), op->get_unique_op_id())
      const unsigned projection_depth = 
        runtime->forest->get_projection_depth(result, req.partition);
      if (projection_depth != functor->get_depth())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT, 
            "Projection functor %d produced an invalid "
            "logical subregion which has projection depth %d which "
            "is different from stated projection depth of the functor "
            "which is %d for region requirement %d of operation %s (ID %lld)",
            projection_id, projection_depth, functor->get_depth(),
            idx, op->get_logging_name(), op->get_unique_op_id())
#endif
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_inversion(const Task *task, unsigned index,
                                         const std::vector<DomainPoint> &points)
    //--------------------------------------------------------------------------
    {
      if (points.empty())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
            "Projection functor %d produced an empty inversion result "
            "while inverting region requirement %d of task %s (UID %lld). "
            "Empty inversions are never legal because the point task that "
            "produced the region must always be included.",
            projection_id, index, task->get_task_name(), task->get_unique_id())
#ifdef DEBUG_LEGION
      std::set<DomainPoint> unique_points(points.begin(), points.end());
      if (unique_points.size() != points.size())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
            "Projection functor %d produced an invalid inversion result "
            "containing duplicate points for region requirement %d of "
            "task %s (UID %lld). Each point is only permitted to "
            "appear once in an inversion.", projection_id, index,
            task->get_task_name(), task->get_unique_id())
      if (unique_points.find(task->index_point) == unique_points.end())
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
            "Projection functor %d produced an invalid inversion result "
            "that does not contain the original point for region requirement "
            "%d of task %s (UID %lld).", projection_id, index,
            task->get_task_name(), task->get_unique_id())
#endif
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_inversion(const Mappable *mappable, 
                         unsigned index, const std::vector<DomainPoint> &points)
    //--------------------------------------------------------------------------
    {
      switch (mappable->get_mappable_type())
      {
        case LEGION_COPY_MAPPABLE:
          {
            const Copy *copy = mappable->as_copy();
            if (points.empty())
              REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
                  "Projection functor %d produced an empty inversion result "
                  "while inverting region requirement %d of copy (UID %lld)."
                  "Empty inversions are never legal because the point copy "
                  "that produced the region must always be included.",
                  projection_id, index, copy->get_unique_id())
#ifdef DEBUG_LEGION
            std::set<DomainPoint> unique_points(points.begin(), points.end());
            if (unique_points.size() != points.size())
              REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
                  "Projection functor %d produced an invalid inversion result "
                  "containing duplicate points for region requirement %d of "
                  "copy (UID %lld). Each point is only permitted to "
                  "appear once in an inversion.", projection_id, index,
                  copy->get_unique_id())
            if (unique_points.find(copy->index_point) == unique_points.end())
              REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
                  "Projection functor %d produced an invalid inversion result "
                  "that does not contain the original point for region "
                  "requirement %d of copy (UID %lld).", projection_id, index,
                  copy->get_unique_id())
#endif
            break;
          }
        case LEGION_FILL_MAPPABLE:
          {
            const Fill *fill = mappable->as_fill();
            if (points.empty())
              REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
                  "Projection functor %d produced an empty inversion result "
                  "while inverting region requirement %d of fill (UID %lld)."
                  "Empty inversions are never legal because the point fill "
                  "that produced the region must always be included.",
                  projection_id, index, fill->get_unique_id())
#ifdef DEBUG_LEGION
            std::set<DomainPoint> unique_points(points.begin(), points.end());
            if (unique_points.size() != points.size())
              REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
                  "Projection functor %d produced an invalid inversion result "
                  "containing duplicate points for region requirement %d of "
                  "fill (UID %lld). Each point is only permitted to "
                  "appear once in an inversion.", projection_id, index,
                  fill->get_unique_id())
            if (unique_points.find(fill->index_point) == unique_points.end())
              REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
                  "Projection functor %d produced an invalid inversion result "
                  "that does not contain the original point for region "
                  "requirement %d of fill (UID %lld).", projection_id, index,
                  fill->get_unique_id())
#endif
            break;
          }
        default:
          assert(false);
      }
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_containment(const Task *task, unsigned index,
                                         const std::vector<DomainPoint> &points)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      for (std::vector<DomainPoint>::const_iterator it = 
            points.begin(); it != points.end(); it++)
      {
        if ((*it) == task->index_point)
          return;
      }
      REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
          "Projection functor %d produced an invalid inversion result "
          "that does not contain the original point for region requirement "
          "%d of task %s (UID %lld).", projection_id, index,
          task->get_task_name(), task->get_unique_id())
#endif
    }

    //--------------------------------------------------------------------------
    void ProjectionFunction::check_containment(const Mappable *mappable, 
                         unsigned index, const std::vector<DomainPoint> &points)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      
      switch (mappable->get_mappable_type())
      {
        case LEGION_COPY_MAPPABLE:
          {
            const Copy *copy = mappable->as_copy();
            for (std::vector<DomainPoint>::const_iterator it = 
                  points.begin(); it != points.end(); it++)
            {
              if ((*it) == copy->index_point)
                return;
            }
            REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
              "Projection functor %d produced an invalid inversion result "
              "that does not contain the original point for region requirement "
              "%d of copy (UID %lld).", projection_id, index,
              copy->get_unique_id())
            break;
          }
        case LEGION_FILL_MAPPABLE:
          {
            const Fill *fill = mappable->as_fill();
            for (std::vector<DomainPoint>::const_iterator it = 
                  points.begin(); it != points.end(); it++)
            {
              if ((*it) == fill->index_point)
                return;
            }
            REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_RESULT,
              "Projection functor %d produced an invalid inversion result "
              "that does not contain the original point for region requirement "
              "%d of fill (UID %lld).", projection_id, index,
              fill->get_unique_id())
            break;
          }
        default:
          assert(false);
      
      }
#endif
    }

    /////////////////////////////////////////////////////////////
    // Legion Runtime 
    /////////////////////////////////////////////////////////////

    //--------------------------------------------------------------------------
    Runtime::Runtime(Machine m, const LegionConfiguration &config, 
                     bool background, InputArgs args, AddressSpaceID unique,
                     const std::set<Processor> &locals,
                     const std::set<Processor> &local_utilities,
                     const std::set<AddressSpaceID> &address_spaces,
                     const std::map<Processor,AddressSpaceID> &processor_spaces,
                     bool default_mapper)
      : external(new Legion::Runtime(this)),
        mapper_runtime(new Legion::Mapping::MapperRuntime()),
        machine(m), address_space(unique), 
        total_address_spaces(address_spaces.size()),
        runtime_stride(address_spaces.size()), profiler(NULL),
        forest(new RegionTreeForest(this)), virtual_manager(NULL), 
        num_utility_procs(local_utilities.empty() ? locals.size() : 
                          local_utilities.size()), input_args(args),
        initial_task_window_size(config.initial_task_window_size),
        initial_task_window_hysteresis(config.initial_task_window_hysteresis),
        initial_tasks_to_schedule(config.initial_tasks_to_schedule),
        initial_meta_task_vector_width(config.initial_meta_task_vector_width),
        max_message_size(config.max_message_size),
        gc_epoch_size(config.gc_epoch_size),
        max_local_fields(config.max_local_fields),
        max_replay_parallelism(config.max_replay_parallelism),
        program_order_execution(config.program_order_execution),
        dump_physical_traces(config.dump_physical_traces),
        no_tracing(config.no_tracing),
        no_physical_tracing(config.no_physical_tracing),
        no_trace_optimization(config.no_trace_optimization),
        no_fence_elision(config.no_fence_elision),
        replay_on_cpus(config.replay_on_cpus),
        verify_partitions(config.verify_partitions),
        runtime_warnings(config.runtime_warnings),
        warnings_backtrace(config.warnings_backtrace),
        report_leaks(config.report_leaks),
        separate_runtime_instances(config.separate_runtime_instances),
        record_registration(config.record_registration),
        stealing_disabled(config.stealing_disabled),
        resilient_mode(config.resilient_mode),
        unsafe_launch(config.unsafe_launch),
#ifdef DEBUG_LEGION
        unsafe_mapper(config.unsafe_mapper),
#else
        unsafe_mapper(!config.safe_mapper),
#endif
        disable_independence_tests(config.disable_independence_tests),
        legion_spy_enabled(config.legion_spy_enabled),
        supply_default_mapper(default_mapper),
        enable_test_mapper(config.enable_test_mapper),
        legion_ldb_enabled(!config.ldb_file.empty()),
        replay_file(legion_ldb_enabled ? config.ldb_file : config.replay_file),
#ifdef DEBUG_LEGION
        logging_region_tree_state(config.logging_region_tree_state),
        verbose_logging(config.verbose_logging),
        logical_logging_only(config.logical_logging_only),
        physical_logging_only(config.physical_logging_only),
#endif
        check_privileges(config.check_privileges),
        num_profiling_nodes(config.num_profiling_nodes),
        legion_collective_radix(config.legion_collective_radix),
        legion_collective_log_radix(config.legion_collective_log_radix),
        legion_collective_stages(config.legion_collective_stages),
        legion_collective_last_radix(config.legion_collective_last_radix),
        legion_collective_participating_spaces(
                           config.legion_collective_participating_spaces),
        mpi_rank_table((mpi_rank >= 0) ? new MPIRankTable(this) : NULL),
        prepared_for_shutdown(false), total_outstanding_tasks(0), 
        // In the case where the runtime is backgrounded, have node 0 keep
        // a reference for each node so that we wait until we see all wait
        // call from each node before we start trying to perform a shutdown
        outstanding_top_level_tasks(
            ((unique == 0) && background) ? total_address_spaces : 0),
        local_procs(locals), local_utils(local_utilities),
        proc_spaces(processor_spaces),
        unique_index_space_id((unique == 0) ? runtime_stride : unique),
        unique_index_partition_id((unique == 0) ? runtime_stride : unique), 
        unique_field_space_id((unique == 0) ? runtime_stride : unique),
        unique_index_tree_id((unique == 0) ? runtime_stride : unique),
        unique_region_tree_id((unique == 0) ? runtime_stride : unique),
        unique_field_id(LEGION_MAX_APPLICATION_FIELD_ID + 
                        ((unique == 0) ? runtime_stride : unique)),
        unique_operation_id((unique == 0) ? runtime_stride : unique),
        unique_code_descriptor_id(LG_TASK_ID_AVAILABLE +
                        ((unique == 0) ? runtime_stride : unique)),
        unique_constraint_id((unique == 0) ? runtime_stride : unique),
        unique_is_expr_id((unique == 0) ? runtime_stride : unique),
#ifdef LEGION_SPY
        unique_indirections_id((unique == 0) ? runtime_stride : unique),
#endif
        unique_task_id(get_current_static_task_id()+unique),
        unique_mapper_id(get_current_static_mapper_id()+unique),
        unique_trace_id(get_current_static_trace_id()+unique),
        unique_projection_id(get_current_static_projection_id()+unique),
        unique_redop_id(get_current_static_reduction_id()+unique),
        unique_serdez_id(get_current_static_serdez_id()+unique),
        unique_library_mapper_id(LEGION_INITIAL_LIBRARY_ID_OFFSET),
        unique_library_trace_id(LEGION_INITIAL_LIBRARY_ID_OFFSET),
        unique_library_projection_id(LEGION_INITIAL_LIBRARY_ID_OFFSET),
        unique_library_task_id(LEGION_INITIAL_LIBRARY_ID_OFFSET),
        unique_library_redop_id(LEGION_INITIAL_LIBRARY_ID_OFFSET),
        unique_library_serdez_id(LEGION_INITIAL_LIBRARY_ID_OFFSET),
        unique_distributed_id((unique == 0) ? runtime_stride : unique)
    //--------------------------------------------------------------------------
    {
      if (LEGION_MAX_NUM_NODES <= address_space)
        REPORT_LEGION_ERROR(ERROR_MAXIMUM_NODES_EXCEEDED,
            "Maximum number of nodes exceeded. Detected node %d but "
            "'LEGION_MAX_NUM_NODES' is set to %d. Change the value of "
            "'LEGION_MAX_NUM_NODES' in legion_config.h and recompile. "
            "Please note that 'LEGION_MAX_NUM_NODES' must be a power of two.",
            address_space, LEGION_MAX_NUM_NODES)
      log_run.debug("Initializing Legion runtime in address space %x",
                            address_space);
      // Construct a local utility processor group
      if (local_utils.empty())
      {
        // make the utility group the set of all the local processors
#ifdef DEBUG_LEGION
        assert(!locals.empty());
#endif
        if (locals.size() == 1)
          utility_group = *(locals.begin());
        else
        {
          std::vector<Processor> util_group(locals.begin(), locals.end());
          utility_group = ProcessorGroup::create_group(util_group);
        }
      }
      else if (local_utils.size() == 1)
        utility_group = *(local_utils.begin());
      else
      {
        std::vector<Processor> util_g(local_utils.begin(), local_utils.end());
        utility_group = ProcessorGroup::create_group(util_g);
      }
#ifdef DEBUG_LEGION
      assert(utility_group.exists());
#endif
      // For each of the processors in our local set construct a manager
      for (std::set<Processor>::const_iterator it = local_procs.begin();
            it != local_procs.end(); it++)
      {
#ifdef DEBUG_LEGION
        assert((*it).kind() != Processor::UTIL_PROC);
#endif
        ProcessorManager *manager = new ProcessorManager(*it,
				    (*it).kind(), this,
                                    LEGION_DEFAULT_MAPPER_SLOTS, 
                                    stealing_disabled,
                                    !replay_file.empty());
        proc_managers[*it] = manager;
      }
      // Initialize the message manager array so that we can construct
      // message managers lazily as they are needed
      for (unsigned idx = 0; idx < LEGION_MAX_NUM_NODES; idx++)
        message_managers[idx].store(NULL);
      
      // Make the default number of contexts
      // No need to hold the lock yet because nothing is running
      for (total_contexts = 0; total_contexts < LEGION_DEFAULT_CONTEXTS; 
            total_contexts++)
      {
        available_contexts.push_back(RegionTreeContext(total_contexts)); 
      }
      // Initialize our random number generator state
      random_state[0] = address_space & 0xFFFF; // low-order bits of node ID 
      random_state[1] = (address_space >> 16) & 0xFFFF; // high-order bits
      random_state[2] = LEGION_INIT_SEED;
      // Do some mixing
      for (int i = 0; i < 256; i++)
        nrand48(random_state);
      // We've intentionally switched this to profile all the nodes if we're 
      // profiling any nodes since some information about things like copies
      // usage of instances are now split across multiple log files
      if (num_profiling_nodes > 0)
        initialize_legion_prof(config);
#ifdef LEGION_TRACE_ALLOCATION
      allocation_tracing_count.store(0);
      // Instantiate all the kinds of allocations
      for (unsigned idx = ARGUMENT_MAP_ALLOC; idx < UNTRACKED_ALLOC; idx++)
        allocation_manager[((AllocationType)idx)] = AllocationTracker();
#endif
#ifdef LEGION_GC
      {
        REFERENCE_NAMES_ARRAY(reference_names);
        for (unsigned idx = 0; idx < LAST_SOURCE_REF; idx++)
        {
          log_garbage.info("GC Source Kind %d %s", idx, reference_names[idx]);
        }
      }
#endif 
#ifdef DEBUG_LEGION
      if (logging_region_tree_state)
      {
	tree_state_logger = new TreeStateLogger(address_space, 
                                                verbose_logging,
                                                logical_logging_only,
                                                physical_logging_only);
	assert(tree_state_logger != NULL);
      } else {
	tree_state_logger = NULL;
      }
#endif
#ifdef DEBUG_SHUTDOWN_HANG
      outstanding_counts = std::vector<std::atomic<int> >(LG_LAST_TASK_ID);
      for (unsigned idx = 0; idx < outstanding_counts.size(); idx++)
        outstanding_counts[idx].store(0);
#endif
      // Attach any accessor debug hooks for privilege or bounds checks
#ifdef LEGION_PRIVILEGE_CHECKS
      LegionRuntime::Accessor::DebugHooks::find_privilege_task_name =
	&Legion::Internal::Runtime::find_privilege_task_name;
#endif
#ifdef LEGION_BOUNDS_CHECKS
      LegionRuntime::Accessor::DebugHooks::check_bounds_ptr =
	&Legion::Internal::Runtime::check_bounds;
      LegionRuntime::Accessor::DebugHooks::check_bounds_dpoint =
	&Legion::Internal::Runtime::check_bounds;
#endif 
    }

    //--------------------------------------------------------------------------
    Runtime::Runtime(const Runtime &rhs)
      : external(NULL), mapper_runtime(NULL), machine(rhs.machine), 
        address_space(0), total_address_spaces(0), runtime_stride(0), 
        profiler(NULL), forest(NULL), 
        num_utility_procs(rhs.num_utility_procs), input_args(rhs.input_args),
        initial_task_window_size(rhs.initial_task_window_size),
        initial_task_window_hysteresis(rhs.initial_task_window_hysteresis),
        initial_tasks_to_schedule(rhs.initial_tasks_to_schedule),
        initial_meta_task_vector_width(rhs.initial_meta_task_vector_width),
        max_message_size(rhs.max_message_size),
        gc_epoch_size(rhs.gc_epoch_size), 
        max_local_fields(rhs.max_local_fields),
        max_replay_parallelism(rhs.max_replay_parallelism),
        program_order_execution(rhs.program_order_execution),
        dump_physical_traces(rhs.dump_physical_traces),
        no_tracing(rhs.no_tracing),
        no_physical_tracing(rhs.no_physical_tracing),
        no_trace_optimization(rhs.no_trace_optimization),
        no_fence_elision(rhs.no_fence_elision),
        replay_on_cpus(rhs.replay_on_cpus),
        verify_partitions(rhs.verify_partitions),
        runtime_warnings(rhs.runtime_warnings),
        warnings_backtrace(rhs.warnings_backtrace),
        report_leaks(rhs.report_leaks),
        separate_runtime_instances(rhs.separate_runtime_instances),
        record_registration(rhs.record_registration),
        stealing_disabled(rhs.stealing_disabled),
        resilient_mode(rhs.resilient_mode),
        unsafe_launch(rhs.unsafe_launch),
        unsafe_mapper(rhs.unsafe_mapper),
        disable_independence_tests(rhs.disable_independence_tests),
        legion_spy_enabled(rhs.legion_spy_enabled),
        supply_default_mapper(rhs.supply_default_mapper),
        enable_test_mapper(rhs.enable_test_mapper),
        legion_ldb_enabled(rhs.legion_ldb_enabled),
        replay_file(rhs.replay_file),
#ifdef DEBUG_LEGION
        logging_region_tree_state(rhs.logging_region_tree_state),
        verbose_logging(rhs.verbose_logging),
        logical_logging_only(rhs.logical_logging_only),
        physical_logging_only(rhs.physical_logging_only),
#endif
        check_privileges(rhs.check_privileges),
        num_profiling_nodes(rhs.num_profiling_nodes),
        legion_collective_radix(rhs.legion_collective_radix),
        legion_collective_log_radix(rhs.legion_collective_log_radix),
        legion_collective_stages(rhs.legion_collective_stages),
        legion_collective_last_radix(rhs.legion_collective_last_radix),
        legion_collective_participating_spaces(
                           rhs.legion_collective_participating_spaces),
        mpi_rank_table(NULL), local_procs(rhs.local_procs), 
        local_utils(rhs.local_utils), proc_spaces(rhs.proc_spaces)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
    }

    //--------------------------------------------------------------------------
    Runtime::~Runtime(void)
    //--------------------------------------------------------------------------
    {
      // Make sure we don't send anymore messages
      for (unsigned idx = 0; idx < LEGION_MAX_NUM_NODES; idx++)
      {
        MessageManager *manager = message_managers[idx].load();
        if (manager != NULL)
        {
          delete manager;
          message_managers[idx].store(NULL);
        }
      }
      if (profiler != NULL)
      {
        delete profiler;
        profiler = NULL;
      }
      // Free any input arguments
      if (input_args.argc > 0)
      {
        for (int i = 0; i < input_args.argc; i++)
          if (input_args.argv[i] != NULL)
            free(input_args.argv[i]);
        free(input_args.argv);
      }
      delete forest;
      delete external;
      delete mapper_runtime;
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        delete it->second;
      }
      proc_managers.clear();
      // Avoid duplicate deletions on these for separate runtime
      // instances by just leaking them for now
      if (!separate_runtime_instances)
      {
        for (std::map<ProjectionID,ProjectionFunction*>::
              iterator it = projection_functions.begin(); 
              it != projection_functions.end(); it++)
        {
          delete it->second;
        } 
        projection_functions.clear();
      }
      for (std::deque<IndividualTask*>::const_iterator it = 
            available_individual_tasks.begin(); 
            it != available_individual_tasks.end(); it++)
      {
        delete (*it);
      }
      available_individual_tasks.clear();
      for (std::deque<PointTask*>::const_iterator it = 
            available_point_tasks.begin(); it != 
            available_point_tasks.end(); it++)
      {
        delete (*it);
      }
      available_point_tasks.clear();
      for (std::deque<IndexTask*>::const_iterator it = 
            available_index_tasks.begin(); it != 
            available_index_tasks.end(); it++)
      {
        delete (*it);
      }
      available_index_tasks.clear();
      for (std::deque<SliceTask*>::const_iterator it = 
            available_slice_tasks.begin(); it != 
            available_slice_tasks.end(); it++)
      {
        delete (*it);
      }
      available_slice_tasks.clear();
      for (std::deque<MapOp*>::const_iterator it = 
            available_map_ops.begin(); it != 
            available_map_ops.end(); it++)
      {
        delete (*it);
      }
      available_map_ops.clear();
      for (std::deque<CopyOp*>::const_iterator it = 
            available_copy_ops.begin(); it != 
            available_copy_ops.end(); it++)
      {
        delete (*it);
      }
      available_copy_ops.clear();
      for (std::deque<FenceOp*>::const_iterator it = 
            available_fence_ops.begin(); it != 
            available_fence_ops.end(); it++)
      {
        delete (*it);
      }
      available_fence_ops.clear();
      for (std::deque<FrameOp*>::const_iterator it = 
            available_frame_ops.begin(); it !=
            available_frame_ops.end(); it++)
      {
        delete (*it);
      }
      available_frame_ops.clear();
      for (std::deque<CreationOp*>::const_iterator it = 
            available_creation_ops.begin(); it != 
            available_creation_ops.end(); it++)
      {
        delete (*it);
      }
      available_creation_ops.clear();
      for (std::deque<DeletionOp*>::const_iterator it = 
            available_deletion_ops.begin(); it != 
            available_deletion_ops.end(); it++)
      {
        delete (*it);
      }
      available_deletion_ops.clear();
      for (std::deque<MergeCloseOp*>::const_iterator it = 
            available_merge_close_ops.begin(); it !=
            available_merge_close_ops.end(); it++)
      {
        delete (*it);
      }
      available_merge_close_ops.clear();
      for (std::deque<PostCloseOp*>::const_iterator it = 
            available_post_close_ops.begin(); it !=
            available_post_close_ops.end(); it++)
      {
        delete (*it);
      }
      available_post_close_ops.clear();
      for (std::deque<VirtualCloseOp*>::const_iterator it = 
            available_virtual_close_ops.begin(); it !=
            available_virtual_close_ops.end(); it++)
      {
        delete (*it);
      }
      available_virtual_close_ops.clear();
      for (std::deque<DynamicCollectiveOp*>::const_iterator it = 
            available_dynamic_collective_ops.begin(); it !=
            available_dynamic_collective_ops.end(); it++)
      {
        delete (*it);
      }
      available_dynamic_collective_ops.clear();
      for (std::deque<FuturePredOp*>::const_iterator it = 
            available_future_pred_ops.begin(); it !=
            available_future_pred_ops.end(); it++)
      {
        delete (*it);
      }
      available_future_pred_ops.clear();
      for (std::deque<NotPredOp*>::const_iterator it = 
            available_not_pred_ops.begin(); it !=
            available_not_pred_ops.end(); it++)
      {
        delete (*it);
      }
      available_not_pred_ops.clear();
      for (std::deque<AndPredOp*>::const_iterator it = 
            available_and_pred_ops.begin(); it !=
            available_and_pred_ops.end(); it++)
      {
        delete (*it);
      }
      available_and_pred_ops.clear();
      for (std::deque<OrPredOp*>::const_iterator it = 
            available_or_pred_ops.begin(); it !=
            available_or_pred_ops.end(); it++)
      {
        delete (*it);
      }
      available_or_pred_ops.clear();
      for (std::deque<AcquireOp*>::const_iterator it = 
            available_acquire_ops.begin(); it !=
            available_acquire_ops.end(); it++)
      {
        delete (*it);
      }
      available_acquire_ops.clear();
      for (std::deque<ReleaseOp*>::const_iterator it = 
            available_release_ops.begin(); it !=
            available_release_ops.end(); it++)
      {
        delete (*it);
      }
      available_release_ops.clear();
      for (std::deque<TraceCaptureOp*>::const_iterator it = 
            available_capture_ops.begin(); it !=
            available_capture_ops.end(); it++)
      {
        delete (*it);
      }
      available_capture_ops.clear();
      for (std::deque<TraceCompleteOp*>::const_iterator it = 
            available_trace_ops.begin(); it !=
            available_trace_ops.end(); it++)
      {
        delete (*it);
      }
      available_trace_ops.clear();
      for (std::deque<TraceReplayOp*>::const_iterator it = 
            available_replay_ops.begin(); it !=
            available_replay_ops.end(); it++)
      {
        delete (*it);
      }
      available_replay_ops.clear();
      for (std::deque<TraceBeginOp*>::const_iterator it = 
            available_begin_ops.begin(); it !=
            available_begin_ops.end(); it++)
      {
        delete (*it);
      }
      available_begin_ops.clear();
      for (std::deque<TraceSummaryOp*>::const_iterator it = 
            available_summary_ops.begin(); it !=
            available_summary_ops.end(); it++)
      {
        delete (*it);
      }
      available_summary_ops.clear();
      for (std::deque<MustEpochOp*>::const_iterator it = 
            available_epoch_ops.begin(); it !=
            available_epoch_ops.end(); it++)
      {
        delete (*it);
      }
      available_epoch_ops.clear();
      for (std::deque<PendingPartitionOp*>::const_iterator it = 
            available_pending_partition_ops.begin(); it !=
            available_pending_partition_ops.end(); it++)
      {
        delete (*it);
      }
      available_pending_partition_ops.clear();
      for (std::deque<DependentPartitionOp*>::const_iterator it = 
            available_dependent_partition_ops.begin(); it !=
            available_dependent_partition_ops.end(); it++)
      {
        delete (*it);
      }
      available_dependent_partition_ops.clear();
      for (std::deque<FillOp*>::const_iterator it = 
            available_fill_ops.begin(); it !=
            available_fill_ops.end(); it++)
      {
        delete (*it);
      }
      available_fill_ops.clear();
      for (std::deque<AttachOp*>::const_iterator it = 
            available_attach_ops.begin(); it !=
            available_attach_ops.end(); it++)
      {
        delete (*it);
      }
      available_attach_ops.clear();
      for (std::deque<IndexAttachOp*>::const_iterator it = 
            available_index_attach_ops.begin(); it !=
            available_index_attach_ops.end(); it++)
      {
        delete (*it);
      }
      available_index_attach_ops.clear();
      for (std::deque<PointAttachOp*>::const_iterator it = 
            available_point_attach_ops.begin(); it !=
            available_point_attach_ops.end(); it++)
      {
        delete (*it);
      }
      available_point_attach_ops.clear();
      for (std::deque<DetachOp*>::const_iterator it = 
            available_detach_ops.begin(); it !=
            available_detach_ops.end(); it++)
      {
        delete (*it);
      }
      available_detach_ops.clear();
      for (std::deque<IndexDetachOp*>::const_iterator it = 
            available_index_detach_ops.begin(); it !=
            available_index_detach_ops.end(); it++)
      {
        delete (*it);
      }
      available_index_detach_ops.clear();
      for (std::deque<PointDetachOp*>::const_iterator it = 
            available_point_detach_ops.begin(); it !=
            available_point_detach_ops.end(); it++)
      {
        delete (*it);
      }
      available_point_detach_ops.clear();
      for (std::deque<TimingOp*>::const_iterator it = 
            available_timing_ops.begin(); it != 
            available_timing_ops.end(); it++)
      {
        delete (*it);
      }
      available_timing_ops.clear();
      for (std::deque<TunableOp*>::const_iterator it =
            available_tunable_ops.begin(); it !=
            available_tunable_ops.end(); it++)
      {
        delete (*it);
      }
      available_tunable_ops.clear();
      for (std::deque<AllReduceOp*>::const_iterator it = 
            available_all_reduce_ops.begin(); it !=
            available_all_reduce_ops.end(); it++)
      {
        delete (*it);
      }
      available_all_reduce_ops.clear();
      for (std::map<TaskID,TaskImpl*>::const_iterator it = 
            task_table.begin(); it != task_table.end(); it++)
      {
        delete (it->second);
      }
      task_table.clear();
      // Skip this if we are in separate runtime mode
      if (!separate_runtime_instances)
      {
        for (std::deque<VariantImpl*>::const_iterator it = 
              variant_table.begin(); it != variant_table.end(); it++)
        {
          delete (*it);
        }
      }
      variant_table.clear();
      // Skip this if we are in separate runtime mode
      if (!separate_runtime_instances)
      {
        while (!layout_constraints_table.empty())
        {
          std::map<LayoutConstraintID,LayoutConstraints*>::iterator next_it = 
            layout_constraints_table.begin();
          LayoutConstraints *next = next_it->second;
          layout_constraints_table.erase(next_it);
          if (next->remove_base_resource_ref(RUNTIME_REF))
            delete (next);
        }
        // We can also delete all of our reduction operators
        ReductionOpTable &redop_table = get_reduction_table(true/*safe*/);
        while (!redop_table.empty())
        {
          ReductionOpTable::iterator it = redop_table.begin();
          delete it->second;
          redop_table.erase(it);
        }
      }
      for (LegionMap<uint64_t,LegionDeque<ProcessorGroupInfo>,
            PROCESSOR_GROUP_ALLOC>::const_iterator git = 
            processor_groups.begin(); git != processor_groups.end(); git++)
        for (LegionDeque<ProcessorGroupInfo>::const_iterator it = 
              git->second.begin(); it != git->second.end(); it++)
          it->processor_group.destroy();
      for (std::map<Memory,MemoryManager*>::const_iterator it =
            memory_managers.begin(); it != memory_managers.end(); it++)
      {
        delete it->second;
      }
      memory_managers.clear();
#ifdef DEBUG_LEGION
      if (logging_region_tree_state)
	delete tree_state_logger;
#endif
    }

    //--------------------------------------------------------------------------
    Runtime& Runtime::operator=(const Runtime &rhs)
    //--------------------------------------------------------------------------
    {
      // should never be called
      assert(false);
      return *this;
    }

    //--------------------------------------------------------------------------
    void Runtime::register_static_variants(void)
    //--------------------------------------------------------------------------
    {
      std::deque<PendingVariantRegistration*> &pending_variants = 
        get_pending_variant_table();
      if (!pending_variants.empty())
      {
        for (std::deque<PendingVariantRegistration*>::const_iterator it =
              pending_variants.begin(); it != pending_variants.end(); it++)
        {
          (*it)->perform_registration(this);
          // avoid races on separate runtime instances
          if (!separate_runtime_instances)
            delete *it;
        }
        // avoid races on separate runtime instances
        if (!separate_runtime_instances)
          pending_variants.clear();
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::register_static_constraints(void)
    //--------------------------------------------------------------------------
    {
      // Register any pending constraint sets
      std::map<LayoutConstraintID,LayoutConstraintRegistrar> 
        &pending_constraints = get_pending_constraint_table();
      if (!pending_constraints.empty())
      {
        // Update the next available constraint
        LayoutConstraintID largest = 0;
        // Now do the registrations
        std::map<AddressSpaceID,unsigned> address_counts;
        for (std::map<LayoutConstraintID,LayoutConstraintRegistrar>::
              const_iterator it = pending_constraints.begin(); 
              it != pending_constraints.end(); it++)
        {
          largest = it->first;
          // Figure out the distributed ID that we expect and then
          // check against what we expect on the owner node. This
          // is slightly brittle, but we'll always catch it when
          // we break the invariant.
          const AddressSpaceID owner_space = 
            LayoutConstraints::get_owner_space(it->first, this);
          // Compute the expected DID
          DistributedID expected_did;
          std::map<AddressSpaceID,unsigned>::iterator finder = 
            address_counts.find(owner_space);
          if (finder != address_counts.end())
          {
            if (owner_space == 0)
              expected_did = (finder->second+1) * runtime_stride;
            else
              expected_did = owner_space + (finder->second * runtime_stride);
            finder->second++;
          }
          else
          {
            if (owner_space == 0)
              expected_did = runtime_stride;
            else
              expected_did = owner_space;
            address_counts[owner_space] = 1;
          }
          // Now if we're the owner we have to actually bump the distributed ID
          // number to reflect that we allocated, we'll also confirm that it
          // is what we expected
          if (owner_space == address_space)
          {
            const DistributedID did = get_available_distributed_id();
            if (did != expected_did)
              assert(false);
          }
          register_layout(it->second, it->first, expected_did);
        }
        // Round largest up to the next biggest multiple of the total spaces
        // so that the new unique constraint id still maps to this node
        size_t remainder = largest % total_address_spaces;
        if (remainder != 0)
          largest += (total_address_spaces - remainder);
        // Update all the next unique constraint IDs
        unique_constraint_id += largest;
        // avoid races if we are doing separate runtime creation
        if (!separate_runtime_instances)
          pending_constraints.clear();
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::register_static_projections(void)
    //--------------------------------------------------------------------------
    {
      std::map<ProjectionID,ProjectionFunctor*> &pending_projection_functors =
        get_pending_projection_table();
      for (std::map<ProjectionID,ProjectionFunctor*>::const_iterator it =
            pending_projection_functors.begin(); it !=
            pending_projection_functors.end(); it++)
      {
        it->second->set_runtime(external);
        register_projection_functor(it->first, it->second, true/*need check*/,
                          true/*was preregistered*/, NULL, true/*pregistered*/);
      }
      register_projection_functor(0, 
          new IdentityProjectionFunctor(this->external), false/*need check*/,
                        true/*was preregistered*/, NULL, true/*preregistered*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::initialize_legion_prof(const LegionConfiguration &config)
    //--------------------------------------------------------------------------
    {
      // For the profiler we want to find as many "holes" in the execution
      // as possible in which to run profiler tasks so we can minimize the
      // overhead on the application. To do this we want profiler tasks to
      // run on any processor that has a dedicated core which is either any
      // CPU processor a utility processor. There's no need to use GPU or
      // I/O processors since they share the same cores as the utility cores. 
      std::vector<Processor> prof_procs(local_utils.begin(), local_utils.end());
      for (std::set<Processor>::const_iterator it = local_procs.begin();
            it != local_procs.end(); it++)
      {
        if (it->kind() == Processor::LOC_PROC)
          prof_procs.push_back(*it);
      }
#ifdef DEBUG_LEGION
      assert(!prof_procs.empty());
#endif
      const Processor target_proc_for_profiler = prof_procs.size() > 1 ?
        ProcessorGroup::create_group(prof_procs) : prof_procs.front();
      LG_TASK_DESCRIPTIONS(lg_task_descriptions);
      LG_MESSAGE_DESCRIPTIONS(lg_message_descriptions);
      LEGION_STATIC_ASSERT((LG_MESSAGE_ID+1) == LG_LAST_TASK_ID,
          "LG_MESSAGE_ID must always be the last meta-task ID");
      profiler = new LegionProfiler(target_proc_for_profiler,
                                    machine, this, LG_MESSAGE_ID,
                                    lg_task_descriptions, LAST_SEND_KIND, 
                                    lg_message_descriptions,
                                    Operation::LAST_OP_KIND,
                                    Operation::op_names,
                                    config.serializer_type.c_str(),
                                    config.prof_logfile.c_str(),
                                    total_address_spaces,
                                    config.prof_footprint_threshold << 20,
                                    config.prof_target_latency,
                                    config.slow_config_ok);
      MAPPER_CALL_NAMES(lg_mapper_calls);
      profiler->record_mapper_call_kinds(lg_mapper_calls, LAST_MAPPER_CALL);
#ifdef DETAILED_LEGION_PROF
      RUNTIME_CALL_DESCRIPTIONS(lg_runtime_calls);
      profiler->record_runtime_call_kinds(lg_runtime_calls, 
                                          LAST_RUNTIME_CALL_KIND);
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::log_machine(Machine machine) const
    //--------------------------------------------------------------------------
    {
      if (!legion_spy_enabled)
        return;
      std::set<Processor::Kind> proc_kinds;
      Machine::ProcessorQuery all_procs(machine);
#define COUNTER(X,Y) +1
      constexpr size_t num_procs = REALM_PROCESSOR_KINDS(COUNTER);
      static_assert(num_procs == 9, "Add new processor kinds"); 
#undef COUNTER
      // Log processors
      for (Machine::ProcessorQuery::iterator it = all_procs.begin();
            it != all_procs.end(); it++)
      {
        Processor::Kind kind = it->kind();
        if (proc_kinds.find(kind) == proc_kinds.end())
        {
          switch (kind)
          {
            case Processor::NO_KIND:
              {
                LegionSpy::log_processor_kind(kind, "NoProc");
                break;
              }
            case Processor::TOC_PROC:
              {
                LegionSpy::log_processor_kind(kind, "GPU");
                break;
              }
            case Processor::LOC_PROC:
              {
                LegionSpy::log_processor_kind(kind, "CPU");
                break;
              }
            case Processor::UTIL_PROC:
              {
                LegionSpy::log_processor_kind(kind, "Utility");
                break;
              }
            case Processor::IO_PROC:
              {
                LegionSpy::log_processor_kind(kind, "IO");
                break;
              }
            case Processor::PROC_GROUP:
              {
                LegionSpy::log_processor_kind(kind, "ProcGroup");
                break;
              }
            case Processor::PROC_SET:
              {
                LegionSpy::log_processor_kind(kind, "ProcSet");
                break;
              }
            case Processor::OMP_PROC:
              {
                LegionSpy::log_processor_kind(kind, "OpenMP");
                break;
              }
            case Processor::PY_PROC:
              {
                LegionSpy::log_processor_kind(kind, "Python");
                break;
              }
            default:
              assert(false); // unknown processor kind
          }
          proc_kinds.insert(kind);
        }
        LegionSpy::log_processor(it->id, kind);
      }
      // Log memories
      std::set<Memory::Kind> mem_kinds;
      Machine::MemoryQuery all_mems(machine);
#define COUNTER(X,Y) +1
      constexpr size_t num_mems = REALM_MEMORY_KINDS(COUNTER);
      static_assert(num_mems == 15, "Add new memory kinds"); 
#undef COUNTER
      for (Machine::MemoryQuery::iterator it = all_mems.begin();
            it != all_mems.end(); it++)
      {
        Memory::Kind kind = it->kind();
        if (mem_kinds.find(kind) == mem_kinds.end())
        {
          switch (kind)
          {
	    case Memory::GLOBAL_MEM:
              {
                LegionSpy::log_memory_kind(kind, "GASNet");
                break;
              }
	    case Memory::SYSTEM_MEM:
              {
                LegionSpy::log_memory_kind(kind, "System");
                break;
              }
	    case Memory::REGDMA_MEM:
              {
                LegionSpy::log_memory_kind(kind, "Registered");
                break;
              }
	    case Memory::SOCKET_MEM:
              {
                LegionSpy::log_memory_kind(kind, "NUMA");
                break;
              }
	    case Memory::Z_COPY_MEM:
              {
                LegionSpy::log_memory_kind(kind, "Zero-Copy");
                break;
              }
	    case Memory::GPU_FB_MEM:
              {
                LegionSpy::log_memory_kind(kind, "Framebuffer");
                break;
              }
	    case Memory::DISK_MEM:
              {
                LegionSpy::log_memory_kind(kind, "Disk");
                break;
              }
	    case Memory::HDF_MEM:
              {
                LegionSpy::log_memory_kind(kind, "HDF");
                break;
              }
	    case Memory::FILE_MEM:
              {
                LegionSpy::log_memory_kind(kind, "File");
                break;
              }
	    case Memory::LEVEL3_CACHE:
              {
                LegionSpy::log_memory_kind(kind, "L3");
                break;
              }
	    case Memory::LEVEL2_CACHE:
              {
                LegionSpy::log_memory_kind(kind, "L2");
                break;
              }
	    case Memory::LEVEL1_CACHE:
              {
                LegionSpy::log_memory_kind(kind, "L1");
                break;
              }
            case Memory::GPU_MANAGED_MEM:
              {
                LegionSpy::log_memory_kind(kind, "UVM");
                break;
              }
            case Memory::GPU_DYNAMIC_MEM:
              {
                LegionSpy::log_memory_kind(kind, "Dynamic Framebuffer");
                break;
              }
            default:
              assert(false); // unknown memory kind
          }
        }
        LegionSpy::log_memory(it->id, it->capacity(), it->kind());
      }
      // Log Proc-Mem Affinity
      Machine::ProcessorQuery all_procs2(machine);
      for (Machine::ProcessorQuery::iterator pit = all_procs2.begin();
            pit != all_procs2.end(); pit++)
      {
        std::vector<ProcessorMemoryAffinity> affinities;
        machine.get_proc_mem_affinity(affinities, *pit);
        for (std::vector<ProcessorMemoryAffinity>::const_iterator it = 
              affinities.begin(); it != affinities.end(); it++)
        {
          LegionSpy::log_proc_mem_affinity(pit->id, it->m.id, 
                                           it->bandwidth, it->latency);
        }
      }
      // Log Mem-Mem Affinity
      Machine::MemoryQuery all_mems2(machine);
      for (Machine::MemoryQuery::iterator mit = all_mems2.begin();
            mit != all_mems2.begin(); mit++)
      {
        std::vector<MemoryMemoryAffinity> affinities;
        machine.get_mem_mem_affinity(affinities, *mit);
        for (std::vector<MemoryMemoryAffinity>::const_iterator it = 
              affinities.begin(); it != affinities.end(); it++)
        {
          LegionSpy::log_mem_mem_affinity(it->m1.id, it->m2.id, 
                                          it->bandwidth, it->latency);
        }
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::initialize_mappers(void)
    //--------------------------------------------------------------------------
    {
      if (replay_file.empty()) // This is the normal path
      {
        if (enable_test_mapper)
        {
          // Make test mappers for everyone
          for (std::map<Processor,ProcessorManager*>::const_iterator it = 
                proc_managers.begin(); it != proc_managers.end(); it++)
          {
            Mapper *mapper = 
              new Mapping::TestMapper(mapper_runtime, machine, it->first);
            MapperManager *wrapper = wrap_mapper(this, mapper, 0, it->first);
            it->second->add_mapper(0, wrapper, false/*check*/, true/*owns*/);
          }
        }
        else if (supply_default_mapper)
        {
          // Make default mappers for everyone
          for (std::map<Processor,ProcessorManager*>::const_iterator it = 
                proc_managers.begin(); it != proc_managers.end(); it++)
          {
            Mapper *mapper = 
              new Mapping::DefaultMapper(mapper_runtime, machine, it->first);
            MapperManager *wrapper = 
             wrap_mapper(this, mapper, 0, it->first, true/*is default mapper*/);
            it->second->add_mapper(0, wrapper, false/*check*/, true/*owns*/);
          } 
        }
      }
      else // This is the replay/debug path
      {
        if (legion_ldb_enabled)
        {
          // This path is not quite ready yet
          assert(false);
          for (std::map<Processor,ProcessorManager*>::const_iterator it = 
                proc_managers.begin(); it != proc_managers.end(); it++)
          {
            Mapper *mapper = new Mapping::DebugMapper(mapper_runtime, 
                                    machine, it->first, replay_file.c_str());
            MapperManager *wrapper = wrap_mapper(this, mapper, 0, it->first);
            it->second->add_mapper(0, wrapper, false/*check*/, true/*owns*/, 
                                    true/*skip replay*/);
          }
        }
        else
        {
          for (std::map<Processor,ProcessorManager*>::const_iterator it =
                proc_managers.begin(); it != proc_managers.end(); it++)
          {
            Mapper *mapper = new Mapping::ReplayMapper(mapper_runtime, 
                                    machine, it->first, replay_file.c_str());
            MapperManager *wrapper = wrap_mapper(this, mapper, 0, it->first);
            it->second->add_mapper(0, wrapper, false/*check*/, true/*owns*/,
                                    true/*skip replay*/);
          }
        }
      }
      
    }

    //--------------------------------------------------------------------------
    void Runtime::initialize_virtual_manager(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(virtual_manager == NULL);
#endif
      // make a layout constraints
      LayoutConstraintSet constraint_set;
      constraint_set.add_constraint(
          SpecializedConstraint(LEGION_VIRTUAL_SPECIALIZE));
      LayoutConstraints *constraints = 
        register_layout(FieldSpace::NO_SPACE, constraint_set, true/*internal*/);
      FieldMask all_ones(LEGION_FIELD_MASK_FIELD_ALL_ONES);
      std::vector<unsigned> mask_index_map;
      std::vector<CustomSerdezID> serdez;
      std::vector<std::pair<FieldID,size_t> > field_sizes;
      LayoutDescription *layout = new LayoutDescription(all_ones, constraints);
      virtual_manager = new VirtualManager(this, 0/*did*/, layout);
      virtual_manager->add_base_resource_ref(NEVER_GC_REF);
    }

    //--------------------------------------------------------------------------
    void Runtime::initialize_runtime(void)
    //--------------------------------------------------------------------------
    {  
      // If we have an MPI rank table do the exchanges before initializing
      // the mappers as they may want to look at the rank table
      if (mpi_rank_table != NULL)
        mpi_rank_table->perform_rank_exchange();
      initialize_mappers(); 
      // Pull in any static registrations that were done
      register_static_constraints();
      register_static_variants();
      register_static_projections();
      // Initialize our virtual manager and our mappers
      initialize_virtual_manager();
      // Finally perform the registration callback methods
      std::vector<RegistrationCallback> &registration_callbacks
        = get_pending_registration_callbacks();
      if (!registration_callbacks.empty())
      {
        log_run.info("Invoking registration callback functions...");
        for (std::vector<RegistrationCallback>::const_iterator it = 
              registration_callbacks.begin(); it !=
              registration_callbacks.end(); it++)
        {
          perform_registration_callback(it->has_args ?
              (void*)it->callback.withargs : (void*)it->callback.withoutargs,
              it->buffer.get_ptr(), it->buffer.get_size(), it->has_args,
              false/*global*/, true/*preregistered*/, it->deduplicate,
              it->dedup_tag);
          if (it->buffer.get_size() > 0)
            free(it->buffer.get_ptr());
        }
        log_run.info("Finished execution of registration callbacks");
        registration_callbacks.clear();
      }
    }

#ifdef LEGION_USE_LIBDL
    //--------------------------------------------------------------------------
    void Runtime::send_registration_callback(AddressSpaceID target,
                                         Realm::DSOReferenceImplementation *dso,
                                         RtEvent global_done_event,
                                         std::set<RtEvent> &applied_events,
                                         const void *buffer, size_t buffer_size,
                                         bool withargs, bool deduplicate,
                                         size_t dedup_tag)
    //--------------------------------------------------------------------------
    {
      const RtUserEvent done_event = Runtime::create_rt_user_event();
      Serializer rez;
      {
        RezCheck z(rez);
        const size_t dso_size = dso->dso_name.size() + 1;
        const size_t sym_size = dso->symbol_name.size() + 1;
        rez.serialize(dso_size);
        rez.serialize(dso->dso_name.c_str(), dso_size);
        rez.serialize(sym_size);
        rez.serialize(dso->symbol_name.c_str(), sym_size);
        rez.serialize(buffer_size);
        if (buffer_size > 0)
          rez.serialize(buffer, buffer_size);
        rez.serialize<bool>(withargs);
        rez.serialize<bool>(deduplicate);
        rez.serialize(dedup_tag);
        rez.serialize(global_done_event);
        rez.serialize(done_event);
      }
      find_messenger(target)->send_message<SEND_REGISTRATION_CALLBACK>(rez,
                                                              true/*flush*/);
      applied_events.insert(done_event);
    }
#endif // LEGION_USE_LIBDL

    //--------------------------------------------------------------------------
    RtEvent Runtime::perform_registration_callback(void *callback,
                                 const void *buffer, size_t buffer_size,
                                 bool withargs, bool global, bool preregistered,
                                 bool deduplicate, size_t dedup_tag)
    //--------------------------------------------------------------------------
    { 
      if (inside_registration_callback)
        REPORT_LEGION_ERROR(ERROR_NESTED_REGISTRATION_CALLBACKS,
            "Nested registration callbacks are not permitted in Legion")
      RegistrationKey global_key;
#ifdef LEGION_USE_LIBDL
      Realm::DSOReferenceImplementation *dso = NULL;
      if (global)
      {
        // No such thing as global registration if there's only one addres space
        if (total_address_spaces > 1)
        {
          // Convert this to it's portable representation or raise an error
          // This is a little scary, we could still be inside of dlopen when
          // we get this call as part of the constructor for a shared object
          // and yet we're about to do a call to dladdr. This seems to work
          // but there is no documentation anywhere about whether this is 
          // legal or safe to do...
          Realm::FunctionPointerImplementation impl((void (*)(void))callback);
#ifdef DEBUG_LEGION
          assert(callback_translator.can_translate(
                typeid(Realm::FunctionPointerImplementation),
                typeid(Realm::DSOReferenceImplementation)));
#endif
          dso = static_cast<Realm::DSOReferenceImplementation*>(
              callback_translator.translate(&impl, 
                typeid(Realm::DSOReferenceImplementation)));
          if (dso == NULL)
            REPORT_LEGION_FATAL(LEGION_FATAL_CALLBACK_NOT_PORTABLE,
                "Global registration callback function pointer %p is not "
                "portable. All registration callbacks requesting to be "
                "performed 'globally' must be able to be recognized by "
                "a call to 'dladdr'. This requires that they come from a "
                "shared object or the binary is linked with the '-rdynamic' "
                "flag.", callback)
          global_key = 
            RegistrationKey(dedup_tag, dso->dso_name, dso->symbol_name); 
        }
        else
          global = false;
      }
#else
      if (global)
      {
        if (total_address_spaces > 1)
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_PERFORM_REGISTRATION_CALLBACK,
              "Global registration callbacks are not supported in multi-node "
              "executions without support for libdl. Please build Legion "
              "with LEGION_USE_LIBDL defined.")
        else
          global = false;
      }
#endif
      RtEvent local_done, global_done;
      RtUserEvent local_perform, global_perform;
      if (deduplicate)
      {
        AutoLock c_lock(callback_lock); 
        if (global)
        {
          // See if we're going to perform this or not
          std::map<RegistrationKey,RtEvent>::const_iterator local_finder =
            global_local_done.find(global_key);
          if (local_finder == global_local_done.end())
          {
            local_perform = Runtime::create_rt_user_event();
            global_local_done[global_key] = local_perform;
            // Check to see if we have any pending global callbacks to 
            // notify about being done locally
            std::map<RegistrationKey,std::set<RtUserEvent> >::iterator
              pending_finder = pending_remote_callbacks.find(global_key);
            if (pending_finder != pending_remote_callbacks.end())
            {
              for (std::set<RtUserEvent>::const_iterator it = 
                    pending_finder->second.begin(); it != 
                    pending_finder->second.end(); it++)
                Runtime::trigger_event(*it, local_perform);
              pending_remote_callbacks.erase(pending_finder);
            }
          }
          else
            local_done = local_finder->second;
          // Now see if we need to do our global registration callbacks
          std::map<RegistrationKey,RtEvent>::const_iterator global_finder = 
            global_callbacks_done.find(global_key);
          if (global_finder == global_callbacks_done.end())
          {
            global_perform = Runtime::create_rt_user_event();
            global_callbacks_done[global_key] = global_perform;
          }
          else
            global_done = global_finder->second;
        }
        else
        {
          std::map<void*,RtEvent>::const_iterator
            local_finder = local_callbacks_done.find(callback);
          if (local_finder == local_callbacks_done.end())
          {
            local_perform = Runtime::create_rt_user_event();
            local_callbacks_done[callback] = local_perform;
          }
          else
            return local_finder->second;
        }
      }
      else if (global)
        global_perform = Runtime::create_rt_user_event();
      // Do the local callback and record it now 
      if (!deduplicate || local_perform.exists())
      {
        // All the pregistered cases are effectively global too
        if (global || preregistered)
          inside_registration_callback = GLOBAL_REGISTRATION_CALLBACK;
        else
          inside_registration_callback = LOCAL_REGISTRATION_CALLBACK;
        if (withargs)
        {
          RegistrationWithArgsCallbackFnptr callbackwithargs =
            (RegistrationWithArgsCallbackFnptr)callback;
          RegistrationCallbackArgs args{ machine, external, 
            local_procs, UntypedBuffer(buffer, buffer_size) };
          (*callbackwithargs)(args);
        }
        else
        {
          RegistrationCallbackFnptr callbackwithoutargs =
            (RegistrationCallbackFnptr)callback;
          (*callbackwithoutargs)(machine, external, local_procs);
        }
        inside_registration_callback = NO_REGISTRATION_CALLBACK;
        if (local_perform.exists())
          Runtime::trigger_event(local_perform);
        if (!global)
          return local_perform;
      }
#ifdef LEGION_USE_LIBDL
#ifdef DEBUG_LEGION
      assert(global);
#endif
      if (global_done.exists())
      {
        delete dso;
        return global_done;
      }
#ifdef DEBUG_LEGION
      assert(global_perform.exists());
#endif
      // See if we're inside of a task and can use that to help do the 
      // global invocations of this registration callback
      if (!deduplicate || (implicit_context == NULL))
      {
#ifdef DEBUG_LEGION
        assert(implicit_runtime == NULL);
#endif
        // This means we're in an external thread asking for us to
        // perform a global registration so just send out messages
        // to all the nodes asking them to do the registration
        std::set<RtEvent> preconditions;
        for (AddressSpaceID space = 0; space < total_address_spaces; space++)
        {
          if (space == address_space)
            continue;
          send_registration_callback(space, dso, global_perform, preconditions,
              buffer, buffer_size, withargs, deduplicate, dedup_tag);
        }
        if (!preconditions.empty())
          Runtime::trigger_event(global_perform,
              Runtime::merge_events(preconditions));
        else
          Runtime::trigger_event(global_perform);
      }
      else
      {
        std::set<RtEvent> preconditions;
        implicit_context->perform_global_registration_callbacks(
            dso, buffer, buffer_size, withargs, dedup_tag, local_done,
            global_perform, preconditions);
        if (!preconditions.empty())
          Runtime::trigger_event(global_perform,
              Runtime::merge_events(preconditions));
        else
          Runtime::trigger_event(global_perform);
      }
      delete dso;
#endif // LEGION_USE_LIBDL
      return global_perform;
    }

    //--------------------------------------------------------------------------
    void Runtime::startup_runtime(void)
    //--------------------------------------------------------------------------
    {
      // If stealing is not disabled then startup our mappers
      if (!stealing_disabled)
      {
        for (std::map<Processor,ProcessorManager*>::const_iterator it = 
              proc_managers.begin(); it != proc_managers.end(); it++)
          it->second->startup_mappers();
      }
      if (address_space == 0)
      {
        if (legion_spy_enabled)
            log_machine(machine);
        // If we are runtime 0 then we launch the top-level task
        if (legion_main_set)
        {
          TaskLauncher launcher(Runtime::legion_main_id, 
                                UntypedBuffer(&input_args, sizeof(InputArgs)),
                                Predicate::TRUE_PRED, legion_main_mapper_id);
          launch_top_level_task(launcher); 
        }
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::finalize_runtime(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(virtual_manager != NULL);
#endif
      if (virtual_manager->remove_base_resource_ref(NEVER_GC_REF))
      {
        delete virtual_manager;
        virtual_manager = NULL;
      }
      // Have the memory managers for deletion of all their instances
      for (std::map<Memory,MemoryManager*>::const_iterator it =
           memory_managers.begin(); it != memory_managers.end(); it++)
        it->second->finalize();
      if (profiler != NULL)
        profiler->finalize();
    }
    
    //--------------------------------------------------------------------------
    ApEvent Runtime::launch_mapper_task(Mapper *mapper, Processor proc, 
                                        TaskID tid, const UntypedBuffer &arg,
                                        MapperID map_id)
    //--------------------------------------------------------------------------
    {
      // Get a remote task to serve as the top of the top-level task
      TopLevelContext *map_context = 
        new TopLevelContext(this, get_unique_operation_id());
      map_context->add_reference();
      map_context->set_executing_processor(proc);
      TaskLauncher launcher(tid, arg, Predicate::TRUE_PRED, map_id);
      // Get an individual task to be the top-level task
      IndividualTask *mapper_task = get_available_individual_task();
      Future f = mapper_task->initialize_task(map_context, launcher, 
                                              false/*track parent*/);
      mapper_task->set_current_proc(proc);
      mapper_task->select_task_options(false/*prioritize*/);
      // Create a temporary event to name the result since we 
      // have to pack it in the task that runs, but it also depends
      // on the task being reported back to the mapper
      ApUserEvent result = Runtime::create_ap_user_event(NULL);
      // Add a reference to the future impl to prevent it being collected
      f.impl->add_base_gc_ref(FUTURE_HANDLE_REF);
      // Create a meta-task to return the results to the mapper
      MapperTaskArgs args(f.impl, map_id, proc, result, map_context);
      ApEvent pre = f.impl->get_ready_event();
      ApEvent post(issue_runtime_meta_task(args, LG_LATENCY_WORK_PRIORITY,
                                           Runtime::protect_event(pre)));
      // Chain the events properly
      Runtime::trigger_event(NULL, result, post);
      // Mark that we have another outstanding top level task
      increment_outstanding_top_level_tasks();
      // Now we can put it on the queue
      add_to_ready_queue(proc, mapper_task);
      return result;
    }

    //--------------------------------------------------------------------------
    void Runtime::process_mapper_task_result(const MapperTaskArgs *args)
    //--------------------------------------------------------------------------
    {
#if 0
      MapperManager *mapper = find_mapper(args->proc, args->map_id);
      Mapper::MapperTaskResult result;
      result.mapper_event = args->event;
      result.result = args->future->get_untyped_result();
      result.result_size = args->future->get_untyped_size();
      mapper->invoke_handle_task_result(&result);
#else
      assert(false); // update this
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::create_shared_ownership(IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      const AddressSpaceID owner_space = 
        IndexSpaceNode::get_owner_space(handle, this);
      if (owner_space != address_space)
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<int>(0);
          rez.serialize(handle);
        }
        send_shared_ownership(owner_space, rez);
      }
      else
      {
        IndexSpaceNode *node = forest->get_node(handle);
        if (!node->check_valid_and_increment(APPLICATION_REF))
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_SHARED_OWNERSHIP,
              "Illegal call to add shared ownership to index space %x "
              "which has already been deleted", handle.get_id())
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::create_shared_ownership(IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      const AddressSpaceID owner_space = 
        IndexPartNode::get_owner_space(handle, this);
      if (owner_space != address_space)
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<int>(1);
          rez.serialize(handle);
        }
        send_shared_ownership(owner_space, rez);
      }
      else
      {
        IndexPartNode *node = forest->get_node(handle);
        if (!node->check_valid_and_increment(APPLICATION_REF))
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_SHARED_OWNERSHIP,
              "Illegal call to add shared ownership to index partition %x "
              "which has already been deleted", handle.get_id())
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::create_shared_ownership(FieldSpace handle)
    //--------------------------------------------------------------------------
    {
      const AddressSpaceID owner_space = 
        FieldSpaceNode::get_owner_space(handle, this);
      if (owner_space != address_space)
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<int>(2);
          rez.serialize(handle);
        }
        send_shared_ownership(owner_space, rez);
      }
      else
      {
        FieldSpaceNode *node = forest->get_node(handle);
        if (!node->check_valid_and_increment(APPLICATION_REF))
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_SHARED_OWNERSHIP,
              "Illegal call to add shared ownership to field space %x "
              "which has already been deleted", handle.get_id())
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::create_shared_ownership(LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      const AddressSpaceID owner_space = 
        RegionNode::get_owner_space(handle, this);
      if (owner_space != address_space)
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<int>(3);
          rez.serialize(handle);
        }
        send_shared_ownership(owner_space, rez);
      }
      else
      {
        RegionNode *node = forest->get_node(handle);
        if (!node->check_valid_and_increment(APPLICATION_REF))
          REPORT_LEGION_ERROR(ERROR_ILLEGAL_SHARED_OWNERSHIP,
              "Illegal call to add shared ownership to logical region "
              "(%x,%x,%x) which has already been deleted", 
              handle.index_space.get_id(), handle.field_space.get_id(),
              handle.tree_id)
      }
    }

    //--------------------------------------------------------------------------
    IndexPartition Runtime::get_index_partition(Context ctx, 
                                                IndexSpace parent, Color color)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexPartition result = get_index_partition(parent, color);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    IndexPartition Runtime::get_index_partition(IndexSpace parent, Color color)
    //--------------------------------------------------------------------------
    {
      IndexPartition result = forest->get_index_partition(parent, color);
#ifdef DEBUG_LEGION
      if (!result.exists())
        REPORT_LEGION_ERROR(ERROR_INVALID_INDEX_SPACE_COLOR, 
            "Invalid color %d for get index partitions", color);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_index_partition(Context ctx, IndexSpace parent, 
                                      Color color)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = has_index_partition(parent, color);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_index_partition(IndexSpace parent, Color color)
    //--------------------------------------------------------------------------
    {
      return forest->has_index_partition(parent, color);
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::get_index_subspace(Context ctx, IndexPartition p, 
                                           const void *realm_color,
                                           TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexSpace result = get_index_subspace(p, realm_color, type_tag); 
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::get_index_subspace(IndexPartition p, 
                                           const void *realm_color,
                                           TypeTag type_tag) 
    //--------------------------------------------------------------------------
    {
      return forest->get_index_subspace(p, realm_color, type_tag);
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_index_subspace(Context ctx, IndexPartition p,
                                     const void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = has_index_subspace(p, realm_color, type_tag); 
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_index_subspace(IndexPartition p,
                                     const void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      return forest->has_index_subspace(p, realm_color, type_tag);
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_space_domain(Context ctx, IndexSpace handle,
                                         void *realm_is, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      get_index_space_domain(handle, realm_is, type_tag);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_space_domain(IndexSpace handle, 
                                         void *realm_is, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      forest->get_index_space_domain(handle, realm_is, type_tag);
    }

    //--------------------------------------------------------------------------
    Domain Runtime::get_index_partition_color_space(Context ctx,
                                                    IndexPartition p)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      Domain result = get_index_partition_color_space(p); 
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    Domain Runtime::get_index_partition_color_space(IndexPartition p)
    //--------------------------------------------------------------------------
    {
      IndexPartNode *part = forest->get_node(p);
      const IndexSpace color_space = part->color_space->handle;
      switch (NT_TemplateHelper::get_dim(color_space.get_type_tag()))
      {
#define DIMFUNC(DIM) \
        case DIM: \
          { \
            DomainT<DIM,coord_t> color_index_space; \
            forest->get_index_space_domain(color_space, &color_index_space, \
                                           color_space.get_type_tag()); \
            return Domain(color_index_space); \
          }
        LEGION_FOREACH_N(DIMFUNC)
#undef DIMFUNC
        default:
          assert(false);
      }
      return Domain::NO_DOMAIN;
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_partition_color_space(IndexPartition p,
                                               void *realm_is, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      IndexPartNode *part = forest->get_node(p);
      const IndexSpace color_space = part->color_space->handle;
      forest->get_index_space_domain(color_space, realm_is, type_tag);
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::get_index_partition_color_space_name(Context ctx,
                                                             IndexPartition p)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexSpace result = get_index_partition_color_space_name(p);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::get_index_partition_color_space_name(IndexPartition p)
    //--------------------------------------------------------------------------
    {
      return forest->get_index_partition_color_space(p);
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_space_partition_colors(Context ctx, IndexSpace sp,
                                                   std::set<Color> &colors)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      get_index_space_partition_colors(sp, colors);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_space_partition_colors(IndexSpace handle,
                                                   std::set<Color> &colors)
    //--------------------------------------------------------------------------
    {
      forest->get_index_space_partition_colors(handle, colors);
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_index_partition_disjoint(Context ctx, IndexPartition p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(implicit_reference_tracker == NULL);
#endif
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      const bool result = forest->is_index_partition_disjoint(p);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      else if (implicit_reference_tracker != NULL)
      {
        delete implicit_reference_tracker;
        implicit_reference_tracker = NULL;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_index_partition_disjoint(IndexPartition p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(implicit_reference_tracker == NULL);
#endif
      const bool result = forest->is_index_partition_disjoint(p);
      if (implicit_reference_tracker != NULL)
      {
        delete implicit_reference_tracker;
        implicit_reference_tracker = NULL;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_index_partition_complete(Context ctx, IndexPartition p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(implicit_reference_tracker == NULL);
#endif
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = forest->is_index_partition_complete(p);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      else if (implicit_reference_tracker != NULL)
      {
        delete implicit_reference_tracker;
        implicit_reference_tracker = NULL;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_index_partition_complete(IndexPartition p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(implicit_reference_tracker == NULL);
#endif
      const bool result = forest->is_index_partition_complete(p);
      if (implicit_reference_tracker != NULL)
      {
        delete implicit_reference_tracker;
        implicit_reference_tracker = NULL;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_space_color_point(Context ctx, IndexSpace handle,
                                            void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      forest->get_index_space_color(handle, realm_color, type_tag);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
    }

    //--------------------------------------------------------------------------
    void Runtime::get_index_space_color_point(IndexSpace handle,
                                            void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      forest->get_index_space_color(handle, realm_color, type_tag);
    }

    //--------------------------------------------------------------------------
    DomainPoint Runtime::get_index_space_color_point(Context ctx, 
                                                     IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexSpaceNode *node = forest->get_node(handle);
      DomainPoint result = node->get_domain_point_color();
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    DomainPoint Runtime::get_index_space_color_point(IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode *node = forest->get_node(handle);
      return node->get_domain_point_color();
    }

    //--------------------------------------------------------------------------
    Color Runtime::get_index_partition_color(Context ctx, 
                                                   IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      Color result = forest->get_index_partition_color(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    Color Runtime::get_index_partition_color(IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_index_partition_color(handle);
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::get_parent_index_space(Context ctx,   
                                               IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexSpace result = forest->get_parent_index_space(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::get_parent_index_space(IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_parent_index_space(handle);
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_parent_index_partition(Context ctx, IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = forest->has_parent_index_partition(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_parent_index_partition(IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      return forest->has_parent_index_partition(handle);
    }

    //--------------------------------------------------------------------------
    IndexPartition Runtime::get_parent_index_partition(Context ctx,
                                                       IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexPartition result = forest->get_parent_index_partition(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    IndexPartition Runtime::get_parent_index_partition(IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_parent_index_partition(handle);
    }

    //--------------------------------------------------------------------------
    unsigned Runtime::get_index_space_depth(Context ctx, IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      unsigned result = forest->get_index_space_depth(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    unsigned Runtime::get_index_space_depth(IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_index_space_depth(handle);
    }

    //--------------------------------------------------------------------------
    unsigned Runtime::get_index_partition_depth(Context ctx, 
                                                IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      unsigned result = forest->get_index_partition_depth(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    unsigned Runtime::get_index_partition_depth(IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_index_partition_depth(handle);
    }

    //--------------------------------------------------------------------------
    bool Runtime::safe_cast(Context ctx, LogicalRegion region,
                            const void *realm_point, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context safe cast!");
      return ctx->safe_cast(forest, region.get_index_space(), 
                            realm_point, type_tag);
    }

    //--------------------------------------------------------------------------
    size_t Runtime::get_field_size(Context ctx, FieldSpace handle, FieldID fid)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      size_t result = forest->get_field_size(handle, fid);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    size_t Runtime::get_field_size(FieldSpace handle, FieldID fid)
    //--------------------------------------------------------------------------
    {
      return forest->get_field_size(handle, fid);
    }

    //--------------------------------------------------------------------------
    void Runtime::get_field_space_fields(Context ctx, FieldSpace handle,
                                         std::vector<FieldID> &fields)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      forest->get_field_space_fields(handle, fields);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
    }

    //--------------------------------------------------------------------------
    void Runtime::get_field_space_fields(FieldSpace handle, 
                                         std::vector<FieldID> &fields)
    //--------------------------------------------------------------------------
    {
      forest->get_field_space_fields(handle, fields);
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_logical_partition(Context ctx, 
                                    LogicalRegion parent, IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalPartition result = forest->get_logical_partition(parent, handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_logical_partition(LogicalRegion parent,
                                                    IndexPartition handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_partition(parent, handle);
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_logical_partition_by_color(
                                    Context ctx, LogicalRegion parent, Color c)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalPartition result = 
        forest->get_logical_partition_by_color(parent, c);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_logical_partition_by_color(LogicalRegion par,
                                                             Color c)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_partition_by_color(par, c);
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_logical_partition_by_color(Context ctx, 
                                              LogicalRegion parent, Color color)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = forest->has_logical_partition_by_color(parent, color);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_logical_partition_by_color(LogicalRegion parent, 
                                                 Color color)
    //--------------------------------------------------------------------------
    {
      return forest->has_logical_partition_by_color(parent, color);
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_logical_partition_by_tree(
                                            Context ctx, IndexPartition handle, 
                                            FieldSpace fspace, RegionTreeID tid)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalPartition result = 
        forest->get_logical_partition_by_tree(handle, fspace, tid);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_logical_partition_by_tree(
                                                            IndexPartition part,
                                                            FieldSpace fspace,
                                                            RegionTreeID tid)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_partition_by_tree(part, fspace, tid);
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_logical_subregion(Context ctx, 
                                    LogicalPartition parent, IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalRegion result = forest->get_logical_subregion(parent, handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_logical_subregion(LogicalPartition parent,
                                                 IndexSpace handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_subregion(parent, handle);
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_logical_subregion_by_color(Context ctx,
             LogicalPartition parent, const void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalRegion result = 
        forest->get_logical_subregion_by_color(parent, realm_color, type_tag);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_logical_subregion_by_color(LogicalPartition par,
                                      const void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_subregion_by_color(par, realm_color, type_tag);
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_logical_subregion_by_color(Context ctx,
             LogicalPartition parent, const void *realm_point, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = 
        forest->has_logical_subregion_by_color(parent, realm_point, type_tag);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_logical_subregion_by_color(LogicalPartition parent, 
                                      const void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      return forest->has_logical_subregion_by_color(parent, 
                                                    realm_color, type_tag);
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_logical_subregion_by_tree(Context ctx, 
                        IndexSpace handle, FieldSpace fspace, RegionTreeID tid)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalRegion result = 
        forest->get_logical_subregion_by_tree(handle, fspace, tid);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_logical_subregion_by_tree(IndexSpace handle,
                                                         FieldSpace fspace,
                                                         RegionTreeID tid)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_subregion_by_tree(handle, fspace, tid);
    }

    //--------------------------------------------------------------------------
    void Runtime::get_logical_region_color(Context ctx, LogicalRegion handle, 
                                           void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      forest->get_logical_region_color(handle, realm_color, type_tag);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
    }

    //--------------------------------------------------------------------------
    void Runtime::get_logical_region_color(LogicalRegion handle,
                                            void *realm_color, TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      forest->get_logical_region_color(handle, realm_color, type_tag);
    }

    //--------------------------------------------------------------------------
    DomainPoint Runtime::get_logical_region_color_point(Context ctx,
                                                        LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      IndexSpaceNode *node = forest->get_node(handle.get_index_space());
      DomainPoint result = node->get_domain_point_color();
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    DomainPoint Runtime::get_logical_region_color_point(LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode *node = forest->get_node(handle.get_index_space());
      return node->get_domain_point_color();
    }

    //--------------------------------------------------------------------------
    Color Runtime::get_logical_partition_color(Context ctx,
                                                     LogicalPartition handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      Color result = forest->get_logical_partition_color(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    Color Runtime::get_logical_partition_color(LogicalPartition handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_logical_partition_color(handle);
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_parent_logical_region(Context ctx, 
                                                     LogicalPartition handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalRegion result = forest->get_parent_logical_region(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalRegion Runtime::get_parent_logical_region(LogicalPartition handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_parent_logical_region(handle);
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_parent_logical_partition(Context ctx, 
                                               LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      bool result = forest->has_parent_logical_partition(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_parent_logical_partition(LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      return forest->has_parent_logical_partition(handle);
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_parent_logical_partition(Context ctx,
                                                           LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      LogicalPartition result = forest->get_parent_logical_partition(handle);
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    LogicalPartition Runtime::get_parent_logical_partition(
                                                           LogicalRegion handle)
    //--------------------------------------------------------------------------
    {
      return forest->get_parent_logical_partition(handle);
    }

    //--------------------------------------------------------------------------
    ArgumentMap Runtime::create_argument_map(void)
    //--------------------------------------------------------------------------
    {
      ArgumentMapImpl *impl = new ArgumentMapImpl();
#ifdef DEBUG_LEGION
      assert(impl != NULL);
#endif
      return ArgumentMap(impl);
    }

    //--------------------------------------------------------------------------
    Future Runtime::execute_task(Context ctx, const TaskLauncher &launcher)
    //--------------------------------------------------------------------------
    { 
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context execute task!");
      return ctx->execute_task(launcher); 
    }

    //--------------------------------------------------------------------------
    FutureMap Runtime::execute_index_space(Context ctx, 
                                           const IndexTaskLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context execute index space!");
      return ctx->execute_index_space(launcher); 
    }

    //--------------------------------------------------------------------------
    Future Runtime::execute_index_space(Context ctx, 
     const IndexTaskLauncher &launcher, ReductionOpID redop, bool deterministic)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context execute index space!");
      return ctx->execute_index_space(launcher, redop, deterministic); 
    }

    //--------------------------------------------------------------------------
    PhysicalRegion Runtime::map_region(Context ctx, 
                                                const InlineLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context map region!");
      return ctx->map_region(launcher); 
    }

    //--------------------------------------------------------------------------
    PhysicalRegion Runtime::map_region(Context ctx, unsigned idx, 
                          MapperID id, MappingTagID tag, const char *provenance)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context map region!");
      PhysicalRegion result = ctx->get_physical_region(idx);
      // Check to see if we are already mapped, if not, then remap it
      if (!result.impl->is_mapped())
        remap_region(ctx, result, provenance);
      return result;
    }

    //--------------------------------------------------------------------------
    void Runtime::remap_region(Context ctx, const PhysicalRegion &region,
                               const char *provenance)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context remap region!");
      ctx->remap_region(region, provenance);
    }

    //--------------------------------------------------------------------------
    void Runtime::unmap_region(Context ctx, PhysicalRegion region)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context unmap region!");
      ctx->unmap_region(region); 
    }

    //--------------------------------------------------------------------------
    void Runtime::fill_fields(Context ctx, const FillLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context fill operation!");
      ctx->fill_fields(launcher); 
    }

    //--------------------------------------------------------------------------
    void Runtime::fill_fields(Context ctx, const IndexFillLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context fill operation!");
      ctx->fill_fields(launcher);
    }

    //--------------------------------------------------------------------------
    void Runtime::issue_copy_operation(Context ctx,const CopyLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context issue copy operation!");
      ctx->issue_copy(launcher); 
    }

    //--------------------------------------------------------------------------
    void Runtime::issue_copy_operation(Context ctx,
                                       const IndexCopyLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context issue copy operation!");
      ctx->issue_copy(launcher);
    }

    //--------------------------------------------------------------------------
    void Runtime::issue_acquire(Context ctx, const AcquireLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context issue acquire!");
      ctx->issue_acquire(launcher); 
    }

    //--------------------------------------------------------------------------
    void Runtime::issue_release(Context ctx, const ReleaseLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context issue release!");
      ctx->issue_release(launcher); 
    }

    //--------------------------------------------------------------------------
    TraceID Runtime::generate_dynamic_trace_id(bool check_context/*= true*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->generate_dynamic_trace_id();
      TraceID result = unique_trace_id.fetch_add(runtime_stride);
      // Check for hitting the library limit
      if (result >= LEGION_INITIAL_LIBRARY_ID_OFFSET)
        REPORT_LEGION_FATAL(LEGION_FATAL_EXCEEDED_LIBRARY_ID_OFFSET,
            "Dynamic Trace IDs exceeded library ID offset %d",
            LEGION_INITIAL_LIBRARY_ID_OFFSET)
      return result;
    }
    
    //--------------------------------------------------------------------------
    TraceID Runtime::generate_library_trace_ids(const char *name, size_t count)
    //--------------------------------------------------------------------------
    {
      // Easy case if the user asks for no IDs
      if (count == 0)
        return LEGION_AUTO_GENERATE_ID;
      const std::string library_name(name); 
      // Take the lock in read only mode and see if we can find the result
      RtEvent wait_on;
      {
        AutoLock l_lock(library_lock,1,false/*exclusive*/);
        std::map<std::string,LibraryTraceIDs>::const_iterator finder = 
          library_trace_ids.find(library_name);
        if (finder != library_trace_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != count)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "TraceID generation counts %zd and %zd differ for library %s",
                finder->second.count, count, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
      }
      RtUserEvent request_event;
      if (!wait_on.exists())
      {
        AutoLock l_lock(library_lock);
        // Check to make sure we didn't lose the race
        std::map<std::string,LibraryTraceIDs>::const_iterator finder = 
          library_trace_ids.find(library_name);
        if (finder != library_trace_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != count)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "TraceID generation counts %zd and %zd differ for library %s",
                finder->second.count, count, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
        if (!wait_on.exists())
        {
          LibraryTraceIDs &record = library_trace_ids[library_name];
          record.count = count;
          if (address_space == 0)
          {
            // We're going to make the result
            record.result = unique_library_trace_id;
            unique_library_trace_id += count;
#ifdef DEBUG_LEGION
            assert(unique_library_trace_id > record.result);
#endif
            record.result_set = true;
            return record.result;
          }
          else
          {
            // We're going to request the result
            request_event = Runtime::create_rt_user_event();
            record.ready = request_event;
            record.result_set = false;
            wait_on = request_event;
          }
        }
      }
      // Should only get here on nodes other than 0
#ifdef DEBUG_LEGION
      assert(address_space > 0);
      assert(wait_on.exists());
#endif
      if (request_event.exists())
      {
        // Include the null terminator in length
        const size_t string_length = strlen(name) + 1;
        // Send the request to node 0 for the result
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<size_t>(string_length);
          rez.serialize(name, string_length);
          rez.serialize<size_t>(count);
          rez.serialize(request_event);
        }
        send_library_trace_request(0/*target*/, rez);
      }
      wait_on.wait();
      // When we wake up we should be able to find the result
      AutoLock l_lock(library_lock,1,false/*exclusive*/);
      std::map<std::string,LibraryTraceIDs>::const_iterator finder = 
          library_trace_ids.find(library_name);
#ifdef DEBUG_LEGION
      assert(finder != library_trace_ids.end());
      assert(finder->second.result_set);
#endif
      return finder->second.result;
    }

    //--------------------------------------------------------------------------
    /*static*/ TraceID& Runtime::get_current_static_trace_id(void)
    //--------------------------------------------------------------------------
    {
      static TraceID next_trace_id = LEGION_MAX_APPLICATION_TRACE_ID;
      return next_trace_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ TraceID Runtime::generate_static_trace_id(void)
    //--------------------------------------------------------------------------
    {
      TraceID &next_trace = get_current_static_trace_id();
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'generate_static_trace_id' after "
                      "the runtime has been started!")
      return next_trace++;
    }

    //--------------------------------------------------------------------------
    FutureMap Runtime::execute_must_epoch(Context ctx, 
                                          const MustEpochLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT("Illegal dummy context issue must epoch!");
      return ctx->execute_must_epoch(launcher); 
    }

    //--------------------------------------------------------------------------
    Future Runtime::issue_timing_measurement(Context ctx,
                                             const TimingLauncher &launcher)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT(
            "Illegal dummy context in timing measurement!");
      return ctx->issue_timing_measurement(launcher); 
    }

    //--------------------------------------------------------------------------
    void* Runtime::get_local_task_variable(Context ctx, LocalVariableID id)
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT(
            "Illegal dummy context get local task variable!");
      return ctx->get_local_task_variable(id);
    }

    //--------------------------------------------------------------------------
    void Runtime::set_local_task_variable(Context ctx, LocalVariableID id,
                                   const void *value, void (*destructor)(void*))
    //--------------------------------------------------------------------------
    {
      if (ctx == DUMMY_CONTEXT)
        REPORT_DUMMY_CONTEXT(
            "Illegal dummy context set local task variable!");
      ctx->set_local_task_variable(id, value, destructor);
    }

    //--------------------------------------------------------------------------
    Mapper* Runtime::get_mapper(Context ctx, MapperID id, Processor target)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      if (!target.exists())
      {
        Processor proc = ctx->get_executing_processor();
#ifdef DEBUG_LEGION
        assert(proc_managers.find(proc) != proc_managers.end());
#endif
        if (ctx != DUMMY_CONTEXT)
          ctx->end_runtime_call();
        return proc_managers[proc]->find_mapper(id)->mapper;
      }
      else
      {
        std::map<Processor,ProcessorManager*>::const_iterator finder = 
          proc_managers.find(target);
        if (finder == proc_managers.end())
          REPORT_LEGION_ERROR(ERROR_INVALID_PROCESSOR_NAME, 
           "Invalid processor " IDFMT " passed to get mapper call.", target.id);
        if (ctx != DUMMY_CONTEXT)
          ctx->end_runtime_call();
        return finder->second->find_mapper(id)->mapper;
      }
    }

    //--------------------------------------------------------------------------
    MappingCallInfo* Runtime::begin_mapper_call(Context ctx, MapperID id, 
                                                Processor target)
    //--------------------------------------------------------------------------
    {
      if (ctx != DUMMY_CONTEXT)
        ctx->begin_runtime_call();
      MapperManager *manager;
      if (!target.exists())
      {
        Processor proc = ctx->get_executing_processor();
#ifdef DEBUG_LEGION
        assert(proc_managers.find(proc) != proc_managers.end());
#endif
        manager = proc_managers[proc]->find_mapper(id);
      }
      else
      {
        std::map<Processor,ProcessorManager*>::const_iterator finder = 
          proc_managers.find(target);
        if (finder == proc_managers.end())
          REPORT_LEGION_ERROR(ERROR_INVALID_PROCESSOR_NAME, "Invalid processor "
                              IDFMT " passed to begin mapper call.", target.id)
        manager = finder->second->find_mapper(id);
      }
      RtEvent ready;
      MappingCallInfo *result = manager->begin_mapper_call(
          APPLICATION_MAPPER_CALL, NULL, ready);
      if (ready.exists() && !ready.has_triggered())
        ready.wait();
      if (ctx != DUMMY_CONTEXT)
        ctx->end_runtime_call();
      return result;
    }

    //--------------------------------------------------------------------------
    void Runtime::end_mapper_call(MappingCallInfo *info)
    //--------------------------------------------------------------------------
    {
      info->manager->finish_mapper_call(info);
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_MPI_interop_configured(void)
    //--------------------------------------------------------------------------
    {
      return (mpi_rank_table != NULL);
    }

    //--------------------------------------------------------------------------
    const std::map<int,AddressSpace>& Runtime::find_forward_MPI_mapping(void)
    //--------------------------------------------------------------------------
    {
      if (mpi_rank_table == NULL)
        REPORT_LEGION_ERROR(ERROR_MPI_INTEROPERABILITY_NOT_CONFIGURED, 
             "Forward MPI mapping call not supported without "
                      "calling configure_MPI_interoperability during "
                      "start up")
#ifdef DEBUG_LEGION
      assert(!mpi_rank_table->forward_mapping.empty());
#endif
      return mpi_rank_table->forward_mapping;
    }

    //--------------------------------------------------------------------------
    const std::map<AddressSpace,int>& Runtime::find_reverse_MPI_mapping(void)
    //--------------------------------------------------------------------------
    {
      if (mpi_rank_table == NULL)
        REPORT_LEGION_ERROR(ERROR_MPI_INTEROPERABILITY_NOT_CONFIGURED,
             "Reverse MPI mapping call not supported without "
                      "calling configure_MPI_interoperability during "
                      "start up")
#ifdef DEBUG_LEGION
      assert(!mpi_rank_table->reverse_mapping.empty());
#endif
      return mpi_rank_table->reverse_mapping;
    }

    //--------------------------------------------------------------------------
    int Runtime::find_local_MPI_rank(void)
    //-------------------------------------------------------------------------
    {
      if (mpi_rank_table == NULL)
        REPORT_LEGION_ERROR(ERROR_MPI_INTEROPERABILITY_NOT_CONFIGURED,
             "Findling local MPI rank not supported without "
                      "calling configure_MPI_interoperability during "
                      "start up")
      return mpi_rank;
    }

    //--------------------------------------------------------------------------
    void Runtime::add_mapper(MapperID map_id, Mapper *mapper, Processor proc)
    //--------------------------------------------------------------------------
    {
      // If we have a custom mapper then silently ignore this
      if (!replay_file.empty() || enable_test_mapper)
      {
        // We take ownership of these things so delete it now
        delete mapper;
        return;
      }
      const bool all_local_procs = !proc.exists();
      if (all_local_procs)
      {
        std::vector<Processor> all_local_processors;
        all_local_processors.reserve(proc_managers.size());
        for (std::map<Processor,ProcessorManager*>::const_iterator it = 
              proc_managers.begin(); it != proc_managers.end(); it++)
          all_local_processors.push_back(it->first);
        proc = find_processor_group(all_local_processors);
      }
      // First, wrap this mapper in a mapper manager
      MapperManager *manager = wrap_mapper(this, mapper, map_id, proc);
      if (all_local_procs)
      {
        bool own = true;
        // Save it to all the managers
        for (std::map<Processor,ProcessorManager*>::const_iterator it = 
              proc_managers.begin(); it != proc_managers.end(); it++)
        {
          it->second->add_mapper(map_id, manager, true/*check*/, own);
          own = false;
        }
      }
      else if (proc.address_space() == address_space)
      {
#ifdef DEBUG_LEGION
        assert(proc_managers.find(proc) != proc_managers.end());
#endif
        proc_managers[proc]->add_mapper(map_id, manager, 
                                        true/*check*/, true/*own*/);
      }
      else
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_MAPPER_PROCESSOR,
            "Illegal attempt to register mapper %s as mapper %d "
            "for processor " IDFMT ". That processor is not local to the "
            "process where 'Runtime::add_mapper' was called.",
            manager->get_mapper_name(), map_id, proc.id);
    }

    //--------------------------------------------------------------------------
    Mapping::MapperRuntime* Runtime::get_mapper_runtime(void)
    //--------------------------------------------------------------------------
    {
      return mapper_runtime;
    }

    //--------------------------------------------------------------------------
    MapperID Runtime::generate_dynamic_mapper_id(bool check_context/*= true*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->generate_dynamic_mapper_id();
      MapperID result = unique_mapper_id.fetch_add(runtime_stride);
      // Check for hitting the library limit
      if (result >= LEGION_INITIAL_LIBRARY_ID_OFFSET)
        REPORT_LEGION_FATAL(LEGION_FATAL_EXCEEDED_LIBRARY_ID_OFFSET,
            "Dynamic Mapper IDs exceeded library ID offset %d",
            LEGION_INITIAL_LIBRARY_ID_OFFSET)
      return result;
    }

    //--------------------------------------------------------------------------
    MapperID Runtime::generate_library_mapper_ids(const char *name, size_t cnt)
    //--------------------------------------------------------------------------
    {
      // Easy case if the user asks for no IDs
      if (cnt == 0)
        return LEGION_AUTO_GENERATE_ID;
      const std::string library_name(name); 
      // Take the lock in read only mode and see if we can find the result
      RtEvent wait_on;
      {
        AutoLock l_lock(library_lock,1,false/*exclusive*/);
        std::map<std::string,LibraryMapperIDs>::const_iterator finder = 
          library_mapper_ids.find(library_name);
        if (finder != library_mapper_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != cnt)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "MapperID generation counts %zd and %zd differ for library %s",
                finder->second.count, cnt, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
      }
      RtUserEvent request_event;
      if (!wait_on.exists())
      {
        AutoLock l_lock(library_lock);
        // Check to make sure we didn't lose the race
        std::map<std::string,LibraryMapperIDs>::const_iterator finder = 
          library_mapper_ids.find(library_name);
        if (finder != library_mapper_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != cnt)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "MapperID generation counts %zd and %zd differ for library %s",
                finder->second.count, cnt, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
        if (!wait_on.exists())
        {
          LibraryMapperIDs &record = library_mapper_ids[library_name];
          record.count = cnt;
          if (address_space == 0)
          {
            // We're going to make the result
            record.result = unique_library_mapper_id;
            unique_library_mapper_id += cnt;
#ifdef DEBUG_LEGION
            assert(unique_library_mapper_id > record.result);
#endif
            record.result_set = true;
            return record.result;
          }
          else
          {
            // We're going to request the result
            request_event = Runtime::create_rt_user_event();
            record.ready = request_event;
            record.result_set = false;
            wait_on = request_event;
          }
        }
      }
      // Should only get here on nodes other than 0
#ifdef DEBUG_LEGION
      assert(address_space > 0);
      assert(wait_on.exists());
#endif
      if (request_event.exists())
      {
        // Include the null terminator in length
        const size_t string_length = strlen(name) + 1;
        // Send the request to node 0 for the result
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<size_t>(string_length);
          rez.serialize(name, string_length);
          rez.serialize<size_t>(cnt);
          rez.serialize(request_event);
        }
        send_library_mapper_request(0/*target*/, rez);
      }
      wait_on.wait();
      // When we wake up we should be able to find the result
      AutoLock l_lock(library_lock,1,false/*exclusive*/);
      std::map<std::string,LibraryMapperIDs>::const_iterator finder = 
          library_mapper_ids.find(library_name);
#ifdef DEBUG_LEGION
      assert(finder != library_mapper_ids.end());
      assert(finder->second.result_set);
#endif
      return finder->second.result;
    }

    //--------------------------------------------------------------------------
    /*static*/ MapperID& Runtime::get_current_static_mapper_id(void)
    //--------------------------------------------------------------------------
    {
      static MapperID current_mapper_id = LEGION_MAX_APPLICATION_MAPPER_ID;
      return current_mapper_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ MapperID Runtime::generate_static_mapper_id(void)
    //--------------------------------------------------------------------------
    {
      MapperID &next_mapper = get_current_static_mapper_id(); 
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'generate_static_mapper_id' after "
                      "the runtime has been started!")
      return next_mapper++;
    }

    //--------------------------------------------------------------------------
    void Runtime::replace_default_mapper(Mapper *mapper, Processor proc)
    //--------------------------------------------------------------------------
    {
      // If we have a custom mapper then silently ignore this
      if (!replay_file.empty() || enable_test_mapper)
      {
        // We take ownership of mapper so delete it now
        delete mapper;
        return;
      }
      const bool all_local_procs = !proc.exists();
      if (all_local_procs)
      {
        std::vector<Processor> all_local_processors;
        all_local_processors.reserve(proc_managers.size());
        for (std::map<Processor,ProcessorManager*>::const_iterator it = 
              proc_managers.begin(); it != proc_managers.end(); it++)
          all_local_processors.push_back(it->first);
        proc = find_processor_group(all_local_processors);
      }
      // First, wrap this mapper in a mapper manager
      MapperManager *manager = wrap_mapper(this, mapper, 0, proc); 
      if (all_local_procs)
      {
        bool own = true;
        // Save it to all the managers
        for (std::map<Processor,ProcessorManager*>::const_iterator it = 
              proc_managers.begin(); it != proc_managers.end(); it++)
        {
          it->second->replace_default_mapper(manager, own);
          own = false;
        }
      }
      else if (proc.address_space() == address_space)
      {
#ifdef DEBUG_LEGION
        assert(proc_managers.find(proc) != proc_managers.end());
#endif
        proc_managers[proc]->replace_default_mapper(manager, true/*own*/);
      }
      else
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_MAPPER_PROCESSOR,
            "Illegal attempt to register mapper %s as the default mapper "
            "for processor " IDFMT ". That processor is not local to the "
            "process where 'Runtime::replace_default_mapper' was called.",
            manager->get_mapper_name(), proc.id);
    }

    //--------------------------------------------------------------------------
    /*static*/ MapperManager* Runtime::wrap_mapper(Runtime *rt, Mapper *mapper,
                                  MapperID map_id, Processor p, bool is_default)
    //--------------------------------------------------------------------------
    {
      MapperManager *manager = NULL;
      switch (mapper->get_mapper_sync_model())
      {
        case Mapper::CONCURRENT_MAPPER_MODEL:
          {
            manager = new ConcurrentManager(rt, mapper, map_id, p, is_default);
            break;
          }
        case Mapper::SERIALIZED_REENTRANT_MAPPER_MODEL:
          {
            manager = new SerializingManager(rt, mapper, map_id, p, 
                                             true/*reentrant*/, is_default);
            break;
          }
        case Mapper::SERIALIZED_NON_REENTRANT_MAPPER_MODEL:
          {
            manager = new SerializingManager(rt, mapper, map_id, p,
                                             false/*reentrant*/, is_default);
            break;
          }
        default:
          assert(false);
      }
      return manager;
    }

    //--------------------------------------------------------------------------
    MapperManager* Runtime::find_mapper(MapperID map_id)
    //--------------------------------------------------------------------------
    {
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        MapperManager *result = it->second->find_mapper(map_id);
        if (result != NULL)
          return result;
      }
      return NULL;
    }

    //--------------------------------------------------------------------------
    MapperManager* Runtime::find_mapper(Processor target, MapperID map_id)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(target.exists());
#endif
      std::map<Processor,ProcessorManager*>::const_iterator finder = 
        proc_managers.find(target);
#ifdef DEBUG_LEGION
      assert(finder != proc_managers.end());
#endif
      return finder->second->find_mapper(map_id);
    }

    //--------------------------------------------------------------------------
    ProjectionID Runtime::generate_dynamic_projection_id(
                                                   bool check_context/*= true*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->generate_dynamic_projection_id();
      ProjectionID result = unique_projection_id.fetch_add(runtime_stride);
      // Check for hitting the library limit
      if (result >= LEGION_INITIAL_LIBRARY_ID_OFFSET)
        REPORT_LEGION_FATAL(LEGION_FATAL_EXCEEDED_LIBRARY_ID_OFFSET,
            "Dynamic Projection IDs exceeded library ID offset %d",
            LEGION_INITIAL_LIBRARY_ID_OFFSET)
      return result;
    }

    //--------------------------------------------------------------------------
    ProjectionID Runtime::generate_library_projection_ids(const char *name, 
                                                          size_t cnt)
    //--------------------------------------------------------------------------
    {
      // Easy case if the user asks for no IDs
      if (cnt == 0)
        return LEGION_AUTO_GENERATE_ID;
      const std::string library_name(name); 
      // Take the lock in read only mode and see if we can find the result
      RtEvent wait_on;
      {
        AutoLock l_lock(library_lock,1,false/*exclusive*/);
        std::map<std::string,LibraryProjectionIDs>::const_iterator finder = 
          library_projection_ids.find(library_name);
        if (finder != library_projection_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != cnt)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "ProjectionID generation counts %zd and %zd differ for "
                "library %s", finder->second.count, cnt, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
      }
      RtUserEvent request_event;
      if (!wait_on.exists())
      {
        AutoLock l_lock(library_lock);
        // Check to make sure we didn't lose the race
        std::map<std::string,LibraryProjectionIDs>::const_iterator finder = 
          library_projection_ids.find(library_name);
        if (finder != library_projection_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != cnt)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "ProjectionID generation counts %zd and %zd differ for "
                "library %s", finder->second.count, cnt, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
        if (!wait_on.exists())
        {
          LibraryProjectionIDs &record = library_projection_ids[library_name];
          record.count = cnt;
          if (address_space == 0)
          {
            // We're going to make the result
            record.result = unique_library_projection_id;
            unique_library_projection_id += cnt;
#ifdef DEBUG_LEGION
            assert(unique_library_projection_id > record.result);
#endif
            record.result_set = true;
            return record.result;
          }
          else
          {
            // We're going to request the result
            request_event = Runtime::create_rt_user_event();
            record.ready = request_event;
            record.result_set = false;
            wait_on = request_event;
          }
        }
      }
      // Should only get here on nodes other than 0
#ifdef DEBUG_LEGION
      assert(address_space > 0);
      assert(wait_on.exists());
#endif
      if (request_event.exists())
      {
        // Include the null terminator in length
        const size_t string_length = strlen(name) + 1;
        // Send the request to node 0 for the result
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<size_t>(string_length);
          rez.serialize(name, string_length);
          rez.serialize<size_t>(cnt);
          rez.serialize(request_event);
        }
        send_library_projection_request(0/*target*/, rez);
      }
      wait_on.wait();
      // When we wake up we should be able to find the result
      AutoLock l_lock(library_lock,1,false/*exclusive*/);
      std::map<std::string,LibraryProjectionIDs>::const_iterator finder = 
          library_projection_ids.find(library_name);
#ifdef DEBUG_LEGION
      assert(finder != library_projection_ids.end());
      assert(finder->second.result_set);
#endif
      return finder->second.result;
    }
    
    //--------------------------------------------------------------------------
    /*static*/ ProjectionID& Runtime::get_current_static_projection_id(void)
    //--------------------------------------------------------------------------
    {
      static ProjectionID current_projection_id = 
        LEGION_MAX_APPLICATION_PROJECTION_ID;
      return current_projection_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ ProjectionID Runtime::generate_static_projection_id(void)
    //--------------------------------------------------------------------------
    {
      ProjectionID &next_projection = get_current_static_projection_id();
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'generate_static_projection_id' after "
                      "the runtime has been started!");
      return next_projection++;
    }

    //--------------------------------------------------------------------------
    void Runtime::register_projection_functor(ProjectionID pid,
                                              ProjectionFunctor *functor,
                                              bool need_zero_check,
                                              bool silence_warnings,
                                              const char *warning_string,
                                              bool preregistered)
    //--------------------------------------------------------------------------
    {
      if (need_zero_check && (pid == 0))
        REPORT_LEGION_ERROR(ERROR_RESERVED_PROJECTION_ID, 
                            "ProjectionID zero is reserved.\n");
      if (!preregistered && !inside_registration_callback && !silence_warnings)
        REPORT_LEGION_WARNING(LEGION_WARNING_NON_CALLBACK_REGISTRATION,
            "Projection functor %d was dynamically registered outside of a "
            "registration callback invocation. In the near future this will "
            "become an error in order to support task subprocesses. Please "
            "use 'perform_registration_callback' to generate a callback where "
            "it will be safe to perform dynamic registrations.", pid)
      if (!silence_warnings && (total_address_spaces > 1) &&
          (inside_registration_callback != GLOBAL_REGISTRATION_CALLBACK))
        REPORT_LEGION_WARNING(LEGION_WARNING_DYNAMIC_PROJECTION_REG,
                        "Projection functor %d is being dynamically "
                        "registered for a multi-node run with %d nodes. It is "
                        "currently the responsibility of the application to "
                        "ensure that this projection functor is registered on "
                        "all nodes where it will be required. "
                        "Warning string: %s", pid, total_address_spaces,
                        (warning_string == NULL) ? "" : warning_string)
      ProjectionFunction *function = new ProjectionFunction(pid, functor);
      AutoLock p_lock(projection_lock);
      // No need for a lock because these all need to be reserved at
      // registration time before the runtime starts up
      std::map<ProjectionID,ProjectionFunction*>::
        const_iterator finder = projection_functions.find(pid);
      if (finder != projection_functions.end())
        REPORT_LEGION_ERROR(ERROR_DUPLICATE_PROJECTION_ID, 
                      "ProjectionID %d has already been used in "
                      "the region projection table\n", pid)
      projection_functions[pid] = function;
      if (legion_spy_enabled)
        LegionSpy::log_projection_function(pid, function->depth, 
                                           function->is_invertible);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::preregister_projection_functor(ProjectionID pid,
                                                     ProjectionFunctor *functor)
    //--------------------------------------------------------------------------
    {
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'preregister_projection_functor' after "
                      "the runtime has started!")
      if (pid == 0)
        REPORT_LEGION_ERROR(ERROR_RESERVED_PROJECTION_ID, 
                            "ProjectionID zero is reserved.\n");
      std::map<ProjectionID,ProjectionFunctor*> &pending_projection_functors =
        get_pending_projection_table();
      std::map<ProjectionID,ProjectionFunctor*>::const_iterator finder = 
        pending_projection_functors.find(pid);
      if (finder != pending_projection_functors.end())
        REPORT_LEGION_ERROR(ERROR_DUPLICATE_PROJECTION_ID, 
                      "ProjectionID %d has already been used in "
                      "the region projection table\n", pid)
      pending_projection_functors[pid] = functor;
    }

    //--------------------------------------------------------------------------
    ProjectionFunction* Runtime::find_projection_function(ProjectionID pid,
                                                          bool can_fail)
    //--------------------------------------------------------------------------
    {
      AutoLock p_lock(projection_lock,1,false/*exclusive*/);
      std::map<ProjectionID,ProjectionFunction*>::
        const_iterator finder = projection_functions.find(pid);
      if (finder == projection_functions.end())
      {
        if (can_fail)
          return NULL;
        REPORT_LEGION_ERROR(ERROR_INVALID_PROJECTION_ID, 
                        "Unable to find registered region projection ID %d. "
                        "Please upgrade to using projection functors!", pid);
      }
      return finder->second;
    }

    //--------------------------------------------------------------------------
    /*static*/ ProjectionFunctor* Runtime::get_projection_functor(
                                                               ProjectionID pid) 
    //--------------------------------------------------------------------------
    {
      if (runtime_started)
      {
        ProjectionFunction *func = 
          the_runtime->find_projection_function(pid, true/*can fail*/);
        if (func != NULL)
          return func->functor;
      }
      else
      {
        std::map<ProjectionID,ProjectionFunctor*> &pending_projection_functors =
          get_pending_projection_table();
        std::map<ProjectionID,ProjectionFunctor*>::const_iterator finder = 
          pending_projection_functors.find(pid);
        if (finder != pending_projection_functors.end())
          return finder->second;
      }
      return NULL;
    }

    //--------------------------------------------------------------------------
    void Runtime::unregister_projection_functor(ProjectionID pid)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(runtime_started);
#endif
      AutoLock p_lock(projection_lock);
      std::map<ProjectionID,ProjectionFunction*>::iterator finder =
        projection_functions.find(pid);
      if (finder != projection_functions.end())
      {
        delete finder->second;
        projection_functions.erase(finder);
        return;
      }
#ifdef DEBUG_LEGION
      assert(separate_runtime_instances);
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(TaskID task_id, SemanticTag tag,
           const void *buffer, size_t size, bool is_mutable, bool send_to_owner)
    //--------------------------------------------------------------------------
    {
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(send_to_owner))
        return;
      if ((tag == LEGION_NAME_SEMANTIC_TAG) && legion_spy_enabled)
        LegionSpy::log_task_name(task_id, static_cast<const char*>(buffer));
      TaskImpl *impl = find_or_create_task_impl(task_id);
      impl->attach_semantic_information(tag, address_space, buffer, size, 
                                        is_mutable, send_to_owner);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(IndexSpace handle, 
                                              SemanticTag tag,
                                              const void *buffer, size_t size,
                                              bool is_mutable)
    //--------------------------------------------------------------------------
    {
      bool global = true;
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(global))
        return;
      forest->attach_semantic_information(handle, tag, address_space, 
                                          buffer, size, is_mutable, !global);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(IndexPartition handle, 
                                              SemanticTag tag,
                                              const void *buffer, size_t size,
                                              bool is_mutable)
    //--------------------------------------------------------------------------
    {
      bool global = true;
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(global))
        return;
      forest->attach_semantic_information(handle, tag, address_space, 
                                          buffer, size, is_mutable, !global);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(FieldSpace handle, 
                                              SemanticTag tag,
                                              const void *buffer, size_t size,
                                              bool is_mutable)
    //--------------------------------------------------------------------------
    {
      bool global = true;
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(global))
        return;
      forest->attach_semantic_information(handle, tag, address_space, 
                                          buffer, size, is_mutable, !global);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(FieldSpace handle, FieldID fid,
                                              SemanticTag tag,
                                              const void *buffer, size_t size,
                                              bool is_mutable)
    //--------------------------------------------------------------------------
    {
      bool global = true;
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(global))
        return;
      forest->attach_semantic_information(handle, fid, tag, address_space, 
                                          buffer, size, is_mutable, !global);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(LogicalRegion handle, 
                                              SemanticTag tag,
                                              const void *buffer, size_t size,
                                              bool is_mutable)
    //--------------------------------------------------------------------------
    {
      bool global = true;
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(global))
        return;
      forest->attach_semantic_information(handle, tag, address_space, 
                                          buffer, size, is_mutable, !global);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    void Runtime::attach_semantic_information(LogicalPartition handle, 
                                              SemanticTag tag,
                                              const void *buffer, size_t size,
                                              bool is_mutable)
    //--------------------------------------------------------------------------
    {
      bool global = true;
      if ((implicit_context != NULL) && 
          !implicit_context->perform_semantic_attach(global))
        return;
      forest->attach_semantic_information(handle, tag, address_space, 
                                          buffer, size, is_mutable, !global);
      if (implicit_context != NULL)
        implicit_context->post_semantic_attach();
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(TaskID task_id,SemanticTag tag,
              const void *&result, size_t &size, bool can_fail, bool wait_until)
    //--------------------------------------------------------------------------
    {
      TaskImpl *impl = find_or_create_task_impl(task_id);
      return impl->retrieve_semantic_information(tag, result, size, 
                                                 can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(IndexSpace handle,
                                                SemanticTag tag,
                                                const void *&result, 
                                                size_t &size, bool can_fail,
                                                bool wait_until)
    //--------------------------------------------------------------------------
    {
      return forest->retrieve_semantic_information(handle, tag, result, size,
                                                   can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(IndexPartition handle,
                                                SemanticTag tag,
                                                const void *&result, 
                                                size_t &size, bool can_fail,
                                                bool wait_until)
    //--------------------------------------------------------------------------
    {
      return forest->retrieve_semantic_information(handle, tag, result, size, 
                                                   can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(FieldSpace handle,
                                                SemanticTag tag,
                                                const void *&result, 
                                                size_t &size, bool can_fail,
                                                bool wait_until)
    //--------------------------------------------------------------------------
    {
      return forest->retrieve_semantic_information(handle, tag, result, size,
                                                   can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(FieldSpace handle, FieldID fid,
                                                SemanticTag tag,
                                                const void *&result, 
                                                size_t &size, bool can_fail,
                                                bool wait_until)
    //--------------------------------------------------------------------------
    {
      return forest->retrieve_semantic_information(handle, fid, tag, result, 
                                                   size, can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(LogicalRegion handle,
                                                SemanticTag tag,
                                                const void *&result, 
                                                size_t &size, bool can_fail,
                                                bool wait_until)
    //--------------------------------------------------------------------------
    {
      return forest->retrieve_semantic_information(handle, tag, result, size,
                                                   can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    bool Runtime::retrieve_semantic_information(LogicalPartition handle,
                                                SemanticTag tag,
                                                const void *&result, 
                                                size_t &size, bool can_fail,
                                                bool wait_until)
    //--------------------------------------------------------------------------
    {
      return forest->retrieve_semantic_information(handle, tag, result, size,
                                                   can_fail, wait_until);
    }

    //--------------------------------------------------------------------------
    TaskID Runtime::generate_dynamic_task_id(bool check_context/*= true*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->generate_dynamic_task_id();
      TaskID result = unique_task_id.fetch_add(runtime_stride);
      // Check for hitting the library limit
      if (result >= LEGION_INITIAL_LIBRARY_ID_OFFSET)
        REPORT_LEGION_FATAL(LEGION_FATAL_EXCEEDED_LIBRARY_ID_OFFSET,
            "Dynamic Task IDs exceeded library ID offset %d",
            LEGION_INITIAL_LIBRARY_ID_OFFSET)
      return result;
    }

    //--------------------------------------------------------------------------
    TaskID Runtime::generate_library_task_ids(const char *name, size_t cnt)
    //--------------------------------------------------------------------------
    {
      // Easy case if the user asks for no IDs
      if (cnt == 0)
        return LEGION_AUTO_GENERATE_ID;
      const std::string library_name(name); 
      // Take the lock in read only mode and see if we can find the result
      RtEvent wait_on;
      {
        AutoLock l_lock(library_lock,1,false/*exclusive*/);
        std::map<std::string,LibraryTaskIDs>::const_iterator finder = 
          library_task_ids.find(library_name);
        if (finder != library_task_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != cnt)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "TaskID generation counts %zd and %zd differ for library %s",
                finder->second.count, cnt, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
      }
      RtUserEvent request_event;
      if (!wait_on.exists())
      {
        AutoLock l_lock(library_lock);
        // Check to make sure we didn't lose the race
        std::map<std::string,LibraryTaskIDs>::const_iterator finder = 
          library_task_ids.find(library_name);
        if (finder != library_task_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != cnt)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "TaskID generation counts %zd and %zd differ for library %s",
                finder->second.count, cnt, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
        if (!wait_on.exists())
        {
          LibraryTaskIDs &record = library_task_ids[library_name];
          record.count = cnt;
          if (address_space == 0)
          {
            // We're going to make the result
            record.result = unique_library_task_id;
            unique_library_task_id += cnt;
#ifdef DEBUG_LEGION
            assert(unique_library_task_id > record.result);
#endif
            record.result_set = true;
            return record.result;
          }
          else
          {
            // We're going to request the result
            request_event = Runtime::create_rt_user_event();
            record.ready = request_event;
            record.result_set = false;
            wait_on = request_event;
          }
        }
      }
      // Should only get here on nodes other than 0
#ifdef DEBUG_LEGION
      assert(address_space > 0);
      assert(wait_on.exists());
#endif
      if (request_event.exists())
      {
        // Include the null terminator in length
        const size_t string_length = strlen(name) + 1;
        // Send the request to node 0 for the result
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<size_t>(string_length);
          rez.serialize(name, string_length);
          rez.serialize<size_t>(cnt);
          rez.serialize(request_event);
        }
        send_library_task_request(0/*target*/, rez);
      }
      wait_on.wait();
      // When we wake up we should be able to find the result
      AutoLock l_lock(library_lock,1,false/*exclusive*/);
      std::map<std::string,LibraryTaskIDs>::const_iterator finder = 
          library_task_ids.find(library_name);
#ifdef DEBUG_LEGION
      assert(finder != library_task_ids.end());
      assert(finder->second.result_set);
#endif
      return finder->second.result;
    }

    //--------------------------------------------------------------------------
    VariantID Runtime::register_variant(const TaskVariantRegistrar &registrar,
                                  const void *user_data, size_t user_data_size,
                                  const CodeDescriptor &realm_code_desc,
                                  size_t return_type_size,
                                  VariantID vid /*= AUTO_GENERATE_ID*/,
                                  bool check_task_id /*= true*/,
                                  bool check_context /*= true*/,
                                  bool preregistered /*= false*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->register_variant(registrar, user_data,
         user_data_size, realm_code_desc, return_type_size, vid, check_task_id);
      // TODO: figure out a way to make this check safe with dynamic generation
#if 0
      if (check_task_id && 
          (registrar.task_id >= LEGION_MAX_APPLICATION_TASK_ID))
        REPORT_LEGION_ERROR(ERROR_MAX_APPLICATION_TASK_ID_EXCEEDED, 
                      "Error registering task with ID %d. Exceeds the "
                      "statically set bounds on application task IDs of %d. "
                      "See %s in legion_config.h.", 
                      registrar.task_id, LEGION_MAX_APPLICATION_TASK_ID, 
                      LEGION_MACRO_TO_STRING(LEGION_MAX_APPLICATION_TASK_ID))
#endif  
      // First find the task implementation
      TaskImpl *task_impl = find_or_create_task_impl(registrar.task_id);
      // See if we need to make a new variant ID
      if (vid == LEGION_AUTO_GENERATE_ID) // Make a variant ID to use
        vid = task_impl->get_unique_variant_id();
      else if (vid == 0)
        REPORT_LEGION_ERROR(ERROR_RESERVED_VARIANT_ID,
                      "Error registering variant for task ID %d with "
                      "variant ID 0. Variant ID 0 is reserved for task "
                      "generators.", registrar.task_id)
      // Make our variant and add it to the set of variants
      VariantImpl *impl = new VariantImpl(this, vid, task_impl, registrar,
                                          return_type_size, realm_code_desc,
                                          user_data, user_data_size);
      // Add this variant to the owner
      task_impl->add_variant(impl);
      {
        AutoLock tv_lock(task_variant_lock);
        variant_table.push_back(impl);
      }
      // If this is a global registration we need to broadcast the variant
      if (registrar.global_registration && (total_address_spaces > 1))
      {
        RtUserEvent done_event = Runtime::create_rt_user_event();
        impl->broadcast_variant(done_event, address_space, 0);
        done_event.wait();
      }
      if (legion_spy_enabled)
        LegionSpy::log_task_variant(registrar.task_id, vid, 
                                    impl->is_inner(), impl->is_leaf(),
                                    impl->is_idempotent(), impl->get_name());
      return vid;
    }

    //--------------------------------------------------------------------------
    TaskImpl* Runtime::find_or_create_task_impl(TaskID task_id)
    //--------------------------------------------------------------------------
    {
      {
        AutoLock tv_lock(task_variant_lock,1,false/*exclusive*/);
        std::map<TaskID,TaskImpl*>::const_iterator finder = 
          task_table.find(task_id);
        if (finder != task_table.end())
          return finder->second;
      }
      AutoLock tv_lock(task_variant_lock);
      std::map<TaskID,TaskImpl*>::const_iterator finder = 
        task_table.find(task_id);
      // Check to see if we lost the race
      if (finder == task_table.end())
      {
        TaskImpl *result = new TaskImpl(task_id, this);
        task_table[task_id] = result;
        return result;
      }
      else // Lost the race as it already exists
        return finder->second;
    }

    //--------------------------------------------------------------------------
    TaskImpl* Runtime::find_task_impl(TaskID task_id)
    //--------------------------------------------------------------------------
    {
      AutoLock tv_lock(task_variant_lock,1,false/*exclusive*/);
      std::map<TaskID,TaskImpl*>::const_iterator finder = 
        task_table.find(task_id);
#ifdef DEBUG_LEGION
      assert(finder != task_table.end());
#endif
      return finder->second;
    }

    //--------------------------------------------------------------------------
    VariantImpl* Runtime::find_variant_impl(TaskID task_id, 
                                             VariantID variant_id,bool can_fail)
    //--------------------------------------------------------------------------
    {
      TaskImpl *owner = find_or_create_task_impl(task_id);
      return owner->find_variant_impl(variant_id, can_fail);
    }

    //--------------------------------------------------------------------------
    ReductionOpID Runtime::generate_dynamic_reduction_id(
                                                   bool check_context/*= true*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->generate_dynamic_reduction_id();
      ReductionOpID result = unique_redop_id.fetch_add(runtime_stride);
      // Check for hitting the library limit
      if (result >= LEGION_INITIAL_LIBRARY_ID_OFFSET)
        REPORT_LEGION_FATAL(LEGION_FATAL_EXCEEDED_LIBRARY_ID_OFFSET,
            "Dynamic Reduction IDs exceeded library ID offset %d",
            LEGION_INITIAL_LIBRARY_ID_OFFSET)
      return result;
    }

    //--------------------------------------------------------------------------
    ReductionOpID Runtime::generate_library_reduction_ids(const char *name,
                                                          size_t count)
    //--------------------------------------------------------------------------
    {
      // Easy case if the user asks for no IDs
      if (count == 0)
        return (ReductionOpID)LEGION_AUTO_GENERATE_ID;
      const std::string library_name(name); 
      // Take the lock in read only mode and see if we can find the result
      RtEvent wait_on;
      {
        AutoLock l_lock(library_lock,1,false/*exclusive*/);
        std::map<std::string,LibraryRedopIDs>::const_iterator finder = 
          library_redop_ids.find(library_name);
        if (finder != library_redop_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != count)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "ReductionOpID generation counts %zd and %zd differ for "
                "library %s", finder->second.count, count, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
      }
      RtUserEvent request_event;
      if (!wait_on.exists())
      {
        AutoLock l_lock(library_lock);
        // Check to make sure we didn't lose the race
        std::map<std::string,LibraryRedopIDs>::const_iterator finder = 
          library_redop_ids.find(library_name);
        if (finder != library_redop_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != count)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "ReductionOpID generation counts %zd and %zd differ for "
                "library %s", finder->second.count, count, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
        if (!wait_on.exists())
        {
          LibraryRedopIDs &record = library_redop_ids[library_name];
          record.count = count;
          if (address_space == 0)
          {
            // We're going to make the result
            record.result = unique_library_redop_id;
            unique_library_redop_id += count;
#ifdef DEBUG_LEGION
            assert(unique_library_redop_id > unsigned(record.result));
#endif
            record.result_set = true;
            return record.result;
          }
          else
          {
            // We're going to request the result
            request_event = Runtime::create_rt_user_event();
            record.ready = request_event;
            record.result_set = false;
            wait_on = request_event;
          }
        }
      }
      // Should only get here on nodes other than 0
#ifdef DEBUG_LEGION
      assert(address_space > 0);
      assert(wait_on.exists());
#endif
      if (request_event.exists())
      {
        // Include the null terminator in length
        const size_t string_length = strlen(name) + 1;
        // Send the request to node 0 for the result
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<size_t>(string_length);
          rez.serialize(name, string_length);
          rez.serialize<size_t>(count);
          rez.serialize(request_event);
        }
        send_library_redop_request(0/*target*/, rez);
      }
      wait_on.wait();
      // When we wake up we should be able to find the result
      AutoLock l_lock(library_lock,1,false/*exclusive*/);
      std::map<std::string,LibraryRedopIDs>::const_iterator finder = 
          library_redop_ids.find(library_name);
#ifdef DEBUG_LEGION
      assert(finder != library_redop_ids.end());
      assert(finder->second.result_set);
#endif
      return finder->second.result;
    }

    //--------------------------------------------------------------------------
    CustomSerdezID Runtime::generate_dynamic_serdez_id(
                                                   bool check_context/*= true*/)
    //--------------------------------------------------------------------------
    {
      if (check_context && (implicit_context != NULL))
        return implicit_context->generate_dynamic_serdez_id();
      CustomSerdezID result = unique_serdez_id.fetch_add(runtime_stride);
      // Check for hitting the library limit
      if (result >= LEGION_INITIAL_LIBRARY_ID_OFFSET)
        REPORT_LEGION_FATAL(LEGION_FATAL_EXCEEDED_LIBRARY_ID_OFFSET,
            "Dynamic Custom Serdez IDs exceeded library ID offset %d",
            LEGION_INITIAL_LIBRARY_ID_OFFSET)
      return result;
    }

    //--------------------------------------------------------------------------
    CustomSerdezID Runtime::generate_library_serdez_ids(const char *name,
                                                        size_t count)
    //--------------------------------------------------------------------------
    {
      // Easy case if the user asks for no IDs
      if (count == 0)
        return (CustomSerdezID)LEGION_AUTO_GENERATE_ID;
      const std::string library_name(name); 
      // Take the lock in read only mode and see if we can find the result
      RtEvent wait_on;
      {
        AutoLock l_lock(library_lock,1,false/*exclusive*/);
        std::map<std::string,LibrarySerdezIDs>::const_iterator finder = 
          library_serdez_ids.find(library_name);
        if (finder != library_serdez_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != count)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "CustomSerdezID generation counts %zd and %zd differ for "
                "library %s", finder->second.count, count, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
      }
      RtUserEvent request_event;
      if (!wait_on.exists())
      {
        AutoLock l_lock(library_lock);
        // Check to make sure we didn't lose the race
        std::map<std::string,LibrarySerdezIDs>::const_iterator finder = 
          library_serdez_ids.find(library_name);
        if (finder != library_serdez_ids.end())
        {
          // First do a check to see if the counts match
          if (finder->second.count != count)
            REPORT_LEGION_ERROR(ERROR_LIBRARY_COUNT_MISMATCH,
                "CustomSerdezID generation counts %zd and %zd differ for "
                "library %s", finder->second.count, count, name)
          if (finder->second.result_set)
            return finder->second.result;
          // This should never happen unless we are on a node other than 0
#ifdef DEBUG_LEGION
          assert(address_space > 0);
#endif
          wait_on = finder->second.ready;
        }
        if (!wait_on.exists())
        {
          LibrarySerdezIDs &record = library_serdez_ids[library_name];
          record.count = count;
          if (address_space == 0)
          {
            // We're going to make the result
            record.result = unique_library_serdez_id;
            unique_library_serdez_id += count;
#ifdef DEBUG_LEGION
            assert(unique_library_serdez_id > unsigned(record.result));
#endif
            record.result_set = true;
            return record.result;
          }
          else
          {
            // We're going to request the result
            request_event = Runtime::create_rt_user_event();
            record.ready = request_event;
            record.result_set = false;
            wait_on = request_event;
          }
        }
      }
      // Should only get here on nodes other than 0
#ifdef DEBUG_LEGION
      assert(address_space > 0);
      assert(wait_on.exists());
#endif
      if (request_event.exists())
      {
        // Include the null terminator in length
        const size_t string_length = strlen(name) + 1;
        // Send the request to node 0 for the result
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize<size_t>(string_length);
          rez.serialize(name, string_length);
          rez.serialize<size_t>(count);
          rez.serialize(request_event);
        }
        send_library_serdez_request(0/*target*/, rez);
      }
      wait_on.wait();
      // When we wake up we should be able to find the result
      AutoLock l_lock(library_lock,1,false/*exclusive*/);
      std::map<std::string,LibrarySerdezIDs>::const_iterator finder = 
          library_serdez_ids.find(library_name);
#ifdef DEBUG_LEGION
      assert(finder != library_serdez_ids.end());
      assert(finder->second.result_set);
#endif
      return finder->second.result;
    }

    //--------------------------------------------------------------------------
    MemoryManager* Runtime::find_memory_manager(Memory mem)
    //--------------------------------------------------------------------------
    {
      {
        AutoLock m_lock(memory_manager_lock,1,false/*exclusive*/);
        std::map<Memory,MemoryManager*>::const_iterator finder = 
          memory_managers.find(mem);
        if (finder != memory_managers.end())
          return finder->second;
      }
      // Not there?  Take exclusive lock and check again, create if needed
      AutoLock m_lock(memory_manager_lock);
      std::map<Memory,MemoryManager*>::const_iterator finder =
        memory_managers.find(mem);
      if (finder != memory_managers.end())
        return finder->second;
      // Really do need to create it (and put it in the map)
      MemoryManager *result = new MemoryManager(mem, this);
      memory_managers[mem] = result;
      return result;
    }

    //--------------------------------------------------------------------------
    AddressSpaceID Runtime::find_address_space(Memory handle) const
    //--------------------------------------------------------------------------
    {
      // Just use the standard translation for now
      AddressSpaceID result = handle.address_space();
      return result;
    }

#ifdef LEGION_MALLOC_INSTANCES
    //--------------------------------------------------------------------------
    uintptr_t Runtime::allocate_deferred_instance(Memory memory, size_t size,
                                                  bool free)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(memory);
      // Note that we don't need to defer this because this call had to 
      // come from an application processor where we can do the call
      // to allocate directly (e.g. CUDA contexts are already here)
      uintptr_t result = manager->allocate_legion_instance(size,false/*defer*/);
      if (free)
        manager->free_legion_instance(
            RtEvent(Processor::get_current_finish_event()), result, false);
      return result;
    }
#endif

    //--------------------------------------------------------------------------
    MessageManager* Runtime::find_messenger(AddressSpaceID sid)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(sid < LEGION_MAX_NUM_NODES);
      assert(sid != address_space); // shouldn't be sending messages to ourself
#endif
      MessageManager *result = message_managers[sid].load();
      if (result != NULL)
        return result;
      // If we made it here, then we don't have a message manager yet
      // re-take the lock and re-check to see if we don't have a manager
      // If we still don't then we need to make one
      RtEvent wait_on;
      bool send_request = false;
      {
        AutoLock m_lock(message_manager_lock);
        // Re-check to see if we lost the race, force the compiler
        // to re-load the value here
        result = message_managers[sid].load();
        if (result != NULL)
          return result;
        // Figure out if there is an event to wait on yet
        std::map<AddressSpace,RtUserEvent>::const_iterator finder = 
          pending_endpoint_requests.find(sid);
        if (finder == pending_endpoint_requests.end())
        {
          RtUserEvent done = Runtime::create_rt_user_event();
          pending_endpoint_requests[sid] = done;
          wait_on = done;
          send_request = true;
        }
        else
          wait_on = finder->second;
      }
      if (send_request)
      {
#ifdef DEBUG_LEGION
        bool found = false;
#endif
        // Find a processor on which to send the task
        for (std::map<Processor,AddressSpaceID>::const_iterator it = 
              proc_spaces.begin(); it != proc_spaces.end(); it++)
        {
          if (it->second != sid)
            continue;
#ifdef DEBUG_LEGION
          found = true;
#endif
          Serializer rez;
          {
            RezCheck z(rez);
            rez.serialize<bool>(true); // request
            rez.serialize(utility_group);
          }
          const Realm::ProfilingRequestSet empty_requests;
          it->first.spawn(LG_ENDPOINT_TASK_ID, rez.get_buffer(),
              rez.get_used_bytes(), empty_requests);
          break;
        }
#ifdef DEBUG_LEGION
        assert(found);
#endif
      }
#ifdef DEBUG_LEGION
      assert(wait_on.exists());
#endif
      if (!wait_on.has_triggered())
        wait_on.wait();
      // When we wake up there should be a result
      result = message_managers[sid].load();
#ifdef DEBUG_LEGION
      assert(result != NULL);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    MessageManager* Runtime::find_messenger(Processor target)
    //--------------------------------------------------------------------------
    {
      return find_messenger(find_address_space(target));
    }

    //--------------------------------------------------------------------------
    AddressSpaceID Runtime::find_address_space(Processor target) const
    //--------------------------------------------------------------------------
    {
      std::map<Processor,AddressSpaceID>::const_iterator finder = 
        proc_spaces.find(target);
      if (finder != proc_spaces.end())
        return finder->second;
#ifdef DEBUG_LEGION
      // If we get here then this better be a processor group
      assert(target.kind() == Processor::PROC_GROUP);
#endif
      AutoLock m_lock(message_manager_lock,1,false/*exclusive*/);
      finder = endpoint_spaces.find(target);
#ifdef DEBUG_LEGION
      assert(finder != endpoint_spaces.end());
#endif
      return finder->second;
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_endpoint_creation(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      bool request;
      derez.deserialize(request);
      Processor remote_utility_group;
      derez.deserialize(remote_utility_group);
      if (request)
      {
        Serializer rez;
        {
          RezCheck z2(rez);
          rez.serialize<bool>(false/*request*/);
          rez.serialize(utility_group);
          rez.serialize(address_space);
        }
        const Realm::ProfilingRequestSet empty_requests;
        remote_utility_group.spawn(LG_ENDPOINT_TASK_ID, rez.get_buffer(),
            rez.get_used_bytes(), empty_requests); 
      }
      else
      {
        AddressSpaceID remote_space;
        derez.deserialize(remote_space);
        AutoLock m_lock(message_manager_lock);
        message_managers[remote_space].store(new MessageManager(remote_space,
                              this, max_message_size, remote_utility_group));
        // Also update the endpoint spaces
        endpoint_spaces[remote_utility_group] = remote_space;
        std::map<AddressSpaceID,RtUserEvent>::iterator finder = 
          pending_endpoint_requests.find(remote_space);
#ifdef DEBUG_LEGION
        assert(finder != pending_endpoint_requests.end());
#endif
        Runtime::trigger_event(finder->second);
        pending_endpoint_requests.erase(finder);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::process_mapper_message(Processor target, MapperID map_id,
                                     Processor source, const void *message,
                                     size_t message_size, unsigned message_kind)
    //--------------------------------------------------------------------------
    {
      if (is_local(target))
      {
        Mapper::MapperMessage message_args;
        message_args.sender = source;
        message_args.kind = message_kind;
        message_args.message = message;
        message_args.size = message_size;
        message_args.broadcast = false;
        MapperManager *mapper = find_mapper(target, map_id);
        mapper->invoke_handle_message(&message_args);
      }
      else
      {
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(target);
          rez.serialize(map_id);
          rez.serialize(source);
          rez.serialize(message_kind);
          rez.serialize(message_size);
          rez.serialize(message, message_size);
        }
        send_mapper_message(find_address_space(target), rez);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::process_mapper_broadcast(MapperID map_id, Processor source, 
                                    const void *message, size_t message_size, 
                                    unsigned message_kind, int radix, int index)
    //--------------------------------------------------------------------------
    {
      // First forward the message onto any remote nodes
      int base = index * radix;
      int init;
      if (separate_runtime_instances)
      {
        std::map<Processor,AddressSpaceID>::const_iterator finder = 
          proc_spaces.find(source); 
#ifdef DEBUG_LEGION
        // only works with a single process
        assert(finder != proc_spaces.end()); 
#endif
        init = finder->second;
      }
      else
        init = source.address_space();
      // The runtime stride is the same as the number of nodes
      const int total_nodes = runtime_stride;
      for (int r = 1; r <= radix; r++)
      {
        int offset = base + r;
        // If we've handled all of our nodes then we are done
        if (offset >= total_nodes)
          break;
        AddressSpaceID target = (init + offset) % total_nodes;
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(map_id);
          rez.serialize(source);
          rez.serialize(message_kind);
          rez.serialize(radix);
          rez.serialize(offset);
          rez.serialize(message_size);
          rez.serialize(message, message_size);
        }
        send_mapper_broadcast(target, rez);
      }
      // Then send it to all our local mappers, set will deduplicate
      std::set<MapperManager*> managers;
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        managers.insert(it->second->find_mapper(map_id));
      }
      Mapper::MapperMessage message_args;
      message_args.sender = source;
      message_args.kind = message_kind;
      message_args.message = message;
      message_args.size = message_size;
      message_args.broadcast = true;
      for (std::set<MapperManager*>::const_iterator it = 
            managers.begin(); it != managers.end(); it++)
        (*it)->invoke_handle_message(&message_args);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_task(TaskOp *task)
    //--------------------------------------------------------------------------
    {
      Processor target = task->target_proc;
      if (!target.exists())
        REPORT_LEGION_ERROR(ERROR_INVALID_TARGET_PROC, 
                      "Mapper requested invalid NO_PROC as target proc!");
      // Check to see if the target processor is still local 
      std::map<Processor,ProcessorManager*>::const_iterator finder = 
        proc_managers.find(target);
      if (finder != proc_managers.end())
      {
        // Update the current processor
        task->set_current_proc(target);
        finder->second->add_to_ready_queue(task);
      }
      else
      {
        MessageManager *manager = find_messenger(target);
        Serializer rez;
        bool deactivate_task;
        const AddressSpaceID target_addr = find_address_space(target);
        {
          RezCheck z(rez);
          rez.serialize(target);
          rez.serialize(task->get_task_kind());
          deactivate_task = task->pack_task(rez, target_addr);
        }
        manager->send_message<TASK_MESSAGE>(rez, true/*flush*/);
        if (deactivate_task)
          task->deactivate();
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::send_tasks(Processor target, const std::set<TaskOp*> &tasks)
    //--------------------------------------------------------------------------
    {
      if (!target.exists())
        REPORT_LEGION_ERROR(ERROR_INVALID_TARGET_PROC, 
                      "Mapper requested invalid NO_PROC as target proc!");
      // Check to see if the target processor is still local 
      std::map<Processor,ProcessorManager*>::const_iterator finder = 
        proc_managers.find(target);
      if (finder != proc_managers.end())
      {
        // Still local
        for (std::set<TaskOp*>::const_iterator it = tasks.begin();
              it != tasks.end(); it++)
        {
          // Update the current processor
          (*it)->set_current_proc(target);
          finder->second->add_to_ready_queue(*it);
        }
      }
      else
      {
        // Otherwise we need to send it remotely
        MessageManager *manager = find_messenger(target);
        unsigned idx = 1;
        const AddressSpaceID target_addr = find_address_space(target);
        for (std::set<TaskOp*>::const_iterator it = tasks.begin();
              it != tasks.end(); it++,idx++)
        {
          Serializer rez;
          bool deactivate_task;
          {
            RezCheck z(rez);
            rez.serialize(target);
            rez.serialize((*it)->get_task_kind());
            deactivate_task = (*it)->pack_task(rez, target_addr);
          }
          // Put it in the queue, flush the last task
          manager->send_message<TASK_MESSAGE>(rez, (idx == tasks.size()));
          // Deactivate the task if it is remote
          if (deactivate_task)
            (*it)->deactivate();
        }
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::send_steal_request(
              const std::multimap<Processor,MapperID> &targets, Processor thief)
    //--------------------------------------------------------------------------
    {
      for (std::multimap<Processor,MapperID>::const_iterator it = 
            targets.begin(); it != targets.end(); it++)
      {
        Processor target = it->first;
        std::map<Processor,ProcessorManager*>::const_iterator finder = 
          proc_managers.find(target);
        if (finder == proc_managers.end())
        {
          // Need to send remotely
          MessageManager *manager = find_messenger(target);
          Serializer rez;
          {
            RezCheck z(rez);
            rez.serialize(target);
            rez.serialize(thief);
            int num_mappers = targets.count(target);
            rez.serialize(num_mappers);
            for ( ; it != targets.upper_bound(target); it++)
              rez.serialize(it->second);
          }
          manager->send_message<STEAL_MESSAGE>(rez, true/*flush*/);
        }
        else
        {
          // Still local, so notify the processor manager
          std::vector<MapperID> thieves;
          for ( ; it != targets.upper_bound(target); it++)
            thieves.push_back(it->second);
          finder->second->process_steal_request(thief, thieves);
          
        }
        if (it == targets.end())
          break;
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::send_advertisements(const std::set<Processor> &targets,
                                            MapperID map_id, Processor source)
    //--------------------------------------------------------------------------
    {
      std::set<MessageManager*> already_sent;
      for (std::set<Processor>::const_iterator it = targets.begin();
            it != targets.end(); it++)
      {
        std::map<Processor,ProcessorManager*>::const_iterator finder = 
          proc_managers.find(*it);
        if (finder != proc_managers.end())
        {
          // still local
          finder->second->process_advertisement(source, map_id);
        }
        else
        {
          // otherwise remote, check to see if we already sent it
          MessageManager *messenger = find_messenger(*it);
          if (already_sent.find(messenger) != already_sent.end())
            continue;
          Serializer rez;
          {
            RezCheck z(rez);
            rez.serialize(source);
            rez.serialize(map_id);
          }
          messenger->send_message<ADVERTISEMENT_MESSAGE>(rez, true/*flush*/);
          already_sent.insert(messenger);
        }
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_task_replay(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_TASK_REPLAY>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_task_profiling_response(Processor target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_TASK_PROFILING_RESPONSE>( 
                                          rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_shared_ownership(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_SHARED_OWNERSHIP>(rez,
                                      true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_request(AddressSpaceID target,
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_REQUEST>(rez, 
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_return(AddressSpaceID target,
                                     Serializer &rez, RtEvent send_precondition)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_RETURN>(rez,
         true/*flush*/, true/*response*/, false/*shutdown*/, send_precondition);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_set(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_SET>(rez,
                                      true/*flush*/, true/*return*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_child_request(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_CHILD_REQUEST>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_child_response(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_CHILD_RESPONSE>(rez,
                                               true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_colors_request(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_COLORS_REQUEST>(rez,
                                                                 true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_colors_response(AddressSpaceID target,
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_COLORS_RESPONSE>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_remote_expression_request(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_INDEX_SPACE_REMOTE_EXPRESSION_REQUEST>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_remote_expression_response(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_INDEX_SPACE_REMOTE_EXPRESSION_RESPONSE>(rez,
          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_generate_color_request(AddressSpaceID target,
                                                          Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_INDEX_SPACE_GENERATE_COLOR_REQUEST>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_generate_color_response(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_INDEX_SPACE_GENERATE_COLOR_RESPONSE>(rez,
            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_release_color(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // This has to go on the reference virtual channel so that it is 
      // handled before the owner node is deleted
      find_messenger(target)->send_message<SEND_INDEX_SPACE_RELEASE_COLOR>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_notification(AddressSpaceID target,
                                                    Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_NOTIFICATION>( 
                                                          rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_request(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_REQUEST>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_return(AddressSpaceID target,
                                     Serializer &rez, RtEvent send_precondition)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_RETURN>(rez,
        true/*flush*/, true/*response*/, false/*shutdown*/, send_precondition);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_child_request(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_CHILD_REQUEST>(
                                                            rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_child_response(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_CHILD_RESPONSE>( 
                                          rez, true/*flush*/, true/*response*/); 
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_disjoint_update(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_INDEX_PARTITION_DISJOINT_UPDATE>(rez,
            true/*flush*/, true/*response*/); 
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_node(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // Will be flushed by return
      find_messenger(target)->send_message<SEND_FIELD_SPACE_NODE>(rez,
                                                      false/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_request(AddressSpaceID target,
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_REQUEST>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_return(AddressSpaceID target,
                                          Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_RETURN>(rez,
                                        true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_allocator_request(AddressSpaceID target,
                                                     Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_ALLOCATOR_REQUEST>(
                                                            rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_allocator_response(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_ALLOCATOR_RESPONSE>(
                                          rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_allocator_invalidation(AddressSpaceID target,
                                                          Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_FIELD_SPACE_ALLOCATOR_INVALIDATION>(rez,
          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_allocator_flush(AddressSpaceID target,
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_ALLOCATOR_FLUSH>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_allocator_free(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_ALLOCATOR_FREE>(
                                                        rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_infos_request(AddressSpaceID target, 
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_INFOS_REQUEST>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_infos_response(AddressSpaceID target, 
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_INFOS_RESPONSE>(rez,
                                               true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_alloc_request(AddressSpaceID target,
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_ALLOC_REQUEST>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_size_update(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // put this on the reference virtual channel since it has no effects
      // tracking and we need to make sure it is handled before references
      // are removed from the remote copies
      find_messenger(target)->send_message<SEND_FIELD_SIZE_UPDATE>(rez,
                                      true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_free(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_FREE>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_free_indexes(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_FREE_INDEXES>(
                                                  rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_layout_invalidation(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // Send this on the reference virtual channel since it's effects
      // are not being tracked and we need to know it is handled before
      // the remote objects have their references removed
      find_messenger(target)->send_message<
        SEND_FIELD_SPACE_LAYOUT_INVALIDATION>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_local_field_alloc_request(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOCAL_FIELD_ALLOC_REQUEST>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_local_field_alloc_response(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOCAL_FIELD_ALLOC_RESPONSE>(rez,
                                               true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_local_field_free(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOCAL_FIELD_FREE>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_local_field_update(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOCAL_FIELD_UPDATE>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_top_level_region_request(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_TOP_LEVEL_REGION_REQUEST>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_top_level_region_return(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_TOP_LEVEL_REGION_RETURN>(rez,
                                            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_destruction(IndexSpace handle, 
                                               AddressSpaceID target,
                                               std::set<RtEvent> &applied)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(handle);
        const RtUserEvent done = create_rt_user_event();
        rez.serialize(done);
        applied.insert(done);
      }
      // Put this message on the same virtual channel as the unregister
      // messages for distributed collectables to make sure that they 
      // are properly ordered
      find_messenger(target)->send_message<INDEX_SPACE_DESTRUCTION_MESSAGE>(
                                                        rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_destruction(IndexPartition handle, 
                                                   AddressSpaceID target,
                                                   std::set<RtEvent> &applied)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(handle);
        const RtUserEvent done = create_rt_user_event();
        rez.serialize(done);
        applied.insert(done);
      }
      // Put this message on the same virtual channel as the unregister
      // messages for distributed collectables to make sure that they 
      // are properly ordered
      find_messenger(target)->send_message<
        INDEX_PARTITION_DESTRUCTION_MESSAGE>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_destruction(FieldSpace handle, 
                                               AddressSpaceID target,
                                               std::set<RtEvent> &applied)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(handle);
        const RtUserEvent done = create_rt_user_event();
        rez.serialize(done);
        applied.insert(done);
      }
      // Put this message on the same virtual channel as the unregister
      // messages for distributed collectables to make sure that they 
      // are properly ordered
      find_messenger(target)->send_message<FIELD_SPACE_DESTRUCTION_MESSAGE>(
                                                          rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_logical_region_destruction(LogicalRegion handle, 
                                                  AddressSpaceID target,
                                                  std::set<RtEvent> &applied)
    //--------------------------------------------------------------------------
    {
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(handle);
        const RtUserEvent done = create_rt_user_event();
        rez.serialize(done);
        applied.insert(done);
      }
      // Put this message on the same virtual channel as the unregister
      // messages for distributed collectables to make sure that they 
      // are properly ordered
      find_messenger(target)->send_message<LOGICAL_REGION_DESTRUCTION_MESSAGE>(
                                                            rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_individual_remote_complete(Processor target,
                                                        Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<INDIVIDUAL_REMOTE_COMPLETE>(rez,
                                          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_individual_remote_commit(Processor target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<INDIVIDUAL_REMOTE_COMMIT>(rez,
                                        true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_remote_mapped(Processor target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_REMOTE_MAPPED>(rez,
                                    true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_remote_complete(Processor target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_REMOTE_COMPLETE>(rez,
                                      true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_remote_commit(Processor target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_REMOTE_COMMIT>(rez,
                                    true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_find_intra_space_dependence(Processor target,
                                                         Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_FIND_INTRA_DEP>(rez,
                                                      true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_record_intra_space_dependence(Processor target,
                                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_RECORD_INTRA_DEP>(rez,
                                                         true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_collective_instance_request(Processor target,
                                                         Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_COLLECTIVE_REQUEST>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_slice_collective_instance_response(AddressSpaceID target,
                                                          Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SLICE_COLLECTIVE_RESPONSE>(rez,
                                          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_remote_registration(AddressSpaceID target, 
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_REMOTE_REGISTRATION>(rez,
                                               true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_remote_valid_update(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_VALID_UPDATE>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_remote_gc_update(AddressSpaceID target,
                                            Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_GC_UPDATE>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_remote_resource_update(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_RESOURCE_UPDATE>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_add_create_reference(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_CREATE_ADD>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_remove_create_reference(AddressSpaceID target,
                                                    Serializer &rez, bool flush)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_CREATE_REMOVE>(rez,
                                                                      flush);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_did_remote_unregister(AddressSpaceID target, 
                                             Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<DISTRIBUTED_UNREGISTER>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_back_logical_state(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // No need to flush, it will get flushed by the remote map return
      find_messenger(target)->send_message<SEND_BACK_LOGICAL_STATE>(rez,
                                                        false/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_atomic_reservation_request(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_ATOMIC_RESERVATION_REQUEST>(rez,
                                                                 true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_atomic_reservation_response(AddressSpaceID target,
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_ATOMIC_RESERVATION_RESPONSE>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_padded_reservation_request(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_PADDED_RESERVATION_REQUEST>(rez,
                                                                 true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_padded_reservation_response(AddressSpaceID target,
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_PADDED_RESERVATION_RESPONSE>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_materialized_view(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_MATERIALIZED_VIEW>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_fill_view(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FILL_VIEW>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_phi_view(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_PHI_VIEW>(rez, true/*flush*/); 
    }

    //--------------------------------------------------------------------------
    void Runtime::send_reduction_view(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REDUCTION_VIEW>(rez,
                                                      true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_instance_manager(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INSTANCE_MANAGER>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_collective_instance_manager(AddressSpaceID target, 
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_COLLECTIVE_MANAGER>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_collective_instance_message(AddressSpaceID target,
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // Put all these messages on the reference virtual channel to keep them
      // all in order and make sure that we never send any of this messages
      // once the references on the collective instance are removed
      find_messenger(target)->send_message<SEND_COLLECTIVE_MESSAGE>(rez,
                                                          true/*flush*/); 
    }

    //--------------------------------------------------------------------------
    void Runtime::send_create_top_view_request(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_CREATE_TOP_VIEW_REQUEST>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_create_top_view_response(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_CREATE_TOP_VIEW_RESPONSE>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_view_register_user(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_REGISTER_USER>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_view_find_copy_preconditions_request(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_FIND_COPY_PRE_REQUEST>(rez,
                                                                 true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_view_find_copy_preconditions_response(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_FIND_COPY_PRE_RESPONSE>(
                                        rez, true/*flush*/, true/*response*/);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::send_view_add_copy_user(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_ADD_COPY_USER>(rez,
                                                          true/*flush*/);
    }

#ifdef ENABLE_VIEW_REPLICATION
    //--------------------------------------------------------------------------
    void Runtime::send_view_replication_request(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_REPLICATION_REQUEST>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_view_replication_response(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_REPLICATION_RESPONSE>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_view_replication_removal(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VIEW_REPLICATION_REMOVAL>(rez,
                                                                true/*flush*/);
    }
#endif

    //--------------------------------------------------------------------------
    void Runtime::send_future_result(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FUTURE_RESULT>(rez,
                                  true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_future_subscription(AddressSpaceID target,
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // Since this message is fused with doing the remote registration for
      // the future it also needs to go on the same virtual channel as 
      // send_did_remote_registration which is the REFERENCE_VIRTUAL_CHANNEL 
      find_messenger(target)->send_message<SEND_FUTURE_SUBSCRIPTION>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_future_notification(AddressSpaceID target,
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // This also has to happen on the reference virtual channel to prevent
      // the owner from being deleted before its references are removed
      find_messenger(target)->send_message<SEND_FUTURE_NOTIFICATION>(rez,
                                        true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_future_broadcast(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // We need all these to be ordered, preferably with respect to 
      // reference removals too so put them on the reference virtual channel
      find_messenger(target)->send_message<SEND_FUTURE_BROADCAST>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_future_map_request_future(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FUTURE_MAP_REQUEST>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_future_map_response_future(AddressSpaceID target,
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FUTURE_MAP_RESPONSE>(rez,
                                        true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_mapper_message(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_MAPPER_MESSAGE>(rez,
                                                      true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_mapper_broadcast(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_MAPPER_BROADCAST>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_task_impl_semantic_request(AddressSpaceID target,
                                                   Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_TASK_IMPL_SEMANTIC_REQ>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_semantic_request(AddressSpaceID target,
                                                    Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_SEMANTIC_REQ>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_semantic_request(AddressSpaceID target,
                                                        Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_SEMANTIC_REQ>( 
                                                            rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_semantic_request(AddressSpaceID target,
                                                    Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_SEMANTIC_REQ>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_semantic_request(AddressSpaceID target,
                                              Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SEMANTIC_REQ>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_logical_region_semantic_request(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOGICAL_REGION_SEMANTIC_REQ>( 
                                                          rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_logical_partition_semantic_request(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOGICAL_PARTITION_SEMANTIC_REQ>( 
                                                            rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_task_impl_semantic_info(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_TASK_IMPL_SEMANTIC_INFO>(rez,
                                            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_space_semantic_info(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_SPACE_SEMANTIC_INFO>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_index_partition_semantic_info(AddressSpaceID target,
                                                     Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INDEX_PARTITION_SEMANTIC_INFO>(
                                          rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_space_semantic_info(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SPACE_SEMANTIC_INFO>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_field_semantic_info(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_FIELD_SEMANTIC_INFO>(rez,
                                        true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_logical_region_semantic_info(AddressSpaceID target,
                                                    Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LOGICAL_REGION_SEMANTIC_INFO>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_logical_partition_semantic_info(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_LOGICAL_PARTITION_SEMANTIC_INFO>(
            rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_context_request(AddressSpaceID target,
                                              Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_CONTEXT_REQUEST>(rez, 
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_context_response(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_CONTEXT_RESPONSE>(rez, 
                                            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_context_release(AddressSpaceID target,
                                              Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_CONTEXT_RELEASE>(rez,
                                                              true/*flush*/);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::send_remote_context_free(AddressSpaceID target, 
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_CONTEXT_FREE>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_context_physical_request(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_REMOTE_CONTEXT_PHYSICAL_REQUEST>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_context_physical_response(AddressSpaceID target,
                                                        Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_REMOTE_CONTEXT_PHYSICAL_RESPONSE>(rez,
              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_compute_equivalence_sets_request(AddressSpaceID target,
                                                        Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_COMPUTE_EQUIVALENCE_SETS_REQUEST>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_response(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EQUIVALENCE_SET_RESPONSE>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_subset_request(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    { 
      find_messenger(target)->send_message<SEND_EQUIVALENCE_SET_SUBSET_REQUEST>(
                                                            rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_subset_response(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // This also goes on the subset virtual channel so that it is
      // ordered (always before) any update messages
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_SUBSET_RESPONSE>(rez,
              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_subset_update(AddressSpaceID target, 
                                                     Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EQUIVALENCE_SET_SUBSET_UPDATE>(
          rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_ray_trace_request(AddressSpaceID target,
                                                         Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_EQUIVALENCE_SET_RAY_TRACE_REQUEST>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_ray_trace_response(AddressSpaceID target,
                                                          Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_EQUIVALENCE_SET_RAY_TRACE_RESPONSE>(rez,
            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_migration(AddressSpaceID target,
                                                 Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EQUIVALENCE_SET_MIGRATION>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_owner_update(AddressSpaceID target,
                                                    Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EQUIVALENCE_SET_OWNER_UPDATE>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_refinement(AddressSpaceID target,
                                                         Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_REFINEMENT>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_request_instances(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_REQUEST_INSTANCES>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_request_invalid(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_REQUEST_INVALID>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_updates(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_UPDATES>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_acquires(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_ACQUIRES>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_releases(AddressSpaceID target,
                                                       Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_RELEASES>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_copies_across(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_COPIES_ACROSS>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_overwrites(AddressSpaceID target,
                                                         Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_OVERWRITES>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_filters(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_FILTERS>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_remote_instances(AddressSpaceID target,
                                                        Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
          SEND_EQUIVALENCE_SET_REMOTE_INSTANCES>(rez,
              true/*flush*/, true/*return*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_equivalence_set_stale_update(AddressSpaceID target,
                                                    Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EQUIVALENCE_SET_STALE_UPDATE>(
                                          rez, true/*flush*/, true/*return*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_instance_request(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INSTANCE_REQUEST>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_instance_response(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_INSTANCE_RESPONSE>(rez,
                                      true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_external_create_request(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EXTERNAL_CREATE_REQUEST>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_external_create_response(AddressSpaceID target,
                                                Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EXTERNAL_CREATE_RESPONSE>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_external_attach(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EXTERNAL_ATTACH>(rez,
                                                      true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_external_detach(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_EXTERNAL_DETACH>(rez,
                                                      true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_gc_priority_update(AddressSpaceID target,Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_PRIORITY_UPDATE>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_gc_request(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_REQUEST>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_gc_response(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_RESPONSE>(rez, 
                                true/*flush*/, true/*response*/);
    } 

    //--------------------------------------------------------------------------
    void Runtime::send_gc_acquire(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_ACQUIRE>(rez, true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_gc_acquired(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_ACQUIRED>(rez,
                                true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_gc_debug_request(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_DEBUG_REQUEST>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_gc_debug_response(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_GC_DEBUG_RESPONSE>(rez,
                                       true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_acquire_request(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_ACQUIRE_REQUEST>(rez,
                                                      true/*flush*/);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::send_acquire_response(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_ACQUIRE_RESPONSE>(rez,
                                      true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_variant_broadcast(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_VARIANT_BROADCAST>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_constraint_request(AddressSpaceID target, 
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_CONSTRAINT_REQUEST>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_constraint_response(AddressSpaceID target, 
                                            Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // This is paging in constraints so it needs its own virtual channel
      find_messenger(target)->send_message<SEND_CONSTRAINT_RESPONSE>(rez,
                                        true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_constraint_release(AddressSpaceID target,
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_CONSTRAINT_RELEASE>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_mpi_rank_exchange(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_MPI_RANK_EXCHANGE>(rez,
                                                        true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_mapper_request(AddressSpaceID target, 
                                              Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_MAPPER_REQUEST>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_mapper_response(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_MAPPER_RESPONSE>(rez,
                                            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_trace_request(AddressSpaceID target, 
                                             Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_TRACE_REQUEST>(rez,
                                                            true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_trace_response(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_TRACE_RESPONSE>(rez,
                                            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_projection_request(AddressSpaceID target, 
                                                  Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_PROJECTION_REQUEST>(rez,
                                                                 true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_projection_response(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_PROJECTION_RESPONSE>(
                                        rez, true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_task_request(AddressSpaceID target, 
                                            Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_TASK_REQUEST>(rez,
                                                            true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_task_response(AddressSpaceID target,
                                             Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_TASK_RESPONSE>(rez,
                                          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_redop_request(AddressSpaceID target, 
                                             Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_REDOP_REQUEST>(rez,
                                                            true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_redop_response(AddressSpaceID target,
                                              Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_REDOP_RESPONSE>(rez,
                                            true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_serdez_request(AddressSpaceID target, 
                                              Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_SERDEZ_REQUEST>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_library_serdez_response(AddressSpaceID target,
                                               Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_LIBRARY_SERDEZ_RESPONSE>(rez,
                                            true/*flush*/, true/*response*/);
    } 

    //--------------------------------------------------------------------------
    void Runtime::send_remote_op_report_uninitialized(AddressSpaceID target,
                                                      Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_REMOTE_OP_REPORT_UNINIT>(rez,
                                                              true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_op_profiling_count_update(AddressSpaceID target,
                                                        Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<
        SEND_REMOTE_OP_PROFILING_COUNT_UPDATE>(rez, 
          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_trace_update(AddressSpaceID target, 
                                           Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // All these messages must be on the same ordered virtual channel
      // so that they are ordered in their program order and handled on
      // the target node in this order as they would have been if they
      // were being handled directly on the owner node
      find_messenger(target)->send_message<SEND_REMOTE_TRACE_UPDATE>(rez,
                                                          true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_trace_response(AddressSpaceID target, 
                                             Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // No need for responses to be ordered so they can be handled on
      // the default virtual channel in whatever order
      find_messenger(target)->send_message<SEND_REMOTE_TRACE_RESPONSE>(rez,
                                          true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_trace_equivalence_sets_request(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // We're paging in these eq sets so there is no need for order
      find_messenger(target)->send_message<SEND_REMOTE_TRACE_EQ_REQUEST>(rez,
                                                                true/*flush*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_remote_trace_equivalence_sets_response(
                                         AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      // Same as above for why we don't need order
      find_messenger(target)->send_message<SEND_REMOTE_TRACE_EQ_RESPONSE>(rez,
                                              true/*flush*/, true/*response*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_shutdown_notification(AddressSpaceID target, 
                                             Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_SHUTDOWN_NOTIFICATION>(rez,
                        true/*flush*/, false/*response*/, true/*shutdown*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::send_shutdown_response(AddressSpaceID target, Serializer &rez)
    //--------------------------------------------------------------------------
    {
      find_messenger(target)->send_message<SEND_SHUTDOWN_RESPONSE>(rez,
                        true/*flush*/, false/*response*/, true/*shutdown*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_task(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      TaskOp::process_unpack_task(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_steal(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Processor target;
      derez.deserialize(target);
      Processor thief;
      derez.deserialize(thief);
      int num_mappers;
      derez.deserialize(num_mappers);
      std::vector<MapperID> thieves(num_mappers);
      for (int idx = 0; idx < num_mappers; idx++)
        derez.deserialize(thieves[idx]);
#ifdef DEBUG_LEGION
      assert(proc_managers.find(target) != proc_managers.end());
#endif
      proc_managers[target]->process_steal_request(thief, thieves);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_advertisement(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Processor source;
      derez.deserialize(source);
      MapperID map_id;
      derez.deserialize(map_id);
      // Just advertise it to all the managers
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        it->second->process_advertisement(source, map_id);
      }
    }

#ifdef LEGION_USE_LIBDL
    //--------------------------------------------------------------------------
    void Runtime::handle_registration_callback(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(implicit_context == NULL);
      assert(implicit_runtime != NULL);
#endif
      DerezCheck z(derez);
      size_t dso_size;
      derez.deserialize(dso_size);
      const std::string dso_name((const char*)derez.get_current_pointer());
      derez.advance_pointer(dso_size);
      size_t sym_size;
      derez.deserialize(sym_size);
      const std::string sym_name((const char*)derez.get_current_pointer());
      derez.advance_pointer(sym_size);
      size_t buffer_size;
      derez.deserialize(buffer_size);
      const void *buffer = derez.get_current_pointer();
      if (buffer_size > 0)
        derez.advance_pointer(buffer_size);
      bool withargs;
      derez.deserialize<bool>(withargs);
      bool deduplicate;
      derez.deserialize(deduplicate);
      size_t dedup_tag;
      derez.deserialize(dedup_tag);
      RtEvent global_done_event;
      derez.deserialize(global_done_event);
      RtUserEvent done_event;
      derez.deserialize(done_event);

      // Converting the DSO reference could call dlopen and might block
      // us if the constructor for that shared object requests its own
      // global registration callback, so register our guards first
      const RegistrationKey key(dedup_tag, dso_name, sym_name);
      if (deduplicate)
      {
        AutoLock c_lock(callback_lock);
        // First see if the local case has already been done in which case
        // we know that we are done also when it is done
        std::map<RegistrationKey,RtEvent>::const_iterator finder =
          global_local_done.find(key);
        if (finder != global_local_done.end())
        {
          Runtime::trigger_event(done_event, finder->second);
          return;
        }
        // No one has attempted a global registration callback here yet
        // Record that we are pending and put in a guard for all the
        // of the global registrations being done
        if (global_callbacks_done.find(key) == global_callbacks_done.end())
          global_callbacks_done[key] = global_done_event;
        pending_remote_callbacks[key].insert(done_event);
      }

      // Now we can do the translation of ourselves to get the function pointer
      Realm::DSOReferenceImplementation dso(dso_name, sym_name);
#ifdef DEBUG_LEGION
      assert(callback_translator.can_translate(
            typeid(Realm::DSOReferenceImplementation),
            typeid(Realm::FunctionPointerImplementation)));
#endif
      Realm::FunctionPointerImplementation *impl = 
        static_cast<Realm::FunctionPointerImplementation*>(
            callback_translator.translate(&dso, 
              typeid(Realm::FunctionPointerImplementation)));
#ifdef DEBUG_LEGION
      assert(impl != NULL);
#endif
      void* callback = impl->get_impl<void*>();
      RtEvent precondition;
      // Now take the lock and see if we need to perform anything
      if (deduplicate)
      {
        AutoLock c_lock(callback_lock);
        std::map<RegistrationKey,std::set<RtUserEvent> >::iterator finder =
            pending_remote_callbacks.find(key);
        // If someone already handled everything then we are done
        if (finder != pending_remote_callbacks.end())
        {
          // We should still be in there
#ifdef DEBUG_LEGION
          assert(finder->second.find(done_event) != finder->second.end());
#endif
          finder->second.erase(done_event);
          if (finder->second.empty())
            pending_remote_callbacks.erase(finder);
          // Now see if anyone else has done the local registration
          std::map<void*,RtEvent>::const_iterator
            finder = local_callbacks_done.find(callback);
          if (finder != local_callbacks_done.end())
          {
#ifdef DEBUG_LEGION
            assert(finder->second.exists());
#endif
            precondition = finder->second;
          }
          else
          {
            local_callbacks_done[callback] = done_event;
            global_local_done[key] = done_event; 
          }
        }
        else // We were already handled so nothing to do
          done_event = RtUserEvent::NO_RT_USER_EVENT;
      }
      if (!deduplicate || done_event.exists())
      {
        // This is the signal that we need to do the callback
        if (!precondition.exists())
        {
          inside_registration_callback = GLOBAL_REGISTRATION_CALLBACK;
          if (withargs)
          {
            RegistrationWithArgsCallbackFnptr callbackwithargs =
              (RegistrationWithArgsCallbackFnptr)callback;
            RegistrationCallbackArgs args{ machine, external, 
              local_procs, UntypedBuffer(buffer, buffer_size) };
            (*callbackwithargs)(args);
          }
          else
          {
            RegistrationCallbackFnptr callbackwithoutargs =
              (RegistrationCallbackFnptr)callback;
            (*callbackwithoutargs)(machine, external, local_procs);
          }
          inside_registration_callback = NO_REGISTRATION_CALLBACK;
        }
        if (done_event.exists())
          Runtime::trigger_event(done_event, precondition);
      }
      // Delete our resources that we allocated
      delete impl;
    }
#endif // LEGION_USE_LIBDL

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_task_replay(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      TaskOp::process_remote_replay(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_task_profiling_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      SingleTask::process_remote_profiling_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_shared_ownership(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      int kind;
      derez.deserialize(kind);
      switch (kind)
      {
        case 0:
          {
            IndexSpace handle;
            derez.deserialize(handle);
            create_shared_ownership(handle);
            break;
          }
        case 1:
          {
            IndexPartition handle;
            derez.deserialize(handle);
            create_shared_ownership(handle);
            break;
          }
        case 2:
          {
            FieldSpace handle;
            derez.deserialize(handle);
            create_shared_ownership(handle);
            break;
          }
        case 3:
          {
            LogicalRegion handle;
            derez.deserialize(handle);
            create_shared_ownership(handle);
            break;
          }
        default:
          assert(false);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_request(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_node_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_return(Deserializer &derez,
                                            AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_node_return(forest, derez, source); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_set(Deserializer &derez, 
                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_index_space_set(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_child_request(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_node_child_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_child_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_node_child_response(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_colors_request(Deserializer &derez,
                                                    AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_colors_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_colors_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_colors_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_remote_expression_request(
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      forest->handle_remote_expression_request(derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_remote_expression_response(
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      forest->handle_remote_expression_response(derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_generate_color_request(Deserializer &derez,
                                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_generate_color_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_generate_color_response(
                                                            Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_generate_color_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_release_color(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_release_color(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_notification(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_notification(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_request(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_node_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_return(Deserializer &derez,
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_node_return(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_child_request(Deserializer &derez,
                                                       AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_node_child_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_child_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_node_child_response(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_disjoint_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_node_disjoint_update(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_node(Deserializer &derez, 
                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_node_creation(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_request(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_node_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_return(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_node_return(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_allocator_request(Deserializer &derez,
                                                       AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_allocator_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_allocator_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_allocator_response(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_allocator_invalidation(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_allocator_invalidation(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_allocator_flush(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_allocator_flush(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_allocator_free(Deserializer &derez,
                                                    AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_allocator_free(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_infos_request(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_infos_request(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_infos_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_infos_response(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_alloc_request(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_alloc_request(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_size_update(Deserializer &derez,
                                           AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_field_size_update(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_free(Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_field_free(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_free_indexes(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_field_free_indexes(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_layout_invalidation(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_layout_invalidation(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_local_field_alloc_request(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_local_alloc_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_local_field_alloc_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_local_alloc_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_local_field_free(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_local_free(forest, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_local_field_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      RemoteContext::handle_local_field_update(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_top_level_region_request(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RegionNode::handle_top_level_request(forest, derez, source); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_top_level_region_return(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RegionNode::handle_top_level_return(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_destruction(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      IndexSpace handle;
      derez.deserialize(handle);
      RtUserEvent done;
      derez.deserialize(done);
#ifdef DEBUG_LEGION
      assert(done.exists());
#endif
      std::set<RtEvent> applied;
      forest->destroy_index_space(handle, source, applied);
      if (!applied.empty())
        Runtime::trigger_event(done, Runtime::merge_events(applied));
      else
        Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_destruction(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      IndexPartition handle;
      derez.deserialize(handle);
      RtUserEvent done;
      derez.deserialize(done);
#ifdef DEBUG_LEGION
      assert(done.exists());
#endif
      std::set<RtEvent> applied;
      forest->destroy_index_partition(handle, applied);
      if (!applied.empty())
        Runtime::trigger_event(done, Runtime::merge_events(applied));
      else
        Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_destruction(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      FieldSpace handle;
      derez.deserialize(handle);
      RtUserEvent done;
      derez.deserialize(done);
#ifdef DEBUG_LEGION
      assert(done.exists());
#endif
      std::set<RtEvent> applied;
      forest->destroy_field_space(handle, applied);
      if (!applied.empty())
        Runtime::trigger_event(done, Runtime::merge_events(applied));
      else
        Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_logical_region_destruction(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      LogicalRegion handle;
      derez.deserialize(handle);
      RtUserEvent done;
      derez.deserialize(done);
      std::set<RtEvent> applied;
      forest->destroy_logical_region(handle, applied);
      if (done.exists())
      {
        if (!applied.empty())
          Runtime::trigger_event(done, Runtime::merge_events(applied));
        else
          Runtime::trigger_event(done);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_individual_remote_complete(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndividualTask::process_unpack_remote_complete(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_individual_remote_commit(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndividualTask::process_unpack_remote_commit(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_remote_mapped(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexTask::process_slice_mapped(derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_remote_complete(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexTask::process_slice_complete(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_remote_commit(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexTask::process_slice_commit(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_find_intra_dependence(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexTask::process_slice_find_intra_dependence(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_record_intra_dependence(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      IndexTask::process_slice_record_intra_dependence(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_collective_request(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      SliceTask::handle_collective_instance_request(derez, source, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_slice_collective_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      SliceTask::handle_collective_instance_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_remote_registration(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_did_remote_registration(this,derez,source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_remote_valid_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_did_remote_valid_update(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_remote_gc_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_did_remote_gc_update(this, derez); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_remote_resource_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_did_remote_resource_update(this, derez); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_create_add(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_did_add_create(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_create_remove(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_did_remove_create(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_did_remote_unregister(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable::handle_unregister_collectable(this, derez);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::handle_send_back_logical_state(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RegionTreeNode::handle_logical_state_return(this, derez, source); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_atomic_reservation_request(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_send_atomic_reservation_request(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_atomic_reservation_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_send_atomic_reservation_response(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_padded_reservation_request(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_padded_reservation_request(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_padded_reservation_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_padded_reservation_response(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_materialized_view(Deserializer &derez, 
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      MaterializedView::handle_send_materialized_view(this, derez, source); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_fill_view(Deserializer &derez, 
                                        AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FillView::handle_send_fill_view(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_phi_view(Deserializer &derez,
                                       AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhiView::handle_send_phi_view(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_reduction_view(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      ReductionView::handle_send_reduction_view(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_send_instance_manager(Deserializer &derez,
                                               AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndividualManager::handle_send_manager(this, source, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_collective_instance_manager(Deserializer &derez,
                                                     AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      CollectiveManager::handle_send_manager(this, source, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_collective_instance_message(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      CollectiveManager::handle_collective_message(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_create_top_view_request(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InnerContext::handle_create_top_view_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_create_top_view_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      InnerContext::handle_create_top_view_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_view_request(Deserializer &derez, 
                                      AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      LogicalView::handle_view_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_view_register_user(Deserializer &derez,
                                            AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_register_user(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_view_copy_pre_request(Deserializer &derez,
                                               AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_find_copy_pre_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_view_copy_pre_response(Deserializer &derez,
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_find_copy_pre_response(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_view_add_copy_user(Deserializer &derez,
                                            AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_add_copy_user(derez, this, source);
    }

#ifdef ENABLE_VIEW_REPLICATION
    //--------------------------------------------------------------------------
    void Runtime::handle_view_replication_request(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_replication_request(derez, this, source);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::handle_view_replication_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_replication_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_view_replication_removal(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InstanceView::handle_view_replication_removal(derez, this, source);
    }
#endif // ENABLE_VIEW_REPLICATION

    //--------------------------------------------------------------------------
    void Runtime::handle_manager_request(Deserializer &derez, 
                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_manager_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_future_result(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FutureImpl::handle_future_result(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_future_subscription(Deserializer &derez, 
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FutureImpl::handle_future_subscription(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_future_notification(Deserializer &derez, 
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FutureImpl::handle_future_notification(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_future_broadcast(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FutureImpl::handle_future_broadcast(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_future_map_future_request(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FutureMapImpl::handle_future_map_future_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_future_map_future_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FutureMapImpl::handle_future_map_future_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_mapper_message(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Processor target;
      derez.deserialize(target);
      MapperID map_id;
      derez.deserialize(map_id);
      Processor source;
      derez.deserialize(source);
      unsigned message_kind;
      derez.deserialize(message_kind);
      size_t message_size;
      derez.deserialize(message_size);
      const void *message = derez.get_current_pointer();
      derez.advance_pointer(message_size);
      process_mapper_message(target, map_id, source, message, 
                             message_size, message_kind);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_mapper_broadcast(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      MapperID map_id;
      derez.deserialize(map_id);
      Processor source;
      derez.deserialize(source);
      unsigned message_kind;
      derez.deserialize(message_kind);
      int radix;
      derez.deserialize(radix);
      int index;
      derez.deserialize(index);
      size_t message_size;
      derez.deserialize(message_size);
      const void *message = derez.get_current_pointer();
      derez.advance_pointer(message_size);
      process_mapper_broadcast(map_id, source, message, 
                               message_size, message_kind, radix, index);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_task_impl_semantic_request(Deserializer &derez,
                                                     AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      TaskImpl::handle_semantic_request(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_semantic_request(Deserializer &derez,
                                                      AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_semantic_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_semantic_request(Deserializer &derez, 
                                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_semantic_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_semantic_request(Deserializer &derez,
                                                      AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_semantic_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_semantic_request(Deserializer &derez,
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_field_semantic_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_logical_region_semantic_request(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RegionNode::handle_semantic_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_logical_partition_semantic_request(
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PartitionNode::handle_semantic_request(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_task_impl_semantic_info(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      TaskImpl::handle_semantic_info(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_space_semantic_info(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexSpaceNode::handle_semantic_info(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_index_partition_semantic_info(Deserializer &derez, 
                                                       AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      IndexPartNode::handle_semantic_info(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_space_semantic_info(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_semantic_info(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_field_semantic_info(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_field_semantic_info(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_logical_region_semantic_info(Deserializer &derez,
                                                      AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RegionNode::handle_semantic_info(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_logical_partition_semantic_info(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PartitionNode::handle_semantic_info(forest, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_context_request(Deserializer &derez,
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      UniqueID context_uid;
      derez.deserialize(context_uid);
      RemoteContext *target;
      derez.deserialize(target);
      InnerContext *context = find_context(context_uid);
      context->send_remote_context(source, target);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_context_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      RemoteContext *context;
      derez.deserialize(context);
      // Unpack the result
      std::set<RtEvent> preconditions;
      context->unpack_remote_context(derez, preconditions);
      // Then register it
      UniqueID context_uid = context->get_context_uid();
      register_remote_context(context_uid, context, preconditions);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_context_release(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      UniqueID context_uid;
      derez.deserialize(context_uid);
      InnerContext *context = find_context(context_uid);
      context->invalidate_remote_tree_contexts(derez);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::handle_remote_context_free(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      UniqueID remote_owner_uid;
      derez.deserialize(remote_owner_uid);
      unregister_remote_context(remote_owner_uid);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_context_physical_request(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      RemoteContext::handle_physical_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_remote_context_physical_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      RemoteContext::handle_physical_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_compute_equivalence_sets_request(Deserializer &derez,
                                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InnerContext::handle_compute_equivalence_sets_request(derez, this,source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_request(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_equivalence_set_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_response(Deserializer &derez,
                                                  AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_equivalence_set_response(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_subset_request(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_subset_request(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_subset_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_subset_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_subset_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_subset_update(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_ray_trace_request(Deserializer &derez,
                                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_ray_trace_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_ray_trace_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_ray_trace_response(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_migration(Deserializer &derez,
                                                   AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_migration(derez, this, source); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_owner_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_owner_update(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_refinement(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      EquivalenceSet::handle_remote_refinement(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_request_instances(
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      ValidInstAnalysis::handle_remote_request_instances(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_request_invalid(
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      InvalidInstAnalysis::handle_remote_request_invalid(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_updates(Deserializer &derez,
                                                        AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      UpdateAnalysis::handle_remote_updates(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_acquires(Deserializer &derez,
                                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      AcquireAnalysis::handle_remote_acquires(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_releases(Deserializer &derez,
                                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      ReleaseAnalysis::handle_remote_releases(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_copies_across(
                                     Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      CopyAcrossAnalysis::handle_remote_copies_across(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_overwrites(Deserializer &derez,
                                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      OverwriteAnalysis::handle_remote_overwrites(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_filters(Deserializer &derez,
                                                        AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FilterAnalysis::handle_remote_filters(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_remote_instances(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      PhysicalAnalysis::handle_remote_instances(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_equivalence_set_stale_update(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      VersionManager::handle_stale_update(derez, this);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_instance_request(Deserializer &derez, 
                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Memory target_memory;
      derez.deserialize(target_memory);
      MemoryManager *manager = find_memory_manager(target_memory);
      manager->process_instance_request(derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_instance_response(Deserializer &derez,
                                           AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Memory target_memory;
      derez.deserialize(target_memory);
      MemoryManager *manager = find_memory_manager(target_memory);
      manager->process_instance_response(derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_external_create_request(Deserializer &derez,
                                                 AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_external_create_request(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_external_create_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      FieldSpaceNode::handle_external_create_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_external_attach(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Memory target_memory;
      derez.deserialize(target_memory);
      DistributedID did;
      derez.deserialize(did);
      RtEvent manager_ready;
      PhysicalManager *manager = 
        find_or_request_instance_manager(did, manager_ready);
      RtUserEvent done_event;
      derez.deserialize(done_event);
      MemoryManager *memory_manager = find_memory_manager(target_memory);
      if (manager_ready.exists() && !manager_ready.has_triggered())
        manager_ready.wait();
      RtEvent local_done = memory_manager->attach_external_instance(manager);
      Runtime::trigger_event(done_event, local_done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_external_detach(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      Memory target_memory;
      derez.deserialize(target_memory);
      DistributedID did;
      derez.deserialize(did);
      RtEvent manager_ready;
      PhysicalManager *manager = 
        find_or_request_instance_manager(did, manager_ready);
      RtUserEvent done_event;
      derez.deserialize(done_event);
      MemoryManager *memory_manager = find_memory_manager(target_memory);
      if (manager_ready.exists() && !manager_ready.has_triggered())
        manager_ready.wait();
      RtEvent local_done = memory_manager->detach_external_instance(manager);
      Runtime::trigger_event(done_event, local_done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_priority_update(Deserializer &derez,
                                            AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_priority_update(this, derez,
                                                                 source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_request(Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_request(this, derez, source); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_response(derez); 
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_acquire(Deserializer &derez, AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_acquire(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_acquired(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_acquired(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_debug_request(Deserializer &derez,
                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_debug_request(this, derez,
                                                               source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_gc_debug_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_garbage_collection_debug_response(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_acquire_request(Deserializer &derez, 
                                         AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_acquire_request(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_acquire_response(Deserializer &derez, 
                                          AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      PhysicalManager::handle_acquire_response(derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_variant_broadcast(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      VariantImpl::handle_variant_broadcast(this, derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_constraint_request(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints::process_request(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_constraint_response(Deserializer &derez,
                                             AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints::process_response(this, derez, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_constraint_release(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      LayoutConstraintID layout_id;
      derez.deserialize(layout_id);
      release_layout(layout_id);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_top_level_task_request(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(address_space == 0); // should only happen on node 0
#endif
      RtUserEvent to_trigger;
      derez.deserialize(to_trigger);
      increment_outstanding_top_level_tasks();
      Runtime::trigger_event(to_trigger);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_top_level_task_complete(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(address_space == 0); // should only happen on node 0
#endif
      decrement_outstanding_top_level_tasks();
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_mpi_rank_exchange(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(mpi_rank_table != NULL);
#endif
      mpi_rank_table->handle_mpi_rank_exchange(derez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_mapper_request(Deserializer &derez,
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      size_t count;
      derez.deserialize(count);
      RtUserEvent done;
      derez.deserialize(done);
      
      MapperID result = generate_library_mapper_ids(name, count);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(string_length);
        rez.serialize(name, string_length);
        rez.serialize(result);
        rez.serialize(done);
      }
      send_library_mapper_response(source, rez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_mapper_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      MapperID result;
      derez.deserialize(result);
      RtUserEvent done;
      derez.deserialize(done);

      const std::string library_name(name);
      {
        AutoLock l_lock(library_lock); 
        std::map<std::string,LibraryMapperIDs>::iterator finder = 
          library_mapper_ids.find(library_name);
#ifdef DEBUG_LEGION
        assert(finder != library_mapper_ids.end());
        assert(!finder->second.result_set);
        assert(finder->second.ready == done);
#endif
        finder->second.result = result;
        finder->second.result_set = true;
      }
      Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_trace_request(Deserializer &derez,
                                               AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      size_t count;
      derez.deserialize(count);
      RtUserEvent done;
      derez.deserialize(done);
      
      TraceID result = generate_library_trace_ids(name, count);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(string_length);
        rez.serialize(name, string_length);
        rez.serialize(result);
        rez.serialize(done);
      }
      send_library_trace_response(source, rez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_trace_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      TraceID result;
      derez.deserialize(result);
      RtUserEvent done;
      derez.deserialize(done);

      const std::string library_name(name);
      {
        AutoLock l_lock(library_lock); 
        std::map<std::string,LibraryTraceIDs>::iterator finder = 
          library_trace_ids.find(library_name);
#ifdef DEBUG_LEGION
        assert(finder != library_trace_ids.end());
        assert(!finder->second.result_set);
        assert(finder->second.ready == done);
#endif
        finder->second.result = result;
        finder->second.result_set = true;
      }
      Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_projection_request(Deserializer &derez,
                                                    AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      size_t count;
      derez.deserialize(count);
      RtUserEvent done;
      derez.deserialize(done);
      
      ProjectionID result = generate_library_projection_ids(name, count);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(string_length);
        rez.serialize(name, string_length);
        rez.serialize(result);
        rez.serialize(done);
      }
      send_library_projection_response(source, rez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_projection_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      ProjectionID result;
      derez.deserialize(result);
      RtUserEvent done;
      derez.deserialize(done);

      const std::string library_name(name);
      {
        AutoLock l_lock(library_lock); 
        std::map<std::string,LibraryProjectionIDs>::iterator finder = 
          library_projection_ids.find(library_name);
#ifdef DEBUG_LEGION
        assert(finder != library_projection_ids.end());
        assert(!finder->second.result_set);
        assert(finder->second.ready == done);
#endif
        finder->second.result = result;
        finder->second.result_set = true;
      }
      Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_task_request(Deserializer &derez,
                                              AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      size_t count;
      derez.deserialize(count);
      RtUserEvent done;
      derez.deserialize(done);
      
      TaskID result = generate_library_task_ids(name, count);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(string_length);
        rez.serialize(name, string_length);
        rez.serialize(result);
        rez.serialize(done);
      }
      send_library_task_response(source, rez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_task_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      TaskID result;
      derez.deserialize(result);
      RtUserEvent done;
      derez.deserialize(done);

      const std::string library_name(name);
      {
        AutoLock l_lock(library_lock); 
        std::map<std::string,LibraryTaskIDs>::iterator finder = 
          library_task_ids.find(library_name);
#ifdef DEBUG_LEGION
        assert(finder != library_task_ids.end());
        assert(!finder->second.result_set);
        assert(finder->second.ready == done);
#endif
        finder->second.result = result;
        finder->second.result_set = true;
      }
      Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_redop_request(Deserializer &derez,
                                               AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      size_t count;
      derez.deserialize(count);
      RtUserEvent done;
      derez.deserialize(done);
      
      ReductionOpID result = generate_library_reduction_ids(name, count);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(string_length);
        rez.serialize(name, string_length);
        rez.serialize(result);
        rez.serialize(done);
      }
      send_library_redop_response(source, rez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_redop_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      ReductionOpID result;
      derez.deserialize(result);
      RtUserEvent done;
      derez.deserialize(done);

      const std::string library_name(name);
      {
        AutoLock l_lock(library_lock); 
        std::map<std::string,LibraryRedopIDs>::iterator finder = 
          library_redop_ids.find(library_name);
#ifdef DEBUG_LEGION
        assert(finder != library_redop_ids.end());
        assert(!finder->second.result_set);
        assert(finder->second.ready == done);
#endif
        finder->second.result = result;
        finder->second.result_set = true;
      }
      Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_serdez_request(Deserializer &derez,
                                                AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      size_t count;
      derez.deserialize(count);
      RtUserEvent done;
      derez.deserialize(done);
      
      CustomSerdezID result = generate_library_serdez_ids(name, count);
      Serializer rez;
      {
        RezCheck z2(rez);
        rez.serialize(string_length);
        rez.serialize(name, string_length);
        rez.serialize(result);
        rez.serialize(done);
      }
      send_library_serdez_response(source, rez);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_library_serdez_response(Deserializer &derez)
    //--------------------------------------------------------------------------
    {
      DerezCheck z(derez);
      size_t string_length;
      derez.deserialize(string_length);
      const char *name = (const char*)derez.get_current_pointer();
      derez.advance_pointer(string_length);
      CustomSerdezID result;
      derez.deserialize(result);
      RtUserEvent done;
      derez.deserialize(done);

      const std::string library_name(name);
      {
        AutoLock l_lock(library_lock); 
        std::map<std::string,LibrarySerdezIDs>::iterator finder = 
          library_serdez_ids.find(library_name);
#ifdef DEBUG_LEGION
        assert(finder != library_serdez_ids.end());
        assert(!finder->second.result_set);
        assert(finder->second.ready == done);
#endif
        finder->second.result = result;
        finder->second.result_set = true;
      }
      Runtime::trigger_event(done);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_shutdown_notification(Deserializer &derez,
                                               AddressSpaceID source)
    //--------------------------------------------------------------------------
    {
      ShutdownManager::handle_shutdown_notification(derez, this, source);
    }

    //--------------------------------------------------------------------------
    void Runtime::handle_shutdown_response(Deserializer &derez) 
    //--------------------------------------------------------------------------
    {
      ShutdownManager::handle_shutdown_response(derez);
    }

    //--------------------------------------------------------------------------
    bool Runtime::create_physical_instance(Memory target_memory,
                                     const LayoutConstraintSet &constraints,
                                     const std::vector<LogicalRegion> &regions,
                                     MappingInstance &result,
                                     MapperID mapper_id, Processor processor, 
                                     bool acquire, GCPriority priority,
                                     bool tight_bounds, 
                                     const LayoutConstraint **unsat,
                                     size_t *footprint, UniqueID creator_id,
                                     CollectiveManager *target, DomainPoint *p)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(target_memory);
      if (unsat != NULL)
      {
        LayoutConstraintKind unsat_kind = LEGION_SPECIALIZED_CONSTRAINT;
        unsigned unsat_index = 0;
        if (!manager->create_physical_instance(constraints, regions, result,
                         mapper_id, processor, acquire, priority, tight_bounds,
                         &unsat_kind, &unsat_index, footprint, target, p,
                         creator_id))
        {
          *unsat = constraints.convert_unsatisfied(unsat_kind, unsat_index);
          return false;
        }
        else
          return true;
      }
      else
        return manager->create_physical_instance(constraints, regions, result,
                         mapper_id, processor, acquire, priority, tight_bounds,
                         NULL, NULL, footprint, target, p, creator_id);
    }

    //--------------------------------------------------------------------------
    bool Runtime::create_physical_instance(Memory target_memory,
                                     LayoutConstraints *constraints,
                                     const std::vector<LogicalRegion> &regions,
                                     MappingInstance &result,
                                     MapperID mapper_id, Processor processor,
                                     bool acquire, GCPriority priority,
                                     bool tight_bounds, 
                                     const LayoutConstraint **unsat,
                                     size_t *footprint, UniqueID creator_id,
                                     CollectiveManager *target, DomainPoint *p)
    //--------------------------------------------------------------------------
    { 
      MemoryManager *manager = find_memory_manager(target_memory);
      if (unsat != NULL)
      {
        LayoutConstraintKind unsat_kind = LEGION_SPECIALIZED_CONSTRAINT;
        unsigned unsat_index = 0;
        if (!manager->create_physical_instance(constraints, regions, result,
                         mapper_id, processor, acquire, priority, tight_bounds,
                         &unsat_kind, &unsat_index, footprint, target, p,
                         creator_id))
        {
          *unsat = constraints->convert_unsatisfied(unsat_kind, unsat_index);
          return false;
        }
        else
          return true;
      }
      else
        return manager->create_physical_instance(constraints, regions, result,
                         mapper_id, processor, acquire, priority, tight_bounds,
                         NULL, NULL, footprint, target, p, creator_id);
    }

    //--------------------------------------------------------------------------
    bool Runtime::find_or_create_physical_instance(Memory target_memory,
                                     const LayoutConstraintSet &constraints,
                                     const std::vector<LogicalRegion> &regions,
                                     MappingInstance &result, bool &created, 
                                     MapperID mapper_id, Processor processor,
                                     bool acquire, GCPriority priority,
                                     bool tight_bounds, 
                                     const LayoutConstraint **unsat,
                                     size_t *footprint, UniqueID creator_id)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(target_memory);
      if (unsat != NULL)
      {
        LayoutConstraintKind unsat_kind = LEGION_SPECIALIZED_CONSTRAINT;
        unsigned unsat_index = 0;
        if (!manager->find_or_create_physical_instance(constraints, regions, 
                         result, created, mapper_id, processor, acquire, 
                         priority, tight_bounds, &unsat_kind, &unsat_index,
                         footprint, creator_id))
        {
          *unsat = constraints.convert_unsatisfied(unsat_kind, unsat_index);
          return false;
        }
        else
          return true;
      }
      else
        return manager->find_or_create_physical_instance(constraints, regions, 
                         result, created, mapper_id, processor, acquire, 
                         priority, tight_bounds,NULL,NULL,footprint,creator_id);
    }

    //--------------------------------------------------------------------------
    bool Runtime::find_or_create_physical_instance(Memory target_memory,
                                    LayoutConstraints *constraints,
                                    const std::vector<LogicalRegion> &regions,
                                    MappingInstance &result, bool &created, 
                                    MapperID mapper_id, Processor processor,
                                    bool acquire, GCPriority priority,
                                    bool tight_bounds, 
                                    const LayoutConstraint **unsat,
                                    size_t *footprint, UniqueID creator_id)
    //--------------------------------------------------------------------------
    { 
      MemoryManager *manager = find_memory_manager(target_memory);
      if (unsat != NULL)
      {
        LayoutConstraintKind unsat_kind = LEGION_SPECIALIZED_CONSTRAINT;
        unsigned unsat_index = 0;
        if (!manager->find_or_create_physical_instance(constraints, regions,
                           result, created, mapper_id, processor, acquire, 
                           priority, tight_bounds, &unsat_kind, &unsat_index,
                           footprint, creator_id))
        {
          *unsat = constraints->convert_unsatisfied(unsat_kind, unsat_index);
          return false;
        }
        else
          return true;
      }
      else
        return manager->find_or_create_physical_instance(constraints, regions,
                     result, created, mapper_id, processor, acquire, 
                     priority, tight_bounds, NULL, NULL, footprint, creator_id);
    }

    //--------------------------------------------------------------------------
    bool Runtime::find_physical_instance(Memory target_memory,
                                      const LayoutConstraintSet &constraints,
                                      const std::vector<LogicalRegion> &regions,
                                      MappingInstance &result, bool acquire,
                                      bool tight_region_bounds)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(target_memory);
      return manager->find_physical_instance(constraints, regions, 
                             result, acquire, tight_region_bounds);
    }

    //--------------------------------------------------------------------------
    bool Runtime::find_physical_instance(Memory target_memory,
                                      LayoutConstraints *constraints,
                                      const std::vector<LogicalRegion> &regions,
                                      MappingInstance &result, bool acquire,
                                      bool tight_region_bounds)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(target_memory);
      return manager->find_physical_instance(constraints, regions, 
                                     result, acquire, tight_region_bounds);
    }

    //--------------------------------------------------------------------------
    void Runtime::find_physical_instances(Memory target_memory,
                                      const LayoutConstraintSet &constraints,
                                      const std::vector<LogicalRegion> &regions,
                                      std::vector<MappingInstance> &results, 
                                      bool acquire, bool tight_region_bounds)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(target_memory);
      return manager->find_physical_instances(constraints, regions, 
                             results, acquire, tight_region_bounds);
    }

    //--------------------------------------------------------------------------
    void Runtime::find_physical_instances(Memory target_memory,
                                      LayoutConstraints *constraints,
                                      const std::vector<LogicalRegion> &regions,
                                      std::vector<MappingInstance> &results, 
                                      bool acquire, bool tight_region_bounds)
    //--------------------------------------------------------------------------
    {
      MemoryManager *manager = find_memory_manager(target_memory);
      return manager->find_physical_instances(constraints, regions, 
                                     results, acquire, tight_region_bounds);
    }

    //--------------------------------------------------------------------------
    void Runtime::release_tree_instances(RegionTreeID tid)
    //--------------------------------------------------------------------------
    {
      std::map<Memory,MemoryManager*> copy_managers;
      {
        AutoLock m_lock(memory_manager_lock,1,false/*exclusive*/);
        copy_managers = memory_managers;
      }
      for (std::map<Memory,MemoryManager*>::const_iterator it = 
            copy_managers.begin(); it != copy_managers.end(); it++)
        it->second->release_tree_instances(tid);
    }

    //--------------------------------------------------------------------------
    void Runtime::process_schedule_request(Processor proc)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(local_procs.find(proc) != local_procs.end());
#endif
      log_run.debug("Running scheduler on processor " IDFMT "", proc.id);
      ProcessorManager *manager = proc_managers[proc];
      manager->perform_scheduling();
#ifdef LEGION_TRACE_ALLOCATION
      unsigned long long trace_count = allocation_tracing_count.fetch_add(1); 
      if ((trace_count % LEGION_TRACE_ALLOCATION_FREQUENCY) == 0)
        dump_allocation_info();
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::process_message_task(const void *args, size_t arglen)
    //--------------------------------------------------------------------------
    {
      const char *buffer = (const char*)args;
      AddressSpaceID sender = *((const AddressSpaceID*)buffer);
      buffer += sizeof(sender);
      arglen -= sizeof(sender);
      find_messenger(sender)->receive_message(buffer, arglen);
    }

    //--------------------------------------------------------------------------
    void Runtime::activate_context(InnerContext *context)
    //--------------------------------------------------------------------------
    {
      for (std::map<Processor,ProcessorManager*>::const_iterator it =
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        it->second->activate_context(context);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::deactivate_context(InnerContext *context)
    //--------------------------------------------------------------------------
    {
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        it->second->deactivate_context(context);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::add_to_ready_queue(Processor p, TaskOp *task)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(p.kind() != Processor::UTIL_PROC);
      assert(proc_managers.find(p) != proc_managers.end());
#endif
      proc_managers[p]->add_to_ready_queue(task);
    }

    //--------------------------------------------------------------------------
    Processor Runtime::find_processor_group(const std::vector<Processor> &procs)
    //--------------------------------------------------------------------------
    {
      // Compute a hash of all the processor ids to avoid testing all sets 
      // Only need to worry about local IDs since all processors are
      // in this address space.
      ProcessorMask local_mask = find_processor_mask(procs);
      uint64_t hash = local_mask.get_hash_key();
      AutoLock g_lock(group_lock);
      std::map<uint64_t,LegionDeque<ProcessorGroupInfo> >::iterator 
        finder = processor_groups.find(hash);
      if (finder != processor_groups.end())
      {
        for (LegionDeque<ProcessorGroupInfo>::const_iterator it = 
              finder->second.begin(); it != finder->second.end(); it++)
        {
          if (local_mask == it->processor_mask)
            return it->processor_group;
        }
      }
      // If we make it here create a new processor group and add it
      ProcessorGroup group = ProcessorGroup::create_group(procs);
      if (finder != processor_groups.end())
        finder->second.push_back(ProcessorGroupInfo(group, local_mask));
      else
        processor_groups[hash].push_back(ProcessorGroupInfo(group, local_mask));
      return group;
    }

    //--------------------------------------------------------------------------
    ProcessorMask Runtime::find_processor_mask(
                                            const std::vector<Processor> &procs)
    //--------------------------------------------------------------------------
    {
      ProcessorMask result;
      std::vector<Processor> need_allocation;
      {
        AutoLock p_lock(processor_mapping_lock,1,false/*exclusive*/);
        for (std::vector<Processor>::const_iterator it = procs.begin();
              it != procs.end(); it++)
        {
          std::map<Processor,unsigned>::const_iterator finder = 
            processor_mapping.find(*it);
          if (finder == processor_mapping.end())
          {
            need_allocation.push_back(*it);
            continue;
          }
          result.set_bit(finder->second);
        }
      }
      if (need_allocation.empty())
        return result;
      AutoLock p_lock(processor_mapping_lock);
      for (std::vector<Processor>::const_iterator it = 
            need_allocation.begin(); it != need_allocation.end(); it++)
      {
        // Check to make sure we didn't lose the race
        std::map<Processor,unsigned>::const_iterator finder = 
            processor_mapping.find(*it);
        if (finder != processor_mapping.end())
        {
          result.set_bit(finder->second);
          continue;
        }
        unsigned next_index = processor_mapping.size();
#ifdef DEBUG_LEGION
        assert(next_index < LEGION_MAX_NUM_PROCS);
#endif
        processor_mapping[*it] = next_index;
        result.set_bit(next_index);
      }
      return result;
    }

    //--------------------------------------------------------------------------
    DistributedID Runtime::get_available_distributed_id(void)
    //--------------------------------------------------------------------------
    {
      DistributedID result = unique_distributed_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // Check for overflow
      assert(result < LEGION_DISTRIBUTED_ID_MASK);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    AddressSpaceID Runtime::determine_owner(DistributedID did) const
    //--------------------------------------------------------------------------
    {
      return ((did & LEGION_DISTRIBUTED_ID_MASK) % runtime_stride);
    }

    //--------------------------------------------------------------------------
    void Runtime::register_distributed_collectable(DistributedID did,
                                                   DistributedCollectable *dc)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK;
      RtUserEvent to_trigger;
      {
        AutoLock dc_lock(distributed_collectable_lock);
        // If we make it here then we have the lock
#ifdef DEBUG_LEGION
        assert(dist_collectables.find(did) == dist_collectables.end());
#endif
        dist_collectables[did] = dc;
        // See if this was a pending collectable
        std::map<DistributedID,
                 std::pair<DistributedCollectable*,RtUserEvent> >::iterator 
            finder = pending_collectables.find(did);
        if (finder != pending_collectables.end())
        {
#ifdef DEBUG_LEGION
          assert(finder->second.first == dc);
#endif
          to_trigger = finder->second.second;
          pending_collectables.erase(finder);
        }
      }
      if (to_trigger.exists())
        Runtime::trigger_event(to_trigger);
    }

    //--------------------------------------------------------------------------
    bool Runtime::unregister_distributed_collectable(DistributedID did)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK;
      AutoLock d_lock(distributed_collectable_lock);
      std::map<DistributedID,DistributedCollectable*>::iterator finder =
        dist_collectables.find(did);
      if ((finder == dist_collectables.end()) ||
          !finder->second->confirm_deletion())
        return false;
      dist_collectables.erase(finder);
      return true;
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_distributed_collectable(DistributedID did)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK;
      AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
      return (dist_collectables.find(did) != dist_collectables.end());
    }

    //--------------------------------------------------------------------------
    DistributedCollectable* Runtime::find_distributed_collectable(
                                                              DistributedID did)
    //--------------------------------------------------------------------------
    {
      const DistributedID to_find = LEGION_DISTRIBUTED_ID_FILTER(did);
      AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
      std::map<DistributedID,DistributedCollectable*>::const_iterator finder = 
        dist_collectables.find(to_find);
#ifdef DEBUG_LEGION
      if (finder == dist_collectables.end())
        log_run.error("Unable to find distributed collectable %llx "
                    "with type %lld", did, LEGION_DISTRIBUTED_HELP_DECODE(did));
      assert(finder != dist_collectables.end());
#endif
      return finder->second;
    }

    //--------------------------------------------------------------------------
    DistributedCollectable* Runtime::find_distributed_collectable(
                                              DistributedID did, RtEvent &ready)
    //--------------------------------------------------------------------------
    {
      const DistributedID to_find = LEGION_DISTRIBUTED_ID_FILTER(did);
      AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
      std::map<DistributedID,DistributedCollectable*>::const_iterator finder = 
        dist_collectables.find(to_find);
      if (finder == dist_collectables.end())
      {
        // Check to see if it is in the pending set too
        std::map<DistributedID,
          std::pair<DistributedCollectable*,RtUserEvent> >::const_iterator
            pending_finder = pending_collectables.find(to_find);
        if (pending_finder != pending_collectables.end())
        {
          ready = pending_finder->second.second;
          return pending_finder->second.first;
        }
      }
#ifdef DEBUG_LEGION
      if (finder == dist_collectables.end())
        log_run.error("Unable to find distributed collectable %llx "
                    "with type %lld", did, LEGION_DISTRIBUTED_HELP_DECODE(did));
      assert(finder != dist_collectables.end());
#endif
      return finder->second;
    }

    //--------------------------------------------------------------------------
    DistributedCollectable* Runtime::weak_find_distributed_collectable(
                                                              DistributedID did)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK;
      AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
      std::map<DistributedID,DistributedCollectable*>::const_iterator finder = 
        dist_collectables.find(did);
      if (finder == dist_collectables.end())
        return NULL;
      return finder->second;
    } 

    //--------------------------------------------------------------------------
    bool Runtime::find_pending_collectable_location(DistributedID did,
                                                    void *&location)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK;
      AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
#ifdef DEBUG_LEGION
      assert(dist_collectables.find(did) == dist_collectables.end());
#endif
      std::map<DistributedID,std::pair<DistributedCollectable*,RtUserEvent> >::
        const_iterator finder = pending_collectables.find(did);
      if (finder != pending_collectables.end())
      {
        location = finder->second.first;
        return true;
      }
      return false;
    }

    //--------------------------------------------------------------------------
    LogicalView* Runtime::find_or_request_logical_view(DistributedID did,
                                                       RtEvent &ready)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable *dc = NULL;
      if (LogicalView::is_materialized_did(did))
        dc = find_or_request_distributed_collectable<
         MaterializedView,SEND_VIEW_REQUEST>(did,ready);
      else if (LogicalView::is_reduction_did(did))
        dc = find_or_request_distributed_collectable<
          ReductionView, SEND_VIEW_REQUEST>(did,ready);
      else if (LogicalView::is_fill_did(did))
        dc = find_or_request_distributed_collectable<
          FillView, SEND_VIEW_REQUEST>(did, ready);
      else
        assert(false);
      // Have to static cast since the memory might not have been initialized
      return static_cast<LogicalView*>(dc);
    }

    //--------------------------------------------------------------------------
    PhysicalManager* Runtime::find_or_request_instance_manager(
                                              DistributedID did, RtEvent &ready)
    //--------------------------------------------------------------------------
    {
      DistributedCollectable *dc = NULL;
      if (InstanceManager::is_collective_did(did))
        dc = find_or_request_distributed_collectable<
          CollectiveManager, SEND_MANAGER_REQUEST>(did, ready);
      else if (InstanceManager::is_physical_did(did))
        dc = find_or_request_distributed_collectable<
          IndividualManager, SEND_MANAGER_REQUEST>(did, ready);
      else
        assert(false);
      // Have to static cast since the memory might not have been initialized
      return static_cast<PhysicalManager*>(dc);
    }

    //--------------------------------------------------------------------------
    EquivalenceSet* Runtime::find_or_request_equivalence_set(DistributedID did,
                                                             RtEvent &ready)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(LEGION_DISTRIBUTED_HELP_DECODE(did) == EQUIVALENCE_SET_DC);
#endif
      DistributedCollectable *dc = find_or_request_distributed_collectable<
        EquivalenceSet, SEND_EQUIVALENCE_SET_REQUEST>(did, ready);
      // Have to static cast since the memory might not have been initialized
      return static_cast<EquivalenceSet*>(dc);
    }

    //--------------------------------------------------------------------------
    template<typename T, MessageKind MK>
    DistributedCollectable* Runtime::find_or_request_distributed_collectable(
                                          DistributedID to_find, RtEvent &ready)
    //--------------------------------------------------------------------------
    {
      const DistributedID did = LEGION_DISTRIBUTED_ID_FILTER(to_find);
      DistributedCollectable *result = NULL;
      {
        AutoLock d_lock(distributed_collectable_lock);
        std::map<DistributedID,DistributedCollectable*>::const_iterator finder =
          dist_collectables.find(did);
        // If we've already got it, then we are done
        if (finder != dist_collectables.end())
        {
          ready = RtEvent::NO_RT_EVENT;
          return finder->second;
        }
        // If it is already pending, we can just return the ready event
        std::map<DistributedID,std::pair<DistributedCollectable*,RtUserEvent> 
          >::const_iterator pending_finder = pending_collectables.find(did);
        if (pending_finder != pending_collectables.end())
        {
          ready = pending_finder->second.second;
          return pending_finder->second.first;
        }
        // This is the first request we've seen for this did, make it now
        // Allocate space for the result and type case
        result = (T*)legion_alloc_aligned<T,false/*bytes*/>(1/*count*/);  
        RtUserEvent to_trigger = Runtime::create_rt_user_event();
        pending_collectables[did] = 
          std::pair<DistributedCollectable*,RtUserEvent>(result, to_trigger);
        ready = to_trigger;
      }
      AddressSpaceID target = determine_owner(did);
#ifdef DEBUG_LEGION
      assert(target != address_space); // shouldn't be sending to ourself
#endif
      // Now send the message
      Serializer rez;
      {
        RezCheck z(rez);
        rez.serialize(to_find);
      }
      find_messenger(target)->send_message<MK>(rez, true/*flush*/);
      return result;
    }
    
    //--------------------------------------------------------------------------
    FutureImpl* Runtime::find_or_create_future(DistributedID did,
                                UniqueID context_uid, ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK; 
      {
        AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
        std::map<DistributedID,DistributedCollectable*>::const_iterator 
          finder = dist_collectables.find(did);
        if (finder != dist_collectables.end())
        {
#ifdef DEBUG_LEGION
          FutureImpl *result = dynamic_cast<FutureImpl*>(finder->second);
          assert(result != NULL);
#else
          FutureImpl *result = static_cast<FutureImpl*>(finder->second);
#endif
          return result;
        }
      }
      const AddressSpaceID owner_space = determine_owner(did);
#ifdef DEBUG_LEGION
      assert(owner_space != address_space);
#endif
      InnerContext *context = find_context(context_uid);
      FutureImpl *result = new FutureImpl(context, this, false/*register*/, did,
                                          owner_space, ApEvent::NO_AP_EVENT);
      // Retake the lock and see if we lost the race
      {
        AutoLock d_lock(distributed_collectable_lock);
        std::map<DistributedID,DistributedCollectable*>::const_iterator 
          finder = dist_collectables.find(did);
        if (finder != dist_collectables.end())
        {
          // We lost the race
          if (!result->is_owner() && 
              result->remove_base_resource_ref(REMOTE_DID_REF))
            delete (result);
#ifdef DEBUG_LEGION
          result = dynamic_cast<FutureImpl*>(finder->second);
          assert(result != NULL);
#else
          result = static_cast<FutureImpl*>(finder->second);
#endif
          return result;
        }
        result->record_future_registered(mutator);
        dist_collectables[did] = result;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    FutureMapImpl* Runtime::find_or_create_future_map(DistributedID did,
                  TaskContext *ctx, RtEvent complete, ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      did &= LEGION_DISTRIBUTED_ID_MASK;
      {
        AutoLock d_lock(distributed_collectable_lock,1,false/*exclusive*/);
        std::map<DistributedID,DistributedCollectable*>::const_iterator 
          finder = dist_collectables.find(did);
        if (finder != dist_collectables.end())
        {
#ifdef DEBUG_LEGION
          FutureMapImpl *result = dynamic_cast<FutureMapImpl*>(finder->second);
          assert(result != NULL);
#else
          FutureMapImpl *result = static_cast<FutureMapImpl*>(finder->second);
#endif
          return result;
        }
      }
      const AddressSpaceID owner_space = determine_owner(did);
#ifdef DEBUG_LEGION
      assert(owner_space != address_space);
#endif
      FutureMapImpl *result = new FutureMapImpl(ctx, this, did, owner_space,
                                          complete, false/*register now */);
      // Retake the lock and see if we lost the race
      {
        AutoLock d_lock(distributed_collectable_lock);
        std::map<DistributedID,DistributedCollectable*>::const_iterator 
          finder = dist_collectables.find(did);
        if (finder != dist_collectables.end())
        {
          // We lost the race
          if (!result->is_owner() &&
              result->remove_base_resource_ref(REMOTE_DID_REF))
            delete (result);
#ifdef DEBUG_LEGION
          result = dynamic_cast<FutureMapImpl*>(finder->second);
          assert(result != NULL);
#else
          result = static_cast<FutureMapImpl*>(finder->second);
#endif
          return result;
        }
        result->record_future_map_registered(mutator);
        dist_collectables[did] = result;
      }
      return result;
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::find_or_create_index_slice_space(const Domain &domain,
                                       TypeTag type_tag, Provenance *provenance)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(type_tag != 0);
#endif
      const std::pair<Domain,TypeTag> key(domain, type_tag);
      {
        AutoLock is_lock(is_slice_lock,1,false/*exclusive*/);
        std::map<std::pair<Domain,TypeTag>,IndexSpace>::const_iterator finder =
          index_slice_spaces.find(key);
        if (finder != index_slice_spaces.end())
          return finder->second;
      }
      const IndexSpace result(get_unique_index_space_id(),
                              get_unique_index_tree_id(), type_tag);
      const DistributedID did = get_available_distributed_id();
      forest->create_index_space(result, &domain, did, provenance);
      if (legion_spy_enabled)
        LegionSpy::log_top_index_space(result.id, address_space,
            (provenance == NULL) ? NULL : provenance->human.c_str());
      // Overwrite and leak for now, don't care too much as this 
      // should occur infrequently
      AutoLock is_lock(is_slice_lock);
      index_slice_spaces[key] = result;
      return result;
    } 

    //--------------------------------------------------------------------------
    void Runtime::increment_outstanding_top_level_tasks(void)
    //--------------------------------------------------------------------------
    {
      // Check to see if we are on node 0 or not
      if (address_space != 0)
      {
        // Send a message to node 0 requesting permission to 
        // lauch a new top-level task and wait on an event
        // to signal that permission has been granted
        RtUserEvent grant_event = Runtime::create_rt_user_event();
        Serializer rez;
        rez.serialize(grant_event);
        find_messenger(0)->send_message<SEND_TOP_LEVEL_TASK_REQUEST>(rez,
                                                          true/*flush*/);
        grant_event.wait();
      }
      else
      {
        outstanding_top_level_tasks.fetch_add(1);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::decrement_outstanding_top_level_tasks(void)
    //--------------------------------------------------------------------------
    {
      // Check to see if we are on node 0 or not
      if (address_space != 0)
      {
        // Send a message to node 0 indicating that we finished
        // executing a top-level task
        Serializer rez;
        find_messenger(0)->send_message<SEND_TOP_LEVEL_TASK_COMPLETE>(rez,
                                                            true/*flush*/);
      }
      else
      {
        unsigned prev = outstanding_top_level_tasks.fetch_sub(1);
#ifdef DEBUG_LEGION
        assert(prev > 0);
#endif
        // Check to see if we have no more outstanding top-level tasks
        // If we don't launch a task to handle the try to shutdown the runtime 
        if (prev == 1)
          issue_runtime_shutdown_attempt();
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::issue_runtime_shutdown_attempt(void)
    //--------------------------------------------------------------------------
    {
      ShutdownManager::RetryShutdownArgs args(
            ShutdownManager::CHECK_TERMINATION);
      // Issue this with a low priority so that other meta-tasks
      // have an opportunity to run
      issue_runtime_meta_task(args, LG_LOW_PRIORITY);
    }

    //--------------------------------------------------------------------------
    void Runtime::initiate_runtime_shutdown(AddressSpaceID source,
                                           ShutdownManager::ShutdownPhase phase,
                                           ShutdownManager *owner)
    //--------------------------------------------------------------------------
    {
      log_shutdown.info("Received notification on node %d for phase %d",
                        address_space, phase);
      // If this is the first phase, do all our normal stuff
      if (phase == ShutdownManager::CHECK_TERMINATION)
      {
        // Get the preconditions for any outstanding operations still
        // available for garabage collection and wait on them to 
        // try and get close to when there are no more outstanding tasks
        std::map<Memory,MemoryManager*> copy_managers;
        {
          AutoLock m_lock(memory_manager_lock,1,false/*exclusive*/);
          copy_managers = memory_managers;
        }
        std::set<ApEvent> wait_events;
        for (std::map<Memory,MemoryManager*>::const_iterator it = 
              copy_managers.begin(); it != copy_managers.end(); it++)
          it->second->find_shutdown_preconditions(wait_events);
        if (!wait_events.empty())
        {
          RtEvent wait_on = Runtime::protect_merge_events(wait_events);
          wait_on.wait();
        }
      }
      else if ((phase == ShutdownManager::CHECK_SHUTDOWN) && 
                !prepared_for_shutdown)
      {
        // First time we check for shutdown we do the prepare for shutdown
        prepare_runtime_shutdown();  
      }
      ShutdownManager *shutdown_manager = 
        new ShutdownManager(phase, this, source, 
                            LEGION_SHUTDOWN_RADIX, owner);
      if (shutdown_manager->attempt_shutdown())
        delete shutdown_manager;
    }

    //--------------------------------------------------------------------------
    void Runtime::confirm_runtime_shutdown(ShutdownManager *shutdown_manager, 
                                           bool phase_one)
    //--------------------------------------------------------------------------
    {
      if (has_outstanding_tasks())
      {
        shutdown_manager->record_outstanding_tasks();
#ifdef DEBUG_LEGION
        LG_TASK_DESCRIPTIONS(meta_task_names);
        AutoLock out_lock(outstanding_task_lock,1,false/*exclusive*/);
        for (std::map<std::pair<unsigned,bool>,unsigned>::const_iterator it =
              outstanding_task_counts.begin(); it != 
              outstanding_task_counts.end(); it++)
        {
          if (it->second == 0)
            continue;
          if (it->first.second)
            log_shutdown.info("RT %d: %d outstanding meta task(s) %s",
                              address_space, it->second, 
                              meta_task_names[it->first.first]);
          else                
            log_shutdown.info("RT %d: %d outstanding application task(s) %d",
                              address_space, it->second, it->first.first);
        }
#endif
      }
      // Check all our message managers for outstanding messages
      for (unsigned idx = 0; idx < LEGION_MAX_NUM_NODES; idx++)
      {
        MessageManager *manager = message_managers[idx].load();
        if (manager != NULL)
          manager->confirm_shutdown(shutdown_manager, phase_one);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::prepare_runtime_shutdown(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!prepared_for_shutdown);
#endif
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
        it->second->prepare_for_shutdown();
      for (std::map<Memory,MemoryManager*>::const_iterator it = 
            memory_managers.begin(); it != memory_managers.end(); it++)
        it->second->prepare_for_shutdown();
      // Destroy any index slice spaces that we made during execution
      std::set<RtEvent> applied;
      for (std::map<std::pair<Domain,TypeTag>,IndexSpace>::const_iterator it =
            index_slice_spaces.begin(); it != index_slice_spaces.end(); it++)
        forest->destroy_index_space(it->second, address_space, applied);
      // If there are still any layout constraints that the application
      // failed to remove its references to then we can remove the reference
      // for them and make sure it's effects propagate
      if (!separate_runtime_instances)
      {
        std::vector<LayoutConstraints*> to_remove;
        {
          AutoLock l_lock(layout_constraints_lock,1,false/*exclusive*/);
          for (std::map<LayoutConstraintID,LayoutConstraints*>::const_iterator
                it = layout_constraints_table.begin(); it !=
                layout_constraints_table.end(); it++)
            if (it->second->is_owner() && !it->second->internal)
              to_remove.push_back(it->second);
        }
        if (!to_remove.empty())
        {
          WrapperReferenceMutator mutator(applied); 
          for (std::vector<LayoutConstraints*>::const_iterator it = 
                to_remove.begin(); it != to_remove.end(); it++)
            if ((*it)->remove_base_gc_ref(APPLICATION_REF, &mutator))
              delete (*it);
        }
      }
      if (!redop_fill_views.empty())
      {
        WrapperReferenceMutator mutator(applied);
        for (std::map<ReductionOpID,FillView*>::const_iterator it = 
              redop_fill_views.begin(); it != redop_fill_views.end(); it++)
          if (it->second->remove_base_valid_ref(RUNTIME_REF, &mutator))
            delete it->second;
        redop_fill_views.clear();
      }
      if (!applied.empty())
      {
        const RtEvent wait_on = Runtime::merge_events(applied);
        if (wait_on.exists() && !wait_on.has_triggered())
          wait_on.wait();
      }
      prepared_for_shutdown = true;
    }

    //--------------------------------------------------------------------------
    void Runtime::finalize_runtime_shutdown(int exit_code)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(address_space == 0); // only happens on node 0
#endif
      std::set<RtEvent> shutdown_events;
      // Launch tasks to shutdown all the runtime instances
      Machine::ProcessorQuery all_procs(machine);
      Realm::ProfilingRequestSet empty_requests;
      if (Runtime::separate_runtime_instances)
      {
        // If we are doing separate runtime instances, run it once on every
        // processor since we have separate runtimes for every processor
        for (Machine::ProcessorQuery::iterator it = all_procs.begin();
              it != all_procs.end(); it++)
        {
          shutdown_events.insert(
              RtEvent(it->spawn(LG_SHUTDOWN_TASK_ID, NULL, 0, empty_requests)));
        }
      }
      else
      {
        // In the normal case we just have to run this once on every node
        std::set<AddressSpace> shutdown_spaces;
        for (Machine::ProcessorQuery::iterator it = all_procs.begin();
              it != all_procs.end(); it++)
        {
          AddressSpace space = it->address_space();
          if (shutdown_spaces.find(space) == shutdown_spaces.end())
          {
            shutdown_events.insert(
                RtEvent(it->spawn(LG_SHUTDOWN_TASK_ID,NULL,0,empty_requests)));
            shutdown_spaces.insert(space);
          }
        }
      }
      // One last really crazy precondition on shutdown, we actually need to
      // make sure that this task itself is done executing before trying to
      // shutdown so add our own completion event as a precondition
      shutdown_events.insert(RtEvent(Processor::get_current_finish_event()));
      // Then tell Realm to shutdown when they are all done
      RtEvent shutdown_precondition = Runtime::merge_events(shutdown_events);
      RealmRuntime realm = RealmRuntime::get_runtime();
      realm.shutdown(shutdown_precondition, exit_code);
    }

    //--------------------------------------------------------------------------
    bool Runtime::has_outstanding_tasks(void)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      AutoLock out_lock(outstanding_task_lock);
      return (total_outstanding_tasks > 0);
#else
      return total_outstanding_tasks.load();
#endif
    }

#ifdef DEBUG_LEGION
    //--------------------------------------------------------------------------
    void Runtime::increment_total_outstanding_tasks(unsigned tid, bool meta)
    //--------------------------------------------------------------------------
    {
      AutoLock out_lock(outstanding_task_lock); 
      total_outstanding_tasks++;
      std::pair<unsigned,bool> key(tid,meta);
      std::map<std::pair<unsigned,bool>,unsigned>::iterator finder = 
        outstanding_task_counts.find(key);
      if (finder == outstanding_task_counts.end())
        outstanding_task_counts[key] = 1;
      else
        finder->second++;
    }

    //--------------------------------------------------------------------------
    void Runtime::decrement_total_outstanding_tasks(unsigned tid, bool meta)
    //--------------------------------------------------------------------------
    {
      AutoLock out_lock(outstanding_task_lock);
      assert(total_outstanding_tasks > 0);
      total_outstanding_tasks--;
      std::pair<unsigned,bool> key(tid,meta);
      std::map<std::pair<unsigned,bool>,unsigned>::iterator finder = 
        outstanding_task_counts.find(key);
      assert(finder != outstanding_task_counts.end());
      assert(finder->second > 0);
      finder->second--;
    }
#endif

    //--------------------------------------------------------------------------
    IndividualTask* Runtime::get_available_individual_task(void)
    //--------------------------------------------------------------------------
    {
      IndividualTask *result = get_available(individual_task_lock, 
                                         available_individual_tasks);
#ifdef DEBUG_LEGION
      AutoLock i_lock(individual_task_lock);
      out_individual_tasks.insert(result);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    PointTask* Runtime::get_available_point_task(void)
    //--------------------------------------------------------------------------
    {
      PointTask *result = get_available(point_task_lock, 
                                        available_point_tasks);
#ifdef DEBUG_LEGION
      AutoLock p_lock(point_task_lock);
      out_point_tasks.insert(result);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    IndexTask* Runtime::get_available_index_task(void)
    //--------------------------------------------------------------------------
    {
      IndexTask *result = get_available(index_task_lock, 
                                       available_index_tasks);
#ifdef DEBUG_LEGION
      AutoLock i_lock(index_task_lock);
      out_index_tasks.insert(result);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    SliceTask* Runtime::get_available_slice_task(void)
    //--------------------------------------------------------------------------
    {
      SliceTask *result = get_available(slice_task_lock,
                                       available_slice_tasks);
#ifdef DEBUG_LEGION
      AutoLock s_lock(slice_task_lock);
      out_slice_tasks.insert(result);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    MapOp* Runtime::get_available_map_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(map_op_lock, available_map_ops);
    }

    //--------------------------------------------------------------------------
    CopyOp* Runtime::get_available_copy_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(copy_op_lock, available_copy_ops);
    }

    //--------------------------------------------------------------------------
    IndexCopyOp* Runtime::get_available_index_copy_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(copy_op_lock, available_index_copy_ops);
    }

    //--------------------------------------------------------------------------
    PointCopyOp* Runtime::get_available_point_copy_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(copy_op_lock, available_point_copy_ops);
    }

    //--------------------------------------------------------------------------
    FenceOp* Runtime::get_available_fence_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(fence_op_lock, available_fence_ops);
    }

    //--------------------------------------------------------------------------
    FrameOp* Runtime::get_available_frame_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(frame_op_lock, available_frame_ops);
    }

    //--------------------------------------------------------------------------
    CreationOp* Runtime::get_available_creation_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(creation_op_lock, available_creation_ops);
    }

    //--------------------------------------------------------------------------
    DeletionOp* Runtime::get_available_deletion_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(deletion_op_lock, available_deletion_ops);
    }

    //--------------------------------------------------------------------------
    MergeCloseOp* Runtime::get_available_merge_close_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(merge_close_op_lock, available_merge_close_ops);
    }

    //--------------------------------------------------------------------------
    PostCloseOp* Runtime::get_available_post_close_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(post_close_op_lock, available_post_close_ops);
    }

    //--------------------------------------------------------------------------
    VirtualCloseOp* Runtime::get_available_virtual_close_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(virtual_close_op_lock, available_virtual_close_ops);
    }

    //--------------------------------------------------------------------------
    DynamicCollectiveOp* Runtime::get_available_dynamic_collective_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(dynamic_collective_op_lock, 
                           available_dynamic_collective_ops);
    }

    //--------------------------------------------------------------------------
    FuturePredOp* Runtime::get_available_future_pred_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(future_pred_op_lock, available_future_pred_ops);
    }

    //--------------------------------------------------------------------------
    NotPredOp* Runtime::get_available_not_pred_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(not_pred_op_lock, available_not_pred_ops);
    }

    //--------------------------------------------------------------------------
    AndPredOp* Runtime::get_available_and_pred_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(and_pred_op_lock, available_and_pred_ops);
    }

    //--------------------------------------------------------------------------
    OrPredOp* Runtime::get_available_or_pred_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(or_pred_op_lock, available_or_pred_ops);
    }

    //--------------------------------------------------------------------------
    AcquireOp* Runtime::get_available_acquire_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(acquire_op_lock, available_acquire_ops);
    }

    //--------------------------------------------------------------------------
    ReleaseOp* Runtime::get_available_release_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(release_op_lock, available_release_ops);
    }

    //--------------------------------------------------------------------------
    TraceCaptureOp* Runtime::get_available_capture_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(capture_op_lock, available_capture_ops);
    }

    //--------------------------------------------------------------------------
    TraceCompleteOp* Runtime::get_available_trace_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(trace_op_lock, available_trace_ops);
    }

    //--------------------------------------------------------------------------
    TraceReplayOp* Runtime::get_available_replay_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(replay_op_lock, available_replay_ops);
    }

    //--------------------------------------------------------------------------
    TraceBeginOp* Runtime::get_available_begin_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(begin_op_lock, available_begin_ops);
    }

    //--------------------------------------------------------------------------
    TraceSummaryOp* Runtime::get_available_summary_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(summary_op_lock, available_summary_ops);
    }

    //--------------------------------------------------------------------------
    MustEpochOp* Runtime::get_available_epoch_op(void)
    //--------------------------------------------------------------------------
    {
      MustEpochOp *result = get_available(epoch_op_lock, available_epoch_ops);
#ifdef DEBUG_LEGION
      AutoLock e_lock(epoch_op_lock);
      out_must_epoch.insert(result);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    PendingPartitionOp* Runtime::get_available_pending_partition_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(pending_partition_op_lock, 
                           available_pending_partition_ops);
    }

    //--------------------------------------------------------------------------
    DependentPartitionOp* Runtime::get_available_dependent_partition_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(dependent_partition_op_lock, 
                           available_dependent_partition_ops);
    }

    //--------------------------------------------------------------------------
    PointDepPartOp* Runtime::get_available_point_dep_part_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(dependent_partition_op_lock,
                           available_point_dep_part_ops);
    }

    //--------------------------------------------------------------------------
    FillOp* Runtime::get_available_fill_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(fill_op_lock, available_fill_ops);
    }

    //--------------------------------------------------------------------------
    IndexFillOp* Runtime::get_available_index_fill_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(fill_op_lock, available_index_fill_ops);
    }

    //--------------------------------------------------------------------------
    PointFillOp* Runtime::get_available_point_fill_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(fill_op_lock, available_point_fill_ops);
    }

    //--------------------------------------------------------------------------
    AttachOp* Runtime::get_available_attach_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(attach_op_lock, available_attach_ops);
    }

    //--------------------------------------------------------------------------
    IndexAttachOp* Runtime::get_available_index_attach_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(attach_op_lock, available_index_attach_ops);
    }

    //--------------------------------------------------------------------------
    PointAttachOp* Runtime::get_available_point_attach_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(attach_op_lock, available_point_attach_ops);
    }

    //--------------------------------------------------------------------------
    DetachOp* Runtime::get_available_detach_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(detach_op_lock, available_detach_ops);
    }

    //--------------------------------------------------------------------------
    IndexDetachOp* Runtime::get_available_index_detach_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(detach_op_lock, available_index_detach_ops);
    }

    //--------------------------------------------------------------------------
    PointDetachOp* Runtime::get_available_point_detach_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(detach_op_lock, available_point_detach_ops);
    }

    //--------------------------------------------------------------------------
    TimingOp* Runtime::get_available_timing_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(timing_op_lock, available_timing_ops);
    }

    //--------------------------------------------------------------------------
    TunableOp* Runtime::get_available_tunable_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(tunable_op_lock, available_tunable_ops);
    }

    //--------------------------------------------------------------------------
    AllReduceOp* Runtime::get_available_all_reduce_op(void)
    //--------------------------------------------------------------------------
    {
      return get_available(all_reduce_op_lock, available_all_reduce_ops);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_individual_task(IndividualTask *task)
    //--------------------------------------------------------------------------
    {
      AutoLock i_lock(individual_task_lock);
      release_operation<false>(available_individual_tasks, task);
#ifdef DEBUG_LEGION
      out_individual_tasks.erase(task);
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::free_point_task(PointTask *task)
    //--------------------------------------------------------------------------
    {
      AutoLock p_lock(point_task_lock);
#ifdef DEBUG_LEGION
      out_point_tasks.erase(task);
#endif
      // Note that we can safely delete point tasks because they are
      // never registered in the logical state of the region tree
      // as part of the dependence analysis. This does not apply
      // to all operation objects.
      release_operation<true>(available_point_tasks, task);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_index_task(IndexTask *task)
    //--------------------------------------------------------------------------
    {
      AutoLock i_lock(index_task_lock);
      release_operation<false>(available_index_tasks, task);
#ifdef DEBUG_LEGION
      out_index_tasks.erase(task);
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::free_slice_task(SliceTask *task)
    //--------------------------------------------------------------------------
    {
      AutoLock s_lock(slice_task_lock);
#ifdef DEBUG_LEGION
      out_slice_tasks.erase(task);
#endif
      // Note that we can safely delete slice tasks because they are
      // never registered in the logical state of the region tree
      // as part of the dependence analysis. This does not apply
      // to all operation objects.
      release_operation<true>(available_slice_tasks, task);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_map_op(MapOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock m_lock(map_op_lock);
      release_operation<false>(available_map_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_copy_op(CopyOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock c_lock(copy_op_lock);
      release_operation<false>(available_copy_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_index_copy_op(IndexCopyOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock c_lock(copy_op_lock);
      release_operation<false>(available_index_copy_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_point_copy_op(PointCopyOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock c_lock(copy_op_lock);
      release_operation<true>(available_point_copy_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_fence_op(FenceOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(fence_op_lock);
      release_operation<false>(available_fence_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_frame_op(FrameOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(frame_op_lock);
      release_operation<false>(available_frame_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_creation_op(CreationOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock d_lock(creation_op_lock);
      release_operation<false>(available_creation_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_deletion_op(DeletionOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock d_lock(deletion_op_lock);
      release_operation<false>(available_deletion_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_merge_close_op(MergeCloseOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock i_lock(merge_close_op_lock);
      release_operation<false>(available_merge_close_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_post_close_op(PostCloseOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock p_lock(post_close_op_lock);
      release_operation<false>(available_post_close_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_virtual_close_op(VirtualCloseOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock v_lock(virtual_close_op_lock);
      release_operation<false>(available_virtual_close_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_dynamic_collective_op(DynamicCollectiveOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock dc_lock(dynamic_collective_op_lock);
      release_operation<false>(available_dynamic_collective_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_future_predicate_op(FuturePredOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(future_pred_op_lock);
      release_operation<false>(available_future_pred_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_not_predicate_op(NotPredOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock n_lock(not_pred_op_lock);
      release_operation<false>(available_not_pred_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_and_predicate_op(AndPredOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(and_pred_op_lock);
      release_operation<false>(available_and_pred_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_or_predicate_op(OrPredOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock o_lock(or_pred_op_lock);
      release_operation<false>(available_or_pred_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_acquire_op(AcquireOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(acquire_op_lock);
      release_operation<false>(available_acquire_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_release_op(ReleaseOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock r_lock(release_op_lock);
      release_operation<false>(available_release_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_capture_op(TraceCaptureOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock c_lock(capture_op_lock);
      release_operation<false>(available_capture_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_trace_op(TraceCompleteOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(trace_op_lock);
      release_operation<false>(available_trace_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_replay_op(TraceReplayOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(replay_op_lock);
      release_operation<false>(available_replay_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_begin_op(TraceBeginOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(begin_op_lock);
      release_operation<false>(available_begin_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_summary_op(TraceSummaryOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(summary_op_lock);
      release_operation<false>(available_summary_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_epoch_op(MustEpochOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock e_lock(epoch_op_lock);
      release_operation<false>(available_epoch_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_pending_partition_op(PendingPartitionOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock p_lock(pending_partition_op_lock);
      release_operation<false>(available_pending_partition_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_dependent_partition_op(DependentPartitionOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock p_lock(dependent_partition_op_lock);
      release_operation<false>(available_dependent_partition_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_point_dep_part_op(PointDepPartOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock p_lock(dependent_partition_op_lock);
      release_operation<true>(available_point_dep_part_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_fill_op(FillOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(fill_op_lock);
      release_operation<false>(available_fill_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_index_fill_op(IndexFillOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(fill_op_lock);
      release_operation<false>(available_index_fill_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_point_fill_op(PointFillOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock f_lock(fill_op_lock);
      release_operation<true>(available_point_fill_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_attach_op(AttachOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(attach_op_lock);
      release_operation<false>(available_attach_ops, op);
    }
    
    //--------------------------------------------------------------------------
    void Runtime::free_index_attach_op(IndexAttachOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(attach_op_lock);
      release_operation<false>(available_index_attach_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_point_attach_op(PointAttachOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(attach_op_lock);
      release_operation<true>(available_point_attach_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_detach_op(DetachOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock d_lock(detach_op_lock);
      release_operation<false>(available_detach_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_index_detach_op(IndexDetachOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock d_lock(detach_op_lock);
      release_operation<false>(available_index_detach_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_point_detach_op(PointDetachOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock d_lock(detach_op_lock);
      release_operation<true>(available_point_detach_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_timing_op(TimingOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(timing_op_lock);
      release_operation<false>(available_timing_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_tunable_op(TunableOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock t_lock(tunable_op_lock);
      release_operation<false>(available_tunable_ops, op);
    }

    //--------------------------------------------------------------------------
    void Runtime::free_all_reduce_op(AllReduceOp *op)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(all_reduce_op_lock);
      release_operation<false>(available_all_reduce_ops, op);
    }

    //--------------------------------------------------------------------------
    RegionTreeContext Runtime::allocate_region_tree_context(void)
    //--------------------------------------------------------------------------
    {
      // Try getting something off the list of available contexts
      AutoLock ctx_lock(context_lock);
      if (!available_contexts.empty())
      {
        RegionTreeContext result = available_contexts.front();
        available_contexts.pop_front();
        return result;
      }
      // If we failed to get a context, double the number of total 
      // contexts and then update the forest nodes to have the right
      // number of contexts available
      RegionTreeContext result(total_contexts);
      for (unsigned idx = 1; idx < total_contexts; idx++)
        available_contexts.push_back(RegionTreeContext(total_contexts+idx));
      // Mark that we doubled the total number of contexts
      // Very important that we do this before calling the
      // RegionTreeForest's resize method!
      total_contexts *= 2;
#ifdef DEBUG_LEGION
      assert(!available_contexts.empty());
#endif
      // Tell all the processor managers about the additional contexts
      for (std::map<Processor,ProcessorManager*>::const_iterator it = 
            proc_managers.begin(); it != proc_managers.end(); it++)
      {
        it->second->update_max_context_count(total_contexts); 
      }
      return result;
    }

    //--------------------------------------------------------------------------
    void Runtime::free_region_tree_context(RegionTreeContext context)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(context.exists());
      forest->check_context_state(context);
#endif
      AutoLock ctx_lock(context_lock);
      available_contexts.push_back(context);
    }

    //--------------------------------------------------------------------------
    void Runtime::register_local_context(UniqueID context_uid,InnerContext *ctx)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert((context_uid % runtime_stride) == address_space); // sanity check
#endif
      AutoLock ctx_lock(context_lock);
#ifdef DEBUG_LEGION
      assert(local_contexts.find(context_uid) == local_contexts.end());
#endif
      local_contexts[context_uid] = ctx;
    }
    
    //--------------------------------------------------------------------------
    void Runtime::unregister_local_context(UniqueID context_uid)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert((context_uid % runtime_stride) == address_space); // sanity check
#endif
      AutoLock ctx_lock(context_lock);
      std::map<UniqueID,InnerContext*>::iterator finder = 
        local_contexts.find(context_uid);
#ifdef DEBUG_LEGION
      assert(finder != local_contexts.end());
#endif
      local_contexts.erase(finder);
    }

    //--------------------------------------------------------------------------
    void Runtime::register_remote_context(UniqueID context_uid, 
                       RemoteContext *context, std::set<RtEvent> &preconditions)
    //--------------------------------------------------------------------------
    {
      RtUserEvent to_trigger;
      {
        AutoLock ctx_lock(context_lock);
        std::map<UniqueID,std::pair<RtUserEvent,RemoteContext*> >::iterator 
          finder = pending_remote_contexts.find(context_uid);
#ifdef DEBUG_LEGION
        assert(remote_contexts.find(context_uid) == remote_contexts.end());
        assert(finder != pending_remote_contexts.end());
#endif
        to_trigger = finder->second.first;
        pending_remote_contexts.erase(finder);
        remote_contexts[context_uid] = context; 
      }
#ifdef DEBUG_LEGION
      assert(to_trigger.exists());
#endif
      if (!preconditions.empty())
        Runtime::trigger_event(to_trigger,Runtime::merge_events(preconditions));
      else
        Runtime::trigger_event(to_trigger);
    }

    //--------------------------------------------------------------------------
    void Runtime::unregister_remote_context(UniqueID context_uid)
    //--------------------------------------------------------------------------
    {
      RemoteContext *context = NULL;
      {
        AutoLock ctx_lock(context_lock);
        std::map<UniqueID,RemoteContext*>::iterator finder = 
          remote_contexts.find(context_uid);
#ifdef DEBUG_LEGION
        assert(finder != remote_contexts.end());
#endif
        context = finder->second;
        remote_contexts.erase(finder);
      }
      // Remove our reference and delete it if we're done with it
      if (context->remove_reference())
        delete context;
    }

    //--------------------------------------------------------------------------
    InnerContext* Runtime::find_context(UniqueID context_uid,
                                      bool return_null_if_not_found /*=false*/,
                                      RtEvent *wait_for /*=NULL*/)
    //--------------------------------------------------------------------------
    {
      RtEvent wait_on;
      RtUserEvent ready_event;
      RemoteContext *result = NULL;
      {
        // Need exclusive permission since we might mutate stuff
        AutoLock ctx_lock(context_lock,1,false/*exclusive*/);
        // See if it is local first
        std::map<UniqueID,InnerContext*>::const_iterator
          local_finder = local_contexts.find(context_uid);
        if (local_finder != local_contexts.end())
          return local_finder->second;
        // Now see if it is remote
        std::map<UniqueID,RemoteContext*>::const_iterator
          remote_finder = remote_contexts.find(context_uid);
        if (remote_finder != remote_contexts.end())
          return remote_finder->second;
        // If we don't have it, see if we should send the response or not
        std::map<UniqueID,
                 std::pair<RtUserEvent,RemoteContext*> >::const_iterator 
          pending_finder = pending_remote_contexts.find(context_uid);
        if (pending_finder != pending_remote_contexts.end())
        {
          if (wait_for != NULL)
          {
            *wait_for = pending_finder->second.first;
            return pending_finder->second.second;
          }
          else
          {
            wait_on = pending_finder->second.first;
            result = pending_finder->second.second;
          }
        } else if (return_null_if_not_found)
          // If its not here and we are supposed to return null do that
          return NULL;
      }
      if (result == NULL)
      {
        // Make a remote context here in case we need to request it, 
        // we can't make it while holding the lock
        RemoteContext *temp = new RemoteContext(this, context_uid);
        // Add a reference to the newly created context
        temp->add_reference();
        InnerContext *local_result = NULL;
        // Use a do while (false) loop here for easy breaks
        do 
        { 
          // Retake the lock in exclusive mode and see if we lost the race
          AutoLock ctx_lock(context_lock);
          // See if it is local first
          std::map<UniqueID,InnerContext*>::const_iterator
            local_finder = local_contexts.find(context_uid);
          if (local_finder != local_contexts.end())
          {
            // Need to jump to end to avoid leaking memory with temp
            local_result = local_finder->second;
            break;
          }
          // Now see if it is remote
          std::map<UniqueID,RemoteContext*>::const_iterator
            remote_finder = remote_contexts.find(context_uid);
          if (remote_finder != remote_contexts.end())
          {
            // Need to jump to end to avoid leaking memory with temp
            local_result = remote_finder->second;
            break;
          }
          // If we don't have it, see if we should send the response or not
          std::map<UniqueID,
                   std::pair<RtUserEvent,RemoteContext*> >::const_iterator 
            pending_finder = pending_remote_contexts.find(context_uid);
          if (pending_finder == pending_remote_contexts.end())
          {
#ifdef DEBUG_LEGION
            assert(!return_null_if_not_found);
#endif
            // Make an event to trigger for when we are done
            ready_event = Runtime::create_rt_user_event();
            pending_remote_contexts[context_uid] = 
              std::pair<RtUserEvent,RemoteContext*>(ready_event, temp); 
            result = temp;
            // Add a result that will be removed when the response
            // message comes back from the owner, this also prevents
            // temp from being deleted at the end of this block
            result->add_reference();
          }
          else // if we're going to have it we might as well wait
          {
            if (wait_for != NULL)
            {
              *wait_for = pending_finder->second.first;
              local_result = pending_finder->second.second;
              // Need to continue to end to avoid leaking memory with temp
            }
            else
            {
              wait_on = pending_finder->second.first;
              result = pending_finder->second.second;
            }
          }
        } while (false); // only go through this block once
        if (temp->remove_reference())
          delete temp;
        if (local_result != NULL)
          return local_result;
      }
#ifdef DEBUG_LEGION
      assert(result != NULL);
#endif
      // If there is no wait event, we have to send the message
      if (!wait_on.exists())
      {
#ifdef DEBUG_LEGION
        assert(ready_event.exists());
#endif
        // We have to send the message
        // Figure out the target
        const AddressSpaceID target = get_runtime_owner(context_uid);
#ifdef DEBUG_LEGION
        assert(target != address_space);
#endif
        // Send the message
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(context_uid);
          rez.serialize(result);
        }
        send_remote_context_request(target, rez); 
        if (wait_for != NULL)
        {
          *wait_for = ready_event;
          return result;
        }
        else
        {
          // Wait for it to be ready
          ready_event.wait();
          // We already know the answer cause we sent the message
          return result;
        }
      }
      else
      {
        // Can't wait in some cases
        if (return_null_if_not_found && !wait_on.has_triggered())
          return NULL;
        // We wait for the results to be ready
        wait_on.wait();
        return result;
      }
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_local(Processor proc) const
    //--------------------------------------------------------------------------
    {
      return (local_procs.find(proc) != local_procs.end());
    }

    //--------------------------------------------------------------------------
    bool Runtime::is_visible_memory(Processor proc, Memory memory)
    //--------------------------------------------------------------------------
    {
      // If we cached it locally for our processors, then just go
      // ahead and get the result
      std::map<Processor,ProcessorManager*>::const_iterator finder = 
        proc_managers.find(proc);
      if (finder != proc_managers.end())
        return finder->second->is_visible_memory(memory);
      // Otherwise look up the result
      Machine::MemoryQuery visible_memories(machine);
      // Have to handle the case where this is a processor group
      if (proc.kind() == Processor::PROC_GROUP)
      {
        std::vector<Processor> group_members;
        proc.get_group_members(group_members);
        for (std::vector<Processor>::const_iterator it =
              group_members.begin(); it != group_members.end(); it++)
          visible_memories.has_affinity_to(*it);
      }
      else
        visible_memories.has_affinity_to(proc);
      for (Machine::MemoryQuery::iterator it =
            visible_memories.begin(); it != visible_memories.end(); it++)
        if ((*it) == memory)
          return true;
      return false;
    }

    //--------------------------------------------------------------------------
    void Runtime::find_visible_memories(Processor proc, 
                                        std::set<Memory> &visible)
    //--------------------------------------------------------------------------
    {
      // If we cached it locally for our processors, then just go
      // ahead and get the result
      std::map<Processor,ProcessorManager*>::const_iterator finder = 
        proc_managers.find(proc);
      if (finder != proc_managers.end())
      {
        finder->second->find_visible_memories(visible);
        return;
      }
      // Otherwise look up the result
      Machine::MemoryQuery visible_memories(machine);
      // Have to handle the case where this is a processor group
      if (proc.kind() == Processor::PROC_GROUP)
      {
        std::vector<Processor> group_members;
        proc.get_group_members(group_members);
        for (std::vector<Processor>::const_iterator it = 
              group_members.begin(); it != group_members.end(); it++)
          visible_memories.has_affinity_to(*it);
      }
      else
        visible_memories.has_affinity_to(proc);
      for (Machine::MemoryQuery::iterator it = visible_memories.begin();
            it != visible_memories.end(); it++)
        visible.insert(*it);
    }

    //--------------------------------------------------------------------------
    IndexSpaceID Runtime::get_unique_index_space_id(void)
    //--------------------------------------------------------------------------
    {
      IndexSpaceID result = unique_index_space_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      // If we have overflow on the number of partitions created
      // then we are really in a bad place.
      assert(result <= unique_index_space_id); 
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    IndexPartitionID Runtime::get_unique_index_partition_id(void)
    //--------------------------------------------------------------------------
    {
      IndexPartitionID result =
        unique_index_partition_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      // If we have overflow on the number of partitions created
      // then we are really in a bad place.
      assert(result <= unique_index_partition_id); 
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    FieldSpaceID Runtime::get_unique_field_space_id(void)
    //--------------------------------------------------------------------------
    {
      FieldSpaceID result = unique_field_space_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      // If we have overflow on the number of field spaces
      // created then we are really in a bad place.
      assert(result <= unique_field_space_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    IndexTreeID Runtime::get_unique_index_tree_id(void)
    //--------------------------------------------------------------------------
    {
      IndexTreeID result = unique_index_tree_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      // If we have overflow on the number of region trees
      // created then we are really in a bad place.
      assert(result <= unique_index_tree_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    RegionTreeID Runtime::get_unique_region_tree_id(void)
    //--------------------------------------------------------------------------
    {
      RegionTreeID result = unique_region_tree_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      // If we have overflow on the number of region trees
      // created then we are really in a bad place.
      assert(result <= unique_region_tree_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    UniqueID Runtime::get_unique_operation_id(void)
    //--------------------------------------------------------------------------
    {
      UniqueID result = unique_operation_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      assert(result <= unique_operation_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    FieldID Runtime::get_unique_field_id(void)
    //--------------------------------------------------------------------------
    {
      FieldID result = unique_field_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      assert(result <= unique_field_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    CodeDescriptorID Runtime::get_unique_code_descriptor_id(void)
    //--------------------------------------------------------------------------
    {
      CodeDescriptorID result = 
        unique_code_descriptor_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      assert(result <= unique_code_descriptor_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    LayoutConstraintID Runtime::get_unique_constraint_id(void)
    //--------------------------------------------------------------------------
    {
      LayoutConstraintID result =
        unique_constraint_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      assert(result <= unique_constraint_id);
#endif
      return result;
    }

    //--------------------------------------------------------------------------
    IndexSpaceExprID Runtime::get_unique_index_space_expr_id(void)
    //--------------------------------------------------------------------------
    {
      IndexSpaceExprID result = unique_is_expr_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      assert(result <= unique_is_expr_id);
#endif
      return result;
    }

#ifdef LEGION_SPY
    //--------------------------------------------------------------------------
    unsigned Runtime::get_unique_indirections_id(void)
    //--------------------------------------------------------------------------
    {
      unsigned result = unique_indirections_id.fetch_add(runtime_stride);
#ifdef DEBUG_LEGION
      // check for overflow
      assert(result <= unique_indirections_id);
#endif
      return result;
    }
#endif

    //--------------------------------------------------------------------------
    LegionErrorType Runtime::verify_requirement(
                               const RegionRequirement &req, FieldID &bad_field)
    //--------------------------------------------------------------------------
    {
      FieldSpace sp = (req.handle_type == LEGION_SINGULAR_PROJECTION) 
                      || (req.handle_type == LEGION_REGION_PROJECTION)
                        ? req.region.field_space : req.partition.field_space;
      // First make sure that all the privilege fields are valid for
      // the given field space of the region or partition
      for (std::set<FieldID>::const_iterator it = req.privilege_fields.begin();
            it != req.privilege_fields.end(); it++)
      {
        if (!forest->has_field(sp, *it))
        {
          bad_field = *it;
          return ERROR_FIELD_SPACE_FIELD_MISMATCH;
        }
      }
      // Make sure that the requested node is a valid request
      if ((req.handle_type == LEGION_SINGULAR_PROJECTION) || 
          (req.handle_type == LEGION_REGION_PROJECTION))
      {
        if (!forest->has_node(req.region))
          return ERROR_INVALID_REGION_HANDLE;
        if (req.region.get_tree_id() != req.parent.get_tree_id())
          return ERROR_INVALID_REGION_HANDLE;
      }
      else
      {
        if (!forest->has_node(req.partition))
          return ERROR_INVALID_PARTITION_HANDLE;
        if (req.partition.get_tree_id() != req.parent.get_tree_id())
          return ERROR_INVALID_PARTITION_HANDLE;
      }

      // Then check that any instance fields are included in the privilege 
      // fields.  Make sure that there are no duplicates in the instance fields
      std::set<FieldID> inst_duplicates;
      for (std::vector<FieldID>::const_iterator it = 
            req.instance_fields.begin(); it != 
            req.instance_fields.end(); it++)
      {
        if (req.privilege_fields.find(*it) == req.privilege_fields.end())
        {
          bad_field = *it;
          return ERROR_INVALID_INSTANCE_FIELD;
        }
        if (inst_duplicates.find(*it) != inst_duplicates.end())
        {
          bad_field = *it;
          return ERROR_DUPLICATE_INSTANCE_FIELD;
        }
        inst_duplicates.insert(*it);
      }

      // If this is a projection requirement and the child region selected will 
      // need to be in exclusive mode then the partition must be disjoint
      if ((req.handle_type == LEGION_PARTITION_PROJECTION) && 
          (IS_WRITE(req)))
      {
        if (!forest->is_disjoint(req.partition))
          return ERROR_NON_DISJOINT_PARTITION;
      }

      // Made it here, then there is no error
      return LEGION_NO_ERROR;
    }

    //--------------------------------------------------------------------------
    Future Runtime::help_create_future(TaskContext *ctx, ApEvent complete_event, 
                                       Operation *op /*= NULL*/)
    //--------------------------------------------------------------------------
    {
      return Future(new FutureImpl(ctx, this, true/*register*/,
                                   get_available_distributed_id(),
                                   address_space, complete_event, op));
    }

    //--------------------------------------------------------------------------
    bool Runtime::help_reset_future(const Future &f)
    //--------------------------------------------------------------------------
    {
      return f.impl->reset_future();
    }

    //--------------------------------------------------------------------------
    IndexSpace Runtime::help_create_index_space_handle(TypeTag type_tag)
    //--------------------------------------------------------------------------
    {
      IndexSpace handle(get_unique_index_space_id(),
                        get_unique_index_tree_id(), type_tag);
      return handle;
    }

    //--------------------------------------------------------------------------
    unsigned Runtime::generate_random_integer(void)
    //--------------------------------------------------------------------------
    {
      AutoLock r_lock(random_lock);
      unsigned result = nrand48(random_state);
      return result;
    }

#ifdef LEGION_TRACE_ALLOCATION 
    //--------------------------------------------------------------------------
    void Runtime::trace_allocation(AllocationType type, size_t size, int elems)
    //--------------------------------------------------------------------------
    {
      if (prepared_for_shutdown)
        return;
      AutoLock a_lock(allocation_lock);
      std::map<AllocationType,AllocationTracker>::iterator finder = 
        allocation_manager.find(type);
      size_t alloc_size = size * elems;
      finder->second.total_allocations += elems;
      finder->second.total_bytes += alloc_size;
      finder->second.diff_allocations += elems;
      finder->second.diff_bytes += alloc_size;
    }

    //--------------------------------------------------------------------------
    void Runtime::trace_free(AllocationType type, size_t size, int elems)
    //--------------------------------------------------------------------------
    {
      if (prepared_for_shutdown)
        return;
      AutoLock a_lock(allocation_lock);
      std::map<AllocationType,AllocationTracker>::iterator finder = 
        allocation_manager.find(type);
      size_t free_size = size * elems;
      finder->second.total_allocations -= elems;
      finder->second.total_bytes -= free_size;
      finder->second.diff_allocations -= elems;
      finder->second.diff_bytes -= free_size;
    }

    //--------------------------------------------------------------------------
    void Runtime::dump_allocation_info(void)
    //--------------------------------------------------------------------------
    {
      AutoLock a_lock(allocation_lock);
      for (std::map<AllocationType,AllocationTracker>::iterator it = 
            allocation_manager.begin(); it != allocation_manager.end(); it++)
      {
        // Skip anything that is empty
        if (it->second.total_allocations == 0)
          continue;
        // Skip anything that hasn't changed
        if (it->second.diff_allocations == 0)
          continue;
        log_allocation.info("%s on %d: "
            "total=%d total_bytes=%ld diff=%d diff_bytes=%lld",
            get_allocation_name(it->first), address_space,
            it->second.total_allocations, it->second.total_bytes,
            it->second.diff_allocations, (long long int)it->second.diff_bytes);
        it->second.diff_allocations = 0;
        it->second.diff_bytes = 0;
      }
      log_allocation.info(" ");
    }

    //--------------------------------------------------------------------------
    /*static*/ const char* Runtime::get_allocation_name(AllocationType type)
    //--------------------------------------------------------------------------
    {
      switch (type)
      {
        case ARGUMENT_MAP_ALLOC:
          return "Argument Map";
        case ARGUMENT_MAP_STORE_ALLOC:
          return "Argument Map Store";
        case STORE_ARGUMENT_ALLOC:
          return "Store Argument";
        case MPI_HANDSHAKE_ALLOC:
          return "MPI Handshake";
        case GRANT_ALLOC:
          return "Grant";
        case FUTURE_ALLOC:
          return "Future";
        case FUTURE_MAP_ALLOC:
          return "Future Map";
        case PHYSICAL_REGION_ALLOC:
          return "Physical Region";
        case EXTERNAL_RESOURCES_ALLOC:
          return "External Resources";
        case STATIC_TRACE_ALLOC:
          return "Static Trace";
        case DYNAMIC_TRACE_ALLOC:
          return "Dynamic Trace";
        case ALLOC_MANAGER_ALLOC:
          return "Allocation Manager";
        case ALLOC_INTERNAL_ALLOC:
          return "Allocation Internal";
        case TASK_ARGS_ALLOC:
          return "Task Arguments";
        case REDUCTION_ALLOC:
          return "Reduction Result"; 
        case PREDICATE_ALLOC:
          return "Default Predicate";
        case FUTURE_RESULT_ALLOC:
          return "Future Result";
        case INDIVIDUAL_INST_MANAGER_ALLOC:
          return "Individual Manager";
        case COLLECTIVE_INST_MANAGER_ALLOC:
          return "Collective Manager";
        case TREE_CLOSE_ALLOC:
          return "Tree Close List";
        case TREE_CLOSE_IMPL_ALLOC:
          return "Tree Close Impl";
        case MATERIALIZED_VIEW_ALLOC:
          return "Materialized View";
        case REDUCTION_VIEW_ALLOC:
          return "Reduction View";
        case FILL_VIEW_ALLOC:
          return "Fill View";
        case PHI_VIEW_ALLOC:
          return "Phi View";
        case INDIVIDUAL_TASK_ALLOC:
          return "Individual Task";
        case POINT_TASK_ALLOC:
          return "Point Task";
        case INDEX_TASK_ALLOC:
          return "Index Task";
        case SLICE_TASK_ALLOC:
          return "Slice Task";
        case TOP_TASK_ALLOC:
          return "Top Level Task";
        case REMOTE_TASK_ALLOC:
          return "Remote Task";
        case INLINE_TASK_ALLOC:
          return "Inline Task";
        case MAP_OP_ALLOC:
          return "Map Op";
        case COPY_OP_ALLOC:
          return "Copy Op";
        case FENCE_OP_ALLOC:
          return "Fence Op";
        case FRAME_OP_ALLOC:
          return "Frame Op";
        case CREATION_OP_ALLOC:
          return "Creation Op";
        case DELETION_OP_ALLOC:
          return "Deletion Op";
        case CLOSE_OP_ALLOC:
          return "Close Op";
        case DYNAMIC_COLLECTIVE_OP_ALLOC:
          return "Dynamic Collective Op";
        case FUTURE_PRED_OP_ALLOC:
          return "Future Pred Op";
        case NOT_PRED_OP_ALLOC:
          return "Not Pred Op";
        case AND_PRED_OP_ALLOC:
          return "And Pred Op";
        case OR_PRED_OP_ALLOC:
          return "Or Pred Op";
        case ACQUIRE_OP_ALLOC:
          return "Acquire Op";
        case RELEASE_OP_ALLOC:
          return "Release Op";
        case TRACE_CAPTURE_OP_ALLOC:
          return "Trace Capture Op";
        case TRACE_COMPLETE_OP_ALLOC:
          return "Trace Complete Op";
        case MUST_EPOCH_OP_ALLOC:
          return "Must Epoch Op";
        case PENDING_PARTITION_OP_ALLOC:
          return "Pending Partition Op";
        case DEPENDENT_PARTITION_OP_ALLOC:
          return "Dependent Partition Op";
        case FILL_OP_ALLOC:
          return "Fill Op";
        case ATTACH_OP_ALLOC:
          return "Attach Op";
        case DETACH_OP_ALLOC:
          return "Detach Op";
        case MESSAGE_BUFFER_ALLOC:
          return "Message Buffer";
        case EXECUTING_CHILD_ALLOC:
          return "Executing Children";
        case EXECUTED_CHILD_ALLOC:
          return "Executed Children";
        case COMPLETE_CHILD_ALLOC:
          return "Complete Children";
        case PHYSICAL_MANAGER_ALLOC:
          return "Physical Managers";
        case LOGICAL_VIEW_ALLOC:
          return "Logical Views";
        case LOGICAL_FIELD_VERSIONS_ALLOC:
          return "Logical Field Versions";
        case LOGICAL_FIELD_STATE_ALLOC:
          return "Logical Field States";
        case CURR_LOGICAL_ALLOC:
          return "Current Logical Users";
        case PREV_LOGICAL_ALLOC:
          return "Previous Logical Users";
        case VERSION_ID_ALLOC:
          return "Version IDs";
        case LOGICAL_REC_ALLOC:
          return "Recorded Logical Users";
        case CLOSE_LOGICAL_ALLOC:
          return "Close Logical Users";
        case VALID_VIEW_ALLOC:
          return "Valid Instance Views";
        case VALID_REDUCTION_ALLOC:
          return "Valid Reduction Views";
        case PENDING_UPDATES_ALLOC:
          return "Pending Updates";
        case LAYOUT_DESCRIPTION_ALLOC:
          return "Layout Description";
        case PHYSICAL_USER_ALLOC:
          return "Physical Users";
        case PHYSICAL_VERSION_ALLOC:
          return "Physical Versions";
        case MEMORY_INSTANCES_ALLOC:
          return "Memory Manager Instances";
        case MEMORY_GARBAGE_ALLOC:
          return "Memory Garbage Instances";
        case PROCESSOR_GROUP_ALLOC:
          return "Processor Groups";
        case RUNTIME_DISTRIBUTED_ALLOC:
          return "Runtime Distributed IDs";
        case RUNTIME_DIST_COLLECT_ALLOC:
          return "Distributed Collectables";
        case RUNTIME_GC_EPOCH_ALLOC:
          return "Runtime Garbage Collection Epochs";
        case RUNTIME_FUTURE_ALLOC:
          return "Runtime Futures";
        case RUNTIME_REMOTE_ALLOC:
          return "Runtime Remote Contexts";
        case TASK_INLINE_REGION_ALLOC:
          return "Task Inline Regions";
        case TASK_TRACES_ALLOC:
          return "Task Traces";
        case TASK_RESERVATION_ALLOC:
          return "Task Reservations";
        case TASK_BARRIER_ALLOC:
          return "Task Barriers";
        case TASK_LOCAL_FIELD_ALLOC:
          return "Task Local Fields";
        case SEMANTIC_INFO_ALLOC:
          return "Semantic Information";
        case DIRECTORY_ALLOC:
          return "State Directory";
        case DENSE_INDEX_ALLOC:
          return "Dense Index Set";
        case CURRENT_STATE_ALLOC:
          return "Current State";
        case VERSION_MANAGER_ALLOC:
          return "Version Manager";
        case PHYSICAL_STATE_ALLOC:
          return "Physical State";
        case EQUIVALENCE_SET_ALLOC:
          return "Equivalence Set";
        case AGGREGATE_VERSION_ALLOC:
          return "Aggregate Version";
        case TASK_IMPL_ALLOC:
          return "Task Implementation";
        case VARIANT_IMPL_ALLOC:
          return "Variant Implementation";
        case LAYOUT_CONSTRAINTS_ALLOC:
          return "Layout Constraints";
        case COPY_FILL_AGGREGATOR_ALLOC:
          return "Copy Fill Aggregator";
        case UNION_EXPR_ALLOC:
          return "Union Index Space Expression";
        case INTERSECTION_EXPR_ALLOC:
          return "Intersection Index Space Expression";
        case DIFFERENCE_EXPR_ALLOC:
          return "Difference Index Space Expression";
        case INSTANCE_EXPR_ALLOC:
          return "Instance Index Space Expression";
        case REMOTE_EXPR_ALLOC:
          return "Remote Index Space Expression";
        default:
          assert(false); // should never get here
      }
      return NULL;
    }
#endif

#ifdef DEBUG_LEGION
    //--------------------------------------------------------------------------
    void Runtime::print_out_individual_tasks(FILE *f, int cnt /*= -1*/)
    //--------------------------------------------------------------------------
    {
      // Build a map of the tasks based on their task IDs
      // so we can print them out in the order that they were created.
      // No need to hold the lock because we'll only ever call this
      // in the debugger.
      std::map<UniqueID,IndividualTask*> out_tasks;
      for (std::set<IndividualTask*>::const_iterator it = 
            out_individual_tasks.begin(); it !=
            out_individual_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::map<UniqueID,IndividualTask*>::const_iterator it = 
            out_tasks.begin(); (it != out_tasks.end()); it++)
      {
        ApEvent completion = it->second->get_completion_event();
        fprintf(f,"Outstanding Individual Task %lld: %p %s (" IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id); 
        if (cnt > 0)
          cnt--;
        else if (cnt == 0)
          break;
      }
      fflush(f);
    }

    //--------------------------------------------------------------------------
    void Runtime::print_out_index_tasks(FILE *f, int cnt /*= -1*/)
    //--------------------------------------------------------------------------
    {
      // Build a map of the tasks based on their task IDs
      // so we can print them out in the order that they were created.
      // No need to hold the lock because we'll only ever call this
      // in the debugger.
      std::map<UniqueID,IndexTask*> out_tasks;
      for (std::set<IndexTask*>::const_iterator it = 
            out_index_tasks.begin(); it !=
            out_index_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::map<UniqueID,IndexTask*>::const_iterator it = 
            out_tasks.begin(); (it != out_tasks.end()); it++)
      {
        ApEvent completion = it->second->get_completion_event();
        fprintf(f,"Outstanding Index Task %lld: %p %s (" IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id); 
        if (cnt > 0)
          cnt--;
        else if (cnt == 0)
          break;
      }
      fflush(f);
    }

    //--------------------------------------------------------------------------
    void Runtime::print_out_slice_tasks(FILE *f, int cnt /*= -1*/)
    //--------------------------------------------------------------------------
    {
      // Build a map of the tasks based on their task IDs
      // so we can print them out in the order that they were created.
      // No need to hold the lock because we'll only ever call this
      // in the debugger.
      std::map<UniqueID,SliceTask*> out_tasks;
      for (std::set<SliceTask*>::const_iterator it = 
            out_slice_tasks.begin(); it !=
            out_slice_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::map<UniqueID,SliceTask*>::const_iterator it = 
            out_tasks.begin(); (it != out_tasks.end()); it++)
      {
        ApEvent completion = it->second->get_completion_event();
        fprintf(f,"Outstanding Slice Task %lld: %p %s (" IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id); 
        if (cnt > 0)
          cnt--;
        else if (cnt == 0)
          break;
      }
      fflush(f);
    }

    //--------------------------------------------------------------------------
    void Runtime::print_out_point_tasks(FILE *f, int cnt /*= -1*/)
    //--------------------------------------------------------------------------
    {
      // Build a map of the tasks based on their task IDs
      // so we can print them out in the order that they were created.
      // No need to hold the lock because we'll only ever call this
      // in the debugger.
      std::map<UniqueID,PointTask*> out_tasks;
      for (std::set<PointTask*>::const_iterator it = 
            out_point_tasks.begin(); it !=
            out_point_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::map<UniqueID,PointTask*>::const_iterator it = 
            out_tasks.begin(); (it != out_tasks.end()); it++)
      {
        ApEvent completion = it->second->get_completion_event();
        fprintf(f,"Outstanding Point Task %lld: %p %s (" IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id); 
        if (cnt > 0)
          cnt--;
        else if (cnt == 0)
          break;
      }
      fflush(f);
    }

    //--------------------------------------------------------------------------
    void Runtime::print_outstanding_tasks(FILE *f, int cnt /*= -1*/)
    //--------------------------------------------------------------------------
    {
      std::map<UniqueID,TaskOp*> out_tasks;
      for (std::set<IndividualTask*>::const_iterator it = 
            out_individual_tasks.begin(); it !=
            out_individual_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::set<IndexTask*>::const_iterator it = 
            out_index_tasks.begin(); it !=
            out_index_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::set<SliceTask*>::const_iterator it = 
            out_slice_tasks.begin(); it !=
            out_slice_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::set<PointTask*>::const_iterator it = 
            out_point_tasks.begin(); it !=
            out_point_tasks.end(); it++)
      {
        out_tasks[(*it)->get_unique_id()] = *it;
      }
      for (std::map<UniqueID,TaskOp*>::const_iterator it = 
            out_tasks.begin(); it != out_tasks.end(); it++)
      {
        ApEvent completion = it->second->get_completion_event();
        switch (it->second->get_task_kind())
        {
          case TaskOp::INDIVIDUAL_TASK_KIND:
            {
              fprintf(f,"Outstanding Individual Task %lld: %p %s (" 
                        IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id);
              break;
            }
          case TaskOp::POINT_TASK_KIND:
            {
              fprintf(f,"Outstanding Point Task %lld: %p %s (" 
                        IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id);
              break;
            }
          case TaskOp::INDEX_TASK_KIND:
            {
              fprintf(f,"Outstanding Index Task %lld: %p %s (" 
                        IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id);
              break;
            }
          case TaskOp::SLICE_TASK_KIND:
            {
              fprintf(f,"Outstanding Slice Task %lld: %p %s (" 
                        IDFMT ")\n",
                it->first, it->second, it->second->get_task_name(),
                completion.id);
              break;
            }
          default:
            assert(false);
        }
        if (cnt > 0)
          cnt--;
        else if (cnt == 0)
          break;
      }
      fflush(f);
    }
#endif

    //--------------------------------------------------------------------------
    LayoutConstraintID Runtime::register_layout(
                                const LayoutConstraintRegistrar &registrar,
                                LayoutConstraintID layout_id, DistributedID did)
    //--------------------------------------------------------------------------
    {
      if (layout_id == LEGION_AUTO_GENERATE_ID)
        layout_id = get_unique_constraint_id();
      // Now make our entry and then return the result
      LayoutConstraints *constraints = 
        new LayoutConstraints(layout_id, this, registrar,false/*internal*/,did);
      if (register_layout(constraints, NULL/*mutator*/))
      {
        // These constraints are available on all the nodes so if we own
        // them then record that we have remote instances for everything else
        if ((did > 0) && constraints->is_owner())
        {
          for (AddressSpaceID space = 0; space < total_address_spaces; space++)
            if (space != address_space)
              constraints->update_remote_instances(space);
        }
      }
      else
        // If someone else already registered this ID then we delete our object
        delete constraints;
      return layout_id;
    }

    //--------------------------------------------------------------------------
    LayoutConstraints* Runtime::register_layout(FieldSpace handle,
                                 const LayoutConstraintSet &cons, bool internal)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints *constraints = new LayoutConstraints(
          get_unique_constraint_id(), this, cons, handle, internal);
      register_layout(constraints, NULL/*mutator*/);
      return constraints;
    }

    //--------------------------------------------------------------------------
    bool Runtime::register_layout(LayoutConstraints *new_constraints,
                                  ReferenceMutator *mutator)
    //--------------------------------------------------------------------------
    {
      new_constraints->add_base_resource_ref(RUNTIME_REF);
      // If we're not internal and we're the owner then we also
      // add an application reference to prevent early collection
      if (!new_constraints->internal && new_constraints->is_owner())
        new_constraints->add_base_gc_ref(APPLICATION_REF);
      AutoLock l_lock(layout_constraints_lock);
      std::map<LayoutConstraintID,LayoutConstraints*>::const_iterator finder =
        layout_constraints_table.find(new_constraints->layout_id);
      if (finder != layout_constraints_table.end())
        return false;
      layout_constraints_table[new_constraints->layout_id] = new_constraints;
      // Remove any pending requests
      pending_constraint_requests.erase(new_constraints->layout_id);
      // Now we can do the registration with the runtime
      new_constraints->register_with_runtime(mutator);
      return true;
    }

    //--------------------------------------------------------------------------
    void Runtime::release_layout(LayoutConstraintID layout_id)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints *constraints = find_layout_constraints(layout_id);
#ifdef DEBUG_LEGION
      assert(!constraints->internal);
#endif
      // Check to see if this is the owner
      if (constraints->is_owner())
      {
        if (constraints->remove_base_gc_ref(APPLICATION_REF))
          delete constraints;
      }
      else
      {
        // Send a message to the owner asking it to do the release
        Serializer rez;
        {
          RezCheck z(rez);
          rez.serialize(layout_id);
        }
        send_constraint_release(constraints->owner_space, rez);
      }
    }

    //--------------------------------------------------------------------------
    void Runtime::unregister_layout(LayoutConstraintID layout_id)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints *constraints = NULL;
      {
        AutoLock l_lock(layout_constraints_lock);
        std::map<LayoutConstraintID,LayoutConstraints*>::iterator finder = 
          layout_constraints_table.find(layout_id);
        if (finder != layout_constraints_table.end())
        {
          constraints = finder->second;
          layout_constraints_table.erase(finder);
        }
      }
      if ((constraints != NULL) && 
          constraints->remove_base_resource_ref(RUNTIME_REF))
        delete (constraints);
    }

    //--------------------------------------------------------------------------
    /*static*/ LayoutConstraintID Runtime::preregister_layout(
                                     const LayoutConstraintRegistrar &registrar,
                                     LayoutConstraintID layout_id)
    //--------------------------------------------------------------------------
    { 
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'preregister_layout' after "
                      "the runtime has started!");
      std::map<LayoutConstraintID,LayoutConstraintRegistrar> 
        &pending_constraints = get_pending_constraint_table();
      // See if we have to generate an ID
      if (layout_id == LEGION_AUTO_GENERATE_ID)
      {
        // Find the first available layout ID
        layout_id = 1;
        for (std::map<LayoutConstraintID,LayoutConstraintRegistrar>::
              const_iterator it = pending_constraints.begin(); 
              it != pending_constraints.end(); it++)
        {
          if (layout_id != it->first)
          {
            // We've found a free one, so we can use it
            break;
          }
          else
            layout_id++;
        }
      }
      else
      {
        if (layout_id == 0)
          REPORT_LEGION_ERROR(ERROR_RESERVED_CONSTRAINT_ID, 
                        "Illegal use of reserved constraint ID 0");
        // Check to make sure it is not already used
        std::map<LayoutConstraintID,LayoutConstraintRegistrar>::const_iterator
          finder = pending_constraints.find(layout_id);
        if (finder != pending_constraints.end())
          REPORT_LEGION_ERROR(ERROR_DUPLICATE_CONSTRAINT_ID, 
                        "Duplicate use of constraint ID %ld", layout_id);
      }
      pending_constraints[layout_id] = registrar;
      return layout_id;
    }

    //--------------------------------------------------------------------------
    FieldSpace Runtime::get_layout_constraint_field_space(
                                                   LayoutConstraintID layout_id)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints *constraints = find_layout_constraints(layout_id);
      return constraints->get_field_space();
    }

    //--------------------------------------------------------------------------
    void Runtime::get_layout_constraints(LayoutConstraintID layout_id,
                                        LayoutConstraintSet &layout_constraints)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints *constraints = find_layout_constraints(layout_id);
      layout_constraints = *constraints;
    }

    //--------------------------------------------------------------------------
    const char* Runtime::get_layout_constraints_name(
                                                   LayoutConstraintID layout_id)
    //--------------------------------------------------------------------------
    {
      LayoutConstraints *constraints = find_layout_constraints(layout_id);
      return constraints->get_name();
    }

    //--------------------------------------------------------------------------
    LayoutConstraints* Runtime::find_layout_constraints(
                      LayoutConstraintID layout_id, bool can_fail /*= false*/, 
                      RtEvent *wait_for /*=NULL*/)
    //--------------------------------------------------------------------------
    {
      // See if we can find it first
      RtEvent wait_on;
      {
        AutoLock l_lock(layout_constraints_lock);
        std::map<LayoutConstraintID,LayoutConstraints*>::const_iterator
          finder = layout_constraints_table.find(layout_id);
        if (finder != layout_constraints_table.end())
        {
          return finder->second;
        }
        else
        {
          // See if a request has already been issued
          std::map<LayoutConstraintID,RtEvent>::const_iterator
            wait_on_finder = pending_constraint_requests.find(layout_id);
          if (can_fail || 
              (wait_on_finder == pending_constraint_requests.end()))
          {
            // Ask for the constraints
            AddressSpaceID target = 
              LayoutConstraints::get_owner_space(layout_id, this); 
            RtUserEvent to_trigger = Runtime::create_rt_user_event();
            Serializer rez;
            {
              RezCheck z(rez);
              rez.serialize(layout_id);
              rez.serialize(to_trigger);
              rez.serialize(can_fail);
            }
            // Send the message
            send_constraint_request(target, rez);
            // Only save the event to wait on if this can't fail
            if (!can_fail)
              pending_constraint_requests[layout_id] = to_trigger;
            wait_on = to_trigger;
          }
          else
            wait_on = wait_on_finder->second;
        }
      }
      // If we want the wait event, just return
      if (wait_for != NULL)
      {
        *wait_for = wait_on;
        return NULL;
      }
      // If we didn't find it send a remote request for the constraints
      wait_on.wait();
      // When we wake up, the result should be there
      AutoLock l_lock(layout_constraints_lock);
      std::map<LayoutConstraintID,LayoutConstraints*>::const_iterator
          finder = layout_constraints_table.find(layout_id);
      if (finder == layout_constraints_table.end())
      {
        if (can_fail)
          return NULL;
#ifdef DEBUG_LEGION
        assert(finder != layout_constraints_table.end());
#endif
      }
      return finder->second;
    }

    /*static*/ TaskID Runtime::legion_main_id = 0;
    /*static*/ MapperID Runtime::legion_main_mapper_id = 0;
    /*static*/ bool Runtime::legion_main_set = false;
    /*static*/ bool Runtime::runtime_initialized = false;
    /*static*/ bool Runtime::runtime_started = false;
    /*static*/ bool Runtime::runtime_backgrounded = false;
    /*static*/ Runtime* Runtime::the_runtime = NULL;
    /*static*/ RtUserEvent Runtime::runtime_started_event = 
                                              RtUserEvent::NO_RT_USER_EVENT;
    /*static*/ std::atomic<int> Runtime::background_waits = {0};
    /*static*/ int Runtime::return_code = 0;
    /*static*/ int Runtime::mpi_rank = -1;

    //--------------------------------------------------------------------------
    /*static*/ int Runtime::start(int argc, char **argv, bool background,
                                  bool supply_default_mapper)
    //--------------------------------------------------------------------------
    {
      // Some static asserts that need to hold true for the runtime to work
      LEGION_STATIC_ASSERT(LEGION_MAX_RETURN_SIZE > 0, 
          "Need a positive and non-zero value for LEGION_MAX_RETURN_SIZE");
      LEGION_STATIC_ASSERT((1 << LEGION_FIELD_LOG2) == LEGION_MAX_FIELDS,
          "LEGION_MAX_FIELDS must be a pwoer of 2");
      LEGION_STATIC_ASSERT(LEGION_MAX_NUM_NODES > 0,
          "Need a positive and non-zero value for LEGION_MAX_NUM_NODES");
      LEGION_STATIC_ASSERT(LEGION_MAX_NUM_PROCS > 0,
          "Need a positive and non-zero value for LEGION_MAX_NUM_PROCS");
      LEGION_STATIC_ASSERT(LEGION_DEFAULT_MAX_TASK_WINDOW > 0,
          "Need a positive and non-zero value for "
          "LEGION_DEFAULT_MAX_TASK_WINDOW");
      LEGION_STATIC_ASSERT(LEGION_DEFAULT_MIN_TASKS_TO_SCHEDULE > 0,
          "Need a positive and non-zero value for "
          "LEGION_DEFAULT_MIN_TASKS_TO_SCHEDULE");
      LEGION_STATIC_ASSERT(LEGION_DEFAULT_MAX_MESSAGE_SIZE > 0,
          "Need a positive and non-zero value for "
          "LEGION_DEFAULT_MAX_MESSAGE_SIZE"); 
#ifdef LEGION_SPY
      LEGION_STATIC_ASSERT(
          Realm::Logger::REALM_LOGGING_MIN_LEVEL <= Realm::Logger::LEVEL_INFO,
        "Legion Spy requires a COMPILE_TIME_MIN_LEVEL of at most LEVEL_INFO.");
#endif
#ifdef LEGION_GC
      LEGION_STATIC_ASSERT(
          Realm::Logger::REALM_LOGGING_MIN_LEVEL <= Realm::Logger::LEVEL_INFO,
          "Legion GC requires a COMPILE_TIME_MIN_LEVEL of at most LEVEL_INFO.");
#endif
#ifdef DEBUG_SHUTDOWN_HANG
      LEGION_STATIC_ASSERT(
          Realm::Logger::REALM_LOGGING_MIN_LEVEL <= Realm::Logger::LEVEL_INFO,
          "DEBUG_SHUTDOWN_HANG requires a COMPILE_TIME_MIN_LEVEL "
          "of at most LEVEL_INFO.");
#endif

      // Register builtin reduction operators
      register_builtin_reduction_operators();

      // Need to pass argc and argv to low-level runtime before we can record 
      // their values as they might be changed by GASNet or MPI or whatever.
      // Note that the logger isn't initialized until after this call returns 
      // which means any logging that occurs before this has undefined behavior.
      const LegionConfiguration &config = initialize(&argc, &argv, false);
      RealmRuntime realm = RealmRuntime::get_runtime();

      // Perform any waits that the user requested before starting
      if (config.delay_start > 0)
          sleep(config.delay_start);
      // Check for any slow configurations
      if (!config.slow_config_ok)
        perform_slow_config_checks(config);
      // Configure legion spy if necessary
      if (config.legion_spy_enabled)
        LegionSpy::log_legion_spy_config();
      // Configure MPI Interoperability
      const std::vector<LegionHandshake> &pending_handshakes =
        get_pending_handshake_table();
      if ((mpi_rank >= 0) || (!pending_handshakes.empty()))
        configure_interoperability(config.separate_runtime_instances);
      // Construct our runtime objects 
      Processor::Kind startup_kind = Processor::NO_KIND;
      const RtEvent tasks_registered = configure_runtime(argc, argv,
          config, realm, startup_kind, background, supply_default_mapper);
#ifdef DEBUG_LEGION
      // Startup kind should be a CPU or a Utility processor
      assert((startup_kind == Processor::LOC_PROC) ||
              (startup_kind == Processor::UTIL_PROC));
#endif
      // We have to set these prior to starting Realm as once we start
      // Realm it might fork child processes so they all need to see
      // the same values for these static variables
      runtime_started = true;
      runtime_backgrounded = background;
      // Make a user event that we will trigger once we the 
      // startup task is done. If we're node 0 then we will use this
      // as the precondition for launching the top-level task
      runtime_started_event = Runtime::create_rt_user_event();

      // Now that we have everything setup we can tell Realm to
      // start the processors. It is at this point which fork
      // can be called to spawn subprocesses.
      realm.start();

      // First we issue a "barrier" NOP task that runs on all the
      // Realm processors to make sure that Realm is initialized
      const RtEvent realm_initialized(realm.collective_spawn_by_kind(
            Processor::NO_KIND, 0/*NOP*/, NULL, 0, false/*one per node*/));

      // Now we initialize all the runtimes so that they are ready
      // to begin execution. Note this also acts as a barrier across
      // the machine to ensure that nobody does anything related to
      // startup until all the runtimes are initialized everywhere
      const RtEvent legion_initialized(realm.collective_spawn_by_kind(
            (config.separate_runtime_instances ? Processor::NO_KIND :
             startup_kind), LG_INITIALIZE_TASK_ID, NULL, 0,
            !config.separate_runtime_instances, tasks_registered)); 
      // Now we can do one more spawn call to startup the runtime 
      // across the machine since we know everything is initialized
      const RtEvent runtime_started(realm.collective_spawn_by_kind(
              (config.separate_runtime_instances ? Processor::NO_KIND : 
               startup_kind), LG_STARTUP_TASK_ID, NULL, 0, 
              !config.separate_runtime_instances, 
              Runtime::merge_events(realm_initialized, legion_initialized)));
      // Trigger the start event when the runtime is ready
      Runtime::trigger_event(runtime_started_event, runtime_started);
      // If we are supposed to background this thread, then we wait
      // for the runtime to shutdown, otherwise we can now return
      if (!background)
        return realm.wait_for_shutdown();
      return 0;
    }

    //--------------------------------------------------------------------------
    /*static*/ const Runtime::LegionConfiguration& Runtime::initialize(
                                           int *argc, char ***argv, bool filter)
    //--------------------------------------------------------------------------
    {
      static LegionConfiguration config;
      if (runtime_initialized)
        return config;
      RealmRuntime realm;
#ifndef NDEBUG
      bool ok = 
#endif
        realm.network_init(argc, argv);
      assert(ok);
      // Next we configure the realm runtime after which we can access the
      // machine model and make events and reservations and do reigstrations
      std::vector<std::string> cmdline;
      // Check to see if there are any Legion default args from the environment
      const char *e = getenv("LEGION_DEFAULT_ARGS");
      if (e)
      {
        // This code is borrowed from Realm for parsing default arguments
        // Prepend any default args so they can still be overridden 
        // by actual flags on the command line
        while (*e) 
        {
          if (isspace(*e)) 
          { 
            e++;
            continue; 
          }
          const char *starts = NULL;
          if (*e == '\'') 
          {
            // single quoted string
            e++;
            assert(*e);
            starts = e;
            // read until next single quote
            while (*e && (*e != '\''))
              e++;
            cmdline.emplace_back(std::string(starts, size_t(e++ - starts))); 
            assert(!*e || isspace(*e));
            continue;
          }
          if (*e == '\"')
          {
            // double quoted string
            e++;
            assert(*e);
            starts = e;
            // read until next double quote
            while (*e && (*e != '\"'))
              e++;
            cmdline.emplace_back(std::string(starts, size_t(e++ - starts)));
            assert(!*e || isspace(*e));
            continue;
          }
          // no quotes - just take until next whitespace
          starts = e;
          while (*e && !isspace(*e))
            e++;
          cmdline.emplace_back(std::string(starts, size_t(e - starts)));
        }
      }
      size_t num_args = *argc;
      cmdline.reserve(cmdline.size() + ((num_args > 0) ? num_args-1 : 0));
      for (unsigned i = 1; i < num_args; i++)
        cmdline.emplace_back((*argv)[i]);
#ifndef NDEBUG
      ok = 
#endif
        realm.configure_from_command_line(cmdline, filter);
      assert(ok);
      Realm::CommandLineParser cp; 
      cp.add_option_bool("-lg:warn_backtrace",
                         config.warnings_backtrace, !filter)
        .add_option_bool("-lg:warn", config.runtime_warnings, !filter)
        .add_option_bool("-lg:leaks", config.report_leaks, !filter)
        .add_option_bool("-lg:separate",
                         config.separate_runtime_instances, !filter)
        .add_option_bool("-lg:registration",config.record_registration,!filter)
        .add_option_bool("-lg:nosteal",config.stealing_disabled,!filter)
        .add_option_bool("-lg:resilient",config.resilient_mode,!filter)
        .add_option_bool("-lg:unsafe_launch",config.unsafe_launch,!filter)
        .add_option_bool("-lg:unsafe_mapper",config.unsafe_mapper,!filter)
        .add_option_bool("-lg:safe_mapper",config.safe_mapper,!filter)
        .add_option_bool("-lg:inorder",config.program_order_execution,!filter)
        .add_option_bool("-lg:dump_physical_traces",
                         config.dump_physical_traces, !filter)
        .add_option_bool("-lg:no_tracing",config.no_tracing, !filter)
        .add_option_bool("-lg:no_physical_tracing",
                         config.no_physical_tracing, !filter)
        .add_option_bool("-lg:no_trace_optimization",
                         config.no_trace_optimization, !filter)
        .add_option_bool("-lg:no_fence_elision",
                         config.no_fence_elision, !filter)
        .add_option_bool("-lg:replay_on_cpus",
                         config.replay_on_cpus, !filter)
        .add_option_bool("-lg:disjointness",
                         config.verify_partitions, !filter)
        .add_option_bool("-lg:partcheck",
                         config.verify_partitions, !filter)
        .add_option_int("-lg:window", config.initial_task_window_size, !filter)
        .add_option_int("-lg:hysteresis", 
                        config.initial_task_window_hysteresis, !filter)
        .add_option_int("-lg:sched", 
                        config.initial_tasks_to_schedule, !filter)
        .add_option_int("-lg:vector", 
                        config.initial_meta_task_vector_width, !filter)
        .add_option_int("-lg:message",config.max_message_size, !filter)
        .add_option_int("-lg:epoch", config.gc_epoch_size, !filter)
        .add_option_int("-lg:local", config.max_local_fields, !filter)
        .add_option_int("-lg:parallel_replay", 
                        config.max_replay_parallelism, !filter)
        .add_option_bool("-lg:no_dyn",config.disable_independence_tests,!filter)
        .add_option_bool("-lg:spy",config.legion_spy_enabled, !filter)
        .add_option_bool("-lg:test",config.enable_test_mapper, !filter)
        .add_option_int("-lg:delay", config.delay_start, !filter)
        .add_option_string("-lg:replay", config.replay_file, !filter)
        .add_option_string("-lg:ldb", config.ldb_file, !filter)
#ifdef DEBUG_LEGION
        .add_option_bool("-lg:tree",config.logging_region_tree_state, !filter)
        .add_option_bool("-lg:verbose",config.verbose_logging, !filter)
        .add_option_bool("-lg:logical_only",config.logical_logging_only,!filter)
        .add_option_bool("-lg:physical_only",
                         config.physical_logging_only,!filter)
#endif
        .add_option_int("-lg:prof", config.num_profiling_nodes, !filter)
        .add_option_string("-lg:serializer", config.serializer_type, !filter)
        .add_option_string("-lg:prof_logfile", config.prof_logfile, !filter)
        .add_option_int("-lg:prof_footprint", 
                        config.prof_footprint_threshold, !filter)
        .add_option_int("-lg:prof_latency",config.prof_target_latency, !filter)
        .add_option_bool("-lg:debug_ok",config.slow_config_ok, !filter)
        // These are all the deprecated versions of these flag
        .add_option_bool("-hl:separate",
                         config.separate_runtime_instances, !filter)
        .add_option_bool("-hl:registration",config.record_registration, !filter)
        .add_option_bool("-hl:nosteal",config.stealing_disabled, !filter)
        .add_option_bool("-hl:resilient",config.resilient_mode, !filter)
        .add_option_bool("-hl:unsafe_launch",config.unsafe_launch, !filter)
        .add_option_bool("-hl:unsafe_mapper",config.unsafe_mapper, !filter)
        .add_option_bool("-hl:safe_mapper",config.safe_mapper, !filter)
        .add_option_bool("-hl:inorder",config.program_order_execution, !filter)
        .add_option_bool("-hl:disjointness",config.verify_partitions, !filter)
        .add_option_int("-hl:window", config.initial_task_window_size, !filter)
        .add_option_int("-hl:hysteresis", 
                        config.initial_task_window_hysteresis, !filter)
        .add_option_int("-hl:sched", config.initial_tasks_to_schedule, !filter)
        .add_option_int("-hl:message",config.max_message_size, !filter)
        .add_option_int("-hl:epoch", config.gc_epoch_size, !filter)
        .add_option_bool("-hl:no_dyn",config.disable_independence_tests,!filter)
        .add_option_bool("-hl:spy",config.legion_spy_enabled, !filter)
        .add_option_bool("-hl:test",config.enable_test_mapper, !filter)
        .add_option_int("-hl:delay", config.delay_start, !filter)
        .add_option_string("-hl:replay", config.replay_file, !filter)
        .add_option_string("-hl:ldb", config.ldb_file, !filter)
#ifdef DEBUG_LEGION
        .add_option_bool("-hl:tree",config.logging_region_tree_state,!filter)
        .add_option_bool("-hl:verbose",config.verbose_logging,!filter)
        .add_option_bool("-hl:logical_only",config.logical_logging_only,!filter)
        .add_option_bool("-hl:physical_only",
                         config.physical_logging_only,!filter)
#endif
        .add_option_int("-hl:prof", config.num_profiling_nodes, !filter)
        .add_option_string("-hl:serializer", config.serializer_type, !filter)
        .add_option_string("-hl:prof_logfile", config.prof_logfile, !filter)
        .parse_command_line(cmdline);
      // If we asked to filter the arguments, now we need to go back in
      // and update the arguments so that they reflect the pruned data
      if (filter)
      {
        if (!cmdline.empty())
        {
          unsigned arg_index = 1;
          for (unsigned idx = 0; idx < cmdline.size(); idx++)
          {
            const char *str = cmdline[idx].c_str();
            // Find the location of this string in the original
            // arguments to so that we can get its original pointer 
            assert(arg_index < num_args);
            while (strcmp(str, (*argv)[arg_index]) != 0)
            {
              arg_index++;
              assert(arg_index < num_args);
            }
            // Now that we've got it's original pointer we can move
            // it to the new location in the outputs
            if (arg_index == (idx+1))
              arg_index++; // already in the right place 
            else
              (*argv)[idx+1] = (*argv)[arg_index++];
          }
          *argc = (1 + cmdline.size());
        }
        else
          *argc = 1;
      }
#ifdef DEBUG_LEGION
      if (config.logging_region_tree_state)
        REPORT_LEGION_WARNING(LEGION_WARNING_REGION_TREE_STATE_LOGGING,
            "Region tree state logging is disabled.  To enable region "
            "tree state logging compile in debug mode.")
#endif
      if (config.initial_task_window_hysteresis > 100)
        REPORT_LEGION_ERROR(ERROR_LEGION_CONFIGURATION,
            "Illegal task window hysteresis value of %d which is not a value "
            "between 0 and 100.", config.initial_task_window_hysteresis)
      if (config.max_local_fields > LEGION_MAX_FIELDS)
        REPORT_LEGION_ERROR(ERROR_LEGION_CONFIGURATION,
            "Illegal max local fields value %d which is larger than the "
            "value of LEGION_MAX_FIELDS (%d).", config.max_local_fields,
            LEGION_MAX_FIELDS)
      const Realm::Logger::LoggingLevel compile_time_min_level =
            Realm::Logger::REALM_LOGGING_MIN_LEVEL;
      if (config.legion_spy_enabled && 
          (Realm::Logger::LEVEL_INFO < compile_time_min_level))
        REPORT_LEGION_ERROR(ERROR_LEGION_CONFIGURATION,
            "Legion Spy logging requires a COMPILE_TIME_MIN_LEVEL "
            "of at most LEVEL_INFO, but current setting is %s",
            (compile_time_min_level == Realm::Logger::LEVEL_PRINT) ? 
              "LEVEL_PRINT" : 
            (compile_time_min_level == Realm::Logger::LEVEL_WARNING) ?
              "LEVEL_WARNING" : 
            (compile_time_min_level == Realm::Logger::LEVEL_ERROR) ?
              "LEVEL_ERROR" :
            (compile_time_min_level == Realm::Logger::LEVEL_FATAL) ?
              "LEVEL_FATAL" : "LEVEL_NONE")
      if ((config.num_profiling_nodes > 0) &&
          (strcmp(config.serializer_type.c_str(), "ascii") == 0) &&
          (Realm::Logger::LEVEL_INFO < compile_time_min_level))
        REPORT_LEGION_ERROR(ERROR_LEGION_CONFIGURATION,
            "Legion Prof 'ascii' logging requires a COMPILE_TIME_MIN_LEVEL "
            "of at most LEVEL_INFO, but current setting is %s",
            (compile_time_min_level == Realm::Logger::LEVEL_PRINT) ? 
              "LEVEL_PRINT" : 
            (compile_time_min_level == Realm::Logger::LEVEL_WARNING) ?
              "LEVEL_WARNING" : 
            (compile_time_min_level == Realm::Logger::LEVEL_ERROR) ?
              "LEVEL_ERROR" :
            (compile_time_min_level == Realm::Logger::LEVEL_FATAL) ?
              "LEVEL_FATAL" : "LEVEL_NONE")
      if (config.record_registration &&
          (Realm::Logger::LEVEL_PRINT < compile_time_min_level))
        REPORT_LEGION_ERROR(ERROR_LEGION_CONFIGURATION,
            "Legion registration logging requires a COMPILE_TIME_MIN_LEVEL "
            "of at most LEVEL_PRINT, but current setting is %s",
            (compile_time_min_level == Realm::Logger::LEVEL_WARNING) ?
              "LEVEL_WARNING" : 
            (compile_time_min_level == Realm::Logger::LEVEL_ERROR) ?
              "LEVEL_ERROR" :
            (compile_time_min_level == Realm::Logger::LEVEL_FATAL) ?
              "LEVEL_FATAL" : "LEVEL_NONE")
      if (config.dump_physical_traces &&
          (Realm::Logger::LEVEL_INFO < compile_time_min_level))
        REPORT_LEGION_ERROR(ERROR_LEGION_CONFIGURATION,
            "Legion physical trace logging requires a COMPILE_TIME_MIN_LEVEL "
            "of at most LEVEL_INFO, but current setting is %s",
            (compile_time_min_level == Realm::Logger::LEVEL_PRINT) ? 
              "LEVEL_PRINT" : 
            (compile_time_min_level == Realm::Logger::LEVEL_WARNING) ?
              "LEVEL_WARNING" : 
            (compile_time_min_level == Realm::Logger::LEVEL_ERROR) ?
              "LEVEL_ERROR" :
            (compile_time_min_level == Realm::Logger::LEVEL_FATAL) ?
              "LEVEL_FATAL" : "LEVEL_NONE")
      runtime_initialized = true;
      return config;
    } 

    //--------------------------------------------------------------------------
    Future Runtime::launch_top_level_task(const TaskLauncher &launcher)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(!local_procs.empty());
#endif 
      // Find a target processor, we'll prefer a CPU processor for
      // backwards compatibility, but will take anything we get
      Processor target = Processor::NO_PROC;
      for (std::set<Processor>::const_iterator it = 
            local_procs.begin(); it != local_procs.end(); it++)
      {
        if (it->kind() == Processor::LOC_PROC)
        {
          target = *it;
          break;
        }
        else if (!target.exists())
          target = *it;
      }
#ifdef DEBUG_LEGION
      assert(target.exists());
#endif
      // Get a remote task to serve as the top of the top-level task
      TopLevelContext *top_context = 
        new TopLevelContext(this, get_unique_operation_id());
      // Add a reference to the top level context
      top_context->add_reference();
      // Set the executing processor
      top_context->set_executing_processor(target);
      // Get an individual task to be the top-level task
      IndividualTask *top_task = get_available_individual_task();
      // Mark that this task is the top-level task
      Future result = top_task->initialize_task(top_context, launcher, 
                                false/*track parent*/,true/*top level task*/);
      // Set this to be the current processor
      top_task->set_current_proc(target);
      increment_outstanding_top_level_tasks();
      // Launch a task to deactivate the top-level context
      // when the top-level task is done
      TopFinishArgs args(top_context);
      ApEvent pre = top_task->get_completion_event();
      issue_runtime_meta_task(args, LG_LATENCY_WORK_PRIORITY,
                              Runtime::protect_event(pre));
      // Put the task in the ready queue, make sure that the runtime is all
      // set up across the machine before we launch it as well
      top_task->enqueue_ready_task(false/*target*/, runtime_started_event);
      return result;
    }

    //--------------------------------------------------------------------------
    Context Runtime::begin_implicit_task(TaskID top_task_id,
                                         MapperID top_mapper_id,
                                         Processor::Kind proc_kind,
                                         const char *task_name,
                                         bool control_replicable,
                                         unsigned shards_per_address_space,
                                         int shard_id)
    //--------------------------------------------------------------------------
    {
      if (!runtime_started)
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_IMPLICIT_TOP_LEVEL_TASK,
            "Implicit top-level tasks are not allowed to be started before "
            "the Legion runtime is started.")
      // Check that we're not inside a task
      if (implicit_context != NULL)
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_IMPLICIT_TOP_LEVEL_TASK,
            "Implicit top-level tasks are not allowed to be started inside "
            "of Legion tasks. Only external computations are permitted "
            "to create new implicit top-level tasks.")
      // Wait for the runtime to have started if necessary
      if (!runtime_started_event.has_triggered())
        runtime_started_event.external_wait();

      InnerContext *execution_context = NULL;
      // Now that the runtime is started we can make our context
      if (control_replicable && (total_address_spaces > 1))
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_IMPLICIT_TOP_LEVEL_TASK,
            "Implicit top-level tasks are only supported on multiple "
            "nodes in the control_replication and later branches.")
      // Save the top-level task name if necessary
      if (task_name != NULL)
        attach_semantic_information(top_task_id, 
            LEGION_NAME_SEMANTIC_TAG, task_name, 
            strlen(task_name) + 1, true/*mutable*/);
      // Get a remote task to serve as the top of the top-level task
      TopLevelContext *top_context = 
        new TopLevelContext(this, get_unique_operation_id());
      // Save the context in the implicit context
      implicit_context = top_context;
      implicit_runtime = this;
      // Add a reference to the top level context
      top_context->add_reference();
      // Find a proxy processor for us to use for this task 
      // We might already even be on a Realm processor
      Processor proxy = Processor::get_executing_processor();
      if (!proxy.exists())
      {
#ifdef DEBUG_LEGION
        assert(!local_procs.empty());
#endif
        for (std::set<Processor>::const_iterator it =
              local_procs.begin(); it != local_procs.end(); it++)
        {
          if (it->kind() == proc_kind)
          {
            proxy = *it;
            break;
          }
        }
      }
#ifdef DEBUG_LEGION
      // TODO: remove this once realm supports drafting this thread
      // as a new kind of processor to use
      assert(proxy.exists());
#endif
      top_context->set_executing_processor(proxy);
      TaskLauncher launcher(top_task_id, UntypedBuffer(),
                            Predicate::TRUE_PRED, top_mapper_id);
      // Get an individual task to be the top-level task
      IndividualTask *top_task = get_available_individual_task();
      // Mark that this task is the top-level task
      top_task->initialize_task(top_context, launcher, false/*track parent*/,
                    true/*top level task*/, true/*implicit top level task*/);
      increment_outstanding_top_level_tasks();
      top_context->increment_pending();
#ifdef DEBUG_LEGION
      increment_total_outstanding_tasks(top_task_id, false);
#else
      increment_total_outstanding_tasks();
#endif
      // Launch a task to deactivate the top-level context
      // when the top-level task is done
      TopFinishArgs args(top_context);
      ApEvent pre = top_task->get_completion_event();
      issue_runtime_meta_task(args, LG_LATENCY_WORK_PRIORITY,
                              Runtime::protect_event(pre));
      execution_context = top_task->create_implicit_context();
      Legion::Runtime *dummy_rt;
      execution_context->begin_task(dummy_rt);
      execution_context->set_executing_processor(proxy);
      return execution_context;
    }

    //--------------------------------------------------------------------------
    void Runtime::unbind_implicit_task_from_external_thread(TaskContext *ctx)
    //--------------------------------------------------------------------------
    {
      if (!ctx->implicit_task)
        REPORT_LEGION_ERROR(ERROR_CONFUSED_USER,
            "Illegal call to unbind a context for task %s (UID %lld) that "
            "is not an implicit top-level task",
            ctx->get_task_name(), ctx->get_unique_id())
      implicit_context = NULL;
    }

    //--------------------------------------------------------------------------
    void Runtime::bind_implicit_task_to_external_thread(TaskContext *ctx)
    //--------------------------------------------------------------------------
    {
      if (!ctx->implicit_task)
        REPORT_LEGION_ERROR(ERROR_CONFUSED_USER,
            "Illegal call to bind a context for task %s (UID %lld) that "
            "is not an implicit top-level task",
            ctx->get_task_name(), ctx->get_unique_id())
      implicit_runtime = this;
      implicit_context = ctx;
      implicit_provenance = ctx->owner_task->get_unique_op_id();
    }

    //--------------------------------------------------------------------------
    void Runtime::finish_implicit_task(TaskContext *ctx)
    //--------------------------------------------------------------------------
    {
      if (!ctx->implicit_task)
        REPORT_LEGION_ERROR(ERROR_CONFUSED_USER,
            "Illegal call to finish an implicit task for task %s (UID %lld) "
            "that is not an implicit top-level task",
            ctx->get_task_name(), ctx->get_unique_id())
      // this is just a normal finish operation
      ctx->end_task(NULL, 0, false/*owned*/, PhysicalInstance::NO_INST, NULL);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::perform_slow_config_checks(
                                              const LegionConfiguration &config)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      if (config.num_profiling_nodes > 0)
      {
        // Give a massive warning about profiling with Legion Spy enabled
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"!!! YOU ARE PROFILING IN DEBUG MODE           !!!\n");
        fprintf(stderr,"!!! SERIOUS PERFORMANCE DEGRADATION WILL OCCUR!!!\n");
        fprintf(stderr,"!!! COMPILE WITH DEBUG=0 FOR PROFILING        !!!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"SLEEPING FOR 5 SECONDS SO YOU READ THIS WARNING...\n");
        fflush(stderr);
        sleep(5);
      }
#endif
#ifdef LEGION_SPY
      if (config.num_profiling_nodes > 0)
      {
        // Give a massive warning about profiling with Legion Spy enabled
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"!!! YOU ARE PROFILING WITH LegionSpy ENABLED  !!!\n");
        fprintf(stderr,"!!! SERIOUS PERFORMANCE DEGRADATION WILL OCCUR!!!\n");
        fprintf(stderr,"!!! COMPILE WITHOUT -DLEGION_SPY FOR PROFILING!!!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"SLEEPING FOR 5 SECONDS SO YOU READ THIS WARNING...\n");
        fflush(stderr);
        sleep(5);
      }
#else
      if (config.legion_spy_enabled && (config.num_profiling_nodes > 0))
      {
        // Give a massive warning about profiling with Legion Spy enabled
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"!!! YOU ARE PROFILING WITH LegionSpy ENABLED  !!!\n");
        fprintf(stderr,"!!! SERIOUS PERFORMANCE DEGRADATION WILL OCCUR!!!\n");
        fprintf(stderr,"!!! RUN WITHOUT -lg:spy flag FOR PROFILING    !!!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"SLEEPING FOR 5 SECONDS SO YOU READ THIS WARNING...\n");
        fflush(stderr);
        sleep(5);
      }
#endif
#ifdef LEGION_BOUNDS_CHECKS
      if (config.num_profiling_nodes > 0)
      {
        // Give a massive warning about profiling with Legion Spy enabled
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"!!! YOU ARE PROFILING WITH LEGION_BOUNDS_CHECKS!!!\n");
        fprintf(stderr,"!!! SERIOUS PERFORMANCE DEGRADATION WILL OCCUR !!!\n");
        fprintf(stderr,"!!! PLEASE COMPILE WITHOUT LEGION_BOUNDS_CHECKS!!!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"SLEEPING FOR 5 SECONDS SO YOU READ THIS WARNING...\n");
        fflush(stderr);
        sleep(5);
      }
#endif
#ifdef LEGION_PRIVILEGE_CHECKS
      if (config.num_profiling_nodes > 0)
      {
        // Give a massive warning about profiling with Legion Spy enabled
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"!!!YOU ARE PROFILING WITH LEGION_PRIVILEGE_CHECKS!!\n");
        fprintf(stderr,"!!!SERIOUS PERFORMANCE DEGRADATION WILL OCCUR!!!\n");
        fprintf(stderr,"!!!PLEASE COMPILE WITHOUT LEGION_PRIVILEGE_CHECKS!!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"SLEEPING FOR 5 SECONDS SO YOU READ THIS WARNING...\n");
        fflush(stderr);
        sleep(5);
      }
#endif
      if (config.verify_partitions && (config.num_profiling_nodes > 0))
      {
        // Give a massive warning about profiling with partition checks enabled
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"!!! YOU ARE PROFILING WITH PARTITION CHECKS ON!!!\n");
        fprintf(stderr,"!!! SERIOUS PERFORMANCE DEGRADATION WILL OCCUR!!!\n");
        fprintf(stderr,"!!! DO NOT USE -lg:partcheck WITH PROFILING   !!!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        for (int i = 0; i < 4; i++)
          fprintf(stderr,"!WARNING WARNING WARNING WARNING WARNING WARNING!\n");
        for (int i = 0; i < 2; i++)
          fprintf(stderr,"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
        fprintf(stderr,"\n");
        fprintf(stderr,"SLEEPING FOR 5 SECONDS SO YOU READ THIS WARNING...\n");
        fflush(stderr);
        sleep(5);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::configure_interoperability(
                                                bool separate_runtime_instances)
    //--------------------------------------------------------------------------
    {
      if (separate_runtime_instances && (mpi_rank > 0))
        REPORT_LEGION_ERROR(ERROR_MPI_INTEROP_MISCONFIGURATION,
            "Legion-MPI Interoperability is not supported when running "
            "with separate runtime instances for each processor")
      const std::vector<LegionHandshake> &pending_handshakes = 
        get_pending_handshake_table();
      if (!pending_handshakes.empty())
      {
        for (std::vector<LegionHandshake>::const_iterator it = 
              pending_handshakes.begin(); it != pending_handshakes.end(); it++)
          it->impl->initialize();
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ RtEvent Runtime::configure_runtime(int argc, char **argv,
                         const LegionConfiguration &config, RealmRuntime &realm,
                         Processor::Kind &startup_kind, bool background,
                         bool supply_default_mapper)
    //--------------------------------------------------------------------------
    {
      // Do some error checking in case we are running with separate instances
      Machine machine = Machine::get_machine();
      // Compute the data structures necessary for constructing a runtime 
      std::set<Processor> local_procs;
      std::set<Processor> local_util_procs;
      // First we find all our local processors
      {
        Machine::ProcessorQuery local_proc_query(machine);
        local_proc_query.local_address_space();
        // Check for exceeding the local number of processors
        if (local_proc_query.count() > LEGION_MAX_NUM_PROCS)
          REPORT_LEGION_ERROR(ERROR_MAXIMUM_PROCS_EXCEEDED, 
                        "Maximum number of local processors %zd exceeds "
                        "compile-time maximum of %d.  Change the value "
                        "LEGION_MAX_NUM_PROCS in legion_config.h and recompile."
                        , local_proc_query.count(), LEGION_MAX_NUM_PROCS)
        for (Machine::ProcessorQuery::iterator it = 
              local_proc_query.begin(); it != local_proc_query.end(); it++)
        {
          if (it->kind() == Processor::UTIL_PROC)
          {
            local_util_procs.insert(*it);
            // Startup can also be a utility processor if nothing else
            if (startup_kind == Processor::NO_KIND)
              startup_kind = Processor::UTIL_PROC;
          }
          else
          {
            local_procs.insert(*it);
            // Prefer CPUs for the startup kind
            if (it->kind() == Processor::LOC_PROC)
              startup_kind = Processor::LOC_PROC;
          }
        }
        if (local_procs.empty())
          REPORT_LEGION_ERROR(ERROR_NO_PROCESSORS, 
                        "Machine model contains no local processors!")
      }
      // Check to make sure we have something to do startup
      if (startup_kind == Processor::NO_KIND)
        REPORT_LEGION_ERROR(ERROR_NO_PROCESSORS, "Machine model contains "
            "no CPU processors and no utility processors! At least one "
            "CPU or one utility processor is required for Legion.")
      Realm::ProfilingRequestSet no_requests;
      // Keep track of all the registration events
      std::set<RtEvent> registered_events;
      // Now build the data structures for all processors 
      std::map<Processor,Runtime*> processor_mapping;
      if (config.separate_runtime_instances)
      {
#ifdef LEGION_TRACE_ALLOCATION
        REPORT_LEGION_FATAL(LEGION_FATAL_SEPARATE_RUNTIME_INSTANCES, 
                      "Memory tracing not supported with "
                      "separate runtime instances.")
#endif
        if (!local_util_procs.empty())
          REPORT_LEGION_FATAL(LEGION_FATAL_SEPARATE_RUNTIME_INSTANCES, 
                        "Separate runtime instances are not "
                        "supported when running with explicit "
                        "utility processors")
        std::set<AddressSpaceID> address_spaces;
        std::map<Processor,AddressSpaceID> proc_spaces;
        // If we are doing separate runtime instances then each
        // processor effectively gets its own address space
        Machine::ProcessorQuery all_procs(machine);
        AddressSpaceID sid = 0;
        for (Machine::ProcessorQuery::iterator it = 
              all_procs.begin(); it != all_procs.end(); it++,sid++)
        {
          address_spaces.insert(sid);
          proc_spaces[*it] = sid;
        }
        if (address_spaces.size() > 1)
          config.configure_collective_settings(address_spaces.size());
        
        // Now we make runtime instances for each of the local processors
        for (std::set<Processor>::const_iterator it =
              local_procs.begin(); it != local_procs.end(); it++)
        {
          // Make a separate copy of the input arguments for each runtime
          InputArgs input_args;
          input_args.argc = argc;
          if (argc > 0)
          {
            input_args.argv = (char**)malloc(argc*sizeof(char*));
            for (int i = 0; i < argc; i++)
            {
              if (argv[i] != NULL)
                input_args.argv[i] = strdup(argv[i]);
              else
                input_args.argv[i] = NULL;
            }
          }
          else
            input_args.argv = NULL;
          const AddressSpace local_space = proc_spaces[*it];
          // Only one local processor here
          std::set<Processor> fake_local_procs;
          fake_local_procs.insert(*it);
          Runtime *runtime = new Runtime(machine, config, background,
                                         input_args, local_space,
                                         fake_local_procs, local_util_procs,
                                         address_spaces, proc_spaces,
                                         supply_default_mapper);
          processor_mapping[*it] = runtime;
          // Save the the_runtime as the first one we make
          // just so that things will work in the multi-processor case
          if (the_runtime == NULL)
            the_runtime = runtime;
        }
      }
      else
      {
        // The normal path
        std::set<AddressSpaceID> address_spaces;
        std::map<Processor,AddressSpaceID> proc_spaces;
        Machine::ProcessorQuery all_procs(machine);
        for (Machine::ProcessorQuery::iterator it = 
              all_procs.begin(); it != all_procs.end(); it++)
        {
          AddressSpaceID sid = it->address_space();
          address_spaces.insert(sid);
          proc_spaces[*it] = sid;
        }
        if (address_spaces.size() > 1)
          config.configure_collective_settings(address_spaces.size());
        // Make one runtime instance and record it with all the processors
        const AddressSpace local_space = local_procs.begin()->address_space();
        // Make a separate copy of the input arguments for the runtime
        InputArgs input_args;
        input_args.argc = argc;
        if (argc > 0)
        {
          input_args.argv = (char**)malloc(argc*sizeof(char*));
          for (int i = 0; i < argc; i++)
          {
            if (argv[i] != NULL)
              input_args.argv[i] = strdup(argv[i]);
            else
              input_args.argv[i] = NULL;
          }
        }
        else
          input_args.argv = NULL;
        Runtime *runtime = new Runtime(machine, config, background,
                                       input_args, local_space,
                                       local_procs, local_util_procs,
                                       address_spaces, proc_spaces,
                                       supply_default_mapper);
        // Save THE runtime 
        the_runtime = runtime;
        for (std::set<Processor>::const_iterator it = 
              local_procs.begin(); it != local_procs.end(); it++)
          processor_mapping[*it] = runtime;
        for (std::set<Processor>::const_iterator it = 
              local_util_procs.begin(); it != local_util_procs.end(); it++)
          processor_mapping[*it] = runtime;
      }
      // Make the code descriptors for our tasks
      CodeDescriptor initialize_task(Runtime::initialize_runtime_task);
      CodeDescriptor shutdown_task(Runtime::shutdown_runtime_task);
      CodeDescriptor lg_task(Runtime::legion_runtime_task);
      CodeDescriptor rt_profiling_task(Runtime::profiling_runtime_task);
      CodeDescriptor startup_task(Runtime::startup_runtime_task);
      CodeDescriptor endpoint_task(Runtime::endpoint_runtime_task); 
      CodeDescriptor app_proc_task(Runtime::application_processor_runtime_task);
      for (std::map<Processor,Runtime*>::const_iterator it = 
            processor_mapping.begin(); it != processor_mapping.end(); it++)
      {
        // These tasks get registered on startup_kind processors
        if (it->first.kind() == startup_kind)
        {
          registered_events.insert(RtEvent(
                it->first.register_task(LG_INITIALIZE_TASK_ID, initialize_task,
                  no_requests, &it->second, sizeof(it->second))));
          registered_events.insert(RtEvent(
              it->first.register_task(LG_STARTUP_TASK_ID, startup_task,
                no_requests, &it->second, sizeof(it->second))));
        }
        // Register these tasks on utility processors if we have
        // them otherwise register them on all the processor kinds
        if (local_util_procs.empty() || 
            (it->first.kind() == Processor::UTIL_PROC))
        {
          registered_events.insert(RtEvent(
                it->first.register_task(LG_SHUTDOWN_TASK_ID, shutdown_task,
                  no_requests, &it->second, sizeof(it->second))));
#ifdef LEGION_SEPARATE_META_TASKS
          for (unsigned idx = 0; idx < LG_LAST_TASK_ID; idx++)
          {
            if (idx == LG_MESSAGE_ID)
            {
              for (unsigned msg = 0; msg < LAST_SEND_KIND; msg++)
                registered_events.insert(RtEvent(
                    it->first.register_task(LG_TASK_ID+idx+msg, lg_task,
                        no_requests, &it->second, sizeof(it->second))));
            }
            else
              registered_events.insert(RtEvent(
                    it->first.register_task(LG_TASK_ID+idx, lg_task,
                      no_requests, &it->second, sizeof(it->second))));
          }
#else
          registered_events.insert(RtEvent(
                it->first.register_task(LG_TASK_ID, lg_task,
                  no_requests, &it->second, sizeof(it->second))));
#endif
          registered_events.insert(RtEvent(
                it->first.register_task(LG_ENDPOINT_TASK_ID, endpoint_task,
                  no_requests, &it->second, sizeof(it->second))));
        }
        // Register profiling return meta-task on all processor kinds
        registered_events.insert(RtEvent(
            it->first.register_task(LG_LEGION_PROFILING_ID, rt_profiling_task,
              no_requests, &it->second, sizeof(it->second))));
        // Application processor tasks get registered on all
        // processors which are not utility processors
#ifdef LEGION_SEPARATE_META_TASKS
        if (it->first.kind() != Processor::UTIL_PROC)
        {
          for (unsigned idx = 0; idx < LG_LAST_TASK_ID; idx++)
            registered_events.insert(RtEvent(
                it->first.register_task(LG_APP_PROC_TASK_ID+idx, app_proc_task,
                      no_requests, &it->second, sizeof(it->second))));
        }
#else
        if (it->first.kind() != Processor::UTIL_PROC)
          registered_events.insert(RtEvent(
                it->first.register_task(LG_APP_PROC_TASK_ID, app_proc_task,
                  no_requests, &it->second, sizeof(it->second))));
#endif
      }
      // Lastly do any other registrations we might have
      const ReductionOpTable& red_table = get_reduction_table(true/*safe*/);
      for(ReductionOpTable::const_iterator it = red_table.begin();
          it != red_table.end();
          it++)
        realm.register_reduction(it->first, it->second);

      const SerdezOpTable &serdez_table = get_serdez_table(true/*safe*/);
      for (SerdezOpTable::const_iterator it = serdez_table.begin();
            it != serdez_table.end(); it++)
        realm.register_custom_serdez(it->first, it->second);
      
      if (config.record_registration)
      {
        log_run.print("Legion runtime initialize task has Realm ID %d",
                      LG_INITIALIZE_TASK_ID);
        log_run.print("Legion runtime shutdown task has Realm ID %d", 
                      LG_SHUTDOWN_TASK_ID);
        log_run.print("Legion runtime meta-task has Realm ID %d", 
                      LG_TASK_ID);
        log_run.print("Legion runtime profiling task Realm ID %d",
                      LG_LEGION_PROFILING_ID);
        log_run.print("Legion startup task has Realm ID %d",
                      LG_STARTUP_TASK_ID);
        log_run.print("Legion endpoint task has Realm ID %d",
                      LG_ENDPOINT_TASK_ID);
#ifdef LEGION_SEPARATE_META_TASKS
        LG_TASK_DESCRIPTIONS(descs);
        for (unsigned idx = 0; idx < LG_LAST_TASK_ID; idx++)
        {
          if (idx == LG_MESSAGE_ID)
          {
            LG_MESSAGE_DESCRIPTIONS(msg_descs);
            for (unsigned msg = 0; msg < LAST_SEND_KIND; msg++)
              log_run.print("Legion message %s meta-task has Realm ID %d",
                  msg_descs[msg], LG_TASK_ID+idx+msg);
          }
          else
          {
            log_run.print("Legion runtime %s meta-task has Realm ID %d",
                descs[idx], LG_TASK_ID+idx);
            log_run.print("Legion application %s meta-task has Realm ID %d",
                descs[idx], LG_APP_PROC_TASK_ID+idx);
          }
        }
#endif
      }
      return Runtime::merge_events(registered_events);
    }

    //--------------------------------------------------------------------------
    /*static*/ int Runtime::wait_for_shutdown(void)
    //--------------------------------------------------------------------------
    {
      if (!runtime_backgrounded)
        REPORT_LEGION_ERROR(ERROR_ILLEGAL_WAIT_FOR_SHUTDOWN, 
                      "Illegal call to wait_for_shutdown when runtime was "
                      "not launched in background mode!");
      // If this is the first time we've called this on this node then 
      // we need to remove our reference to allow shutdown to proceed
      if (background_waits.fetch_add(1) == 0)
        the_runtime->decrement_outstanding_top_level_tasks();
      return RealmRuntime::get_runtime().wait_for_shutdown();
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::set_return_code(int code)
    //--------------------------------------------------------------------------
    {
      return_code = code;
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::set_top_level_task_id(TaskID top_id)
    //--------------------------------------------------------------------------
    {
      legion_main_id = top_id;
      legion_main_set = true;
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::set_top_level_task_mapper_id(MapperID mapper_id)
    //--------------------------------------------------------------------------
    {
      legion_main_mapper_id = mapper_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::configure_MPI_interoperability(int rank)
    //--------------------------------------------------------------------------
    {
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'configure_MPI_interoperability' after "
                      "the runtime has been started!");
#ifdef DEBUG_LEGION
      assert(rank >= 0);
#endif
      // Check to see if it was already set
      if (mpi_rank >= 0)
      {
        if (rank != mpi_rank)
          REPORT_LEGION_ERROR(ERROR_DUPLICATE_MPI_CONFIG, 
              "multiple calls to "
              "configure_MPI_interoperability with different ranks "
              "%d and %d on the same Legion runtime!", mpi_rank, rank)
        else
          REPORT_LEGION_WARNING(LEGION_WARNING_DUPLICATE_MPI_CONFIG,
                                "duplicate calls to configure_"
                                "MPI_interoperability on rank %d!", rank);
      }
      mpi_rank = rank;
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::register_handshake(LegionHandshake &handshake)
    //--------------------------------------------------------------------------
    {
      // See if the runtime is started or not
      if (runtime_started)
      {
        // If it's started, we can just do the initialization now
        handshake.impl->initialize();
      }
      else
      {
        std::vector<LegionHandshake> &pending_handshakes = 
          get_pending_handshake_table();
        pending_handshakes.push_back(handshake);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ const ReductionOp* Runtime::get_reduction_op(
                                                        ReductionOpID redop_id,
                                                        bool has_lock/*=false*/)
    //--------------------------------------------------------------------------
    {
      if (redop_id == 0)
        REPORT_LEGION_ERROR(ERROR_RESERVED_REDOP_ID, 
                      "ReductionOpID zero is reserved.")
      if (!runtime_started || has_lock)
      {
        ReductionOpTable &red_table = 
          Runtime::get_reduction_table(true/*safe*/);
#ifdef DEBUG_LEGION
        if (red_table.find(redop_id) == red_table.end())
          REPORT_LEGION_ERROR(ERROR_INVALID_REDOP_ID, 
                        "Invalid ReductionOpID %d",redop_id)
#endif
        return red_table[redop_id];
      }
      else
        return the_runtime->get_reduction(redop_id);
    }

    //--------------------------------------------------------------------------
    const ReductionOp* Runtime::get_reduction(ReductionOpID redop_id)
    //--------------------------------------------------------------------------
    {
      AutoLock r_lock(redop_lock);
      return get_reduction_op(redop_id, true/*has lock*/); 
    }

    //--------------------------------------------------------------------------
    FillView* Runtime::find_or_create_reduction_fill_view(ReductionOpID redop)
    //--------------------------------------------------------------------------
    {
      {
        AutoLock r_lock(redop_lock,1,false/*exclusive*/);
        std::map<ReductionOpID,FillView*>::const_iterator finder = 
          redop_fill_views.find(redop);
        if (finder != redop_fill_views.end())
          return finder->second;
      }
      AutoLock r_lock(redop_lock);
      // Check to see if we lost the race
      std::map<ReductionOpID,FillView*>::const_iterator finder = 
        redop_fill_views.find(redop);
      if (finder != redop_fill_views.end())
        return finder->second;
      const ReductionOp *reduction_op = 
        get_reduction_op(redop, true/*has lock*/);
      void *fill_buffer = malloc(reduction_op->sizeof_rhs);
      memcpy(fill_buffer, reduction_op->identity, reduction_op->sizeof_rhs);
      FillView::FillViewValue *fill_value = 
        new FillView::FillViewValue(fill_buffer, reduction_op->sizeof_rhs);
      FillView *fill_view = new FillView(forest, get_available_distributed_id(),
                                 address_space, fill_value, true/*register now*/
#ifdef LEGION_SPY
                                 , 0/*no creator*/
#endif
                                 );
      fill_view->add_base_valid_ref(RUNTIME_REF);
      redop_fill_views[redop] = fill_view;
      return fill_view;
    }

    //--------------------------------------------------------------------------
    /*static*/ const SerdezOp* Runtime::get_serdez_op(CustomSerdezID serdez_id,
                                                      bool has_lock/*=false*/)
    //--------------------------------------------------------------------------
    {
      if (serdez_id == 0)
        REPORT_LEGION_ERROR(ERROR_RESERVED_SERDEZ_ID, 
                      "CustomSerdezID zero is reserved.")
      if (!runtime_started || has_lock)
      {
        SerdezOpTable &serdez_table = Runtime::get_serdez_table(true/*safe*/);
#ifdef DEBUG_LEGION
        if (serdez_table.find(serdez_id) == serdez_table.end())
          REPORT_LEGION_ERROR(ERROR_INVALID_SERDEZ_ID, 
                        "Invalid CustomSerdezOpID %d", serdez_id)
#endif
        return serdez_table[serdez_id];
      }
      else
        return the_runtime->get_serdez(serdez_id);
    }

    //--------------------------------------------------------------------------
    const SerdezOp* Runtime::get_serdez(CustomSerdezID serdez_id)
    //--------------------------------------------------------------------------
    {
      AutoLock s_lock(serdez_lock);
      return get_serdez_op(serdez_id, true/*has lock*/);
    }

    //--------------------------------------------------------------------------
    /*static*/ const SerdezRedopFns* Runtime::get_serdez_redop_fns(
                                                       ReductionOpID redop_id,
                                                       bool has_lock/*= false*/)
    //--------------------------------------------------------------------------
    {
      if (!runtime_started || has_lock)
      {
        SerdezRedopTable &serdez_table = get_serdez_redop_table(true/*safe*/); 
        SerdezRedopTable::const_iterator finder = serdez_table.find(redop_id);
        if (finder != serdez_table.end())
          return &(finder->second);
        return NULL;
      }
      else
        return the_runtime->get_serdez_redop(redop_id);
    }

    //--------------------------------------------------------------------------
    const SerdezRedopFns* Runtime::get_serdez_redop(ReductionOpID redop_id)
    //--------------------------------------------------------------------------
    {
      AutoLock r_lock(redop_lock);
      return get_serdez_redop_fns(redop_id, true/*has lock*/);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::add_registration_callback(
                                             RegistrationCallbackFnptr callback,
                                             bool deduplicate, size_t dedup_tag)
    //--------------------------------------------------------------------------
    {
      if (!runtime_started)
      {
        std::vector<RegistrationCallback> &registration_callbacks = 
          get_pending_registration_callbacks();
        registration_callbacks.resize(registration_callbacks.size() + 1);
        RegistrationCallback &reg = registration_callbacks.back();
        reg.callback.withoutargs = callback;
        reg.deduplicate = deduplicate;
        reg.dedup_tag = dedup_tag;
        reg.has_args = false;
      }
      else
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'add_registration_callback' after "
                      "the runtime has been started! Please use "
                      "'perform_registration_callback' for registration "
                      "calls to be done after the runtime has started.")
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::add_registration_callback(
                                  RegistrationWithArgsCallbackFnptr callback,
                                  const UntypedBuffer &buffer, 
                                  bool deduplicate, size_t dedup_tag)
    //--------------------------------------------------------------------------
    {
      if (!runtime_started)
      {
        std::vector<RegistrationCallback> &registration_callbacks = 
          get_pending_registration_callbacks();
        registration_callbacks.resize(registration_callbacks.size() + 1);
        RegistrationCallback &reg = registration_callbacks.back();
        reg.callback.withargs = callback;
        reg.deduplicate = deduplicate;
        reg.dedup_tag = dedup_tag;
        reg.has_args = true;
        const size_t size = buffer.get_size();
        if (size > 0)
        {
          void *copy = malloc(size);
          memcpy(copy, buffer.get_ptr(), size);
          reg.buffer = UntypedBuffer(copy, size);
        }
      }
      else
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'add_registration_callback' after "
                      "the runtime has been started! Please use "
                      "'perform_registration_callback' for registration "
                      "calls to be done after the runtime has started.")
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::perform_dynamic_registration_callback(
                                RegistrationCallbackFnptr callback, bool global,
                                bool deduplicate, size_t dedup_tag)
    //--------------------------------------------------------------------------
    {
      if (runtime_started)
      {
        // Wait for the runtime to be started everywhere
        if (!runtime_started_event.has_triggered())
          // If we're here this has to be an external thread
          runtime_started_event.external_wait();
        if (the_runtime->separate_runtime_instances)
            REPORT_LEGION_FATAL(LEGION_FATAL_SEPARATE_RUNTIME_INSTANCES,
                "Dynamic registration callbacks cannot be registered after "
                "the runtime has been started with multiple runtime instances.") 
        const RtEvent done_event = the_runtime->perform_registration_callback(
            (void*)callback, NULL/*buffer*/, 0/*size*/, false/*withargs*/,
            global, false/*preregistered*/, deduplicate, dedup_tag);
        if (done_event.exists() && !done_event.has_triggered())
        {
          // Block waiting for these to finish currently since we need
          // to guarantee that all the resources are registered before
          // we proceed any further
          if (Processor::get_executing_processor().exists())
            done_event.wait();
          else
            done_event.external_wait();
        }
      }
      else // can safely ignore global as this call must be done everywhere
        add_registration_callback(callback, deduplicate, dedup_tag);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::perform_dynamic_registration_callback(
                                     RegistrationWithArgsCallbackFnptr callback,
                                     const UntypedBuffer &buffer, bool global,
                                     bool deduplicate, size_t dedup_tag)
    //--------------------------------------------------------------------------
    {
      if (runtime_started)
      {
        // Wait for the runtime to be started everywhere
        if (!runtime_started_event.has_triggered())
          // If we're here this has to be an external thread
          runtime_started_event.external_wait();
        if (the_runtime->separate_runtime_instances)
            REPORT_LEGION_FATAL(LEGION_FATAL_SEPARATE_RUNTIME_INSTANCES,
                "Dynamic registration callbacks cannot be registered after "
                "the runtime has been started with multiple runtime instances.") 
        const RtEvent done_event = the_runtime->perform_registration_callback(
            (void*)callback, buffer.get_ptr(), buffer.get_size(), 
            true/*withargs*/, global, false/*preregistered*/,
            deduplicate, dedup_tag);
        if (done_event.exists() && !done_event.has_triggered())
        {
          // Block waiting for these to finish currently since we need
          // to guarantee that all the resources are registered before
          // we proceed any further
          if (Processor::get_executing_processor().exists())
            done_event.wait();
          else
            done_event.external_wait();
        }
      }
      else // can safely ignore global as this call must be done everywhere
        add_registration_callback(callback, buffer, deduplicate, dedup_tag);
    }

    //--------------------------------------------------------------------------
    /*static*/ ReductionOpTable& Runtime::get_reduction_table(bool safe)
    //--------------------------------------------------------------------------
    {
      static ReductionOpTable table;
      if (!safe && runtime_started)
        assert(false);
      return table;
    }

    //--------------------------------------------------------------------------
    /*static*/ SerdezOpTable& Runtime::get_serdez_table(bool safe)
    //--------------------------------------------------------------------------
    {
      static SerdezOpTable table;
      if (!safe && runtime_started)
        assert(false);
      return table;
    }
    
    //--------------------------------------------------------------------------
    /*static*/ SerdezRedopTable& Runtime::get_serdez_redop_table(bool safe)
    //--------------------------------------------------------------------------
    {
      static SerdezRedopTable table;
      if (!safe && runtime_started)
        assert(false);
      return table;
    }

#if defined(LEGION_USE_CUDA) || defined(LEGION_USE_HIP)
    // Define a free function for Runtime::register_reduction_op because
    //  legion_redop.cu cannot include runtime.h
    //--------------------------------------------------------------------------
    void runtime_register_reduction_op(ReductionOpID redop_id,
                                       ReductionOp *redop,
                                       SerdezInitFnptr init_fnptr,
                                       SerdezFoldFnptr fold_fnptr,
                                       bool permit_duplicates,
                                       bool has_lock = false)
    //--------------------------------------------------------------------------
    {
      Runtime::register_reduction_op(redop_id, redop, init_fnptr, fold_fnptr,
                                     permit_duplicates, has_lock);
    }
#endif

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::register_reduction_op(ReductionOpID redop_id,
                                                   ReductionOp *redop,
                                                   SerdezInitFnptr init_fnptr,
                                                   SerdezFoldFnptr fold_fnptr,
                                                   bool permit_duplicates,
                                                   bool has_lock/*= false*/)
    //--------------------------------------------------------------------------
    {
      if (!runtime_started || has_lock)
      {
        if (redop_id == 0)
          REPORT_LEGION_ERROR(ERROR_RESERVED_REDOP_ID, 
                              "ERROR: ReductionOpID zero is reserved.")
        if (redop->identity == NULL)
          REPORT_LEGION_ERROR(ERROR_RESERVED_REDOP_ID,
              "ERROR: Legion does not support reduction operators "
              "without identity values. All reduction operators must "
              "have an identity value to support fold operations.")
        ReductionOpTable &red_table = 
          Runtime::get_reduction_table(true/*safe*/);
        // Check to make sure we're not overwriting a prior reduction op 
        if (!permit_duplicates &&
            (red_table.find(redop_id) != red_table.end()))
          REPORT_LEGION_ERROR(ERROR_DUPLICATE_REDOP_ID, "ERROR: ReductionOpID "
              "%d has already been used in the reduction table\n",redop_id)
        red_table[redop_id] = redop;
        if ((init_fnptr != NULL) || (fold_fnptr != NULL))
        {
#ifdef DEBUG_LEGION
          assert((init_fnptr != NULL) && (fold_fnptr != NULL));
#endif
          SerdezRedopTable &serdez_red_table = 
            Runtime::get_serdez_redop_table(true/*safe*/);
          SerdezRedopFns &fns = serdez_red_table[redop_id];
          fns.init_fn = init_fnptr;
          fns.fold_fn = fold_fnptr;
        }
      }
      else
        the_runtime->register_reduction(redop_id, redop, init_fnptr,
              fold_fnptr, permit_duplicates, false/*preregistered*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::register_reduction(ReductionOpID redop_id,
                                     ReductionOp *redop,
                                     SerdezInitFnptr init_fnptr,
                                     SerdezFoldFnptr fold_fnptr,
                                     bool permit_duplicates,
                                     bool preregistered)
    //--------------------------------------------------------------------------
    {
      if (!preregistered && !inside_registration_callback)
        REPORT_LEGION_WARNING(LEGION_WARNING_NON_CALLBACK_REGISTRATION,
            "Reduction operator %d was dynamically registered outside of a "
            "registration callback invocation. In the near future this will "
            "become an error in order to support task subprocesses. Please "
            "use 'perform_registration_callback' to generate a callback where "
            "it will be safe to perform dynamic registrations.", redop_id)
      // Dynamic registration so do it with realm too
      RealmRuntime realm = RealmRuntime::get_runtime();
      realm.register_reduction(redop_id, redop);
      AutoLock r_lock(redop_lock);
      Runtime::register_reduction_op(redop_id, redop, init_fnptr,
                fold_fnptr, permit_duplicates, true/*has locks*/);
    }

    //--------------------------------------------------------------------------
    void Runtime::register_serdez(CustomSerdezID serdez_id, SerdezOp *serdez_op, 
                                  bool permit_duplicates, bool preregistered)
    //--------------------------------------------------------------------------
    {
      if (!preregistered && !inside_registration_callback)
        REPORT_LEGION_WARNING(LEGION_WARNING_NON_CALLBACK_REGISTRATION,
            "Custom serdez operator %d was dynamically registered outside of a "
            "registration callback invocation. In the near future this will "
            "become an error in order to support task subprocesses. Please "
            "use 'perform_registration_callback' to generate a callback where "
            "it will be safe to perform dynamic registrations.", serdez_id)
      // Dynamic registration so do it with realm too
      RealmRuntime realm = RealmRuntime::get_runtime();
      realm.register_custom_serdez(serdez_id, serdez_op);
      AutoLock s_lock(serdez_lock);
      Runtime::register_serdez_op(serdez_id, serdez_op, 
                                  permit_duplicates, true/*has lock*/);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::register_serdez_op(CustomSerdezID serdez_id,
                                                SerdezOp *serdez_op,
                                                bool permit_duplicates,
                                                bool has_lock/*= false*/)
    //--------------------------------------------------------------------------
    {
      if (!runtime_started || has_lock)
      {
        if (serdez_id == 0)
        {
          fprintf(stderr,"ERROR: Custom Serdez ID zero is reserved.\n");
#ifdef DEBUG_LEGION
          assert(false);
#endif
          exit(ERROR_RESERVED_SERDEZ_ID);
        }
        SerdezOpTable &serdez_table = Runtime::get_serdez_table(true/*safe*/);
        // Check to make sure we're not overwriting a prior serdez op
        if (!permit_duplicates &&
            (serdez_table.find(serdez_id) != serdez_table.end()))
        {
          fprintf(stderr,"ERROR: CustomSerdezID %d has already been used "
                         "in the serdez operation table\n", serdez_id);
#ifdef DEBUG_LEGION
          assert(false);
#endif
          exit(ERROR_DUPLICATE_SERDEZ_ID);
        }
        serdez_table[serdez_id] = serdez_op;
      }
      else
        the_runtime->register_serdez(serdez_id, serdez_op, 
                                     permit_duplicates, false/*preregistered*/);
    }

    //--------------------------------------------------------------------------
    /*static*/ std::deque<PendingVariantRegistration*>& 
                                       Runtime::get_pending_variant_table(void)
    //--------------------------------------------------------------------------
    {
      static std::deque<PendingVariantRegistration*> pending_variant_table;
      return pending_variant_table;
    }

    //--------------------------------------------------------------------------
    /*static*/ std::map<LayoutConstraintID,LayoutConstraintRegistrar>&
                                    Runtime::get_pending_constraint_table(void)
    //--------------------------------------------------------------------------
    {
      static std::map<LayoutConstraintID,LayoutConstraintRegistrar>
                                                    pending_constraint_table;
      return pending_constraint_table;
    }

    //--------------------------------------------------------------------------
    /*static*/ std::map<ProjectionID,ProjectionFunctor*>&
                                     Runtime::get_pending_projection_table(void)
    //--------------------------------------------------------------------------
    {
      static std::map<ProjectionID,ProjectionFunctor*> pending_projection_table;
      return pending_projection_table;
    }

    //--------------------------------------------------------------------------
    /*static*/ std::vector<LegionHandshake>& 
                                      Runtime::get_pending_handshake_table(void)
    //--------------------------------------------------------------------------
    {
      static std::vector<LegionHandshake> pending_handshakes_table;
      return pending_handshakes_table;
    }

    //--------------------------------------------------------------------------
    /*static*/ std::vector<Runtime::RegistrationCallback>&
                               Runtime::get_pending_registration_callbacks(void)
    //--------------------------------------------------------------------------
    {
      static std::vector<RegistrationCallback> pending_callbacks;
      return pending_callbacks;
    }

    //--------------------------------------------------------------------------
    /*static*/ TaskID& Runtime::get_current_static_task_id(void)
    //--------------------------------------------------------------------------
    {
      static TaskID current_task_id = LEGION_MAX_APPLICATION_TASK_ID;
      return current_task_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ TaskID Runtime::generate_static_task_id(void)
    //--------------------------------------------------------------------------
    {
      TaskID &next_task = get_current_static_task_id(); 
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'generate_static_task_id' after "
                      "the runtime has been started!")
      return next_task++;
    }

    //--------------------------------------------------------------------------
    /*static*/ ReductionOpID& Runtime::get_current_static_reduction_id(void)
    //--------------------------------------------------------------------------
    {
      // Make sure to reserve space for the built-in reduction operators
      static ReductionOpID current_redop_id = 
        LEGION_MAX_APPLICATION_REDOP_ID + LEGION_REDOP_LAST;
      return current_redop_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ ReductionOpID Runtime::generate_static_reduction_id(void)
    //--------------------------------------------------------------------------
    {
      ReductionOpID &next_redop = get_current_static_reduction_id();
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'generate_static_reduction_id' after "
                      "the runtime has been started!")
      return next_redop++;
    }

    //--------------------------------------------------------------------------
    /*static*/ CustomSerdezID& Runtime::get_current_static_serdez_id(void)
    //--------------------------------------------------------------------------
    {
      static CustomSerdezID current_serdez_id =LEGION_MAX_APPLICATION_SERDEZ_ID;
      return current_serdez_id;
    }

    //--------------------------------------------------------------------------
    /*static*/ CustomSerdezID Runtime::generate_static_serdez_id(void)
    //--------------------------------------------------------------------------
    {
      CustomSerdezID &next_serdez = get_current_static_serdez_id();
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'generate_static_serdez_id' after "
                      "the runtime has been started!")
      return next_serdez++;
    }

    //--------------------------------------------------------------------------
    /*static*/ VariantID Runtime::preregister_variant(
                          const TaskVariantRegistrar &registrar,
                          const void *user_data, size_t user_data_size,
                          const CodeDescriptor &code_desc, size_t return_size, 
                          const char *task_name, VariantID vid, bool check_id)
    //--------------------------------------------------------------------------
    {
      // Report an error if the runtime has already started
      if (runtime_started)
        REPORT_LEGION_ERROR(ERROR_STATIC_CALL_POST_RUNTIME_START, 
                      "Illegal call to 'preregister_task_variant' after "
                      "the runtime has been started!")
      if (check_id && (registrar.task_id >= get_current_static_task_id()))
        REPORT_LEGION_ERROR(ERROR_MAX_APPLICATION_TASK_ID_EXCEEDED, 
                      "Error preregistering task with ID %d. Exceeds the "
                      "statically set bounds on application task IDs of %d. "
                      "See %s in legion_config.h.", 
                      registrar.task_id, LEGION_MAX_APPLICATION_TASK_ID, 
                      LEGION_MACRO_TO_STRING(LEGION_MAX_APPLICATION_TASK_ID))
      std::deque<PendingVariantRegistration*> &pending_table = 
        get_pending_variant_table();
      // See if we need to pick a variant
      if (vid == LEGION_AUTO_GENERATE_ID)
        vid = pending_table.size() + 1;
      else if (vid == 0)
        REPORT_LEGION_ERROR(ERROR_RESERVED_VARIANT_ID,
                      "Error preregistering variant for task ID %d with "
                      "variant ID 0. Variant ID 0 is reserved for task "
                      "generators.", registrar.task_id)
      // Offset by the runtime tasks
      pending_table.push_back(new PendingVariantRegistration(vid, return_size,
                              registrar, user_data, user_data_size, 
                              code_desc, task_name));
      return vid;
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::report_fatal_message(int id,
                                          const char *file_name, const int line,
                                                  const char *message)
    //--------------------------------------------------------------------------
    {
      log_run.fatal(id, "LEGION FATAL: %s (from file %s:%d)",
                    message, file_name, line);
      abort();
    }
    
    //--------------------------------------------------------------------------
    /*static*/ void Runtime::report_error_message(int id,
                                          const char *file_name, const int line,
                                                  const char *message)
    //--------------------------------------------------------------------------
    {
      log_run.error(id, "LEGION ERROR: %s (from file %s:%d)",
                    message, file_name, line);
      abort();
    }
    
    //--------------------------------------------------------------------------
    /*static*/ void Runtime::report_warning_message(
                                         int id,
                                         const char *file_name, const int line,
                                         const char *message)
    //--------------------------------------------------------------------------
    {
      log_run.warning(id, "LEGION WARNING: %s (from file %s:%d)",
                      message, file_name, line);
      if (Runtime::the_runtime && Runtime::the_runtime->warnings_backtrace)
      {
        Realm::Backtrace bt;
        bt.capture_backtrace();
        bt.lookup_symbols();
        log_run.warning() << bt;
      }
#ifdef LEGION_WARNINGS_FATAL
      abort();
#endif
    }

#if defined(LEGION_PRIVILEGE_CHECKS) || defined(LEGION_BOUNDS_CHECKS)
    //--------------------------------------------------------------------------
    /*static*/ const char* Runtime::find_privilege_task_name(void *impl)
    //--------------------------------------------------------------------------
    {
      PhysicalRegionImpl *region = static_cast<PhysicalRegionImpl*>(impl);
      return region->get_task_name();
    }
#endif

#ifdef LEGION_BOUNDS_CHECKS
    //--------------------------------------------------------------------------
    /*static*/ void Runtime::check_bounds(void *impl, ptr_t ptr)
    //--------------------------------------------------------------------------
    {
      PhysicalRegionImpl *region = static_cast<PhysicalRegionImpl*>(impl);
      if (!region->contains_ptr(ptr))
      {
        fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                       "pointer %lld\n", region->get_task_name(), ptr.value);
        assert(false);
      }
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::check_bounds(void *impl, 
                                          const DomainPoint &dp)
    //--------------------------------------------------------------------------
    {
      PhysicalRegionImpl *region = static_cast<PhysicalRegionImpl*>(impl);
      if (!region->contains_point(dp))
      {
        switch(dp.get_dim())
        {
          case 1:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                           "1D point (%lld)\n", region->get_task_name(),
                            dp.point_data[0]);
            break;
#if LEGION_MAX_DIM >= 2
          case 2:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                           "2D point (%lld,%lld)\n", region->get_task_name(),
                            dp.point_data[0], dp.point_data[1]);
            break;
#endif
#if LEGION_MAX_DIM >= 3
          case 3:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                         "3D point (%lld,%lld,%lld)\n", region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2]);
            break;
#endif
#if LEGION_MAX_DIM >= 4
          case 4:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                         "4D point (%lld,%lld,%lld,%lld)\n", 
                          region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2],
                          dp.point_data[3]);
            break;
#endif
#if LEGION_MAX_DIM >= 5
          case 5:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                         "5D point (%lld,%lld,%lld,%lld,%lld)\n", 
                          region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2],
                          dp.point_data[3], dp.point_data[4]);
            break;
#endif
#if LEGION_MAX_DIM >= 6
          case 6:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                         "6D point (%lld,%lld,%lld,%lld,%lld,%lld)\n", 
                          region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2],
                          dp.point_data[3], dp.point_data[4], dp.point_data[5]);
            break;
#endif
#if LEGION_MAX_DIM >= 7
          case 7:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                         "7D point (%lld,%lld,%lld,%lld,%lld,%lld,%lld)\n", 
                          region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2],
                          dp.point_data[3], dp.point_data[4], dp.point_data[5],
                          dp.point_data[6]);
            break;
#endif
#if LEGION_MAX_DIM >= 8
          case 8:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                         "8D point (%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)\n",
                          region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2],
                          dp.point_data[3], dp.point_data[4], dp.point_data[5],
                          dp.point_data[6], dp.point_data[7]);
            break;
#endif
#if LEGION_MAX_DIM >= 9
          case 9:
            fprintf(stderr,"BOUNDS CHECK ERROR IN TASK %s: Accessing invalid "
                   "9D point (%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld,%lld)\n",
                          region->get_task_name(),
                          dp.point_data[0], dp.point_data[1], dp.point_data[2],
                          dp.point_data[3], dp.point_data[4], dp.point_data[5],
                          dp.point_data[6], dp.point_data[7], dp.point_data[8]);
            break;
#endif
          default:
            assert(false);
        }
        assert(false);
      }
    }
#endif

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::initialize_runtime_task(const void *args, 
               size_t arglen, const void *userdata, size_t userlen, Processor p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
#endif
      Runtime *runtime = *((Runtime**)userdata); 
      implicit_runtime = runtime;
      runtime->initialize_runtime();
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::shutdown_runtime_task(const void *args, 
               size_t arglen, const void *userdata, size_t userlen, Processor p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
#endif
      Runtime *runtime = *((Runtime**)userdata); 
      implicit_runtime = runtime;
      // Finalize the runtime and then delete it
      runtime->finalize_runtime();
      delete runtime;
      // Handle a little shutdown race condition here where the 
      // runtime_startup_event on nodes other than zero may not 
      // have triggered yet before shutdown
      if (!runtime_started_event.has_triggered())
        runtime_started_event.wait();
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::legion_runtime_task(
                                  const void *args, size_t arglen, 
				  const void *userdata, size_t userlen,
				  Processor p)
    //--------------------------------------------------------------------------
    {
      Runtime *runtime = *((Runtime**)userdata);
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
#if (!defined(LEGION_MALLOC_INSTANCES) && !defined(LEGION_USE_CUDA)) || \
      (!defined(LEGION_MALLOC_INSTANCES) && !defined(LEGION_USE_HIP))
      // Meta-tasks can run on application processors only when there
      // are no utility processors for us to use
      if (!runtime->local_utils.empty())
        assert(implicit_context == NULL); // this better hold
#endif
      assert(implicit_reference_tracker == NULL);
#endif
      implicit_runtime = runtime;
      // We immediately bump the priority of all meta-tasks once they start
      // up to the highest level to ensure that they drain once they begin
      Processor::set_current_task_priority(LG_RUNNING_PRIORITY);
      const char *data = (const char*)args;
      implicit_provenance = *((const UniqueID*)data);
      data += sizeof(implicit_provenance);
      arglen -= sizeof(implicit_provenance);
      LgTaskID tid = *((const LgTaskID*)data);
      data += sizeof(tid);
      arglen -= sizeof(tid);
      switch (tid)
      {
        case LG_SCHEDULER_ID:
          {
            const ProcessorManager::SchedulerArgs *sched_args = 
              (const ProcessorManager::SchedulerArgs*)args;
            runtime->process_schedule_request(sched_args->proc);
            break;
          }
        case LG_MESSAGE_ID:
          {
            runtime->process_message_task(data, arglen);
            break;
          }
        case LG_POST_END_ID:
          {
            InnerContext::handle_post_end_task(args); 
            break;
          }
        case LG_TRIGGER_READY_ID:
          {
            InnerContext::handle_ready_queue(args);
            break;
          }
        case LG_TRIGGER_RESOLUTION_ID:
          {
            InnerContext::handle_resolution_queue(args);
            break;
          }
        case LG_TRIGGER_COMMIT_ID:
          {
            InnerContext::handle_trigger_commit_queue(args);
            break;
          }
        case LG_DEFERRED_EXECUTION_ID:
          {
            InnerContext::handle_deferred_execution_queue(args);
            break;
          }
        case LG_TRIGGER_EXECUTION_ID:
          {
            InnerContext::handle_trigger_execution_queue(args);
            break;
          }
        case LG_DEFERRED_COMPLETION_ID:
          {
            InnerContext::handle_deferred_completion_queue(args);
            break;
          } 
        case LG_DEFERRED_COMMIT_ID:
          {
            InnerContext::handle_deferred_commit_queue(args);
            break;
          }
        case LG_DEFERRED_COLLECT_ID:
          {
            const PhysicalManager::GarbageCollectionArgs *collect_args =
              (const PhysicalManager::GarbageCollectionArgs*)args;
            CollectableView::handle_deferred_collect(collect_args->view,
                                                    *collect_args->to_collect);
            delete collect_args->to_collect;
            break;
          }
        case LG_PRE_PIPELINE_ID:
          {
            InnerContext::handle_prepipeline_stage(args);
            break;
          }
        case LG_TRIGGER_DEPENDENCE_ID:
          {
            InnerContext::handle_dependence_stage(args);
            break;
          }
        case LG_TRIGGER_COMPLETION_ID:
          {
            InnerContext::handle_trigger_completion_queue(args);
            break;
          }
        case LG_TRIGGER_OP_ID:
          {
            // Key off of args here instead of data
            const Operation::TriggerOpArgs *trigger_args = 
                            (const Operation::TriggerOpArgs*)args;
            trigger_args->op->trigger_mapping();
            break;
          }
        case LG_TRIGGER_TASK_ID:
          {
            // Key off of args here instead of data
            const TaskOp::TriggerTaskArgs *trigger_args = 
                          (const TaskOp::TriggerTaskArgs*)args;
            trigger_args->op->trigger_mapping(); 
            break;
          }
        case LG_DEFER_MAPPER_SCHEDULER_TASK_ID:
          {
            ProcessorManager::handle_defer_mapper(args);
            break;
          }
        case LG_MUST_INDIV_ID:
          {
            MustEpochTriggerer::handle_individual(args);
            break;
          }
        case LG_MUST_INDEX_ID:
          {
            MustEpochTriggerer::handle_index(args);
            break;
          }
        case LG_MUST_MAP_ID:
          {
            MustEpochMapper::handle_map_task(args);
            break;
          }
        case LG_MUST_DIST_ID:
          {
            MustEpochDistributor::handle_distribute_task(args);
            break;
          }
        case LG_MUST_LAUNCH_ID:
          {
            MustEpochDistributor::handle_launch_task(args);
            break;
          }
        case LG_DEFERRED_FUTURE_SET_ID:
          {
            TaskOp::DeferredFutureSetArgs *future_args =  
              (TaskOp::DeferredFutureSetArgs*)args;
            const size_t result_size = 
              future_args->task_op->check_future_size(future_args->result);
            if (result_size > 0)
              future_args->target->set_result(
                  future_args->result->get_untyped_result(),
                  result_size, false/*own*/);
            if (future_args->target->remove_base_gc_ref(DEFERRED_TASK_REF))
              delete (future_args->target);
            if (future_args->result->remove_base_gc_ref(DEFERRED_TASK_REF)) 
              delete (future_args->result);
            break;
          }
        case LG_DEFERRED_FUTURE_MAP_SET_ID:
          {
            TaskOp::DeferredFutureMapSetArgs *future_args = 
              (TaskOp::DeferredFutureMapSetArgs*)args;
            const size_t result_size = 
              future_args->task_op->check_future_size(future_args->result);
            const void *result = future_args->result->get_untyped_result();
            for (Domain::DomainPointIterator itr(future_args->domain); 
                  itr; itr++)
            {
              Future f = future_args->future_map->get_future(itr.p);
              if (result_size > 0)
                f.impl->set_result(result, result_size, false/*own*/);
            }
            if (future_args->future_map->remove_base_gc_ref(
                                                        DEFERRED_TASK_REF))
              delete (future_args->future_map);
            if (future_args->result->remove_base_gc_ref(FUTURE_HANDLE_REF))
              delete (future_args->result);
            future_args->task_op->complete_execution();
            break;
          }
        case LG_RESOLVE_FUTURE_PRED_ID:
          {
            FuturePredOp::ResolveFuturePredArgs *resolve_args = 
              (FuturePredOp::ResolveFuturePredArgs*)args;
            resolve_args->future_pred_op->resolve_future_predicate();
            resolve_args->future_pred_op->remove_predicate_reference();
            break;
          }
        case LG_CONTRIBUTE_COLLECTIVE_ID:
          {
            FutureImpl::handle_contribute_to_collective(args);
            break;
          }
        case LG_TOP_FINISH_TASK_ID:
          {
            TopFinishArgs *fargs = (TopFinishArgs*)args; 
            // Do this before deleting remote contexts
            fargs->ctx->invalidate_region_tree_contexts();
            fargs->ctx->free_remote_contexts();
            if (fargs->ctx->remove_reference())
              delete fargs->ctx;
            // Finally tell the runtime that we have one less top level task
            runtime->decrement_outstanding_top_level_tasks();
            break;
          }
        case LG_MAPPER_TASK_ID:
          {
            MapperTaskArgs *margs = (MapperTaskArgs*)args;
            runtime->process_mapper_task_result(margs);
            // Now indicate that we are done with the future
            if (margs->future->remove_base_gc_ref(FUTURE_HANDLE_REF))
              delete margs->future;
            margs->ctx->invalidate_region_tree_contexts();
            // We can also deactivate the enclosing context 
            if (margs->ctx->remove_reference())
              delete margs->ctx;
            // Finally tell the runtime we have one less top level task
            runtime->decrement_outstanding_top_level_tasks();
            break;
          }
        case LG_DISJOINTNESS_TASK_ID:
          {
            RegionTreeForest::DisjointnessArgs *dargs = 
              (RegionTreeForest::DisjointnessArgs*)args;
            runtime->forest->compute_partition_disjointness(dargs->handle,
                                                            dargs->ready);
            break;
          }
        case LG_DEFER_PHYSICAL_REGISTRATION_TASK_ID:
          {
            runtime->forest->handle_defer_registration(args);
            break;
          }
        case LG_PART_INDEPENDENCE_TASK_ID:
          {
            IndexSpaceNode::handle_disjointness_test(args);
            break;
          }
        case LG_SPACE_INDEPENDENCE_TASK_ID:
          {
            IndexPartNode::handle_disjointness_test(args);
            break;
          }
        case LG_PENDING_CHILD_TASK_ID:
          {
            IndexPartNode::handle_pending_child_task(args);
            break;
          }
        case LG_ISSUE_FRAME_TASK_ID:
          {
            InnerContext::IssueFrameArgs *fargs = 
              (InnerContext::IssueFrameArgs*)args;
            fargs->parent_ctx->perform_frame_issue(fargs->frame, 
                                                   fargs->frame_termination);
            break;
          }
        case LG_MAPPER_CONTINUATION_TASK_ID:
          {
            MapperContinuation::handle_continuation(args);
            break;
          }
        case LG_TASK_IMPL_SEMANTIC_INFO_REQ_TASK_ID:
          {
            TaskImpl::SemanticRequestArgs *req_args = 
              (TaskImpl::SemanticRequestArgs*)args;
            req_args->proxy_this->process_semantic_request(
                          req_args->tag, req_args->source, 
                          false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_INDEX_SPACE_SEMANTIC_INFO_REQ_TASK_ID:
          {
            IndexSpaceNode::SemanticRequestArgs *req_args = 
              (IndexSpaceNode::SemanticRequestArgs*)args;
            req_args->proxy_this->process_semantic_request(
                          req_args->tag, req_args->source, 
                          false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_INDEX_PART_SEMANTIC_INFO_REQ_TASK_ID:
          {
            IndexPartNode::SemanticRequestArgs *req_args = 
              (IndexPartNode::SemanticRequestArgs*)args;
            req_args->proxy_this->process_semantic_request(
                          req_args->tag, req_args->source, 
                          false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_FIELD_SPACE_SEMANTIC_INFO_REQ_TASK_ID:
          {
            FieldSpaceNode::SemanticRequestArgs *req_args = 
              (FieldSpaceNode::SemanticRequestArgs*)args;
            req_args->proxy_this->process_semantic_request(
                          req_args->tag, req_args->source, 
                          false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_FIELD_SEMANTIC_INFO_REQ_TASK_ID:
          {
            FieldSpaceNode::SemanticFieldRequestArgs *req_args = 
              (FieldSpaceNode::SemanticFieldRequestArgs*)args;
            req_args->proxy_this->process_semantic_field_request(
                  req_args->fid, req_args->tag, req_args->source, 
                  false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_DEFER_FIELD_INFOS_TASK_ID:
          {
            FieldSpaceNode::handle_defer_infos_request(args);
            break;
          }
        case LG_REGION_SEMANTIC_INFO_REQ_TASK_ID:
          {
            RegionNode::SemanticRequestArgs *req_args = 
              (RegionNode::SemanticRequestArgs*)args;
            req_args->proxy_this->process_semantic_request(
                          req_args->tag, req_args->source, 
                          false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_PARTITION_SEMANTIC_INFO_REQ_TASK_ID:
          {
            PartitionNode::SemanticRequestArgs *req_args = 
              (PartitionNode::SemanticRequestArgs*)args;
            req_args->proxy_this->process_semantic_request(
                          req_args->tag, req_args->source, 
                          false, false, RtUserEvent::NO_RT_USER_EVENT);
            break;
          }
        case LG_INDEX_SPACE_DEFER_CHILD_TASK_ID:
          {
            IndexSpaceNode::defer_node_child_request(args);
            break;
          }
        case LG_INDEX_PART_DEFER_CHILD_TASK_ID:
          {
            IndexPartNode::defer_node_child_request(args);
            break;
          }
        case LG_DEFERRED_ENQUEUE_TASK_ID:
          {
            InnerContext::handle_enqueue_task_queue(args);
            break;
          }
        case LG_DEFER_MAPPER_MESSAGE_TASK_ID:
          {
            MapperManager::handle_deferred_message(args);
            break;
          }
        case LG_REMOTE_VIEW_CREATION_TASK_ID:
          {
            InnerContext::handle_remote_view_creation(args);
            break;
          }
        case LG_DEFERRED_DISTRIBUTE_TASK_ID:
          {
            InnerContext::handle_distribute_task_queue(args);
            break;
          }
        case LG_DEFER_PERFORM_MAPPING_TASK_ID:
          {
            const TaskOp::DeferMappingArgs *margs = 
              (const TaskOp::DeferMappingArgs*)args;
            const RtEvent deferred = 
              margs->proxy_this->perform_mapping(margs->must_op, margs);
            // Once we've no longer been deferred then we can trigger
            // the done event to signal we are done
            if (!deferred.exists())
              Runtime::trigger_event(margs->done_event);
            break;
          }
        case LG_DEFERRED_LAUNCH_TASK_ID:
          {
            InnerContext::handle_launch_task_queue(args);
            break;
          }
        case LG_MISSPECULATE_TASK_ID:
          {
            const SingleTask::MisspeculationTaskArgs *targs = 
              (const SingleTask::MisspeculationTaskArgs*)args;
            targs->task->handle_misspeculation();
            break;
          }
        case LG_DEFER_FIND_COPY_PRE_TASK_ID:
          {
            InstanceView::handle_view_find_copy_pre_request(args, runtime);
            break;
          }
        case LG_DEFER_MATERIALIZED_VIEW_TASK_ID:
          {
            MaterializedView::handle_defer_materialized_view(args, runtime);
            break;
          }
        case LG_DEFER_REDUCTION_VIEW_TASK_ID:
          {
            ReductionView::handle_defer_reduction_view(args, runtime);
            break;
          }
        case LG_DEFER_PHI_VIEW_REF_TASK_ID:
          {
            PhiView::handle_deferred_view_ref(args);
            break;
          }
        case LG_DEFER_PHI_VIEW_REGISTRATION_TASK_ID:
          {
            PhiView::handle_deferred_view_registration(args);
            break;
          }
        case LG_TIGHTEN_INDEX_SPACE_TASK_ID:
          {
            IndexSpaceExpression::handle_tighten_index_space(args);
            break;
          }
        case LG_REMOTE_PHYSICAL_REQUEST_TASK_ID:
          {
            RemoteContext::defer_physical_request(args, runtime);
            break;
          }
        case LG_REMOTE_PHYSICAL_RESPONSE_TASK_ID:
          {
            RemoteContext::defer_physical_response(args);
            break;
          }
        case LG_REPLAY_SLICE_TASK_ID:
          {
            PhysicalTemplate::handle_replay_slice(args);
            break;
          }
        case LG_TRANSITIVE_REDUCTION_TASK_ID:
          {
            PhysicalTemplate::handle_transitive_reduction(args, runtime);
            break;
          }
        case LG_DELETE_TEMPLATE_TASK_ID:
          {
            PhysicalTemplate::handle_delete_template(args);
            break;
          }
        case LG_REFINEMENT_TASK_ID:
          {
            EquivalenceSet::handle_refinement(args);
            break;
          }
        case LG_REMOTE_REF_TASK_ID:
          {
            EquivalenceSet::handle_remote_references(args);
            break;
          }
        case LG_DEFER_RAY_TRACE_TASK_ID:
          {
            EquivalenceSet::handle_ray_trace(args, runtime);
            break;
          }
        case LG_DEFER_RAY_TRACE_FINISH_TASK_ID:
          {
            EquivalenceSet::handle_ray_trace_finish(args);
            break;
          }
        case LG_DEFER_SUBSET_REQUEST_TASK_ID:
          {
            EquivalenceSet::handle_subset_request(args);
            break;
          }
        case LG_DEFER_MAKE_OWNER_TASK_ID:
          {
            EquivalenceSet::handle_make_owner(args);
            break;
          }
        case LG_DEFER_MERGE_OR_FORWARD_TASK_ID:
          {
            EquivalenceSet::handle_merge_or_forward(args);
            break;
          }
        case LG_DEFER_EQ_RESPONSE_TASK_ID:
          {
            EquivalenceSet::handle_deferred_response(args, runtime);
            break;
          }
        case LG_DEFER_REMOVE_EQ_REF_TASK_ID:
          {
            EquivalenceSet::handle_deferred_remove_refs(args);
            break;
          }
        case LG_DEFER_REMOTE_REF_UPDATE_TASK_ID:
          {
            DistributedCollectable::handle_defer_remote_reference_update(
                                                            runtime, args);
            break;
          }
        case LG_DEFER_REMOTE_UNREGISTER_TASK_ID:
          {
            DistributedCollectable::handle_defer_remote_unregister(runtime,
                                                                   args);
            break;
          }
        case LG_COPY_FILL_AGGREGATION_TASK_ID:
          {
            CopyFillAggregator::handle_aggregation(args);
            break;
          }
        case LG_COPY_FILL_DELETION_TASK_ID:
          {
            CopyFillGuard::handle_deletion(args);
            break;
          }
        case LG_FINALIZE_EQ_SETS_TASK_ID:
          {
            VersionManager::handle_finalize_eq_sets(args);
            break;
          }
        case LG_DEFERRED_COPY_ACROSS_TASK_ID:
          {
            CopyOp::handle_deferred_across(args);
            break;
          }
        case LG_DEFER_REMOTE_OP_DELETION_TASK_ID:
          {
            RemoteOp::handle_deferred_deletion(args);
            break;
          }
        case LG_DEFER_PERFORM_TRAVERSAL_TASK_ID:
          {
            PhysicalAnalysis::handle_deferred_traversal(args);
            break;
          }
        case LG_DEFER_PERFORM_REMOTE_TASK_ID:
          {
            PhysicalAnalysis::handle_deferred_remote(args);
            break;
          }
        case LG_DEFER_PERFORM_UPDATE_TASK_ID:
          {
            PhysicalAnalysis::handle_deferred_update(args);
            break;
          }
        case LG_DEFER_PERFORM_OUTPUT_TASK_ID:
          {
            PhysicalAnalysis::handle_deferred_output(args);
            break;
          }
        case LG_DEFER_INDIVIDUAL_MANAGER_TASK_ID:
          {
            IndividualManager::handle_defer_manager(args, runtime);
            break;
          }
        case LG_DEFER_COLLECTIVE_MANAGER_TASK_ID:
          {
            CollectiveManager::handle_defer_manager(args, runtime);
            break;
          }
        case LG_DEFER_VERIFY_PARTITION_TASK_ID:
          {
            InnerContext::handle_partition_verification(args);
            break;
          }
        case LG_DEFER_RELEASE_ACQUIRED_TASK_ID:
          {
            Operation::handle_deferred_release(args);
            break;
          }
        case LG_DEFER_COPY_ACROSS_TASK_ID:
          {
            CopyAcrossExecutor::handle_deferred_copy_across(args);
            break;
          }
#ifdef LEGION_MALLOC_INSTANCES
        // LG_MALLOC_INSTANCE_TASK_ID should always run app processor
        case LG_FREE_INSTANCE_TASK_ID:
          {
            MemoryManager::handle_free_instance(args);
            break;
          }
#endif
        case LG_YIELD_TASK_ID:
          break; // nothing to do here
        case LG_RETRY_SHUTDOWN_TASK_ID:
          {
            const ShutdownManager::RetryShutdownArgs *shutdown_args = 
              (const ShutdownManager::RetryShutdownArgs*)args;
            runtime->initiate_runtime_shutdown(runtime->address_space,
                                               shutdown_args->phase);
            break;
          }
        default:
          assert(false); // should never get here
      }
      if (implicit_reference_tracker != NULL)
      {
        delete implicit_reference_tracker;
        implicit_reference_tracker = NULL;
      }
#ifdef DEBUG_LEGION
      if (tid < LG_BEGIN_SHUTDOWN_TASK_IDS)
        runtime->decrement_total_outstanding_tasks(tid, true/*meta*/);
#else
      if (tid < LG_BEGIN_SHUTDOWN_TASK_IDS)
        runtime->decrement_total_outstanding_tasks();
#endif
#ifdef DEBUG_SHUTDOWN_HANG
      runtime->outstanding_counts[tid].fetch_sub(1);
#endif
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::profiling_runtime_task(
                                   const void *args, size_t arglen, 
				   const void *userdata, size_t userlen,
				   Processor p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
#endif
      Runtime *runtime = *((Runtime**)userdata);
      implicit_runtime = runtime;
      Realm::ProfilingResponse response(args, arglen);
      const ProfilingResponseBase *base = 
        (const ProfilingResponseBase*)response.user_data();
      if (base->handler == NULL)
      {
        // If we got a NULL let's assume they meant the profiler
        // this mainly happens with messages that cross nodes
        runtime->profiler->handle_profiling_response(base,response,args,arglen);
      }
      else
        base->handler->handle_profiling_response(base, response, args, arglen);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::startup_runtime_task(
                                   const void *args, size_t arglen, 
				   const void *userdata, size_t userlen,
				   Processor p)
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
#endif
      Runtime *runtime = *((Runtime**)userdata);
      implicit_runtime = runtime;
      runtime->startup_runtime();
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::endpoint_runtime_task(
                                   const void *args, size_t arglen, 
				   const void *userdata, size_t userlen,
				   Processor p)
    //--------------------------------------------------------------------------
    {
      Runtime *runtime = *((Runtime**)userdata);
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
#endif
      Deserializer derez(args, arglen);
      runtime->handle_endpoint_creation(derez);
    }

    //--------------------------------------------------------------------------
    /*static*/ void Runtime::application_processor_runtime_task(
                                   const void *args, size_t arglen, 
				   const void *userdata, size_t userlen,
				   Processor p)
    //--------------------------------------------------------------------------
    {
      Runtime *runtime = *((Runtime**)userdata);
#ifdef DEBUG_LEGION
      assert(userlen == sizeof(Runtime**));
      assert(implicit_reference_tracker == NULL);
#endif
      implicit_runtime = runtime;
      // We immediately bump the priority of all meta-tasks once they start
      // up to the highest level to ensure that they drain once they begin
      Processor::set_current_task_priority(LG_RUNNING_PRIORITY);
      const char *data = (const char*)args;
      implicit_provenance = *((const UniqueID*)data);
      data += sizeof(implicit_provenance);
      arglen -= sizeof(implicit_provenance);
      LgTaskID tid = *((const LgTaskID*)data);
      data += sizeof(tid);
      arglen -= sizeof(tid);
      switch (tid)
      {
        case LG_FUTURE_CALLBACK_TASK_ID:
          {
            FutureImpl::handle_callback(args);
            break;
          }
        case LG_REPLAY_SLICE_TASK_ID:
          {
            PhysicalTemplate::handle_replay_slice(args);
            break;
          }
#ifdef LEGION_MALLOC_INSTANCES
        case LG_MALLOC_INSTANCE_TASK_ID:
          {
            MemoryManager::handle_malloc_instance(args);
            break;
          }
        case LG_FREE_INSTANCE_TASK_ID:
          {
            MemoryManager::handle_free_instance(args);
            break;
          }
#endif
        default:
          assert(false); // should never get here
      }
      if (implicit_reference_tracker != NULL)
      {
        delete implicit_reference_tracker;
        implicit_reference_tracker = NULL;
      }
#ifdef DEBUG_LEGION
      runtime->decrement_total_outstanding_tasks(tid, true/*meta*/);
#else
      runtime->decrement_total_outstanding_tasks();
#endif
#ifdef DEBUG_SHUTDOWN_HANG
      runtime->outstanding_counts[tid].fetch_sub(1);
#endif
    }

    //--------------------------------------------------------------------------
    void Runtime::LegionConfiguration::configure_collective_settings(
                                                         int total_spaces) const
    //--------------------------------------------------------------------------
    {
#ifdef DEBUG_LEGION
      assert(legion_collective_radix > 0);
#endif
      const int MultiplyDeBruijnBitPosition[32] = 
      {
        0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
          8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
      };
      // First adjust the radix based on the number of nodes if necessary
      if (legion_collective_radix > total_spaces)
        legion_collective_radix = total_spaces;
      // Adjust the radix to the next smallest power of 2
      uint32_t radix_copy = legion_collective_radix;
      for (int i = 0; i < 5; i++)
        radix_copy |= radix_copy >> (1 << i);
      legion_collective_log_radix = 
        MultiplyDeBruijnBitPosition[(uint32_t)(radix_copy * 0x07C4ACDDU) >> 27];
      if (legion_collective_radix != (1 << legion_collective_log_radix))
        legion_collective_radix = (1 << legion_collective_log_radix);

      // Compute the number of stages
      uint32_t node_copy = total_spaces;
      for (int i = 0; i < 5; i++)
        node_copy |= node_copy >> (1 << i);
      // Now we have it log 2
      int log_nodes = 
        MultiplyDeBruijnBitPosition[(uint32_t)(node_copy * 0x07C4ACDDU) >> 27];
      // Stages round up in case of incomplete stages
      legion_collective_stages = (log_nodes + 
          legion_collective_log_radix - 1) / legion_collective_log_radix;
      int log_remainder = log_nodes % legion_collective_log_radix;
      if (log_remainder > 0)
      {
        // We have an incomplete last stage
        legion_collective_last_radix = 1 << log_remainder;
        // Now we can compute the number of participating stages
        legion_collective_participating_spaces = 
          1 << ((legion_collective_stages - 1) * legion_collective_log_radix +
                 log_remainder);
      }
      else
      {
        legion_collective_last_radix = legion_collective_radix;
        legion_collective_participating_spaces = 
          1 << (legion_collective_stages * legion_collective_log_radix);
      }
    }

#ifdef LEGION_TRACE_ALLOCATION
    //--------------------------------------------------------------------------
    /*static*/ void LegionAllocation::trace_allocation(
                                       AllocationType a, size_t size, int elems)
    //--------------------------------------------------------------------------
    {
      Runtime *rt = Runtime::the_runtime;
      if (rt != NULL)
        rt->trace_allocation(a, size, elems);
    }

    //--------------------------------------------------------------------------
    /*static*/ void LegionAllocation::trace_free(AllocationType a, 
                                                 size_t size, int elems)
    //--------------------------------------------------------------------------
    {
      Runtime *rt = Runtime::the_runtime;
      if (rt != NULL)
        rt->trace_free(a, size, elems);
    }

    //--------------------------------------------------------------------------
    /*static*/ Runtime* LegionAllocation::find_runtime(void)
    //--------------------------------------------------------------------------
    {
      return Runtime::the_runtime;
    }

    //--------------------------------------------------------------------------
    /*static*/ void LegionAllocation::trace_allocation(Runtime *&runtime,
                                       AllocationType a, size_t size, int elems)
    //--------------------------------------------------------------------------
    {
      if (runtime == NULL)
      {
        runtime = LegionAllocation::find_runtime();
        // Only happens during initialization
        if (runtime == NULL)
          return;
      }
      runtime->trace_allocation(a, size, elems);
    }

    //--------------------------------------------------------------------------
    /*static*/ void LegionAllocation::trace_free(Runtime *&runtime,
                                       AllocationType a, size_t size, int elems)
    //--------------------------------------------------------------------------
    {
      if (runtime == NULL)
      {
        runtime = LegionAllocation::find_runtime();
        // Only happens during intialization
        if (runtime == NULL)
          return;
      }
      runtime->trace_free(a, size, elems);
    }
#endif 

  }; // namespace Internal 
}; // namespace Legion 

// EOF

