<commit_before>#include "config.h"
#include "vm.hpp"
#include "on_stack.hpp"
#include "object_memory.hpp"
#include "call_frame.hpp"
#include "metrics.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/module.hpp"
#include "builtin/thread.hpp"
#include "builtin/native_method.hpp"

#include "capi/handle.hpp"

#include "gc/finalize.hpp"

#include "dtrace/dtrace.h"

namespace rubinius {
  FinalizerHandler::iterator::iterator(FinalizerHandler* fh)
    : handler_(fh)
    , current_list_(NULL)
  {
    if(handler_->live_list_->empty()) {
      if(handler_->lists_->empty()) {
        current_ = handler_->live_list_->begin();
        end_ = handler_->live_list_->end();
        return;
      } else {
        current_list_ = handler_->lists_->front();
      }
    } else {
      current_list_ = handler_->live_list_;
    }

    current_ = current_list_->begin();

    if(handler_->lists_->empty()) {
      end_ = current_list_->end();
    } else {
      lists_iterator_ = handler_->lists_->begin();
      end_ = handler_->lists_->back()->end();
    }
  }

  void FinalizerHandler::iterator::next(bool live) {
    if(current_list_ == handler_->live_list_) {
      if(!live) current_->queued();

      if(++current_ == current_list_->end()) {
        if(!handler_->lists_->empty()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    } else {
      if(++current_ == end_) {
        return;
      } else if(current_ == current_list_->end()) {
        if(++lists_iterator_ != handler_->lists_->end()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    }
  }

  bool FinalizerHandler::iterator::end() {
    return current_ == end_;
  }

  Object* finalizer_handler_tramp(STATE) {
    state->shared().finalizer_handler()->perform(state);
    GCTokenImpl gct;
    state->gc_dependent(gct, 0);
    return cNil;
  }

  FinalizerHandler::FinalizerHandler(STATE)
    : AuxiliaryThread()
    , shared_(state->shared())
    , self_(NULL)
    , thread_(state)
    , lists_(NULL)
    , live_list_(NULL)
    , process_list_(NULL)
    , iterator_(NULL)
    , process_item_kind_(eRuby)
    , paused_(false)
    , exit_(false)
    , finishing_(false)
  {
    shared_.auxiliary_threads()->register_thread(this);
    shared_.set_finalizer_handler(this);

    lists_ = new FinalizeObjectsList();
    live_list_ = new FinalizeObjects();

    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    pause_cond_.init();

    supervisor_lock_.init();
    supervisor_cond_.init();
  }

  FinalizerHandler::~FinalizerHandler() {
    shared_.auxiliary_threads()->unregister_thread(this);

    if(iterator_) delete iterator_;
    if(live_list_) delete live_list_;

    if(lists_) {
      for(FinalizeObjectsList::iterator i = lists_->begin(); i != lists_->end(); ++i) {
        delete *i;
      }
      delete lists_;
    }
  }

  void FinalizerHandler::start_thread(STATE) {
    SYNC(state);
    if(self_) return;
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    self_ = state->shared().new_vm();
    self_->metrics()->init(metrics::eFinalizerMetrics);
    paused_ = false;
    exit_ = false;
    thread_.set(Thread::create(state, self_, G(thread), finalizer_handler_tramp, true));
    run(state);
  }

  void FinalizerHandler::stop_thread(STATE) {
    SYNC(state);
    if(!self_) return;

    pthread_t os = self_->os_thread();
    {
      utilities::thread::Mutex::LockGuard lg(worker_lock_);
      // Thread might have already been stopped
      exit_ = true;
      worker_signal();
    }

    void* return_value;
    pthread_join(os, &return_value);
    self_ = NULL;
  }

  void FinalizerHandler::shutdown(STATE) {
    // We do nothing now because we have to finish processing all remaining
    // live objects once everything shuts down.
  }

  void FinalizerHandler::before_exec(STATE) {
    stop_thread(state);
  }

  void FinalizerHandler::after_exec(STATE) {
    start_thread(state);
  }

  void FinalizerHandler::before_fork(STATE) {
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    while(!paused_ && self_->run_state() == ManagedThread::eRunning) {
      pause_cond_.wait(worker_lock_);
    }
  }

  void FinalizerHandler::after_fork_parent(STATE) {
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    pause_cond_.signal();
  }

  void FinalizerHandler::after_fork_child(STATE) {
    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    pause_cond_.init();
    supervisor_lock_.init();
    supervisor_cond_.init();

    if(self_) {
      VM::discard(state, self_);
      self_ = NULL;
    }

    start_thread(state);
  }

  void FinalizerHandler::run(STATE) {
    int error = thread_.get()->fork_attached(state);
    if(error) rubinius::bug("Unable to start finalizer handler thread");
  }

  void FinalizerHandler::perform(STATE) {
    GCTokenImpl gct;
    RBX_DTRACE_CONST char* thread_name = const_cast<RBX_DTRACE_CONST char*>("rbx.finalizer");
    self_->set_name(thread_name);

    RUBINIUS_THREAD_START(const_cast<RBX_DTRACE_CONST char*>(thread_name),
                          state->vm()->thread_id(), 1);

    state->vm()->thread->hard_unlock(state, gct, 0);

    while(!exit_) {
      state->vm()->set_call_frame(0);

      if(!process_list_) first_process_item();

      if(!process_list_) {
        {
          utilities::thread::Mutex::LockGuard lg(worker_lock_);

          if(finishing_) supervisor_signal();

          // exit_ might have been set in the mean while after
          // we grabbed the worker_lock
          if(exit_) break;
          state->gc_independent(gct, 0);
          paused_ = true;
          pause_cond_.signal();
          worker_wait();
          if(exit_) break;
        }
        state->gc_dependent(gct, 0);
        {
          utilities::thread::Mutex::LockGuard lg(worker_lock_);
          paused_ = false;
          if(exit_) break;
        }

        continue;
      }

      finalize(state);
      next_process_item();
    }
    RUBINIUS_THREAD_STOP(const_cast<RBX_DTRACE_CONST char*>(thread_name),
                         state->vm()->thread_id(), 1);
  }

  void FinalizerHandler::finalize(STATE) {

    switch(process_item_kind_) {
    case eRuby: {
      if(process_item_->ruby_finalizer) {
        CallFrame* call_frame = 0;
        // Rubinius specific code. If the finalizer is cTrue, then send the
        // object the __finalize__ message.
        if(process_item_->ruby_finalizer->true_p()) {
          process_item_->object->send(state, call_frame, state->symbol("__finalize__"));
        } else {
          Array* ary = Array::create(state, 1);
          ary->set(state, 0, process_item_->object->id(state));
          process_item_->ruby_finalizer->send(state, call_frame, G(sym_call), ary);
        }
      }

      process_item_->status = FinalizeObject::eRubyFinalized;
      break;
    }
    case eNative:
      if(process_item_->finalizer) {

        NativeMethodEnvironment* env = state->vm()->native_method_environment;
        NativeMethodFrame nmf(env, 0, 0);
        CallFrame* call_frame = ALLOCA_CALLFRAME(0);
        call_frame->previous = 0;
        call_frame->constant_scope_ = 0;
        call_frame->dispatch_data = (void*)&nmf;
        call_frame->compiled_code = 0;
        call_frame->flags = CallFrame::cNativeMethod;
        call_frame->optional_jit_data = 0;
        call_frame->top_scope_ = 0;
        call_frame->scope = 0;
        call_frame->arguments = 0;

        env->set_current_call_frame(0);
        env->set_current_native_frame(&nmf);

        // Register the CallFrame, because we might GC below this.
        state->set_call_frame(call_frame);

        nmf.setup(Qnil, Qnil, Qnil, Qnil);

        (*process_item_->finalizer)(state, process_item_->object);

        state->set_call_frame(0);
        env->set_current_call_frame(0);
        env->set_current_native_frame(0);
      }
      process_item_->status = FinalizeObject::eNativeFinalized;
      break;
    case eRelease:
      // Unhook any handle used by fi->object so that we don't accidentally
      // try and mark it later (after we've finalized it)
      if(capi::Handle* handle = process_item_->object->handle(state)) {
        handle->forget_object();
        process_item_->object->clear_handle(state);
      }

      process_item_->status = FinalizeObject::eReleased;

      break;
    }
  }

  void FinalizerHandler::first_process_item() {
    if(!process_list_ && !lists_->empty()) {
      process_list_ = lists_->back();
      process_item_ = process_list_->begin();
    }
  }

  void FinalizerHandler::next_process_item() {
    if(++process_item_ == process_list_->end()) {
      switch(process_item_kind_) {
      case eRuby:
        process_item_ = process_list_->begin();
        process_item_kind_ = eNative;
        break;
      case eNative:
        process_item_ = process_list_->begin();
        process_item_kind_ = eRelease;
        break;
      case eRelease:
        delete process_list_;
        process_list_ = NULL;
        process_item_kind_ = eRuby;
        lists_->pop_back();
        self_->metrics()->m.finalizer_metrics.objects_finalized++;
        break;
      }
    }
  }

  void FinalizerHandler::finish(STATE, GCToken gct) {
    if(!self_) {
      if(process_list_ || !lists_->empty() || !live_list_->empty()) {
        rubinius::bug("FinalizerHandler worker thread dead during halt");
      } else {
        return;
      }
    }

    finishing_ = true;

    while(true) {
      {
        StopTheWorld stw(state, gct, 0);

        if(!process_list_) {
          if(live_list_->empty() && lists_->empty()) break;

          // Everything is garbage when halting so keep adding live objects to
          // finalize queue until done.
          if(!live_list_->empty()) {
            for(FinalizeObjects::iterator i = live_list_->begin();
                i != live_list_->end();
                ++i)
            {
              i->queued();
            }

            queue_objects();
          }

          first_process_item();
          if(!process_list_) break;
        }
      }

      worker_signal();

      {
        utilities::thread::Mutex::LockGuard lg(supervisor_lock_);

        GCIndependent indy(state, 0);
        if(process_list_) supervisor_wait();
      }
    }

    if(!lists_->empty() || !live_list_->empty() || process_list_ != NULL)
      rubinius::bug("FinalizerHandler exiting with pending finalizers");

    stop_thread(state);
  }

  void FinalizerHandler::record(Object* obj, FinalizerFunction func) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;
    fi.finalizer = func;

    // Makes a copy of fi.
    live_list_->push_front(fi);

    self_->metrics()->m.finalizer_metrics.objects_queued++;
  }

  void FinalizerHandler::set_ruby_finalizer(Object* obj, Object* finalizer) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    // Ignore Ruby finalizers created when finishing running finalizers.
    if(finishing_) return;

    // Check if the object is already in the finalizer list.
    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        ++i)
    {
      if(i->object == obj) {
        if(finalizer->nil_p()) {
          live_list_->erase(i);
        } else {
          i->ruby_finalizer = finalizer;
        }
        return;
      }
    }

    // Adding a nil finalizer is only used to delete an existing finalizer,
    // which we apparently don't have if we get here.
    if(finalizer->nil_p()) {
      return;
    }

    // Ok, create it.

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;

    // Rubinius specific API. If the finalizer is the object, we're going to send
    // the object __finalize__. We mark that the user wants this by putting cTrue
    // as the ruby_finalizer.
    if(obj == finalizer) {
      fi.ruby_finalizer = cTrue;
    } else {
      fi.ruby_finalizer = finalizer;
    }

    // Makes a copy of fi.
    live_list_->push_front(fi);
  }

  void FinalizerHandler::queue_objects() {
    FinalizeObjects* dead_list = new FinalizeObjects();

    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        /* advance is handled in the loop */)
    {
      if(i->queued_p()) {
        dead_list->push_front(*i);
        i = live_list_->erase(i);
      } else {
        ++i;
      }
    }

    if(!dead_list->empty()) {
      lists_->push_front(dead_list);
    } else {
      delete dead_list;
    }
  }

