<commit_before>/* Copyright 2015 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 "event_impl.h"

#include "proc_impl.h"
#include "runtime_impl.h"
#include "logging.h"

#ifdef USE_CUDA
GASNETT_THREADKEY_DECLARE(gpu_thread_ptr);
#endif

namespace Realm {

  Logger log_event("event");
  Logger log_barrier("barrier");

  ////////////////////////////////////////////////////////////////////////
  //
  // class Event
  //

  /*static*/ const Event Event::NO_EVENT = { 0, 0 };
  // Take this you POS c++ type system
  /* static */ const UserEvent UserEvent::NO_USER_EVENT = 
    *(static_cast<UserEvent*>(const_cast<Event*>(&Event::NO_EVENT)));

  bool Event::has_triggered(void) const
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    if(!id) return true; // special case: NO_EVENT has always triggered
    EventImpl *e = get_runtime()->get_event_impl(*this);
    return e->has_triggered(gen);
  }

  // creates an event that won't trigger until all input events have
  /*static*/ Event Event::merge_events(const std::set<Event>& wait_for)
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    return GenEventImpl::merge_events(wait_for);
  }

  /*static*/ Event Event::merge_events(Event ev1, Event ev2,
				       Event ev3 /*= NO_EVENT*/, Event ev4 /*= NO_EVENT*/,
				       Event ev5 /*= NO_EVENT*/, Event ev6 /*= NO_EVENT*/)
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    return GenEventImpl::merge_events(ev1, ev2, ev3, ev4, ev5, ev6);
  }

  void Event::wait(void) const
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    if(!id) return;  // special case: never wait for NO_EVENT
    EventImpl *e = get_runtime()->get_event_impl(*this);

    // early out case too
    if(e->has_triggered(gen)) return;

    // waiting on an event does not count against the low level's time
    DetailedTimer::ScopedPush sp2(TIME_NONE);

    // are we a thread that knows how to do something useful while waiting?
    if(PreemptableThread::preemptable_sleep(*this))
      return;

    // maybe a GPU thread?
#ifdef USE_CUDA
    void *ptr = gasnett_threadkey_get(gpu_thread_ptr);
    if(ptr != 0) {
      //assert(0);
      //printf("oh, good - we're a gpu thread - we'll spin for now\n");
      //printf("waiting for " IDFMT "/%d\n", id, gen);
      while(!e->has_triggered(gen)) {
#ifdef __SSE2__
	_mm_pause();
#else
	usleep(1000);
#endif
      }
      //printf("done\n");
      return;
    }
#endif
    // we're probably screwed here - try waiting and polling gasnet while
    //  we wait
    //printf("waiting on event, polling gasnet to hopefully not die\n");
    while(!e->has_triggered(gen)) {
      // can't poll here - the GPU DMA code sometimes polls from inside an active
      //  message handler (consider turning polling back on once that's fixed)
      //do_some_polling();<commit_msg>(untested) attempt at using new thread wait api<commit_after>/* Copyright 2015 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 "event_impl.h"

#include "proc_impl.h"
#include "runtime_impl.h"
#include "logging.h"
#include "threads.h"

#ifdef USE_CUDA
GASNETT_THREADKEY_DECLARE(gpu_thread_ptr);
#endif

namespace Realm {

  Logger log_event("event");
  Logger log_barrier("barrier");

  ////////////////////////////////////////////////////////////////////////
  //
  // class Event
  //

  /*static*/ const Event Event::NO_EVENT = { 0, 0 };
  // Take this you POS c++ type system
  /* static */ const UserEvent UserEvent::NO_USER_EVENT = 
    *(static_cast<UserEvent*>(const_cast<Event*>(&Event::NO_EVENT)));

  bool Event::has_triggered(void) const
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    if(!id) return true; // special case: NO_EVENT has always triggered
    EventImpl *e = get_runtime()->get_event_impl(*this);
    return e->has_triggered(gen);
  }

  // creates an event that won't trigger until all input events have
  /*static*/ Event Event::merge_events(const std::set<Event>& wait_for)
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    return GenEventImpl::merge_events(wait_for);
  }

  /*static*/ Event Event::merge_events(Event ev1, Event ev2,
				       Event ev3 /*= NO_EVENT*/, Event ev4 /*= NO_EVENT*/,
				       Event ev5 /*= NO_EVENT*/, Event ev6 /*= NO_EVENT*/)
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    return GenEventImpl::merge_events(ev1, ev2, ev3, ev4, ev5, ev6);
  }

  class EventTriggeredCondition {
  public:
    EventTriggeredCondition(EventImpl* _event, Event::gen_t _gen);

    class Callback : public EventWaiter {
    public:
      virtual ~Callback(void);
      virtual bool event_triggered(void);
      virtual void print_info(FILE *f);
      virtual void operator()(void) = 0;
    };

    void add_callback(Callback& cb) const;

  protected:
    EventImpl *event;
    Event::gen_t gen;
  };

  EventTriggeredCondition::EventTriggeredCondition(EventImpl* _event, Event::gen_t _gen)
    : event(_event), gen(_gen)
  {}

  void EventTriggeredCondition::add_callback(Callback& cb) const
  {
    event->add_waiter(gen, &cb);
  }

  EventTriggeredCondition::Callback::~Callback(void)
  {
  }
  
  bool EventTriggeredCondition::Callback::event_triggered(void)
  {
    // call through to the actual callback
    (*this)();
    // we don't manage the memory any more
    return false;
  }

  void EventTriggeredCondition::Callback::print_info(FILE *f)
  {
    fprintf(f, "EventTriggeredCondition (thread unknown)");
  }  

  void Event::wait(void) const
  {
    DetailedTimer::ScopedPush sp(TIME_LOW_LEVEL);
    if(!id) return;  // special case: never wait for NO_EVENT
    EventImpl *e = get_runtime()->get_event_impl(*this);

    // early out case too
    if(e->has_triggered(gen)) return;

    // waiting on an event does not count against the low level's time
    DetailedTimer::ScopedPush sp2(TIME_NONE);

    // all of the stuff below will hopefully get subsumed by this
    Thread *thread = Thread::self();
    if(thread) {
      // describe the condition we want the thread to wait on
      printf("using new-fangled blocking event wait\n");
      thread->wait_for_condition(EventTriggeredCondition(e, gen));
      return;
    }

    // are we a thread that knows how to do something useful while waiting?
    if(PreemptableThread::preemptable_sleep(*this))
      return;

    // maybe a GPU thread?
#ifdef USE_CUDA
    void *ptr = gasnett_threadkey_get(gpu_thread_ptr);
    if(ptr != 0) {
      //assert(0);
      //printf("oh, good - we're a gpu thread - we'll spin for now\n");
      //printf("waiting for " IDFMT "/%d\n", id, gen);
      while(!e->has_triggered(gen)) {
#ifdef __SSE2__
	_mm_pause();
#else
	usleep(1000);
#endif
      }
      //printf("done\n");
      return;
    }
#endif
    // we're probably screwed here - try waiting and polling gasnet while
    //  we wait
    //printf("waiting on event, polling gasnet to hopefully not die\n");
    while(!e->has_triggered(gen)) {
      // can't poll here - the GPU DMA code sometimes polls from inside an active
      //  message handler (consider turning polling back on once that's fixed)
      //do_some_polling();
{'fraction_non_alphanumeric': 0.13388611144982318, 'fraction_numerical': 0.007438117302767955, 'mean_word_length': 3.1868300153139355, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2945500', 'n_tokens_mistral': 2585, 'n_tokens_neox': 2495, 'n_words': 761}