ROOT logo
// $Id: Mountain.cxx 2764 2012-06-09 03:17:46Z matevz $

// Copyright (C) 1999-2008, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.

#include "Mountain.h"

#include <Glasses/Eventor.h>
#include <TSystem.h>

//#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <pthread.h>

#ifdef __APPLE__
#define _XOPEN_SOURCE
#endif
#include <ucontext.h>
#include <fenv.h> // requires _GNU_SOURCE to be defined for trap control

class MountainThread : public GThread
{
public:
  MountainThread(const Text_t* name, GThread_foo foo, void* arg=0, bool detached=false) :
    GThread(name, foo, arg, detached),
    fTerminalSignalId(SigUNDEF),
    fInSigLock(false)
  {}
  virtual ~MountainThread() {}

  ucontext_t   fTerminalSignalRetourContext;
  Signal       fTerminalSignalId;

  bool         fInSigLock;
};

ClassImp(Mountain);

/**************************************************************************/
// Rhythm section ... static level
/**************************************************************************/

void Mountain::DancerCooler(DancerInfo* di)
{
  static const Exc_t _eh("Mountain::DancerCooler ");

  ISdebug(1, _eh + GForm("thread exit for %s", di->fEventor->GetName()));

  di->fOpArg->fStop.SetNow();

  GLensWriteHolder wrlck(di->fEventor);

  DancerInfo* rdi = di->fMountain->UnregisterThread(di->fEventor);
  if (di != rdi)
  {
    ISerr(_eh + "mismatch between local and global thread data.");
  }
  di->fEventor->OnExit(di->fOpArg);
  delete di->fOpArg;
  delete di;
}

/**************************************************************************/

namespace
{
  // For signal-safe eventors -- signal handlers for USR1 and USR2.
  // Now we wait USR1 signal handler until USR2 arrives.
  // Could also be done with two contexts and a condition variable.

  void sh_DancerSuspender(GSignal*)
  {
    MountainThread* mt = (MountainThread*) GThread::Self();

    if (mt->fInSigLock)
      return;

    mt->fInSigLock = true;
    do
    {
      GTime::SleepMiliSec(1000000ul, true, false);
    } while (mt->fInSigLock);
  }

  void sh_DancerUnsuspender(GSignal*)
  {
    MountainThread* mt = (MountainThread*) GThread::Self();
    mt->fInSigLock = false;
  }


  // Handler for terminal signals -- if special handling is requested
  // by the Eventor.
  void sh_TerminalSigHandler(GSignal* sig)
  {
    // ucontext_t *sctx = (ucontext_t*) sfoo;

    fprintf(stderr, "Terminal signal handler entered ...\n");

    MountainThread* mt = (MountainThread*) GThread::Self();
    fprintf(stderr, "thread id=%d name='%s' state=%s.\n", mt->GetIndex(), mt->GetName(),
	    GThread::RunningStateName(mt->GetRunningState()));

    switch (sig->fSignal)
    {
      case GThread::SigILL:
	fprintf(stderr, "Illegal instruction.\n");
	break;
      case GThread::SigBUS:
	fprintf(stderr, "Bus error.\n");
	break;
      case GThread::SigSEGV:
	fprintf(stderr, "Segmentation violation.\n");
	break;
      case GThread::SigFPE:
	fprintf(stderr, "Floating-point exception.\n");
	// The bits are not set ... seems trap setting overrides it.
	// {
	//   int foo = fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
	//   printf(" FE: DIVBYZERO=%d, INVALID=%d, OVERFLOW=%d\n", foo & FE_DIVBYZERO, foo & FE_INVALID, foo & FE_OVERFLOW);
	// }
	// Clear excepts - no need.
	break;

      default:
	fprintf(stderr, "Unexpected signal %d\n", sig->fSignal);
	break;
    }

    gSystem->StackTrace();

    mt->fTerminalSignalId = sig->fSignal;

    if (setcontext(&mt->fTerminalSignalRetourContext))
    {
      perror("Mountain -- setcontext failed in signal handler (will exit):");
      gSystem->Exit(sig->fSignal);
    }
  }
}