  void FinalizerHandler::start_collection(STATE) {
    if(process_item_kind_ == eRelease) {
      while(process_list_) {
        finalize(state);
        next_process_item();
      }
    }
  }

  void FinalizerHandler::finish_collection(STATE) {
    queue_objects();

    if(iterator_) {
      delete iterator_;
      iterator_ = NULL;
    }

    worker_signal();
  }

  void FinalizerHandler::supervisor_signal() {
    supervisor_cond_.signal();
  }

  void FinalizerHandler::supervisor_wait() {
    supervisor_cond_.wait(supervisor_lock_);
  }

  void FinalizerHandler::worker_signal() {
    worker_cond_.signal();
  }

  void FinalizerHandler::worker_wait() {
    worker_cond_.wait(worker_lock_);
  }

  FinalizerHandler::iterator& FinalizerHandler::begin() {
    if(iterator_) delete iterator_;
    iterator_ = new iterator(this);
    return *iterator_;
  }
}
<commit_msg>Removed finalizer worker thread race on shutdown.<commit_after>#include "config.h"
#include "vm.hpp"
#include "on_stack.hpp"
#include "object_memory.hpp"
#include "call_frame.hpp"
#include "metrics.hpp"

#include "builtin/array.hpp"
#include "builtin/class.hpp"
#include "builtin/module.hpp"
#include "builtin/thread.hpp"
#include "builtin/native_method.hpp"

#include "capi/handle.hpp"

#include "gc/finalize.hpp"

#include "dtrace/dtrace.h"

namespace rubinius {
  FinalizerHandler::iterator::iterator(FinalizerHandler* fh)
    : handler_(fh)
    , current_list_(NULL)
  {
    if(handler_->live_list_->empty()) {
      if(handler_->lists_->empty()) {
        current_ = handler_->live_list_->begin();
        end_ = handler_->live_list_->end();
        return;
      } else {
        current_list_ = handler_->lists_->front();
      }
    } else {
      current_list_ = handler_->live_list_;
    }

    current_ = current_list_->begin();

    if(handler_->lists_->empty()) {
      end_ = current_list_->end();
    } else {
      lists_iterator_ = handler_->lists_->begin();
      end_ = handler_->lists_->back()->end();
    }
  }

  void FinalizerHandler::iterator::next(bool live) {
    if(current_list_ == handler_->live_list_) {
      if(!live) current_->queued();

      if(++current_ == current_list_->end()) {
        if(!handler_->lists_->empty()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    } else {
      if(++current_ == end_) {
        return;
      } else if(current_ == current_list_->end()) {
        if(++lists_iterator_ != handler_->lists_->end()) {
          current_list_ = *lists_iterator_;
          current_ = current_list_->begin();
        }
      }
    }
  }

  bool FinalizerHandler::iterator::end() {
    return current_ == end_;
  }

  Object* finalizer_handler_tramp(STATE) {
    state->shared().finalizer_handler()->perform(state);
    GCTokenImpl gct;
    state->gc_dependent(gct, 0);
    return cNil;
  }

  FinalizerHandler::FinalizerHandler(STATE)
    : AuxiliaryThread()
    , shared_(state->shared())
    , self_(NULL)
    , thread_(state)
    , lists_(NULL)
    , live_list_(NULL)
    , process_list_(NULL)
    , iterator_(NULL)
    , process_item_kind_(eRuby)
    , paused_(false)
    , exit_(false)
    , finishing_(false)
  {
    shared_.auxiliary_threads()->register_thread(this);
    shared_.set_finalizer_handler(this);

    lists_ = new FinalizeObjectsList();
    live_list_ = new FinalizeObjects();

    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    pause_cond_.init();

    supervisor_lock_.init();
    supervisor_cond_.init();
  }

  FinalizerHandler::~FinalizerHandler() {
    shared_.auxiliary_threads()->unregister_thread(this);

    if(iterator_) delete iterator_;
    if(live_list_) delete live_list_;

    if(lists_) {
      for(FinalizeObjectsList::iterator i = lists_->begin(); i != lists_->end(); ++i) {
        delete *i;
      }
      delete lists_;
    }
  }

  void FinalizerHandler::start_thread(STATE) {
    SYNC(state);
    if(self_) return;
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    self_ = state->shared().new_vm();
    self_->metrics()->init(metrics::eFinalizerMetrics);
    paused_ = false;
    exit_ = false;
    thread_.set(Thread::create(state, self_, G(thread), finalizer_handler_tramp, true));
    run(state);
  }

  void FinalizerHandler::stop_thread(STATE) {
    SYNC(state);
    if(!self_) return;

    pthread_t os = self_->os_thread();
    {
      utilities::thread::Mutex::LockGuard lg(worker_lock_);
      // Thread might have already been stopped
      exit_ = true;
      worker_signal();
    }

    void* return_value;
    pthread_join(os, &return_value);
    self_ = NULL;
  }

  void FinalizerHandler::shutdown(STATE) {
    // We do nothing now because we have to finish processing all remaining
    // live objects once everything shuts down.
  }

  void FinalizerHandler::before_exec(STATE) {
    stop_thread(state);
  }

  void FinalizerHandler::after_exec(STATE) {
    start_thread(state);
  }

  void FinalizerHandler::before_fork(STATE) {
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    while(!paused_ && self_->run_state() == ManagedThread::eRunning) {
      pause_cond_.wait(worker_lock_);
    }
  }

  void FinalizerHandler::after_fork_parent(STATE) {
    utilities::thread::Mutex::LockGuard lg(worker_lock_);
    pause_cond_.signal();
  }

  void FinalizerHandler::after_fork_child(STATE) {
    live_guard_.init();
    worker_lock_.init();
    worker_cond_.init();
    pause_cond_.init();
    supervisor_lock_.init();
    supervisor_cond_.init();

    if(self_) {
      VM::discard(state, self_);
      self_ = NULL;
    }

    start_thread(state);
  }

  void FinalizerHandler::run(STATE) {
    int error = thread_.get()->fork_attached(state);
    if(error) rubinius::bug("Unable to start finalizer handler thread");
  }

  void FinalizerHandler::perform(STATE) {
    GCTokenImpl gct;
    RBX_DTRACE_CONST char* thread_name =
      const_cast<RBX_DTRACE_CONST char*>("rbx.finalizer");
    self_->set_name(thread_name);

    RUBINIUS_THREAD_START(const_cast<RBX_DTRACE_CONST char*>(thread_name),
                          state->vm()->thread_id(), 1);

    state->vm()->thread->hard_unlock(state, gct, 0);

    while(!exit_) {
      state->vm()->set_call_frame(0);

      if(!process_list_) first_process_item();

      if(!process_list_) {
        {
          utilities::thread::Mutex::LockGuard lg(worker_lock_);

          // exit_ might have been set after we grabbed the worker_lock
          if(exit_) break;

          state->gc_independent(gct, 0);
          paused_ = true;
          pause_cond_.signal();
          worker_wait();

          if(exit_) break;
        }

        state->gc_dependent(gct, 0);

        {
          utilities::thread::Mutex::LockGuard lg(worker_lock_);
          paused_ = false;
          if(exit_) break;
        }

        continue;
      }

      finalize(state);
      next_process_item();
    }
    RUBINIUS_THREAD_STOP(const_cast<RBX_DTRACE_CONST char*>(thread_name),
                         state->vm()->thread_id(), 1);
  }

  void FinalizerHandler::finalize(STATE) {

    switch(process_item_kind_) {
    case eRuby: {
      if(process_item_->ruby_finalizer) {
        CallFrame* call_frame = 0;
        // Rubinius specific code. If the finalizer is cTrue, then send the
        // object the __finalize__ message.
        if(process_item_->ruby_finalizer->true_p()) {
          process_item_->object->send(state, call_frame, state->symbol("__finalize__"));
        } else {
          Array* ary = Array::create(state, 1);
          ary->set(state, 0, process_item_->object->id(state));
          process_item_->ruby_finalizer->send(state, call_frame, G(sym_call), ary);
        }
      }

      process_item_->status = FinalizeObject::eRubyFinalized;
      break;
    }
    case eNative:
      if(process_item_->finalizer) {

        NativeMethodEnvironment* env = state->vm()->native_method_environment;
        NativeMethodFrame nmf(env, 0, 0);
        CallFrame* call_frame = ALLOCA_CALLFRAME(0);
        call_frame->previous = 0;
        call_frame->constant_scope_ = 0;
        call_frame->dispatch_data = (void*)&nmf;
        call_frame->compiled_code = 0;
        call_frame->flags = CallFrame::cNativeMethod;
        call_frame->optional_jit_data = 0;
        call_frame->top_scope_ = 0;
        call_frame->scope = 0;
        call_frame->arguments = 0;

        env->set_current_call_frame(0);
        env->set_current_native_frame(&nmf);

        // Register the CallFrame, because we might GC below this.
        state->set_call_frame(call_frame);

        nmf.setup(Qnil, Qnil, Qnil, Qnil);

        (*process_item_->finalizer)(state, process_item_->object);

        state->set_call_frame(0);
        env->set_current_call_frame(0);
        env->set_current_native_frame(0);
      }
      process_item_->status = FinalizeObject::eNativeFinalized;
      break;
    case eRelease:
      // Unhook any handle used by fi->object so that we don't accidentally
      // try and mark it later (after we've finalized it)
      if(capi::Handle* handle = process_item_->object->handle(state)) {
        handle->forget_object();
        process_item_->object->clear_handle(state);
      }

      process_item_->status = FinalizeObject::eReleased;

      break;
    }
  }

  void FinalizerHandler::first_process_item() {
    if(!process_list_ && !lists_->empty()) {
      process_list_ = lists_->back();
      process_item_ = process_list_->begin();
    }
  }

  void FinalizerHandler::next_process_item() {
    if(++process_item_ == process_list_->end()) {
      switch(process_item_kind_) {
      case eRuby:
        process_item_ = process_list_->begin();
        process_item_kind_ = eNative;
        break;
      case eNative:
        process_item_ = process_list_->begin();
        process_item_kind_ = eRelease;
        break;
      case eRelease:
        delete process_list_;
        process_list_ = NULL;
        process_item_kind_ = eRuby;
        lists_->pop_back();
        self_->metrics()->m.finalizer_metrics.objects_finalized++;
        break;
      }
    }
  }

  void FinalizerHandler::finish(STATE, GCToken gct) {
    finishing_ = true;

    {
      utilities::thread::Mutex::LockGuard lg(worker_lock_);

      exit_ = true;
      worker_signal();
    }

    if(!(process_list_ || !lists_->empty() || !live_list_->empty())) {
      stop_thread(state);
      return;
    }

    while(true) {
      {
        StopTheWorld stw(state, gct, 0);

        if(!process_list_) {
          if(live_list_->empty() && lists_->empty()) break;

          // Everything is garbage when halting so keep adding live objects to
          // finalize queue until done.
          if(!live_list_->empty()) {
            for(FinalizeObjects::iterator i = live_list_->begin();
                i != live_list_->end();
                ++i)
            {
              i->queued();
            }

            queue_objects();
          }

          first_process_item();
          if(!process_list_) break;
        }
      }

      while(process_list_) {
        finalize(state);
        next_process_item();
      }
    }

    if(!lists_->empty() || !live_list_->empty() || process_list_ != NULL) {
      rubinius::bug("FinalizerHandler exiting with pending finalizers");
    }

    stop_thread(state);
  }

  void FinalizerHandler::record(Object* obj, FinalizerFunction func) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;
    fi.finalizer = func;

    // Makes a copy of fi.
    live_list_->push_front(fi);

    self_->metrics()->m.finalizer_metrics.objects_queued++;
  }

  void FinalizerHandler::set_ruby_finalizer(Object* obj, Object* finalizer) {
    utilities::thread::Mutex::LockGuard lg(live_guard_);

    // Ignore Ruby finalizers created when finishing running finalizers.
    if(finishing_) return;

    // Check if the object is already in the finalizer list.
    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        ++i)
    {
      if(i->object == obj) {
        if(finalizer->nil_p()) {
          live_list_->erase(i);
        } else {
          i->ruby_finalizer = finalizer;
        }
        return;
      }
    }

    // Adding a nil finalizer is only used to delete an existing finalizer,
    // which we apparently don't have if we get here.
    if(finalizer->nil_p()) {
      return;
    }

    // Ok, create it.

    FinalizeObject fi;
    fi.object = obj;
    fi.status = FinalizeObject::eLive;

    // Rubinius specific API. If the finalizer is the object, we're going to send
    // the object __finalize__. We mark that the user wants this by putting cTrue
    // as the ruby_finalizer.
    if(obj == finalizer) {
      fi.ruby_finalizer = cTrue;
    } else {
      fi.ruby_finalizer = finalizer;
    }

    // Makes a copy of fi.
    live_list_->push_front(fi);
  }