void* Mountain::DancerBeat(DancerInfo* di)
{
  static const Exc_t _eh("Mountain::DancerBeat ");

  void* err_ret = (void*) 1;

  GThread::SetCancelState(GThread::CS_Enable);
  GThread::SetCancelType(GThread::CT_Async);
  //GThread::SetCancelType(GThread::CT_Deferred);

  { // Signal handle init; only used for SignalSafe threads
    GThread::SetSignalHandler(GThread::SigUSR1, sh_DancerSuspender);
    GThread::SetSignalHandler(GThread::SigUSR2, sh_DancerUnsuspender);
    GThread::UnblockSignal(GThread::SigUSR1);
    GThread::UnblockSignal(GThread::SigUSR2);
  }

  GThread::Self()->SetTerminalPolicy(GThread::TP_ThreadExit);

  Operator::Arg* op_arg;
  {
    GLensWriteHolder wrlck(di->fEventor);
    op_arg = di->fEventor->PreDance();
  }
  if (op_arg == 0) return err_ret;

  di->fThread->CleanupPush((GThread_cu_foo)DancerCooler, di);

  di->fOpArg = op_arg;
  op_arg->fStart.SetNow();
  op_arg->fBeatID = -1;
  {
    GLensWriteHolder wrlck(di->fEventor);
    di->fEventor->OnStart(op_arg);
  }

  {
    if (di->fEventor->GetTrapILL())
    {
      GThread::SetSignalHandler(GThread::SigILL, sh_TerminalSigHandler);
    }

    if (di->fEventor->GetTrapBUS())
    {
      GThread::SetSignalHandler(GThread::SigBUS, sh_TerminalSigHandler);
    }

    if (di->fEventor->GetTrapSEGV())
    {
      GThread::SetSignalHandler(GThread::SigSEGV, sh_TerminalSigHandler);
    }

    if (di->fEventor->GetTrapFPE())
    {
      GThread::SetSignalHandler(GThread::SigFPE, sh_TerminalSigHandler);

      // This is platform dependant.
#ifdef __APPLE__
      fenv_t fe;
      fegetenv(&fe);
#if (defined(__ppc__) || defined(__ppc64__))
      fe |= (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#elif (defined (__i386__) || defined( __x86_64__ ))
      fe.__control |= (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
      fe.__mxcsr   |= (FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#else
#error Unknown architecture
#endif
      fesetenv(&fe);
#else
      feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
#endif
    }

    MountainThread *mt = (MountainThread*) di->fThread;

    if (getcontext(&mt->fTerminalSignalRetourContext))
    {
      perror("getcontext failed:");
      return err_ret;
    }

    if (mt->fTerminalSignalId != GThread::SigUNDEF)
    {
      printf("Strange strange -- who was dead now walks again.\n  The number of his cross was %d and its name %s.\n",
             mt->fTerminalSignalId, GThread::SignalName(mt->fTerminalSignalId));
      int foo = fetestexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
      printf(" FE: DIVBYZERO=%d, INVALID=%d, OVERFLOW=%d\n", foo & FE_DIVBYZERO, foo & FE_INVALID, foo & FE_OVERFLOW);

      di->fEventor->OnTerminalSignal(op_arg, mt->fTerminalSignalId);

      mt->fTerminalSignalId = GThread::SigUNDEF;
    }
  }

  bool exc_p = false, exit_p = false, suspend_p = false;

  if (di->fShouldSuspend)
  {
    // Hack: allows connecting moons to properly initialize multix
    // suspended threads.
    // Time difference is wrong, but this shouldn't matter for multixen.
    op_arg->fBeatStart.SetNow();
    op_arg->fBeatStart -= GTime::MiliSec(di->fEventor->GetInterBeatMS() / 2);
    goto suspend_exit_check;
  }

  while (true)
  {
    exc_p = exit_p = suspend_p = false;

    op_arg->fBeatStart.SetNow();
    ++op_arg->fBeatID;
    try
    {
      {
	GLensWriteHolder wrlck(di->fEventor);
	di->fEventor->PreBeat(op_arg);
      }
      // Operate this the only method NOT called with write lock.
      di->fEventor->Operate(op_arg);
      {
	GLensWriteHolder wrlck(di->fEventor);
	di->fEventor->PostBeat(op_arg);
      }
    }
    catch (Operator::Exception& op_exc)
    {
      exc_p = true;

      switch (op_exc.fExc)
      {
        case Operator::OE_Done:
        {
          GLensWriteHolder wrlck(di->fEventor);
          di->fEventor->PostDance(op_arg);
          exit_p = true;
          break;
        }
        case Operator::OE_Continue:
        {
          GLensWriteHolder wrlck(di->fEventor);
          di->fEventor->OnContinue(op_arg, op_exc);
          break;
        }
        case Operator::OE_Wait:
        {
          GLensWriteHolder wrlck(di->fEventor);
          di->fEventor->OnWait(op_arg, op_exc);
          suspend_p = true;
          break;
        }
        case Operator::OE_Stop:
        {
          GLensWriteHolder wrlck(di->fEventor);
          di->fEventor->OnStop(op_arg, op_exc);
          exit_p = true;
          break;
        }
        case Operator::OE_Break:
        {
          ISerr(_eh + GForm("[%s] Exit with Break", di->fEventor->GetName()));
          GLensWriteHolder wrlck(di->fEventor);
          di->fEventor->OnBreak(op_arg, op_exc);
          exit_p = true;
          break;
        }
      }
    }
    catch (Exc_t& exc)
    {
      exc_p = true;
      ISerr(_eh + GForm("[%s] Unhandled exception, breaking event loop, Exc_t: '%s'",
                        di->fEventor->GetName(), exc.Data()));
      GLensWriteHolder wrlck(di->fEventor);
      di->fEventor->OnBreak(op_arg, exc);
      exit_p = true;
    }
    catch (exception& exc)
    {
      exc_p = true;
      ISerr(_eh + GForm("[%s] Unhandled exception, breaking event loop, std::exception: '%s'",
                        di->fEventor->GetName(), exc.what()));
      GLensWriteHolder wrlck(di->fEventor);
      di->fEventor->OnBreak(op_arg, exc.what());
      exit_p = true;
    }
    catch (...)
    {
      exc_p = true;
      ISerr(_eh + GForm("[%s] Unhandled unknown exception, breaking event loop.",
                        di->fEventor->GetName()));
      GLensWriteHolder wrlck(di->fEventor);
      di->fEventor->OnBreak(op_arg, "");
      exit_p = true;
      throw;
    }

    op_arg->fBeatStop.SetNow();
    op_arg->fBeatSum += op_arg->fBeatStop - op_arg->fBeatStart;
    if (!exc_p && !op_arg->fContinuous)
    {
      GLensWriteHolder wrlck(di->fEventor);
      di->fEventor->PostDance(op_arg);
      exit_p = true;
    }

  suspend_exit_check:
    di->fOpArg->fSuspendidor.Lock();
    if (exit_p || di->fShouldExit)
    {
      di->fOpArg->fSuspendidor.Unlock();
      return 0;
    }

    if (suspend_p || di->fShouldSuspend)
    {
      di->fEventor->OnSuspend(op_arg);
      di->fSuspended = true;
      if (op_arg->fSignalSafe)
      {
	di->fOpArg->fSuspendidor.Unlock();
	di->fThread->Kill(GThread::SigUSR1);
      } else {
	di->fOpArg->fSuspendidor.Wait();
	di->fOpArg->fSuspendidor.Unlock();
      }
      // Check again for exit during suspend
      if (di->fShouldExit)
      {
	return 0;
      }
    }
    else
    {
      di->fOpArg->fSuspendidor.Unlock();
    }

    GTime since_start(GTime::I_Now);
    since_start -= op_arg->fBeatStart;

    Int_t sleep_time = di->fEventor->GetInterBeatMS() - since_start.ToMiliSec();
    if (sleep_time > 0)
    {
      if (op_arg->fSignalSafe)
      {
	gSystem->Sleep(UInt_t(sleep_time));
      }
      else
      {
	di->fOpArg->fSuspendidor.Lock();
	di->fSleeping = true;
	int timed_out = di->fOpArg->fSuspendidor.TimedWait(GTime::MiliSec(sleep_time));
	di->fSleeping = false;
	di->fOpArg->fSuspendidor.Unlock();
	if (!timed_out)
        {
	  goto suspend_exit_check;
	}
      }
    }
  } // end forever

  ISerr(_eh + "Got to the end of function ... not expected to end here.");
  return err_ret;
}

/**************************************************************************/
// Rhythm section ... Mountain<->Eventor interface
/**************************************************************************/

void Mountain::Start(Eventor* e, bool suspend_immediately)
{
  static const Exc_t _eh("Mountain::Start ");

  if (bInSuspend)
  {
    // !!! should use mutex ... rethink suspend all !!!
    // In fact ... should add it to on stage w/ fThread=0 ...
    ISerr(_eh + "Mountain suspended, stalling.");
    return;
  }

  hStageLock.Lock();
  if(hOnStage.find(e) != hOnStage.end()) {
    hStageLock.Unlock();
    ISerr(_eh + "Thread of " + e->GetName() + " already alive.");
    return;
  }

  GThread* t = new MountainThread("Mountain-DancerBeat",
				  (GThread_foo) DancerBeat, 0,
				  true);
  DancerInfo* di = new DancerInfo(t, e, this);
  hOnStage[e] = di;
  t->SetStartArg((void*) di);
  hStageLock.Unlock();

  if (suspend_immediately) di->fShouldSuspend = true;
  t->Spawn();
}

/**************************************************************************/

void Mountain::stop_thread(DancerInfo* di)
{
  di->fOpArg->fSuspendidor.Lock();
  if(di->fOpArg->fSignalSafe) {
    if(di->fSuspended) {
      di->fShouldExit = true;
      di->fThread->Kill(GThread::SigUSR2);
    } else {
      di->fOpArg->fSignalodor.Lock();
      di->fThread->Cancel();
      di->fOpArg->fSignalodor.Unlock();
    }
  } else {
    di->fShouldExit = true;
    if(di->fSuspended || di->fSleeping) {
      di->fOpArg->fSuspendidor.Signal();
    }
  }
  di->fOpArg->fSuspendidor.Unlock();
}

void Mountain::Stop(Eventor* e)
{
  hStageLock.Lock();
  hEv2DI_i i = hOnStage.find(e);
  if(i == hOnStage.end() || i->second==0) {
    hStageLock.Unlock();
    ISerr(GForm("Mountain::Stop ... can't find thread of %s",
		e->GetName()));
    return;
  }
  DancerInfo* di = i->second;
  hStageLock.Unlock();

  stop_thread(di);
}

void Mountain::Suspend(Eventor* e)
{
  hStageLock.Lock();
  hEv2DI_i i = hOnStage.find(e);
  if(i == hOnStage.end() || i->second==0) {
    hStageLock.Unlock();
    ISerr(GForm("Mountain::Suspend ... can't find thread of %s",
		e->GetName()));
    return;
  }
  hStageLock.Unlock();

  DancerInfo* di = i->second;
  di->fOpArg->fSuspendidor.Lock();
  if(di->fOpArg->fSignalSafe) {
    di->fOpArg->fSignalodor.Lock();
    di->fThread->Kill(GThread::SigUSR1);
    di->fOpArg->fSignalodor.Unlock();
    di->fEventor->OnSuspend(di->fOpArg);
    di->fSuspended = true;
  } else {
    di->fShouldSuspend = true;
    if(di->fSleeping) {
      di->fOpArg->fSuspendidor.Signal();
    }
  }
  di->fOpArg->fSuspendidor.Unlock();
}

void Mountain::Resume(Eventor* e)
{
  hStageLock.Lock();
  hEv2DI_i i = hOnStage.find(e);
  if(i == hOnStage.end() || i->second==0) {
    hStageLock.Unlock();
    ISerr(GForm("Mountain::Resume ... can't find thread of %s",
		e->GetName()));
    return;
  }
  hStageLock.Unlock();

  DancerInfo* di = i->second;
  di->fOpArg->fSuspendidor.Lock();
  di->fSuspended = false;
  di->fShouldSuspend = false;
  di->fEventor->OnResume(di->fOpArg);
  if(di->fOpArg->fSignalSafe) {
    di->fThread->Kill(GThread::SigUSR2);
  } else {
    di->fOpArg->fSuspendidor.Signal();
  }
  di->fOpArg->fSuspendidor.Unlock();
}

void Mountain::Cancel(Eventor* e)
{
  hStageLock.Lock();
  hEv2DI_i i = hOnStage.find(e);
  if(i == hOnStage.end() || i->second==0) {
    hStageLock.Unlock();
    ISerr(GForm("Mountain::Cancel ... can't find thread of %s",
		e->GetName()));
    return;
  }
  DancerInfo* di = i->second;
  hStageLock.Unlock();

  di->fThread->Cancel();
}

/**************************************************************************/

DancerInfo* Mountain::UnregisterThread(Eventor* e)
{
  static const Exc_t _eh("Mountain::UnregisterThread ");

  GMutexHolder stg_lck(hStageLock);
  hEv2DI_i i = hOnStage.find(e);
  if(i == hOnStage.end() || i->second==0) {
    ISerr(_eh + GForm("thread of %s not found.", e->GetName()));
    return 0;
  }
  DancerInfo* ret = i->second;
  hOnStage.erase(i);
  return ret;
}

void Mountain::WipeThread(Eventor* e)
{
  DancerInfo* di = UnregisterThread(e);
  delete di;
}

/**************************************************************************/
// Suspending
/**************************************************************************/

Int_t Mountain::SuspendAll()
{
  // Tries to suspend all operators ...
  // fails miserably if some threads have longer periods ... should timeout!!!!
  //
  // Also ... this is not entirely appropriate.
  // Should have per-queen list of threads ... ie dancers.
  // For each of them should also know in what way it affects other structures.

  hSuspendCond.Lock(); // unlocked in resume all
  hSuspendCount = 0;
  bInSuspend = true;
  UInt_t n;
  hStageLock.Lock(); n = hOnStage.size(); hStageLock.Unlock();
  if (n == 0)
  {
    //hSuspendCond.Unlock();
    return 0;
  }
  do
  {
    int ws = hSuspendCond.TimedWait(GTime::MiliSec(5));
    if (ws == 0) hSuspendCount++;
    hStageLock.Lock(); n = hOnStage.size(); hStageLock.Unlock();
    if (ws && hSuspendCount < n)
    {
      ISerr("Mountain::SuspendAll timed out ... stalling");
      //hSuspendCond.Unlock();
      return 1;
    }
  } while(hSuspendCount < n);
  ISmess(GForm("Mountain::SuspendAll success ... %d threads SIGSUSP-ed",
	       hSuspendCount));
  //hSuspendCond.Unlock();
  return 0;
}

void Mountain::ResumeAll()
{
  if(bInSuspend==false) return;
  bInSuspend = false;
  hStageLock.Lock();
  for(hEv2DI_i i=hOnStage.begin(); i!=hOnStage.end(); i++) {
    hSuspendCount--;
    if(i->second->fSuspended) {
      ISmess(GForm("Mountain::RestartAll restarting thread of %s",
		   i->second->fEventor->GetName()));
      i->second->fSuspended = false;
      i->second->fThread->Kill(GThread::SigUSR2);
    }
  }
  hStageLock.Unlock();
  hSuspendCond.Unlock();
}

void Mountain::ConsiderSuspend(DancerInfo* di)
{
  // Called from each DancerBeat ... like offering the mountain to suspend it

  if(bInSuspend) {
    hSuspendCond.Lock(); hSuspendCond.Signal(); hSuspendCond.Unlock();
    ISmess(GForm("Mountain::ConsiderSuspend suspending thread of %s",
		 di->fEventor->GetName()));
    di->fSuspended = true;
    di->fThread->Kill(GThread::SigUSR1);
  }
}

/**************************************************************************/

void Mountain::Shutdown()
{
  // Called from Saturn on shutdown. Kills all threads.

  hStageLock.Lock();
  if(hOnStage.size() == 0) {
    hStageLock.Unlock();
    return;
  }
  for(hEv2DI_i i=hOnStage.begin(); i!=hOnStage.end(); ++i) {
    stop_thread(i->second);
  }
  hStageLock.Unlock();

  int  count = 0;
  while(1) {
    gSystem->Sleep(100);
    hStageLock.Lock();
    int n = hOnStage.size();
    if(n > 0 && count > 10) {
      for(hEv2DI_i i=hOnStage.begin(); i!=hOnStage.end(); ++i) {
	i->second->fThread->Cancel();
      }
    }
    hStageLock.Unlock();
    if(n == 0) break;
    ISmess(GForm("Mountain::Shutdown waiting for %d threads", n));
    ++count;
  }
  ISmess("Mountain::Shutdown all threads stopped");
}
 Mountain.cxx:1
 Mountain.cxx:2
 Mountain.cxx:3
 Mountain.cxx:4
 Mountain.cxx:5
 Mountain.cxx:6
 Mountain.cxx:7
 Mountain.cxx:8
 Mountain.cxx:9
 Mountain.cxx:10
 Mountain.cxx:11
 Mountain.cxx:12
 Mountain.cxx:13
 Mountain.cxx:14
 Mountain.cxx:15
 Mountain.cxx:16
 Mountain.cxx:17
 Mountain.cxx:18
 Mountain.cxx:19
 Mountain.cxx:20
 Mountain.cxx:21
 Mountain.cxx:22
 Mountain.cxx:23
 Mountain.cxx:24
 Mountain.cxx:25
 Mountain.cxx:26
 Mountain.cxx:27
 Mountain.cxx:28
 Mountain.cxx:29
 Mountain.cxx:30
 Mountain.cxx:31
 Mountain.cxx:32
 Mountain.cxx:33
 Mountain.cxx:34
 Mountain.cxx:35
 Mountain.cxx:36
 Mountain.cxx:37
 Mountain.cxx:38
 Mountain.cxx:39
 Mountain.cxx:40
 Mountain.cxx:41
 Mountain.cxx:42
 Mountain.cxx:43
 Mountain.cxx:44
 Mountain.cxx:45
 Mountain.cxx:46
 Mountain.cxx:47
 Mountain.cxx:48
 Mountain.cxx:49
 Mountain.cxx:50
 Mountain.cxx:51
 Mountain.cxx:52
 Mountain.cxx:53
 Mountain.cxx:54
 Mountain.cxx:55
 Mountain.cxx:56
 Mountain.cxx:57
 Mountain.cxx:58
 Mountain.cxx:59
 Mountain.cxx:60
 Mountain.cxx:61
 Mountain.cxx:62
 Mountain.cxx:63
 Mountain.cxx:64
 Mountain.cxx:65
 Mountain.cxx:66
 Mountain.cxx:67
 Mountain.cxx:68
 Mountain.cxx:69
 Mountain.cxx:70
 Mountain.cxx:71
 Mountain.cxx:72
 Mountain.cxx:73
 Mountain.cxx:74
 Mountain.cxx:75
 Mountain.cxx:76
 Mountain.cxx:77
 Mountain.cxx:78
 Mountain.cxx:79
 Mountain.cxx:80
 Mountain.cxx:81
 Mountain.cxx:82
 Mountain.cxx:83
 Mountain.cxx:84
 Mountain.cxx:85
 Mountain.cxx:86
 Mountain.cxx:87
 Mountain.cxx:88
 Mountain.cxx:89
 Mountain.cxx:90
 Mountain.cxx:91
 Mountain.cxx:92
 Mountain.cxx:93
 Mountain.cxx:94
 Mountain.cxx:95
 Mountain.cxx:96
 Mountain.cxx:97
 Mountain.cxx:98
 Mountain.cxx:99
 Mountain.cxx:100
 Mountain.cxx:101
 Mountain.cxx:102
 Mountain.cxx:103
 Mountain.cxx:104
 Mountain.cxx:105
 Mountain.cxx:106
 Mountain.cxx:107
 Mountain.cxx:108
 Mountain.cxx:109
 Mountain.cxx:110
 Mountain.cxx:111
 Mountain.cxx:112
 Mountain.cxx:113
 Mountain.cxx:114
 Mountain.cxx:115
 Mountain.cxx:116
 Mountain.cxx:117
 Mountain.cxx:118
 Mountain.cxx:119
 Mountain.cxx:120
 Mountain.cxx:121
 Mountain.cxx:122
 Mountain.cxx:123
 Mountain.cxx:124
 Mountain.cxx:125
 Mountain.cxx:126
 Mountain.cxx:127
 Mountain.cxx:128
 Mountain.cxx:129
 Mountain.cxx:130
 Mountain.cxx:131
 Mountain.cxx:132
 Mountain.cxx:133
 Mountain.cxx:134
 Mountain.cxx:135
 Mountain.cxx:136
 Mountain.cxx:137
 Mountain.cxx:138
 Mountain.cxx:139
 Mountain.cxx:140
 Mountain.cxx:141
 Mountain.cxx:142
 Mountain.cxx:143
 Mountain.cxx:144
 Mountain.cxx:145
 Mountain.cxx:146
 Mountain.cxx:147
 Mountain.cxx:148
 Mountain.cxx:149
 Mountain.cxx:150
 Mountain.cxx:151
 Mountain.cxx:152
 Mountain.cxx:153
 Mountain.cxx:154
 Mountain.cxx:155
 Mountain.cxx:156
 Mountain.cxx:157
 Mountain.cxx:158
 Mountain.cxx:159
 Mountain.cxx:160
 Mountain.cxx:161
 Mountain.cxx:162
 Mountain.cxx:163
 Mountain.cxx:164
 Mountain.cxx:165
 Mountain.cxx:166
 Mountain.cxx:167
 Mountain.cxx:168
 Mountain.cxx:169
 Mountain.cxx:170
 Mountain.cxx:171
 Mountain.cxx:172
 Mountain.cxx:173
 Mountain.cxx:174
 Mountain.cxx:175
 Mountain.cxx:176
 Mountain.cxx:177
 Mountain.cxx:178
 Mountain.cxx:179
 Mountain.cxx:180
 Mountain.cxx:181
 Mountain.cxx:182
 Mountain.cxx:183
 Mountain.cxx:184
 Mountain.cxx:185
 Mountain.cxx:186
 Mountain.cxx:187
 Mountain.cxx:188
 Mountain.cxx:189
 Mountain.cxx:190
 Mountain.cxx:191
 Mountain.cxx:192
 Mountain.cxx:193
 Mountain.cxx:194
 Mountain.cxx:195
 Mountain.cxx:196
 Mountain.cxx:197
 Mountain.cxx:198
 Mountain.cxx:199
 Mountain.cxx:200
 Mountain.cxx:201
 Mountain.cxx:202
 Mountain.cxx:203
 Mountain.cxx:204
 Mountain.cxx:205
 Mountain.cxx:206
 Mountain.cxx:207
 Mountain.cxx:208
 Mountain.cxx:209
 Mountain.cxx:210
 Mountain.cxx:211
 Mountain.cxx:212
 Mountain.cxx:213
 Mountain.cxx:214
 Mountain.cxx:215
 Mountain.cxx:216
 Mountain.cxx:217
 Mountain.cxx:218
 Mountain.cxx:219
 Mountain.cxx:220
 Mountain.cxx:221
 Mountain.cxx:222
 Mountain.cxx:223
 Mountain.cxx:224
 Mountain.cxx:225
 Mountain.cxx:226
 Mountain.cxx:227
 Mountain.cxx:228
 Mountain.cxx:229
 Mountain.cxx:230
 Mountain.cxx:231
 Mountain.cxx:232
 Mountain.cxx:233
 Mountain.cxx:234
 Mountain.cxx:235
 Mountain.cxx:236
 Mountain.cxx:237
 Mountain.cxx:238
 Mountain.cxx:239
 Mountain.cxx:240
 Mountain.cxx:241
 Mountain.cxx:242
 Mountain.cxx:243
 Mountain.cxx:244
 Mountain.cxx:245
 Mountain.cxx:246
 Mountain.cxx:247
 Mountain.cxx:248
 Mountain.cxx:249
 Mountain.cxx:250
 Mountain.cxx:251
 Mountain.cxx:252
 Mountain.cxx:253
 Mountain.cxx:254
 Mountain.cxx:255
 Mountain.cxx:256
 Mountain.cxx:257
 Mountain.cxx:258
 Mountain.cxx:259
 Mountain.cxx:260
 Mountain.cxx:261
 Mountain.cxx:262
 Mountain.cxx:263
 Mountain.cxx:264
 Mountain.cxx:265
 Mountain.cxx:266
 Mountain.cxx:267
 Mountain.cxx:268
 Mountain.cxx:269
 Mountain.cxx:270
 Mountain.cxx:271
 Mountain.cxx:272
 Mountain.cxx:273
 Mountain.cxx:274
 Mountain.cxx:275
 Mountain.cxx:276
 Mountain.cxx:277
 Mountain.cxx:278
 Mountain.cxx:279
 Mountain.cxx:280
 Mountain.cxx:281
 Mountain.cxx:282
 Mountain.cxx:283
 Mountain.cxx:284
 Mountain.cxx:285
 Mountain.cxx:286
 Mountain.cxx:287
 Mountain.cxx:288
 Mountain.cxx:289
 Mountain.cxx:290
 Mountain.cxx:291
 Mountain.cxx:292
 Mountain.cxx:293
 Mountain.cxx:294
 Mountain.cxx:295
 Mountain.cxx:296
 Mountain.cxx:297
 Mountain.cxx:298
 Mountain.cxx:299
 Mountain.cxx:300
 Mountain.cxx:301
 Mountain.cxx:302
 Mountain.cxx:303
 Mountain.cxx:304
 Mountain.cxx:305
 Mountain.cxx:306
 Mountain.cxx:307
 Mountain.cxx:308
 Mountain.cxx:309
 Mountain.cxx:310
 Mountain.cxx:311
 Mountain.cxx:312
 Mountain.cxx:313
 Mountain.cxx:314
 Mountain.cxx:315
 Mountain.cxx:316
 Mountain.cxx:317
 Mountain.cxx:318
 Mountain.cxx:319
 Mountain.cxx:320
 Mountain.cxx:321
 Mountain.cxx:322
 Mountain.cxx:323
 Mountain.cxx:324
 Mountain.cxx:325
 Mountain.cxx:326
 Mountain.cxx:327
 Mountain.cxx:328
 Mountain.cxx:329
 Mountain.cxx:330
 Mountain.cxx:331
 Mountain.cxx:332
 Mountain.cxx:333
 Mountain.cxx:334
 Mountain.cxx:335
 Mountain.cxx:336
 Mountain.cxx:337
 Mountain.cxx:338
 Mountain.cxx:339
 Mountain.cxx:340
 Mountain.cxx:341
 Mountain.cxx:342
 Mountain.cxx:343
 Mountain.cxx:344
 Mountain.cxx:345
 Mountain.cxx:346
 Mountain.cxx:347
 Mountain.cxx:348
 Mountain.cxx:349
 Mountain.cxx:350
 Mountain.cxx:351
 Mountain.cxx:352
 Mountain.cxx:353
 Mountain.cxx:354
 Mountain.cxx:355
 Mountain.cxx:356
 Mountain.cxx:357
 Mountain.cxx:358
 Mountain.cxx:359
 Mountain.cxx:360
 Mountain.cxx:361
 Mountain.cxx:362
 Mountain.cxx:363
 Mountain.cxx:364
 Mountain.cxx:365
 Mountain.cxx:366
 Mountain.cxx:367
 Mountain.cxx:368
 Mountain.cxx:369
 Mountain.cxx:370
 Mountain.cxx:371
 Mountain.cxx:372
 Mountain.cxx:373
 Mountain.cxx:374
 Mountain.cxx:375
 Mountain.cxx:376
 Mountain.cxx:377
 Mountain.cxx:378
 Mountain.cxx:379
 Mountain.cxx:380
 Mountain.cxx:381
 Mountain.cxx:382
 Mountain.cxx:383
 Mountain.cxx:384
 Mountain.cxx:385
 Mountain.cxx:386
 Mountain.cxx:387
 Mountain.cxx:388
 Mountain.cxx:389
 Mountain.cxx:390
 Mountain.cxx:391
 Mountain.cxx:392
 Mountain.cxx:393
 Mountain.cxx:394
 Mountain.cxx:395
 Mountain.cxx:396
 Mountain.cxx:397
 Mountain.cxx:398
 Mountain.cxx:399
 Mountain.cxx:400
 Mountain.cxx:401
 Mountain.cxx:402
 Mountain.cxx:403
 Mountain.cxx:404
 Mountain.cxx:405
 Mountain.cxx:406
 Mountain.cxx:407
 Mountain.cxx:408
 Mountain.cxx:409
 Mountain.cxx:410
 Mountain.cxx:411
 Mountain.cxx:412
 Mountain.cxx:413
 Mountain.cxx:414
 Mountain.cxx:415
 Mountain.cxx:416
 Mountain.cxx:417
 Mountain.cxx:418
 Mountain.cxx:419
 Mountain.cxx:420
 Mountain.cxx:421
 Mountain.cxx:422
 Mountain.cxx:423
 Mountain.cxx:424
 Mountain.cxx:425
 Mountain.cxx:426
 Mountain.cxx:427
 Mountain.cxx:428
 Mountain.cxx:429
 Mountain.cxx:430
 Mountain.cxx:431
 Mountain.cxx:432
 Mountain.cxx:433
 Mountain.cxx:434
 Mountain.cxx:435
 Mountain.cxx:436
 Mountain.cxx:437
 Mountain.cxx:438
 Mountain.cxx:439
 Mountain.cxx:440
 Mountain.cxx:441
 Mountain.cxx:442
 Mountain.cxx:443
 Mountain.cxx:444
 Mountain.cxx:445
 Mountain.cxx:446
 Mountain.cxx:447
 Mountain.cxx:448
 Mountain.cxx:449
 Mountain.cxx:450
 Mountain.cxx:451
 Mountain.cxx:452
 Mountain.cxx:453
 Mountain.cxx:454
 Mountain.cxx:455
 Mountain.cxx:456
 Mountain.cxx:457
 Mountain.cxx:458
 Mountain.cxx:459
 Mountain.cxx:460
 Mountain.cxx:461
 Mountain.cxx:462
 Mountain.cxx:463
 Mountain.cxx:464
 Mountain.cxx:465
 Mountain.cxx:466
 Mountain.cxx:467
 Mountain.cxx:468
 Mountain.cxx:469
 Mountain.cxx:470
 Mountain.cxx:471
 Mountain.cxx:472
 Mountain.cxx:473
 Mountain.cxx:474
 Mountain.cxx:475
 Mountain.cxx:476
 Mountain.cxx:477
 Mountain.cxx:478
 Mountain.cxx:479
 Mountain.cxx:480
 Mountain.cxx:481
 Mountain.cxx:482
 Mountain.cxx:483
 Mountain.cxx:484
 Mountain.cxx:485
 Mountain.cxx:486
 Mountain.cxx:487
 Mountain.cxx:488
 Mountain.cxx:489
 Mountain.cxx:490
 Mountain.cxx:491
 Mountain.cxx:492
 Mountain.cxx:493
 Mountain.cxx:494
 Mountain.cxx:495
 Mountain.cxx:496
 Mountain.cxx:497
 Mountain.cxx:498
 Mountain.cxx:499
 Mountain.cxx:500
 Mountain.cxx:501
 Mountain.cxx:502
 Mountain.cxx:503
 Mountain.cxx:504
 Mountain.cxx:505
 Mountain.cxx:506
 Mountain.cxx:507
 Mountain.cxx:508
 Mountain.cxx:509
 Mountain.cxx:510
 Mountain.cxx:511
 Mountain.cxx:512
 Mountain.cxx:513
 Mountain.cxx:514
 Mountain.cxx:515
 Mountain.cxx:516
 Mountain.cxx:517
 Mountain.cxx:518
 Mountain.cxx:519
 Mountain.cxx:520
 Mountain.cxx:521
 Mountain.cxx:522
 Mountain.cxx:523
 Mountain.cxx:524
 Mountain.cxx:525
 Mountain.cxx:526
 Mountain.cxx:527
 Mountain.cxx:528
 Mountain.cxx:529
 Mountain.cxx:530
 Mountain.cxx:531
 Mountain.cxx:532
 Mountain.cxx:533
 Mountain.cxx:534
 Mountain.cxx:535
 Mountain.cxx:536
 Mountain.cxx:537
 Mountain.cxx:538
 Mountain.cxx:539
 Mountain.cxx:540
 Mountain.cxx:541
 Mountain.cxx:542
 Mountain.cxx:543
 Mountain.cxx:544
 Mountain.cxx:545
 Mountain.cxx:546
 Mountain.cxx:547
 Mountain.cxx:548
 Mountain.cxx:549
 Mountain.cxx:550
 Mountain.cxx:551
 Mountain.cxx:552
 Mountain.cxx:553
 Mountain.cxx:554
 Mountain.cxx:555
 Mountain.cxx:556
 Mountain.cxx:557
 Mountain.cxx:558
 Mountain.cxx:559
 Mountain.cxx:560
 Mountain.cxx:561
 Mountain.cxx:562
 Mountain.cxx:563
 Mountain.cxx:564
 Mountain.cxx:565
 Mountain.cxx:566
 Mountain.cxx:567
 Mountain.cxx:568
 Mountain.cxx:569
 Mountain.cxx:570
 Mountain.cxx:571
 Mountain.cxx:572
 Mountain.cxx:573
 Mountain.cxx:574
 Mountain.cxx:575
 Mountain.cxx:576
 Mountain.cxx:577
 Mountain.cxx:578
 Mountain.cxx:579
 Mountain.cxx:580
 Mountain.cxx:581
 Mountain.cxx:582
 Mountain.cxx:583
 Mountain.cxx:584
 Mountain.cxx:585
 Mountain.cxx:586
 Mountain.cxx:587
 Mountain.cxx:588
 Mountain.cxx:589
 Mountain.cxx:590
 Mountain.cxx:591
 Mountain.cxx:592
 Mountain.cxx:593
 Mountain.cxx:594
 Mountain.cxx:595
 Mountain.cxx:596
 Mountain.cxx:597
 Mountain.cxx:598
 Mountain.cxx:599
 Mountain.cxx:600
 Mountain.cxx:601
 Mountain.cxx:602
 Mountain.cxx:603
 Mountain.cxx:604
 Mountain.cxx:605
 Mountain.cxx:606
 Mountain.cxx:607
 Mountain.cxx:608
 Mountain.cxx:609
 Mountain.cxx:610
 Mountain.cxx:611
 Mountain.cxx:612
 Mountain.cxx:613
 Mountain.cxx:614
 Mountain.cxx:615
 Mountain.cxx:616
 Mountain.cxx:617
 Mountain.cxx:618
 Mountain.cxx:619
 Mountain.cxx:620
 Mountain.cxx:621
 Mountain.cxx:622
 Mountain.cxx:623
 Mountain.cxx:624
 Mountain.cxx:625
 Mountain.cxx:626
 Mountain.cxx:627
 Mountain.cxx:628
 Mountain.cxx:629
 Mountain.cxx:630
 Mountain.cxx:631
 Mountain.cxx:632
 Mountain.cxx:633
 Mountain.cxx:634
 Mountain.cxx:635
 Mountain.cxx:636
 Mountain.cxx:637
 Mountain.cxx:638
 Mountain.cxx:639
 Mountain.cxx:640
 Mountain.cxx:641
 Mountain.cxx:642
 Mountain.cxx:643
 Mountain.cxx:644
 Mountain.cxx:645
 Mountain.cxx:646
 Mountain.cxx:647
 Mountain.cxx:648
 Mountain.cxx:649
 Mountain.cxx:650
 Mountain.cxx:651
 Mountain.cxx:652
 Mountain.cxx:653
 Mountain.cxx:654
 Mountain.cxx:655
 Mountain.cxx:656
 Mountain.cxx:657
 Mountain.cxx:658
 Mountain.cxx:659
 Mountain.cxx:660
 Mountain.cxx:661
 Mountain.cxx:662
 Mountain.cxx:663
 Mountain.cxx:664
 Mountain.cxx:665
 Mountain.cxx:666
 Mountain.cxx:667
 Mountain.cxx:668
 Mountain.cxx:669
 Mountain.cxx:670
 Mountain.cxx:671
 Mountain.cxx:672
 Mountain.cxx:673
 Mountain.cxx:674
 Mountain.cxx:675
 Mountain.cxx:676
 Mountain.cxx:677
 Mountain.cxx:678
 Mountain.cxx:679
 Mountain.cxx:680
 Mountain.cxx:681
 Mountain.cxx:682