  void FinalizerHandler::queue_objects() {
    FinalizeObjects* dead_list = new FinalizeObjects();

    for(FinalizeObjects::iterator i = live_list_->begin();
        i != live_list_->end();
        /* advance is handled in the loop */)
    {
      if(i->queued_p()) {
        dead_list->push_front(*i);
        i = live_list_->erase(i);
      } else {
        ++i;
      }
    }

    if(!dead_list->empty()) {
      lists_->push_front(dead_list);
    } else {
      delete dead_list;
    }
  }

  void FinalizerHandler::start_collection(STATE) {
    if(process_item_kind_ == eRelease) {
      while(process_list_) {
        finalize(state);
        next_process_item();
      }
    }
  }

  void FinalizerHandler::finish_collection(STATE) {
    queue_objects();

    if(iterator_) {
      delete iterator_;
      iterator_ = NULL;
    }

    worker_signal();
  }

  void FinalizerHandler::supervisor_signal() {
    supervisor_cond_.signal();
  }

  void FinalizerHandler::supervisor_wait() {
    supervisor_cond_.wait(supervisor_lock_);
  }

  void FinalizerHandler::worker_signal() {
    worker_cond_.signal();
  }

  void FinalizerHandler::worker_wait() {
    worker_cond_.wait(worker_lock_);
  }

  FinalizerHandler::iterator& FinalizerHandler::begin() {
    if(iterator_) delete iterator_;
    iterator_ = new iterator(this);
    return *iterator_;
  }
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include "caf/config_value.hpp"
#include "caf/dictionary.hpp"
#include "caf/optional.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_view.hpp"

namespace caf {

/// Software options stored as key-value pairs.
/// @relates config_value
using settings = dictionary<config_value>;

/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
const config_value* get_if(const settings* xs, string_view name);

/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
optional<T> get_if(const settings* xs, string_view name) {
  if (auto value = get_if(xs, name))
    if (auto ptr = get_if<T>(value))
      return *ptr;
  return none;
}

template <class T>
T get(const settings& xs, string_view name) {
  auto result = get_if<T>(&xs, name);
  CAF_ASSERT(result != none);
  return std::move(*result);
}

template <class T, class = typename std::enable_if<
                     !std::is_pointer<T>::value
                     && !std::is_convertible<T, string_view>::value>::type>
T get_or(const settings& xs, string_view name, T default_value) {
  auto result = get_if<T>(&xs, name);
  if (result)
    return std::move(*result);
  return std::move(default_value);
}

std::string get_or(const settings& xs, string_view name,
                   string_view default_value);

/// @private
config_value& put_impl(settings& dict, const std::vector<string_view>& path,
                       config_value& value);

/// @private
config_value& put_impl(settings& dict, string_view key, config_value& value);

/// Converts `value` to a `config_value` and assigns it to `key`.
/// @param dict Dictionary of key-value pairs.
/// @param key Human-readable nested keys in the form `category.key`.
/// @param value New value for given `key`.
template <class T>
config_value& put(settings& dict, string_view key, T&& value) {
  config_value tmp{std::forward<T>(value)};
  return put_impl(dict, key, tmp);
}

/// Converts `value` to a `config_value` and assigns it to `key` unless `xs`
/// already contains `key` (does nothing in this case).
/// @param xs Dictionary of key-value pairs.
/// @param key Human-readable nested keys in the form `category.key`.
/// @param value New value for given `key`.
template <class T>
void put_missing(settings& xs, string_view key, T&& value) {
  if (get_if(&xs, key) != nullptr)
    return;
  config_value tmp{std::forward<T>(value)};
  put_impl(xs, key, tmp);
}

/// Inserts a new list named `name` into the dictionary `xs` and returns
/// a reference to it. Overrides existing entries with the same name.
config_value::list& put_list(settings& xs, std::string name);

/// Inserts a new list named `name` into the dictionary `xs` and returns
/// a reference to it. Overrides existing entries with the same name.
config_value::dictionary& put_dictionary(settings& xs, std::string name);

} // namespace caf
<commit_msg>Add missing holds_alternative overload<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright 2011-2018 Dominik Charousset                                     *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#pragma once

#include "caf/config_value.hpp"
#include "caf/dictionary.hpp"
#include "caf/optional.hpp"
#include "caf/raise_error.hpp"
#include "caf/string_view.hpp"

namespace caf {

/// Software options stored as key-value pairs.
/// @relates config_value
using settings = dictionary<config_value>;

/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
const config_value* get_if(const settings* xs, string_view name);

/// Tries to retrieve the value associated to `name` from `xs`.
/// @relates config_value
template <class T>
optional<T> get_if(const settings* xs, string_view name) {
  if (auto value = get_if(xs, name))
    if (auto ptr = get_if<T>(value))
      return *ptr;
  return none;
}

/// Returns whether `xs` associates a value of type `T` to `name`.
/// @relates config_value
template <class T>
bool holds_alternative(const settings& xs, string_view name) {
  using access = select_config_value_access_t<T>;
  if (auto value = get_if(&xs, name))
    return access::is(*value);
  return false;
}

template <class T>
T get(const settings& xs, string_view name) {
  auto result = get_if<T>(&xs, name);
  CAF_ASSERT(result != none);
  return std::move(*result);
}

template <class T, class = typename std::enable_if<
                     !std::is_pointer<T>::value
                     && !std::is_convertible<T, string_view>::value>::type>
T get_or(const settings& xs, string_view name, T default_value) {
  auto result = get_if<T>(&xs, name);
  if (result)
    return std::move(*result);
  return std::move(default_value);
}

std::string get_or(const settings& xs, string_view name,
                   string_view default_value);

/// @private
config_value& put_impl(settings& dict, const std::vector<string_view>& path,
                       config_value& value);

/// @private
config_value& put_impl(settings& dict, string_view key, config_value& value);

/// Converts `value` to a `config_value` and assigns it to `key`.
/// @param dict Dictionary of key-value pairs.
/// @param key Human-readable nested keys in the form `category.key`.
/// @param value New value for given `key`.
template <class T>
config_value& put(settings& dict, string_view key, T&& value) {
  config_value tmp{std::forward<T>(value)};
  return put_impl(dict, key, tmp);
}

/// Converts `value` to a `config_value` and assigns it to `key` unless `xs`
/// already contains `key` (does nothing in this case).
/// @param xs Dictionary of key-value pairs.
/// @param key Human-readable nested keys in the form `category.key`.
/// @param value New value for given `key`.
template <class T>
void put_missing(settings& xs, string_view key, T&& value) {
  if (get_if(&xs, key) != nullptr)
    return;
  config_value tmp{std::forward<T>(value)};
  put_impl(xs, key, tmp);
}

/// Inserts a new list named `name` into the dictionary `xs` and returns
/// a reference to it. Overrides existing entries with the same name.
config_value::list& put_list(settings& xs, std::string name);

/// Inserts a new list named `name` into the dictionary `xs` and returns
/// a reference to it. Overrides existing entries with the same name.
config_value::dictionary& put_dictionary(settings& xs, std::string name);

} // namespace caf
<|endoftext|>


<commit_before>#undef OBJECT_CAST
#define OBJECT_CAST dynamic_cast

#include <osgAnimation/AnimationManagerBase>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>
namespace  osgAnimation_AnimationManagerBaseWrapper
{
static bool checkAnimations( const osgAnimation::AnimationManagerBase& manager )
{
    return manager.getAnimationList().size()>0;
}

static bool readAnimations( osgDB::InputStream& is, osgAnimation::AnimationManagerBase& manager )
{
    unsigned int size = is.readSize();
    is >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        osg::ref_ptr<osgAnimation::Animation> ani = is.readObjectOfType<osgAnimation::Animation>();
        if ( ani ) manager.registerAnimation( ani.get() );
    }
    is >> is.END_BRACKET;
    return true;
}

static bool writeAnimations( osgDB::OutputStream& os, const osgAnimation::AnimationManagerBase& manager )
{
    const osgAnimation::AnimationList& animations = manager.getAnimationList();
    os.writeSize(animations.size());
    os << os.BEGIN_BRACKET << std::endl;
    for ( osgAnimation::AnimationList::const_iterator itr=animations.begin();
            itr!=animations.end(); ++itr )
    {
        os << itr->get();
    }
    os << os.END_BRACKET << std::endl;
    return true;
}
struct osgAnimation_AnimationManagerBasegetnumAnimations : public osgDB::MethodObject
{
    virtual bool run(void* objectPtr, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const
    {
        osgAnimation::AnimationManagerBase* group =  dynamic_cast<osgAnimation::AnimationManagerBase*>(reinterpret_cast<osg::Object*>(objectPtr));
        outputParameters.push_back(new osg::UIntValueObject("return",group->getNumRegisteredAnimations()));
        return true;
    }
};
struct osgAnimation_AnimationManagerBasegetAnimation : public osgDB::MethodObject
{
    virtual bool run(void* objectPtr, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const
    {
        if (inputParameters.empty()) return false;

        osg::Object* indexObject = inputParameters[0].get();

        unsigned int index = 0;
        osg::DoubleValueObject* dvo = dynamic_cast<osg::DoubleValueObject*>(indexObject);
        if (dvo) index = static_cast<unsigned int>(dvo->getValue());
        else
        {
            osg::UIntValueObject* uivo = dynamic_cast<osg::UIntValueObject*>(indexObject);
            if (uivo) index = uivo->getValue();
        }
        osgAnimation::AnimationManagerBase* group = dynamic_cast<osgAnimation::AnimationManagerBase*>(reinterpret_cast<osg::Object*>(objectPtr));
        outputParameters.push_back(group->getRegisteredAnimation(index));

        return true;
    }
};
REGISTER_OBJECT_WRAPPER( osgAnimation_AnimationManagerBase,
                         /*new osgAnimation::AnimationManagerBase*/NULL,
                         osgAnimation::AnimationManagerBase,
                         "osg::Object osg::NodeCallback osgAnimation::AnimationManagerBase" )
{
    ADD_USER_SERIALIZER( Animations );  // _animations
    ADD_BOOL_SERIALIZER( AutomaticLink, true );  // _automaticLink

    ADD_METHOD_OBJECT( "getRegisteredAnimation", osgAnimation_AnimationManagerBasegetAnimation );
    ADD_METHOD_OBJECT( "getNumRegisteredAnimations", osgAnimation_AnimationManagerBasegetnumAnimations );
}
}
#undef OBJECT_CAST
#define OBJECT_CAST static_cast
<commit_msg>Added versioning to the new serialization additions<commit_after>#undef OBJECT_CAST
#define OBJECT_CAST dynamic_cast

#include <osgAnimation/AnimationManagerBase>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>
namespace  osgAnimation_AnimationManagerBaseWrapper
{
static bool checkAnimations( const osgAnimation::AnimationManagerBase& manager )
{
    return manager.getAnimationList().size()>0;
}

static bool readAnimations( osgDB::InputStream& is, osgAnimation::AnimationManagerBase& manager )
{
    unsigned int size = is.readSize();
    is >> is.BEGIN_BRACKET;
    for ( unsigned int i=0; i<size; ++i )
    {
        osg::ref_ptr<osgAnimation::Animation> ani = is.readObjectOfType<osgAnimation::Animation>();
        if ( ani ) manager.registerAnimation( ani.get() );
    }
    is >> is.END_BRACKET;
    return true;
}

static bool writeAnimations( osgDB::OutputStream& os, const osgAnimation::AnimationManagerBase& manager )
{
    const osgAnimation::AnimationList& animations = manager.getAnimationList();
    os.writeSize(animations.size());
    os << os.BEGIN_BRACKET << std::endl;
    for ( osgAnimation::AnimationList::const_iterator itr=animations.begin();
            itr!=animations.end(); ++itr )
    {
        os << itr->get();
    }
    os << os.END_BRACKET << std::endl;
    return true;
}
struct osgAnimation_AnimationManagerBasegetnumAnimations : public osgDB::MethodObject
{
    virtual bool run(void* objectPtr, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const
    {
        osgAnimation::AnimationManagerBase* group =  dynamic_cast<osgAnimation::AnimationManagerBase*>(reinterpret_cast<osg::Object*>(objectPtr));
        outputParameters.push_back(new osg::UIntValueObject("return",group->getNumRegisteredAnimations()));
        return true;
    }
};
struct osgAnimation_AnimationManagerBasegetAnimation : public osgDB::MethodObject
{
    virtual bool run(void* objectPtr, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const
    {
        if (inputParameters.empty()) return false;

        osg::Object* indexObject = inputParameters[0].get();

        unsigned int index = 0;
        osg::DoubleValueObject* dvo = dynamic_cast<osg::DoubleValueObject*>(indexObject);
        if (dvo) index = static_cast<unsigned int>(dvo->getValue());
        else
        {
            osg::UIntValueObject* uivo = dynamic_cast<osg::UIntValueObject*>(indexObject);
            if (uivo) index = uivo->getValue();
        }
        osgAnimation::AnimationManagerBase* group = dynamic_cast<osgAnimation::AnimationManagerBase*>(reinterpret_cast<osg::Object*>(objectPtr));
        outputParameters.push_back(group->getRegisteredAnimation(index));

        return true;
    }
};
REGISTER_OBJECT_WRAPPER( osgAnimation_AnimationManagerBase,
                         /*new osgAnimation::AnimationManagerBase*/NULL,
                         osgAnimation::AnimationManagerBase,
                         "osg::Object osg::NodeCallback osgAnimation::AnimationManagerBase" )
{
    ADD_USER_SERIALIZER( Animations );  // _animations
    ADD_BOOL_SERIALIZER( AutomaticLink, true );  // _automaticLink

    {
        UPDATE_TO_VERSION_SCOPED( 152 )

        ADD_METHOD_OBJECT( "getRegisteredAnimation", osgAnimation_AnimationManagerBasegetAnimation );
        ADD_METHOD_OBJECT( "getNumRegisteredAnimations", osgAnimation_AnimationManagerBasegetnumAnimations );
    }
}
}
#undef OBJECT_CAST
#define OBJECT_CAST static_cast
<|endoftext|>


<commit_before>#include "pch.h"
#include "RotatingCube.h"
#include "BasicTimer.h"

#define STRINGIFY(x) #x

const char g_colorVertexShader[] = STRINGIFY(
precision mediump float;
attribute vec3 a_position;
attribute vec3 a_color;
varying vec4 v_color;
uniform mat4 u_mvp;
void main(void)
{
    gl_Position = u_mvp * vec4(a_position, 1);
    v_color = vec4(a_color, 1);
}
);

const char g_colorFragmentShader[] = STRINGIFY(
precision mediump float;
varying vec4 v_color;
void main(void)
{
    gl_FragColor = v_color;
}
);

using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
using namespace concurrency;

struct VertexPositionColor
{
	DirectX::XMFLOAT3 pos;
	DirectX::XMFLOAT3 color;
};

RotatingCube::RotatingCube() :
	m_windowClosed(false),
	m_windowVisible(true)
{
}

void RotatingCube::Initialize(CoreApplicationView^ applicationView)
{
	applicationView->Activated +=
        ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &RotatingCube::OnActivated);

	CoreApplication::Suspending +=
        ref new EventHandler<SuspendingEventArgs^>(this, &RotatingCube::OnSuspending);

	CoreApplication::Resuming +=
        ref new EventHandler<Platform::Object^>(this, &RotatingCube::OnResuming);
}

void RotatingCube::SetWindow(CoreWindow^ window)
{
    window->SizeChanged +=
        ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &RotatingCube::OnWindowSizeChanged);

    window->VisibilityChanged +=
        ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &RotatingCube::OnVisibilityChanged);

    window->Closed +=
        ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &RotatingCube::OnWindowClosed);

#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
    window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
#endif

    window->PointerPressed +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &RotatingCube::OnPointerPressed);

    window->PointerMoved +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &RotatingCube::OnPointerMoved);

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
    DisplayProperties::AutoRotationPreferences =
        DisplayOrientations::Landscape |
        DisplayOrientations::LandscapeFlipped |
        DisplayOrientations::Portrait |
        DisplayOrientations::PortraitFlipped;
    DisplayProperties::OrientationChanged +=
        ref new DisplayPropertiesEventHandler(this, &RotatingCube::OnOrientationChanged);
#endif

    m_orientation = DisplayProperties::CurrentOrientation;
    m_windowBounds = window->Bounds;

    esInitContext(&m_esContext);

    HRESULT result = CreateWinrtEglWindow(WINRT_EGL_IUNKNOWN(CoreWindow::GetForCurrentThread()), ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_3, m_eglWindow.GetAddressOf());
    if (SUCCEEDED(result))
    {
        m_esContext.hWnd = m_eglWindow;

        //title, width, and height are unused, but included for backwards compatibility
        esCreateWindow(&m_esContext, nullptr, 0, 0, ES_WINDOW_RGB | ES_WINDOW_DEPTH);

        m_cubeRenderer.CreateResources();
    }
}

void RotatingCube::Load(Platform::String^ entryPoint)
{
}

void RotatingCube::Run()
{
	BasicTimer^ timer = ref new BasicTimer();

	while (!m_windowClosed)
	{
		if (m_windowVisible)
		{
			timer->Update();
			CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
            m_cubeRenderer.Update(timer->Total, timer->Delta);
            m_cubeRenderer.Render();
            eglSwapBuffers(m_esContext.eglDisplay, m_esContext.eglSurface);
		}
		else
		{
			CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
		}
	}
}

void RotatingCube::Uninitialize()
{
}

void RotatingCube::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
    m_cubeRenderer.UpdateForWindowSizeChanged();
}

void RotatingCube::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
	m_windowVisible = args->Visible;
}

void RotatingCube::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
	m_windowClosed = true;
}

void RotatingCube::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
	// Insert your code here.
}

void RotatingCube::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
{
	// Insert your code here.
}

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
void RotatingCube::OnOrientationChanged(Platform::Object^ sender)
{
	m_cubeRenderer.OnOrientationChanged();
}
#endif

void RotatingCube::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
	CoreWindow::GetForCurrentThread()->Activate();
}

void RotatingCube::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
	// Save app state asynchronously after requesting a deferral. Holding a deferral
	// indicates that the application is busy performing suspending operations. Be
	// aware that a deferral may not be held indefinitely. After about five seconds,
	// the app will be forced to exit.
	SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();

	create_task([this, deferral]()
	{

#if (_MSC_VER >= 1800)
        Microsoft::WRL::ComPtr<IDXGIDevice3> dxgiDevice;
        HRESULT result = m_eglWindow->GetAngleD3DDevice().As(&dxgiDevice);
        if (SUCCEEDED(result))
        {
            dxgiDevice->Trim();
        }
#endif
		deferral->Complete();
	});
}

void RotatingCube::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
	// Restore any data or state that was unloaded on suspend. By default, data
	// and state are persisted when resuming from suspend. Note that this event
	// does not occur if the app was previously terminated.
}

IFrameworkView^ Direct3DApplicationSource::CreateView()
{
    return ref new RotatingCube();
}

[Platform::MTAThread]
int main(Platform::Array<Platform::String^>^)
{
	auto direct3DApplicationSource = ref new Direct3DApplicationSource();
	CoreApplication::Run(direct3DApplicationSource);
	return 0;
}
<commit_msg>added support for winrt/angle EGLNativeWindowType<commit_after>#include "pch.h"
#include "RotatingCube.h"
#include "BasicTimer.h"

#define STRINGIFY(x) #x

const char g_colorVertexShader[] = STRINGIFY(
    precision mediump float;
attribute vec3 a_position;
attribute vec3 a_color;
varying vec4 v_color;
uniform mat4 u_mvp;
void main(void)
{
    gl_Position = u_mvp * vec4(a_position, 1);
    v_color = vec4(a_color, 1);
}
);

const char g_colorFragmentShader[] = STRINGIFY(
    precision mediump float;
varying vec4 v_color;
void main(void)
{
    gl_FragColor = v_color;
}
);

using namespace Windows::ApplicationModel;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::ApplicationModel::Activation;
using namespace Windows::UI::Core;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::Graphics::Display;
using namespace concurrency;

struct VertexPositionColor
{
    DirectX::XMFLOAT3 pos;
    DirectX::XMFLOAT3 color;
};

RotatingCube::RotatingCube() :
m_windowClosed(false),
m_windowVisible(true)
{
}

void RotatingCube::Initialize(CoreApplicationView^ applicationView)
{
    applicationView->Activated +=
        ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &RotatingCube::OnActivated);

    CoreApplication::Suspending +=
        ref new EventHandler<SuspendingEventArgs^>(this, &RotatingCube::OnSuspending);

    CoreApplication::Resuming +=
        ref new EventHandler<Platform::Object^>(this, &RotatingCube::OnResuming);
}

void RotatingCube::SetWindow(CoreWindow^ window)
{
    window->SizeChanged +=
        ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &RotatingCube::OnWindowSizeChanged);

    window->VisibilityChanged +=
        ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &RotatingCube::OnVisibilityChanged);

    window->Closed +=
        ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &RotatingCube::OnWindowClosed);

#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
    window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
#endif

    window->PointerPressed +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &RotatingCube::OnPointerPressed);

    window->PointerMoved +=
        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &RotatingCube::OnPointerMoved);

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
    DisplayProperties::AutoRotationPreferences =
        DisplayOrientations::Landscape |
        DisplayOrientations::LandscapeFlipped |
        DisplayOrientations::Portrait |
        DisplayOrientations::PortraitFlipped;
    DisplayProperties::OrientationChanged +=
        ref new DisplayPropertiesEventHandler(this, &RotatingCube::OnOrientationChanged);
#endif

    m_orientation = DisplayProperties::CurrentOrientation;
    m_windowBounds = window->Bounds;

    esInitContext(&m_esContext);

    // we need to select the correct DirectX feature level depending on the platform
    // default is for WinRT on Windows 8.0
    ANGLE_D3D_FEATURE_LEVEL featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_1;

#if (_MSC_VER >= 1800)
    // WinRT on Windows 8.1 can compile shaders at run time so we don't care about the DirectX feature level
    featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_ANY;
#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
    // Windows Phone 8.0 uses D3D_FEATURE_LEVEL_9_3
    featureLevel = ANGLE_D3D_FEATURE_LEVEL::ANGLE_D3D_FEATURE_LEVEL_9_3;
#endif

    HRESULT result = CreateWinrtEglWindow(WINRT_EGL_IUNKNOWN(CoreWindow::GetForCurrentThread()), featureLevel, m_eglWindow.GetAddressOf());
    if (SUCCEEDED(result))
    {
        m_esContext.hWnd = m_eglWindow;

        //title, width, and height are unused, but included for backwards compatibility
        esCreateWindow(&m_esContext, nullptr, 0, 0, ES_WINDOW_RGB | ES_WINDOW_DEPTH);

        m_cubeRenderer.CreateResources();
    }
}

void RotatingCube::Load(Platform::String^ entryPoint)
{
}

void RotatingCube::Run()
{
    BasicTimer^ timer = ref new BasicTimer();

    while (!m_windowClosed)
    {
        if (m_windowVisible)
        {
            timer->Update();
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
            m_cubeRenderer.Update(timer->Total, timer->Delta);
            m_cubeRenderer.Render();
            eglSwapBuffers(m_esContext.eglDisplay, m_esContext.eglSurface);
        }
        else
        {
            CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
        }
    }
}

void RotatingCube::Uninitialize()
{
}

void RotatingCube::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{
    m_cubeRenderer.UpdateForWindowSizeChanged();
}

void RotatingCube::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{
    m_windowVisible = args->Visible;
}

void RotatingCube::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{
    m_windowClosed = true;
}

void RotatingCube::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
{
    // Insert your code here.
}

void RotatingCube::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
{
    // Insert your code here.
}

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE)
void RotatingCube::OnOrientationChanged(Platform::Object^ sender)
{
    m_cubeRenderer.OnOrientationChanged();
}
#endif

void RotatingCube::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{
    CoreWindow::GetForCurrentThread()->Activate();
}

void RotatingCube::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
{
    // Save app state asynchronously after requesting a deferral. Holding a deferral
    // indicates that the application is busy performing suspending operations. Be
    // aware that a deferral may not be held indefinitely. After about five seconds,
    // the app will be forced to exit.
    SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();

    create_task([this, deferral]()
    {

#if (_MSC_VER >= 1800)
        Microsoft::WRL::ComPtr<IDXGIDevice3> dxgiDevice;
        HRESULT result = m_eglWindow->GetAngleD3DDevice().As(&dxgiDevice);
        if (SUCCEEDED(result))
        {
            dxgiDevice->Trim();
        }
#endif
        deferral->Complete();
    });
}

void RotatingCube::OnResuming(Platform::Object^ sender, Platform::Object^ args)
{
    // Restore any data or state that was unloaded on suspend. By default, data
    // and state are persisted when resuming from suspend. Note that this event
    // does not occur if the app was previously terminated.
}

IFrameworkView^ Direct3DApplicationSource::CreateView()
{
    return ref new RotatingCube();
}

[Platform::MTAThread]
int main(Platform::Array<Platform::String^>^)
{
    auto direct3DApplicationSource = ref new Direct3DApplicationSource();
    CoreApplication::Run(direct3DApplicationSource);
    return 0;
}
<|endoftext|>


<commit_before>#include "../Framework.hpp"

#include "../../core/jni_helper.hpp"
#include "partners_api/viator_api.hpp"

namespace
{
jclass g_viatorClass;
jclass g_viatorProductClass;
jmethodID g_viatorProductConstructor;
jmethodID g_viatorCallback;
std::string g_lastRequestId;

void PrepareClassRefs(JNIEnv * env)
{
  if (g_viatorClass)
    return;

  g_viatorClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/viator/Viator");
  g_viatorProductClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/viator/ViatorProduct");
  g_viatorProductConstructor =
      jni::GetConstructorID(env, g_viatorProductClass,
                            "(Ljava/lang/String;DILjava/lang/String;DLjava/lang/String;Ljava/lang/"
                            "String;Ljava/lang/String;Ljava/lang/String;)V");
  g_viatorCallback =
      jni::GetStaticMethodID(env, g_viatorClass, "onViatorProductsReceived",
                             "(Ljava/lang/String;[Lcom/mapswithme/maps/viator/ViatorProduct;)V");
}

void OnViatorProductsReceived(std::string const & destId,
                              std::vector<viator::Product> const & products)
{
  GetPlatform().RunOnGuiThread([=]() {
    if (g_lastRequestId != destId)
      return;

    JNIEnv * env = jni::GetEnv();

    jni::TScopedLocalRef jDestId(env, jni::ToJavaString(env, destId));
    jni::TScopedLocalRef jProducts(
        env,
        jni::ToJavaArray(env, g_viatorProductClass, products, [](JNIEnv * env,
                                                                 viator::Product const & item) {
          jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, item.m_title));
          jni::TScopedLocalRef jDuration(env, jni::ToJavaString(env, item.m_duration));
          jni::TScopedLocalRef jPriceFormatted(env, jni::ToJavaString(env, item.m_priceFormatted));
          jni::TScopedLocalRef jCurrency(env, jni::ToJavaString(env, item.m_currency));
          jni::TScopedLocalRef jPhotoUrl(env, jni::ToJavaString(env, item.m_photoUrl));
          jni::TScopedLocalRef jPageUrl(env, jni::ToJavaString(env, item.m_pageUrl));
          return env->NewObject(g_viatorProductClass, g_viatorProductConstructor, jTitle.get(),
                                item.m_rating, item.m_reviewCount, jDuration.get(), item.m_price,
                                jPriceFormatted.get(), jCurrency.get(), jPhotoUrl.get(),
                                jPageUrl.get());
        }));

    env->CallStaticVoidMethod(g_viatorClass, g_viatorCallback, jDestId.get(), jProducts.get());
  });
}
}  // namespace

extern "C" {

JNIEXPORT void JNICALL Java_com_mapswithme_maps_viator_Viator_nativeRequestViatorProducts(
    JNIEnv * env, jclass clazz, jobject policy, jstring destId, jstring currency)
{
  PrepareClassRefs(env);

  g_lastRequestId = jni::ToNativeString(env, destId);
  g_framework->RequestViatorProducts(env, policy, g_lastRequestId,
                                     jni::ToNativeString(env, currency), &OnViatorProductsReceived);
}
}  // extern "C"
<commit_msg>[android] Review fixes.<commit_after>#include "android/jni/com/mapswithme/maps/Framework.hpp"

#include "android/jni/com/mapswithme/core/jni_helper.hpp"
#include "partners_api/viator_api.hpp"

namespace
{
jclass g_viatorClass;
jclass g_viatorProductClass;
jmethodID g_viatorProductConstructor;
jmethodID g_viatorCallback;
std::string g_lastDestId;

void PrepareClassRefs(JNIEnv * env)
{
  if (g_viatorClass)
    return;

  g_viatorClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/viator/Viator");
  g_viatorProductClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/viator/ViatorProduct");
  g_viatorProductConstructor =
      jni::GetConstructorID(env, g_viatorProductClass,
                            "(Ljava/lang/String;DILjava/lang/String;DLjava/lang/String;Ljava/lang/"
                            "String;Ljava/lang/String;Ljava/lang/String;)V");
  g_viatorCallback =
      jni::GetStaticMethodID(env, g_viatorClass, "onViatorProductsReceived",
                             "(Ljava/lang/String;[Lcom/mapswithme/maps/viator/ViatorProduct;)V");
}

void OnViatorProductsReceived(std::string const & destId,
                              std::vector<viator::Product> const & products)
{
  GetPlatform().RunOnGuiThread([=]() {
    if (g_lastDestId != destId)
      return;

    JNIEnv * env = jni::GetEnv();

    jni::TScopedLocalRef jDestId(env, jni::ToJavaString(env, destId));
    jni::TScopedLocalRef jProducts(
        env,
        jni::ToJavaArray(env, g_viatorProductClass, products, [](JNIEnv * env,
                                                                 viator::Product const & item) {
          jni::TScopedLocalRef jTitle(env, jni::ToJavaString(env, item.m_title));
          jni::TScopedLocalRef jDuration(env, jni::ToJavaString(env, item.m_duration));
          jni::TScopedLocalRef jPriceFormatted(env, jni::ToJavaString(env, item.m_priceFormatted));
          jni::TScopedLocalRef jCurrency(env, jni::ToJavaString(env, item.m_currency));
          jni::TScopedLocalRef jPhotoUrl(env, jni::ToJavaString(env, item.m_photoUrl));
          jni::TScopedLocalRef jPageUrl(env, jni::ToJavaString(env, item.m_pageUrl));
          return env->NewObject(g_viatorProductClass, g_viatorProductConstructor, jTitle.get(),
                                item.m_rating, item.m_reviewCount, jDuration.get(), item.m_price,
                                jPriceFormatted.get(), jCurrency.get(), jPhotoUrl.get(),
                                jPageUrl.get());
        }));

    env->CallStaticVoidMethod(g_viatorClass, g_viatorCallback, jDestId.get(), jProducts.get());
  });
}
}  // namespace

extern "C" {

JNIEXPORT void JNICALL Java_com_mapswithme_maps_viator_Viator_nativeRequestViatorProducts(
    JNIEnv * env, jclass clazz, jobject policy, jstring destId, jstring currency)
{
  PrepareClassRefs(env);

  g_lastDestId = jni::ToNativeString(env, destId);
  g_framework->RequestViatorProducts(env, policy, g_lastDestId, jni::ToNativeString(env, currency),
                                     &OnViatorProductsReceived);
}
}  // extern "C"
<|endoftext|>


<commit_before>#include <scheduler/pthread-coro.hh>

#if defined SCHEDULER_CORO_OSTHREAD

#  include <cerrno>

#  include <libport/config.h>
#  include <libport/assert.hh>
#  include <libport/compiler.hh>
#  include <libport/semaphore.hh>
#  include <libport/thread.hh>

#  include <kernel/kernconf.hh>
#  include <scheduler/coroutine.hh>

/* Os-thread implementation of coroutines, using semaphores to ensure
   that only one coroutine is running at the same time.  */

Coro::Coro()
  : die_(false)
{}

Coro*
coroutine_new(size_t)
{
  return new Coro;
}

void
coroutine_free(Coro* c)
{
  c->die_ = true;
  c->sem_++;
}

void
coroutine_start(Coro* self, Coro* other,
                void (*callback)(void*), void* context)
{
#if defined WIN32
  unsigned long id;
  void* r =
    CreateThread(NULL, 0,
                 reinterpret_cast<void* (*)(void*)>(callback), context,
                 0, &id);
#else
  // Adjust to the requested stack size.
  static pthread_attr_t attr;
  static bool first = true;
  if (first)
  {
    first = false;
    if (pthread_attr_init(&attr))
      errabort("pthread_attr_init");

    if (pthread_attr_setstacksize(&attr, kernconf.default_stack_size))
      errabort("pthread_attr_setstacksize");
  }

  if (pthread_create(&other->thread_, &attr,
		     reinterpret_cast<void* (*)(void*)>(callback), context))
    errabort("pthread_create");
#endif
  self->sem_--;
}

void
coroutine_switch_to(Coro* self, Coro* next)
{
  next->sem_++;
  self->sem_--;
  if (self->die_)
  {
    delete self;
    pthread_exit(0);
  }
}

bool
coroutine_stack_space_almost_gone(Coro*)
{
  return false;
}

void
coroutine_initialize_main(Coro*)
{
}

#endif //! SCHEDULER_CORO_OSTHREAD
<commit_msg>Terminate job synchronously even in pthreads mode.<commit_after>#include <scheduler/pthread-coro.hh>

#if defined SCHEDULER_CORO_OSTHREAD

#  include <cerrno>

#  include <libport/config.h>
#  include <libport/assert.hh>
#  include <libport/compiler.hh>
#  include <libport/semaphore.hh>
#  include <libport/thread.hh>

#  include <kernel/kernconf.hh>
#  include <scheduler/coroutine.hh>

/* Os-thread implementation of coroutines, using semaphores to ensure
   that only one coroutine is running at the same time.  */

Coro::Coro()
  : die_(false)
{}

Coro*
coroutine_new(size_t)
{
  return new Coro;
}

void
coroutine_free(Coro* c)
{
  void *status;
  c->die_ = true;
  c->sem_++;
  if (pthread_join(c->thread_, &status))
    errabort("pthread_join");
}

void
coroutine_start(Coro* self, Coro* other,
                void (*callback)(void*), void* context)
{
#if defined WIN32
  unsigned long id;
  void* r =
    CreateThread(NULL, 0,
                 reinterpret_cast<void* (*)(void*)>(callback), context,
                 0, &id);
#else
  // Adjust to the requested stack size.
  static pthread_attr_t attr;
  static bool first = true;
  if (first)
  {
    first = false;
    if (pthread_attr_init(&attr))
      errabort("pthread_attr_init");

    if (pthread_attr_setstacksize(&attr, kernconf.default_stack_size))
      errabort("pthread_attr_setstacksize");
  }

  if (pthread_create(&other->thread_, &attr,
		     reinterpret_cast<void* (*)(void*)>(callback), context))
    errabort("pthread_create");
#endif
  self->sem_--;
}

void
coroutine_switch_to(Coro* self, Coro* next)
{
  next->sem_++;
  self->sem_--;
  if (self->die_)
  {
    delete self;
    pthread_exit(0);
  }
}

bool
coroutine_stack_space_almost_gone(Coro*)
{
  return false;
}

void
coroutine_initialize_main(Coro*)
{
}

#endif //! SCHEDULER_CORO_OSTHREAD
<|endoftext|>


<commit_before>#pragma once

// std
#include <vector>

// libraries
#include <nlohmann/json.hpp>

// project

#include "depthai-shared/common/optional.hpp"

namespace dai {

enum class TrackerType : std::int32_t {
    /// Ability to track the objects without accessing image data.
    ZERO_TERM_IMAGELESS = 5,
    /// Tracking using image data too.
    ZERO_TERM_COLOR_HISTOGRAM
};

enum class TrackerIdAssigmentPolicy : std::int32_t {
    /// Always take a new, unique ID
    UNIQUE_ID,
    /// Take the smallest available ID
    SMALLEST_ID
};

/**
 * Specify properties for ObjectTracker
 */
struct ObjectTrackerProperties {
    float trackerThreshold = 0.0;
    std::int32_t maxObjectsToTrack = 60;
    std::vector<std::uint32_t> detectionLabelsToTrack;
    TrackerType trackerType = TrackerType::ZERO_TERM_IMAGELESS;
    TrackerIdAssigmentPolicy trackerIdAssigmentPolicy = TrackerIdAssigmentPolicy::UNIQUE_ID;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ObjectTrackerProperties, trackerThreshold, maxObjectsToTrack, detectionLabelsToTrack, trackerType, trackerIdAssigmentPolicy)

}  // namespace dai
<commit_msg>Add KCF and imageless short term tracking algorithms<commit_after>#pragma once

// std
#include <vector>

// libraries
#include <nlohmann/json.hpp>

// project

#include "depthai-shared/common/optional.hpp"

namespace dai {

enum class TrackerType : std::int32_t {
    /// Kernelized Correlation Filter tracking
    SHORT_TERM_KCF = 1,
    /// Short term tracking without using image data
    SHORT_TERM_IMAGELESS = 3,
    /// Ability to track the objects without accessing image data.
    ZERO_TERM_IMAGELESS = 5,
    /// Tracking using image data too.
    ZERO_TERM_COLOR_HISTOGRAM = 6
};

enum class TrackerIdAssigmentPolicy : std::int32_t {
    /// Always take a new, unique ID
    UNIQUE_ID,
    /// Take the smallest available ID
    SMALLEST_ID
};

/**
 * Specify properties for ObjectTracker
 */
struct ObjectTrackerProperties {
    float trackerThreshold = 0.0;
    std::int32_t maxObjectsToTrack = 60;
    std::vector<std::uint32_t> detectionLabelsToTrack;
    TrackerType trackerType = TrackerType::ZERO_TERM_IMAGELESS;
    TrackerIdAssigmentPolicy trackerIdAssigmentPolicy = TrackerIdAssigmentPolicy::UNIQUE_ID;
};

NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ObjectTrackerProperties, trackerThreshold, maxObjectsToTrack, detectionLabelsToTrack, trackerType, trackerIdAssigmentPolicy)

}  // namespace dai
<|endoftext|>