<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <unistd.h>

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>

#include "../../cvmfs/encrypt.h"
#include "../../cvmfs/hash.h"
#include "../../cvmfs/util.h"
#include "testutil.h"

using namespace std;  // NOLINT

namespace cipher {

TEST(T_Encrypt, Entropy) {
  // Enough entropy for 100,000 256 bit keys?
  for (unsigned i = 0; i < 100000; ++i) {
    UniquePtr<Key> k(Key::CreateRandomly(32));
    ASSERT_TRUE(k.IsValid());
  }
}

TEST(T_Encrypt, KeyFiles) {
  CipherNone cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());

  string tmp_path;
  FILE *f = CreateTempFile("./key", 0600, "w+", &tmp_path);
  ASSERT_TRUE(f != NULL);
  fclose(f);
  EXPECT_FALSE(k->SaveToFile("/no/such/file"));
  EXPECT_TRUE(k->SaveToFile(tmp_path));

  UniquePtr<Key> k_restore1(Key::CreateFromFile(tmp_path));
  ASSERT_TRUE(k_restore1.IsValid());
  EXPECT_EQ(k->size(), k_restore1->size());
  EXPECT_EQ( 0, memcmp(k->data(), k_restore1->data(),
                       std::min(k->size(), k_restore1->size())) );

  EXPECT_EQ(0, truncate(tmp_path.c_str(), 0));
  UniquePtr<Key> k_restore2(Key::CreateFromFile(tmp_path));
  EXPECT_FALSE(k_restore2.IsValid());

  unlink(tmp_path.c_str());
  UniquePtr<Key> k_restore3(Key::CreateFromFile(tmp_path));
  EXPECT_FALSE(k_restore3.IsValid());
}

TEST(T_Encrypt, KeyStrings) {
  UniquePtr<Key> k_invalid_small(Key::CreateFromString(""));
  EXPECT_FALSE(k_invalid_small.IsValid());
  UniquePtr<Key> k_invalid_big(
    Key::CreateFromString(string(Key::kMaxSize + 1, 'X')));
  EXPECT_FALSE(k_invalid_big.IsValid());
  UniquePtr<Key> k_max_size(
    Key::CreateFromString(string(Key::kMaxSize, 'X')));
  EXPECT_TRUE(k_max_size.IsValid());

  string secret = "This is a secret";
  UniquePtr<Key> k(Key::CreateFromString(secret));
  ASSERT_TRUE(k.IsValid());
  EXPECT_EQ(k->ToBase64(), Base64(secret));
}

TEST(T_Encrypt, MemoryKeyDatabase) {
  MemoryKeyDatabase database;
  UniquePtr<Key> k(Key::CreateRandomly(32));
  string id;
  EXPECT_TRUE(database.StoreNew(k.weak_ref(), &id));
  EXPECT_FALSE(database.StoreNew(k.weak_ref(), &id));
  EXPECT_EQ(NULL, database.Find("not available"));
  const Key *found = database.Find(id);
  EXPECT_EQ(k.weak_ref(), found);
}

TEST(T_Encrypt, DecryptWrongEnvelope) {
  CipherNone cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());
  UniquePtr<Key> k_bad(Key::CreateRandomly(1));
  ASSERT_TRUE(k_bad.IsValid());

  string ciphertext;
  string plaintext;
  int retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_FALSE(retval);

  ciphertext = "X";
  ciphertext[0] = 0xF0;
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_FALSE(retval);
  ciphertext[0] = 0x0F;
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_FALSE(retval);

  ciphertext[0] = cipher.algorithm() << 4;
  retval = Cipher::Decrypt(ciphertext, *k_bad, &plaintext);
  EXPECT_FALSE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
}

TEST(T_Encrypt, None) {
  CipherNone cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());

  string empty;
  string dummy = "Hello, World!";
  string ciphertext;
  string plaintext;
  bool retval;

  retval = cipher.Encrypt(empty, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(empty, plaintext);

  retval = cipher.Encrypt(dummy, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(dummy, plaintext);
}

TEST(T_Encrypt, Aes_256_Cbc) {
  CipherAes256Cbc cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());

  string empty;
  string dummy = "Hello, World!";
  string ciphertext;
  string ciphertext_two;
  string plaintext;
  bool retval;

  retval = cipher.Encrypt(empty, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(empty, plaintext);

  retval = cipher.Encrypt(dummy, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = cipher.Encrypt(dummy, *k, &ciphertext_two);
  EXPECT_TRUE(retval);
  // Initialization vector should differ
  EXPECT_NE(ciphertext, ciphertext_two);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(dummy, plaintext);

  retval = Cipher::Decrypt(ciphertext.substr(0, 1), *k, &plaintext);
  EXPECT_EQ("", plaintext);
  retval = Cipher::Decrypt(ciphertext.substr(0, 1 + cipher.block_size()),
                           *k, &plaintext);
  EXPECT_EQ("", plaintext);
  retval = Cipher::Decrypt(ciphertext.substr(0, ciphertext.length()-1),
                           *k, &plaintext);
  EXPECT_EQ("", plaintext);
}

TEST(T_Encrypt, Aes_256_Cbc_Iv) {
  CipherAes256Cbc cipher;
  UniquePtr<cipher::Key> key(cipher::Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(key.IsValid());
  // Many Iv requests in a short time should still return unique IVs
  shash::Md5 md5;
  for (unsigned i = 0; i < 100000; ++i) {
    shash::Md5 next_iv = cipher.GenerateIv(*key);
    ASSERT_NE(md5, next_iv);
    md5 = next_iv;
  }
}

}  // namespace cipher
<commit_msg>test decryption with wrong key<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <unistd.h>

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>

#include "../../cvmfs/encrypt.h"
#include "../../cvmfs/hash.h"
#include "../../cvmfs/util.h"
#include "testutil.h"

using namespace std;  // NOLINT

namespace cipher {

TEST(T_Encrypt, Entropy) {
  // Enough entropy for 100,000 256 bit keys?
  for (unsigned i = 0; i < 100000; ++i) {
    UniquePtr<Key> k(Key::CreateRandomly(32));
    ASSERT_TRUE(k.IsValid());
  }
}

TEST(T_Encrypt, KeyFiles) {
  CipherNone cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());

  string tmp_path;
  FILE *f = CreateTempFile("./key", 0600, "w+", &tmp_path);
  ASSERT_TRUE(f != NULL);
  fclose(f);
  EXPECT_FALSE(k->SaveToFile("/no/such/file"));
  EXPECT_TRUE(k->SaveToFile(tmp_path));

  UniquePtr<Key> k_restore1(Key::CreateFromFile(tmp_path));
  ASSERT_TRUE(k_restore1.IsValid());
  EXPECT_EQ(k->size(), k_restore1->size());
  EXPECT_EQ( 0, memcmp(k->data(), k_restore1->data(),
                       std::min(k->size(), k_restore1->size())) );

  EXPECT_EQ(0, truncate(tmp_path.c_str(), 0));
  UniquePtr<Key> k_restore2(Key::CreateFromFile(tmp_path));
  EXPECT_FALSE(k_restore2.IsValid());

  unlink(tmp_path.c_str());
  UniquePtr<Key> k_restore3(Key::CreateFromFile(tmp_path));
  EXPECT_FALSE(k_restore3.IsValid());
}

TEST(T_Encrypt, KeyStrings) {
  UniquePtr<Key> k_invalid_small(Key::CreateFromString(""));
  EXPECT_FALSE(k_invalid_small.IsValid());
  UniquePtr<Key> k_invalid_big(
    Key::CreateFromString(string(Key::kMaxSize + 1, 'X')));
  EXPECT_FALSE(k_invalid_big.IsValid());
  UniquePtr<Key> k_max_size(
    Key::CreateFromString(string(Key::kMaxSize, 'X')));
  EXPECT_TRUE(k_max_size.IsValid());

  string secret = "This is a secret";
  UniquePtr<Key> k(Key::CreateFromString(secret));
  ASSERT_TRUE(k.IsValid());
  EXPECT_EQ(k->ToBase64(), Base64(secret));
}

TEST(T_Encrypt, MemoryKeyDatabase) {
  MemoryKeyDatabase database;
  UniquePtr<Key> k(Key::CreateRandomly(32));
  string id;
  EXPECT_TRUE(database.StoreNew(k.weak_ref(), &id));
  EXPECT_FALSE(database.StoreNew(k.weak_ref(), &id));
  EXPECT_EQ(NULL, database.Find("not available"));
  const Key *found = database.Find(id);
  EXPECT_EQ(k.weak_ref(), found);
}

TEST(T_Encrypt, DecryptWrongEnvelope) {
  CipherNone cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());
  UniquePtr<Key> k_bad(Key::CreateRandomly(1));
  ASSERT_TRUE(k_bad.IsValid());

  string ciphertext;
  string plaintext;
  int retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_FALSE(retval);

  ciphertext = "X";
  ciphertext[0] = 0xF0;
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_FALSE(retval);
  ciphertext[0] = 0x0F;
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_FALSE(retval);

  ciphertext[0] = cipher.algorithm() << 4;
  retval = Cipher::Decrypt(ciphertext, *k_bad, &plaintext);
  EXPECT_FALSE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
}

TEST(T_Encrypt, None) {
  CipherNone cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());

  string empty;
  string dummy = "Hello, World!";
  string ciphertext;
  string plaintext;
  bool retval;

  retval = cipher.Encrypt(empty, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(empty, plaintext);

  retval = cipher.Encrypt(dummy, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(dummy, plaintext);
}

TEST(T_Encrypt, Aes_256_Cbc) {
  CipherAes256Cbc cipher;
  UniquePtr<Key> k(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k.IsValid());

  string empty;
  string dummy = "Hello, World!";
  string ciphertext;
  string ciphertext_two;
  string plaintext;
  bool retval;

  retval = cipher.Encrypt(empty, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(empty, plaintext);

  retval = cipher.Encrypt(dummy, *k, &ciphertext);
  EXPECT_TRUE(retval);
  retval = cipher.Encrypt(dummy, *k, &ciphertext_two);
  EXPECT_TRUE(retval);
  // Initialization vector should differ
  EXPECT_NE(ciphertext, ciphertext_two);
  retval = Cipher::Decrypt(ciphertext, *k, &plaintext);
  EXPECT_TRUE(retval);
  EXPECT_EQ(dummy, plaintext);

  retval = Cipher::Decrypt(ciphertext.substr(0, 1), *k, &plaintext);
  EXPECT_EQ("", plaintext);
  retval = Cipher::Decrypt(ciphertext.substr(0, 1 + cipher.block_size()),
                           *k, &plaintext);
  EXPECT_EQ("", plaintext);
  retval = Cipher::Decrypt(ciphertext.substr(0, ciphertext.length()-1),
                           *k, &plaintext);
  EXPECT_EQ("", plaintext);

  UniquePtr<Key> k2(Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(k2.IsValid());
  Cipher::Decrypt(ciphertext, *k2, &plaintext);
  EXPECT_EQ("", plaintext);
}

TEST(T_Encrypt, Aes_256_Cbc_Iv) {
  CipherAes256Cbc cipher;
  UniquePtr<cipher::Key> key(cipher::Key::CreateRandomly(cipher.key_size()));
  ASSERT_TRUE(key.IsValid());
  // Many Iv requests in a short time should still return unique IVs
  shash::Md5 md5;
  for (unsigned i = 0; i < 100000; ++i) {
    shash::Md5 next_iv = cipher.GenerateIv(*key);
    ASSERT_NE(md5, next_iv);
    md5 = next_iv;
  }
}

}  // namespace cipher
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include <vpr/vpr.h>
#include <vpr/System.h>
#include <vpr/Thread/Thread.h>
#include <vpr/Thread/ThreadFunctor.h>
#include <vpr/Thread/TSTable.h>
#include <vpr/Thread/TSObject.h>
#include <vpr/Thread/TSObjectProxy.h>
#include <vpr/Thread/ThreadManager.h>

#include <cppunit/extensions/MetricRegistry.h>

#include <ThreadTest.h>

namespace vprTest
{

static const vpr::Uint32 ThreadTest_INC_COUNT = 5000;

void ThreadTest::testCreateJoin()
{
   // Spawn off a bunch of threads (m)
   // Have each one increment counter n times
   // join all threads
   // Make sure counter is of valid value

   //std::cout<<"]==================================================\n"<<std::flush;
   //std::cout<<" Thread CreateJoin: \n"<<std::flush;

   const int num_threads(10);
   std::vector<vpr::ThreadMemberFunctor<ThreadTest>*> functors(num_threads);
   std::vector<vpr::Thread*> threads(num_threads);

   for(int t=0;t<num_threads;t++)
   {
      functors[t] = new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::incCounter);

      // Spawns thread here
      threads[t] = new vpr::Thread(functors[t]);
   }

   for(int t=0;t<num_threads;t++)
   {
      if(threads[t]->join() == false)
         CPPUNIT_ASSERT(false && "Thread was not able to be joined");
      delete threads[t];
      delete functors[t];
   }

   CppUnit::TestAssert::assertEquals<long>((num_threads*ThreadTest_INC_COUNT),
                                           mCounter, CppUnit::SourceLine());
   //CPPUNIT_ASSERT(mCounter == (num_threads*50000));

   std::cout << " done\n" << std::flush;
}

void ThreadTest::incCounter(void* arg)
{
   for(vpr::Uint32 i=0;i<ThreadTest_INC_COUNT;i++)
   {
      mItemProtectionMutex->acquire();
      {
         long temp_counter = mCounter;
         mCounter = 0;
         vpr::System::msleep(20);    // Sleep for 20 micro seconds
         mCounter = temp_counter + 1;
      }
      mItemProtectionMutex->release();
      //gfx::Thread::yield();
   }
}

void ThreadTest::counter1Func(void* arg)
{
   for(int i=0;i<10000;i++)
   {
      vpr::System::msleep(10);    // Sleep for 20 micro seconds
      mCounterMutex.acquire();
      {
         long temp_counter = mCounter;
         mCounter = 0;
         vpr::System::msleep(10);    // Sleep for 20 micro seconds
         mCounter = temp_counter + 1;
      }
      mCounterMutex.release();
   }
}

long ThreadTest::sampleCompare(int num)
{
   long sampleValue1=0;
   long sampleValue2=0;

   if (num==1) {
      mCounterMutex.acquire();
         sampleValue1=mCounter;
      mCounterMutex.release();
   }
   else {
      mCounter1Mutex.acquire();
         sampleValue1=mCounter1;
      mCounter1Mutex.release();
   }

   vpr::System::msleep(500 );

   if (num==1) {
      mCounterMutex.acquire();
         sampleValue2=mCounter;
      mCounterMutex.release();
   }
   else {
      mCounter1Mutex.acquire();
         sampleValue2=mCounter1;
      mCounter1Mutex.release();
   }
   std::cout<<sampleValue1<<" : "<<sampleValue2<<std::endl;
   return sampleValue2-sampleValue1;
}

void ThreadTest::testSuspendResume()
{
   //std::cout<<"]==================================================\n"<<std::flush;
   //std::cout<<" Thread SuspendResume: \n"<<std::flush;

   mCounter=0;

   // spawn an counter thread
   vpr::ThreadMemberFunctor<ThreadTest>* counter_functor =
      new vpr::ThreadMemberFunctor<ThreadTest>( this, &ThreadTest::counter1Func );
   vpr::Thread counter_thread( counter_functor);

   vpr::System::msleep(100 );

   CPPUNIT_ASSERT(sampleCompare(1)!=0 && "Counter doesn't work");

   counter_thread.suspend();
   vpr::System::msleep(100);

   CPPUNIT_ASSERT(sampleCompare(1)==0 && "thread can not be suspended");

   counter_thread.resume();
   vpr::System::msleep(100);

   CPPUNIT_ASSERT(sampleCompare(1)!=0 && "thread can not be resumed");

   counter_thread.kill();
   std::cout << " done\n" << std::flush;
}

void ThreadTest::counter2Func(void* arg)
{
   for(int i=0;i<10000;i++)
   {
      vpr::System::msleep(10);    // Sleep for 20 micro seconds
      mCounter1Mutex.acquire();
      {
         long temp_counter = mCounter1;
         mCounter = 0;
         vpr::System::msleep(10);    // Sleep for 20 micro seconds
         mCounter1 = temp_counter + 1;
      }
      mCounter1Mutex.release();
   }
}

void ThreadTest::testPriority()
{
   //std::cout<<"]==================================================\n"<<std::flush;
   //std::cout<<" Thread Priority: \n"<<std::flush;

   mCounter=0;
   mCounter1=0;

   long diff1=0;
   long diff2=0;

   // spawn two counter threads
   vpr::ThreadMemberFunctor<ThreadTest>* counter1_functor =
      new vpr::ThreadMemberFunctor<ThreadTest>( this, &ThreadTest::counter1Func );
   vpr::Thread counter1_thread( counter1_functor);
   vpr::System::msleep(500 );

   vpr::ThreadMemberFunctor<ThreadTest>* counter2_functor =
      new vpr::ThreadMemberFunctor<ThreadTest>( this, &ThreadTest::counter2Func );
   vpr::Thread counter2_thread( counter2_functor);
//   counter2_thread.suspend();
   vpr::System::msleep(500 );
//   counter2_thread.resume();

   diff1=sampleCompare(1);
   diff2=sampleCompare(2);
   std::cout<<"diff1= "<<diff1<<" : "<<std::endl;
   std::cout<<"diff2= "<<diff2<<" : "<<std::endl;
//   CPPUNIT_ASSERT(abs(diff2-diff1)<2 && "Counters don't work correctly);

   counter1_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_HIGH);
   counter2_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_LOW);
   vpr::System::msleep(100 );

   diff1=sampleCompare(1);
   diff2=sampleCompare(2);
   std::cout<<"diff1= "<<diff1<<" : "<<std::endl;
   std::cout<<"diff2= "<<diff2<<" : "<<std::endl;
//   CPPUNIT_ASSERT(abs(diff2-diff1)<2 && "Counters don't work correctly);

   counter1_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_LOW);
   counter2_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_HIGH);
   vpr::System::msleep(100 );

   diff1=sampleCompare(1);
   diff2=sampleCompare(2);
   std::cout<<"diff1= "<<diff1<<" : "<<std::endl;
   std::cout<<"diff2= "<<diff2<<" : "<<std::endl;
//   CPPUNIT_ASSERT(abs(diff2-diff1)<2 && "Counters don't work correctly);

   counter1_thread.kill();
   counter2_thread.kill();
}

void ThreadTest::interactiveTestCPUGrind()
{
   // Spawn off user specified number of threads
   // Have each grind the CPU until the user enters a value
   int num_threads(0);
   std::vector<vpr::ThreadMemberFunctor<ThreadTest>*> functors(num_threads);
   std::vector<vpr::Thread*>                          threads(num_threads);

   mStopGrindingCPU = false;

   // -- GET NUM THREADS -- //
   std::cout << "CPU grind: Enter num threads:";
   std::cin >> num_threads;
   std::cout << "\nSpawning " << num_threads << " threads.\n";
   if(num_threads == 0)
      return;

   // -- SPAWN THE THREADS -- //
   for(int t=0;t<num_threads;t++)
   {
      functors.push_back( new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::grindCPUWorker));
      threads.push_back( new vpr::Thread(functors[t]) );
   }

   // -- ASK FOR USER STOP -- //
   char answer;
   std::cout << "Are the CPUs grinding: (y/n)?  --> ";
   std::cin >> answer;
   std::cout << std::endl;

   mStopGrindingCPU = true;

   for(int t=0;t<num_threads;t++)
   {
      if(threads[t]->join() == false)
         CPPUNIT_ASSERT(false && "Thread was not able to be joined");
      delete threads[t];
      delete functors[t];
   }

   CPPUNIT_ASSERT((answer == 'y') || (answer == 'Y'));
}

// This function just grinds the CPU and waits for the flag to flip
void ThreadTest::grindCPUWorker(void* arg)
{
   double bogus_sum(0.0);
   double da_arg(0.1);
   const double inc(0.005);

   while(!mStopGrindingCPU)
   {
      bogus_sum += (sin(da_arg) + cos(1.0/da_arg));
      da_arg += inc;
   }
}

void ThreadTest::testThreadStackSize()
{
   // Spawn off a thread and have it consume some stack space
   mStackSpaceConsumed = 0;
   mNumRecursions = 200;
   const long stack_size = 64000;

   int arg;

   vpr::ThreadMemberFunctor<ThreadTest>* functor;
   vpr::Thread* the_thread;

   functor = new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::recurseConsumeResources, &arg);

   the_thread = new vpr::Thread(functor, vpr::BaseThread::VPR_PRIORITY_NORMAL, vpr::BaseThread::VPR_LOCAL_THREAD, vpr::BaseThread::VPR_JOINABLE_THREAD, stack_size);
   CPPUNIT_ASSERT(the_thread != NULL);

   CPPUNIT_ASSERT(the_thread->join() && "Failed to join with testThreadStackSize thread");

   //CPPUNIT_ASSERT(mCounter == (num_threads*50000));
}

// Recurse and consume some resources
// Arg is a pointer to a long
void ThreadTest::recurseConsumeResources(void* arg)
{
   // Allocate some stack variables
   long var1(5), var2(3), var3(7);
   static long total_sum;
   total_sum += (var1+var2+var3);
   CPPUNIT_ASSERT(total_sum > 0);              // Just to use the vars

   mStackSpaceConsumed += (3 * sizeof(long));
   mNumRecursions--;

   if(mNumRecursions > 0)
      recurseConsumeResources(arg);
   else
      return;
}

// ------------------------------------ //
// ---- Thread specific data stuff ---- //
// ------------------------------------ //
void ThreadTest::testThreadSpecificData()
{
   threadAssertReset();

   // Spawn off a bunch of threads (m)
   // Have each one increment counter n times
   // join all threads
   // Make sure counter is of valid value

   const int num_threads(10);
   std::vector<vpr::ThreadMemberFunctor<ThreadTest>*> functors(num_threads);
   std::vector<vpr::Thread*> threads(num_threads);
   std::vector<std::string*> thread_names(num_threads);

   for(int t=0;t<num_threads;t++)
   {
      char buffer[256];
      sprintf(buffer, "%d", t);
      thread_names[t] = new std::string(buffer);

      functors[t] = new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::tsIncCounter, thread_names[t]);

      // Spawns thread here
      threads[t] = new vpr::Thread(functors[t]);
   }

   for(int t=0;t<num_threads;t++)
   {
      /*
      if(threads[t]->join() == false)
      {
         CPPUNIT_ASSERT(false && "Thread was not able to be joined");
      }
      */
      threads[t]->join();
      delete threads[t];
      delete functors[t];
      delete thread_names[t];
   }

   checkThreadAssertions();
}

/**
* @param arg - ptr to std::string id of thread
*/
void ThreadTest::tsIncCounter(void* arg)
{
   std::string* thread_name = static_cast<std::string*>(arg);
   std::string test_name("TSDataOverhead");
   test_name += (*thread_name);

   const unsigned long IncCount(100000);

   (*mTSCounter) = 0;

   try
   {
      CPPUNIT_METRIC_START_TIMING();

      for(unsigned long i=0;i<IncCount;i++)
      {
         (*mTSCounter) = (*mTSCounter) + 1;
//         vpr::System::usleep(0);    // Sleep for 20 micro seconds
      }

      assertTestThread((*mTSCounter) == IncCount);

      CPPUNIT_METRIC_STOP_TIMING();
      CPPUNIT_ASSERT_METRIC_TIMING_LE(test_name, IncCount, 0.075f, 0.1f);  // warn at 7.5%, error at 10%
   }
   catch (...)
   {
      std::cout << "F" << std::flush;
   }
}

} // End of vprTest namespace
<commit_msg>Fixed some ugliness added in the last revision.<commit_after>#include <iostream>
#include <vector>

#include <vpr/vpr.h>
#include <vpr/System.h>
#include <vpr/Thread/Thread.h>
#include <vpr/Thread/ThreadFunctor.h>
#include <vpr/Thread/TSTable.h>
#include <vpr/Thread/TSObject.h>
#include <vpr/Thread/TSObjectProxy.h>
#include <vpr/Thread/ThreadManager.h>

#include <cppunit/extensions/MetricRegistry.h>

#include <ThreadTest.h>

namespace vprTest
{

static const vpr::Uint32 ThreadTest_INC_COUNT = 5000;

void ThreadTest::testCreateJoin()
{
   // Spawn off a bunch of threads (m)
   // Have each one increment counter n times
   // join all threads
   // Make sure counter is of valid value

   //std::cout<<"]==================================================\n"<<std::flush;
   //std::cout<<" Thread CreateJoin: \n"<<std::flush;

   const int num_threads(10);
   std::vector<vpr::ThreadMemberFunctor<ThreadTest>*> functors(num_threads);
   std::vector<vpr::Thread*> threads(num_threads);

   for(int t=0;t<num_threads;t++)
   {
      functors[t] = new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::incCounter);

      // Spawns thread here
      threads[t] = new vpr::Thread(functors[t]);
   }

   for(int t=0;t<num_threads;t++)
   {
      if(threads[t]->join() == false)
         CPPUNIT_ASSERT(false && "Thread was not able to be joined");
      delete threads[t];
      delete functors[t];
   }

   CPPUNIT_ASSERT_EQUAL((unsigned long) num_threads * ThreadTest_INC_COUNT,
                        (unsigned long) mCounter);
   //CPPUNIT_ASSERT(mCounter == (num_threads*50000));

   std::cout << " done\n" << std::flush;
}

void ThreadTest::incCounter(void* arg)
{
   for(vpr::Uint32 i=0;i<ThreadTest_INC_COUNT;i++)
   {
      mItemProtectionMutex->acquire();
      {
         long temp_counter = mCounter;
         mCounter = 0;
         vpr::System::msleep(20);    // Sleep for 20 micro seconds
         mCounter = temp_counter + 1;
      }
      mItemProtectionMutex->release();
      //gfx::Thread::yield();
   }
}

void ThreadTest::counter1Func(void* arg)
{
   for(int i=0;i<10000;i++)
   {
      vpr::System::msleep(10);    // Sleep for 20 micro seconds
      mCounterMutex.acquire();
      {
         long temp_counter = mCounter;
         mCounter = 0;
         vpr::System::msleep(10);    // Sleep for 20 micro seconds
         mCounter = temp_counter + 1;
      }
      mCounterMutex.release();
   }
}

long ThreadTest::sampleCompare(int num)
{
   long sampleValue1=0;
   long sampleValue2=0;

   if (num==1) {
      mCounterMutex.acquire();
         sampleValue1=mCounter;
      mCounterMutex.release();
   }
   else {
      mCounter1Mutex.acquire();
         sampleValue1=mCounter1;
      mCounter1Mutex.release();
   }

   vpr::System::msleep(500 );

   if (num==1) {
      mCounterMutex.acquire();
         sampleValue2=mCounter;
      mCounterMutex.release();
   }
   else {
      mCounter1Mutex.acquire();
         sampleValue2=mCounter1;
      mCounter1Mutex.release();
   }
   std::cout<<sampleValue1<<" : "<<sampleValue2<<std::endl;
   return sampleValue2-sampleValue1;
}

void ThreadTest::testSuspendResume()
{
   //std::cout<<"]==================================================\n"<<std::flush;
   //std::cout<<" Thread SuspendResume: \n"<<std::flush;

   mCounter=0;

   // spawn an counter thread
   vpr::ThreadMemberFunctor<ThreadTest>* counter_functor =
      new vpr::ThreadMemberFunctor<ThreadTest>( this, &ThreadTest::counter1Func );
   vpr::Thread counter_thread( counter_functor);

   vpr::System::msleep(100 );

   CPPUNIT_ASSERT(sampleCompare(1)!=0 && "Counter doesn't work");

   counter_thread.suspend();
   vpr::System::msleep(100);

   CPPUNIT_ASSERT(sampleCompare(1)==0 && "thread can not be suspended");

   counter_thread.resume();
   vpr::System::msleep(100);

   CPPUNIT_ASSERT(sampleCompare(1)!=0 && "thread can not be resumed");

   counter_thread.kill();
   std::cout << " done\n" << std::flush;
}

void ThreadTest::counter2Func(void* arg)
{
   for(int i=0;i<10000;i++)
   {
      vpr::System::msleep(10);    // Sleep for 20 micro seconds
      mCounter1Mutex.acquire();
      {
         long temp_counter = mCounter1;
         mCounter = 0;
         vpr::System::msleep(10);    // Sleep for 20 micro seconds
         mCounter1 = temp_counter + 1;
      }
      mCounter1Mutex.release();
   }
}

void ThreadTest::testPriority()
{
   //std::cout<<"]==================================================\n"<<std::flush;
   //std::cout<<" Thread Priority: \n"<<std::flush;

   mCounter=0;
   mCounter1=0;

   long diff1=0;
   long diff2=0;

   // spawn two counter threads
   vpr::ThreadMemberFunctor<ThreadTest>* counter1_functor =
      new vpr::ThreadMemberFunctor<ThreadTest>( this, &ThreadTest::counter1Func );
   vpr::Thread counter1_thread( counter1_functor);
   vpr::System::msleep(500 );

   vpr::ThreadMemberFunctor<ThreadTest>* counter2_functor =
      new vpr::ThreadMemberFunctor<ThreadTest>( this, &ThreadTest::counter2Func );
   vpr::Thread counter2_thread( counter2_functor);
//   counter2_thread.suspend();
   vpr::System::msleep(500 );
//   counter2_thread.resume();

   diff1=sampleCompare(1);
   diff2=sampleCompare(2);
   std::cout<<"diff1= "<<diff1<<" : "<<std::endl;
   std::cout<<"diff2= "<<diff2<<" : "<<std::endl;
//   CPPUNIT_ASSERT(abs(diff2-diff1)<2 && "Counters don't work correctly);

   counter1_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_HIGH);
   counter2_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_LOW);
   vpr::System::msleep(100 );

   diff1=sampleCompare(1);
   diff2=sampleCompare(2);
   std::cout<<"diff1= "<<diff1<<" : "<<std::endl;
   std::cout<<"diff2= "<<diff2<<" : "<<std::endl;
//   CPPUNIT_ASSERT(abs(diff2-diff1)<2 && "Counters don't work correctly);

   counter1_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_LOW);
   counter2_thread.setPrio(vpr::BaseThread::VPR_PRIORITY_HIGH);
   vpr::System::msleep(100 );

   diff1=sampleCompare(1);
   diff2=sampleCompare(2);
   std::cout<<"diff1= "<<diff1<<" : "<<std::endl;
   std::cout<<"diff2= "<<diff2<<" : "<<std::endl;
//   CPPUNIT_ASSERT(abs(diff2-diff1)<2 && "Counters don't work correctly);

   counter1_thread.kill();
   counter2_thread.kill();
}

void ThreadTest::interactiveTestCPUGrind()
{
   // Spawn off user specified number of threads
   // Have each grind the CPU until the user enters a value
   int num_threads(0);
   std::vector<vpr::ThreadMemberFunctor<ThreadTest>*> functors(num_threads);
   std::vector<vpr::Thread*>                          threads(num_threads);

   mStopGrindingCPU = false;

   // -- GET NUM THREADS -- //
   std::cout << "CPU grind: Enter num threads:";
   std::cin >> num_threads;
   std::cout << "\nSpawning " << num_threads << " threads.\n";
   if(num_threads == 0)
      return;

   // -- SPAWN THE THREADS -- //
   for(int t=0;t<num_threads;t++)
   {
      functors.push_back( new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::grindCPUWorker));
      threads.push_back( new vpr::Thread(functors[t]) );
   }

   // -- ASK FOR USER STOP -- //
   char answer;
   std::cout << "Are the CPUs grinding: (y/n)?  --> ";
   std::cin >> answer;
   std::cout << std::endl;

   mStopGrindingCPU = true;

   for(int t=0;t<num_threads;t++)
   {
      if(threads[t]->join() == false)
         CPPUNIT_ASSERT(false && "Thread was not able to be joined");
      delete threads[t];
      delete functors[t];
   }

   CPPUNIT_ASSERT((answer == 'y') || (answer == 'Y'));
}

// This function just grinds the CPU and waits for the flag to flip
void ThreadTest::grindCPUWorker(void* arg)
{
   double bogus_sum(0.0);
   double da_arg(0.1);
   const double inc(0.005);

   while(!mStopGrindingCPU)
   {
      bogus_sum += (sin(da_arg) + cos(1.0/da_arg));
      da_arg += inc;
   }
}

void ThreadTest::testThreadStackSize()
{
   // Spawn off a thread and have it consume some stack space
   mStackSpaceConsumed = 0;
   mNumRecursions = 200;
   const long stack_size = 64000;

   int arg;

   vpr::ThreadMemberFunctor<ThreadTest>* functor;
   vpr::Thread* the_thread;

   functor = new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::recurseConsumeResources, &arg);

   the_thread = new vpr::Thread(functor, vpr::BaseThread::VPR_PRIORITY_NORMAL, vpr::BaseThread::VPR_LOCAL_THREAD, vpr::BaseThread::VPR_JOINABLE_THREAD, stack_size);
   CPPUNIT_ASSERT(the_thread != NULL);

   CPPUNIT_ASSERT(the_thread->join() && "Failed to join with testThreadStackSize thread");

   //CPPUNIT_ASSERT(mCounter == (num_threads*50000));
}

// Recurse and consume some resources
// Arg is a pointer to a long
void ThreadTest::recurseConsumeResources(void* arg)
{
   // Allocate some stack variables
   long var1(5), var2(3), var3(7);
   static long total_sum;
   total_sum += (var1+var2+var3);
   CPPUNIT_ASSERT(total_sum > 0);              // Just to use the vars

   mStackSpaceConsumed += (3 * sizeof(long));
   mNumRecursions--;

   if(mNumRecursions > 0)
      recurseConsumeResources(arg);
   else
      return;
}

// ------------------------------------ //
// ---- Thread specific data stuff ---- //
// ------------------------------------ //
void ThreadTest::testThreadSpecificData()
{
   threadAssertReset();

   // Spawn off a bunch of threads (m)
   // Have each one increment counter n times
   // join all threads
   // Make sure counter is of valid value

   const int num_threads(10);
   std::vector<vpr::ThreadMemberFunctor<ThreadTest>*> functors(num_threads);
   std::vector<vpr::Thread*> threads(num_threads);
   std::vector<std::string*> thread_names(num_threads);

   for(int t=0;t<num_threads;t++)
   {
      char buffer[256];
      sprintf(buffer, "%d", t);
      thread_names[t] = new std::string(buffer);

      functors[t] = new vpr::ThreadMemberFunctor<ThreadTest>(this,&ThreadTest::tsIncCounter, thread_names[t]);

      // Spawns thread here
      threads[t] = new vpr::Thread(functors[t]);
   }

   for(int t=0;t<num_threads;t++)
   {
      /*
      if(threads[t]->join() == false)
      {
         CPPUNIT_ASSERT(false && "Thread was not able to be joined");
      }
      */
      threads[t]->join();
      delete threads[t];
      delete functors[t];
      delete thread_names[t];
   }

   checkThreadAssertions();
}

/**
* @param arg - ptr to std::string id of thread
*/
void ThreadTest::tsIncCounter(void* arg)
{
   std::string* thread_name = static_cast<std::string*>(arg);
   std::string test_name("TSDataOverhead");
   test_name += (*thread_name);

   const unsigned long IncCount(100000);

   (*mTSCounter) = 0;

   try
   {
      CPPUNIT_METRIC_START_TIMING();

      for(unsigned long i=0;i<IncCount;i++)
      {
         (*mTSCounter) = (*mTSCounter) + 1;
//         vpr::System::usleep(0);    // Sleep for 20 micro seconds
      }

      assertTestThread((*mTSCounter) == IncCount);

      CPPUNIT_METRIC_STOP_TIMING();
      CPPUNIT_ASSERT_METRIC_TIMING_LE(test_name, IncCount, 0.075f, 0.1f);  // warn at 7.5%, error at 10%
   }
   catch (...)
   {
      std::cout << "F" << std::flush;
   }
}

} // End of vprTest namespace
<|endoftext|>


<commit_before>/**
 * \file Exception.hpp
 * \brief Defines custom exceptions used in framework.
 */

#ifndef ATLAS_INCLUDE_ATLAS_CORE_EXCEPTION_HPP
#define ATLAS_INCLUDE_ATLAS_CORE_EXCEPTION_HPP

#pragma once

#include "Log.hpp"

#include <stdexcept>

namespace atlas
{
    namespace core
    {
        /**
         * \class Exception
         * \brief Defines a custom exception.
         *
         * This class extends the exception class provided by the STD library
         * and links it to the existing logging system so error messages
         * can always be displayed.
         */
        class Exception : public std::exception
        {
        public:
            /**
             * Standard constructor with char array.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            Exception(const char* msg) :
                message(msg)
            { }

            /**
             * Standard constructor with string.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            Exception(std::string const& msg) :
                message(msg)
            { }

            /**
             * Constructs the error message for the exception with the
             * following format: \verbatim Exception: <message> \endverbatim.
             * The function then outputs the message to the log using the
             * critical flag and then returns the message.
             *
             * \return The message with the specified format.
             */
            virtual const char* what() const throw()
            {
                std::string text = "Exception: " + message;
                CRITICAL_LOG(text);
                return text.c_str();
            }

        protected:
            std::string message;
        };

        /**
         * \class RuntimeException
         * \brief Defines an exception for runtime errors.
         *
         * Extends the base Exception class and modifies the final error
         * message that is produced. This is mostly for code readability so
         * different kinds of errors can be differentiated.
         */
        class RuntimeException : public Exception
        {
        public:
            /**
             * Standard constructor with char array.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            RuntimeException(const char* msg) :
                Exception(msg)
            { }

            /**
             * Standard constructor with string.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            RuntimeException(std::string const& msg) :
                Exception(msg)
            { }

            /**
             * Constructs the error message for the exception with the
             * following format:
             * \verbatim Runtime Exception: <message> \endverbatim.
             * The function then outputs the message to the log using the
             * critical flag and then returns the message.
             *
             * \return The message with the specified format.
             */
            virtual const char* what() const throw()
            {
                std::string text = "Runtime Exception : " + message;
                CRITICAL_LOG(text);
                return text.c_str();
            }
        };

        /**
         * \class LogicException
         * \brief Defines an exception for logic errors.
         *
         * Extends the base Exception class and modifies the final error
         * message that is produced. This is mostly for code readability so
         * different kinds of errors can be differentiated.
         */
        class LogicException : public Exception
        {
            /**
             * Standard constructor with char array.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            LogicException(const char* msg) :
                Exception(msg)
            { }

            /**
             * Standard constructor with string.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            LogicException(std::string const& msg) :
                Exception(msg)
            { }

            /**
             * Constructs the error message for the exception with the
             * following format:
             * \verbatim Logic Exception: <message> \endverbatim.
             * The function then outputs the message to the log using the
             * critical flag and then returns the message.
             *
             * \return The message with the specified format.
             */
            virtual const char* what() const throw()
            {
                std::string text = "Logic Exception: " + message;
                CRITICAL_LOG(text);
                return text.c_str();
            }
        };

    }
}

#endif<commit_msg>[brief] Documents missing member for Exception class.<commit_after>/**
 * \file Exception.hpp
 * \brief Defines custom exceptions used in framework.
 */

#ifndef ATLAS_INCLUDE_ATLAS_CORE_EXCEPTION_HPP
#define ATLAS_INCLUDE_ATLAS_CORE_EXCEPTION_HPP

#pragma once

#include "Log.hpp"

#include <stdexcept>

namespace atlas
{
    namespace core
    {
        /**
         * \class Exception
         * \brief Defines a custom exception.
         *
         * This class extends the exception class provided by the STD library
         * and links it to the existing logging system so error messages
         * can always be displayed.
         */
        class Exception : public std::exception
        {
        public:
            /**
             * Standard constructor with char array.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            Exception(const char* msg) :
                message(msg)
            { }

            /**
             * Standard constructor with string.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            Exception(std::string const& msg) :
                message(msg)
            { }

            /**
             * Constructs the error message for the exception with the
             * following format: \verbatim Exception: <message> \endverbatim.
             * The function then outputs the message to the log using the
             * critical flag and then returns the message.
             *
             * \return The message with the specified format.
             */
            virtual const char* what() const throw()
            {
                std::string text = "Exception: " + message;
                CRITICAL_LOG(text);
                return text.c_str();
            }

        protected:
            /**
             * \var message
             * Contains the message that is displayed whenever the exception
             * is thrown.
             */
            std::string message;
        };

        /**
         * \class RuntimeException
         * \brief Defines an exception for runtime errors.
         *
         * Extends the base Exception class and modifies the final error
         * message that is produced. This is mostly for code readability so
         * different kinds of errors can be differentiated.
         */
        class RuntimeException : public Exception
        {
        public:
            /**
             * Standard constructor with char array.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            RuntimeException(const char* msg) :
                Exception(msg)
            { }

            /**
             * Standard constructor with string.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            RuntimeException(std::string const& msg) :
                Exception(msg)
            { }

            /**
             * Constructs the error message for the exception with the
             * following format:
             * \verbatim Runtime Exception: <message> \endverbatim.
             * The function then outputs the message to the log using the
             * critical flag and then returns the message.
             *
             * \return The message with the specified format.
             */
            virtual const char* what() const throw()
            {
                std::string text = "Runtime Exception : " + message;
                CRITICAL_LOG(text);
                return text.c_str();
            }
        };

        /**
         * \class LogicException
         * \brief Defines an exception for logic errors.
         *
         * Extends the base Exception class and modifies the final error
         * message that is produced. This is mostly for code readability so
         * different kinds of errors can be differentiated.
         */
        class LogicException : public Exception
        {
            /**
             * Standard constructor with char array.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            LogicException(const char* msg) :
                Exception(msg)
            { }

            /**
             * Standard constructor with string.
             *
             * \param[in] msg The message to be displayed when the exception
             * is triggered.
             */
            LogicException(std::string const& msg) :
                Exception(msg)
            { }

            /**
             * Constructs the error message for the exception with the
             * following format:
             * \verbatim Logic Exception: <message> \endverbatim.
             * The function then outputs the message to the log using the
             * critical flag and then returns the message.
             *
             * \return The message with the specified format.
             */
            virtual const char* what() const throw()
            {
                std::string text = "Logic Exception: " + message;
                CRITICAL_LOG(text);
                return text.c_str();
            }
        };

    }
}

#endif<|endoftext|>


<commit_before>#include "entitysystem.h"
#include "systems/movementsystem.h"
#include "systems/updatesystem.h"
#include "systems/chatsystem.h"
#include "systems/inventorysystem.h"
#include "systems/partysystem.h"
#include "systems/mapsystem.h"
#include "systems/luasystem.h"
#include "connection.h"
#include "cmapclient.h"

#include <vector>
#include <set>

using namespace RoseCommon;
EntitySystem::EntitySystem() : systemManager_(*this) {
    systemManager_.add<Systems::MovementSystem>();
    systemManager_.add<Systems::UpdateSystem>();
    systemManager_.add<Systems::ChatSystem>();
    systemManager_.add<Systems::InventorySystem>();
    systemManager_.add<Systems::PartySystem>();
    systemManager_.add<Systems::MapSystem>();
    systemManager_.add<Systems::LuaSystem>();
}

EntityManager &EntitySystem::getEntityManager() {
    return entityManager_;
}

void EntitySystem::registerEntity(Entity entity) {
    if (!entity)
        return;
    auto basic = entity.component<BasicInfo>();
    if (!basic || basic->name_ == "" || !basic->id_)
        return;
    nameToEntity_[basic->name_] = entity;
    idToEntity_[basic->id_] = entity;
}

Entity EntitySystem::getEntity(const std::string &name) {
    return nameToEntity_[name];
}

Entity EntitySystem::getEntity(uint32_t charId) {
    return idToEntity_[charId];
}

void EntitySystem::update(double dt) {
    std::lock_guard<std::mutex> lock(access_);
    while (toDispatch_.size()) {
        auto tmp = std::move(toDispatch_.front());
        systemManager_.dispatch(tmp.first, *tmp.second);
        toDispatch_.pop();
    }
    systemManager_.update(dt);
    for (auto it : toDestroy_) {
        if (it) {
            saveCharacter(it.component<CharacterInfo>()->charId_, it);
          auto basic = it.component<BasicInfo>();
          nameToEntity_.erase(basic->name_);
          idToEntity_.erase(basic->id_);
          it.destroy();
        }
    }
    toDestroy_.clear();
}

void EntitySystem::destroy(Entity entity) {
    if (!entity)
        return;
    std::lock_guard<std::mutex> lock(access_);
    toDestroy_.push_back(entity);
}

Entity EntitySystem::create() {
    return entityManager_.create();
}

bool EntitySystem::isNearby(Entity a, Entity b) {
    return true; // FIXME : actually implement the sight calculation instead of the distance
    if (!a || !b)
        return false;
    auto posa = a.component<Position>();
    auto posb = b.component<Position>();
    if (!posa || !posb)
        return false; // FIXME : is it a bug if there is no position?
    if (posa->map_ != posb->map_)
        return false;
    double dist = (posa->x_ - posb->x_) * (posa->x_ - posb->x_) + (posa->y_ - posb->y_) * (posa->y_ - posb->y_);
    if (dist > NEARBY_DIST)
        return false;
    return true;
}

bool EntitySystem::dispatch(Entity entity, std::unique_ptr<RoseCommon::CRosePacket> packet) {
    if (!entity)
        return false;
    if (systemManager_.wouldDispatch(*packet)) {
        std::lock_guard<std::mutex> lock(access_);
        toDispatch_.emplace(std::make_pair(entity, std::move(packet)));
        return true;
    }
    return false;
}

Entity EntitySystem::loadCharacter(uint32_t charId, bool platinium, uint32_t id) {
    auto conn = Core::connectionPool.getConnection(Core::osirose);
    Core::CharacterTable characters;
    Core::InventoryTable inventoryTable;
    Core::SkillTable skillsTable;

    auto charRes = conn(sqlpp::select(sqlpp::count(characters.id), sqlpp::all_of(characters))
                .from(characters)
                .where(characters.id == charId));

    std::lock_guard<std::mutex> lock(access_);
    auto entity = create();
    if (static_cast<long>(charRes.front().count) != 1L) {
        entity.destroy();
        return Entity();
    }
    const auto &charRow = charRes.front();

    entity.assign<Position>(charRow);
    entity.assign<BasicInfo>(charRow, id);
    entity.assign<Stats>(charRow);
    entity.assign<AdvancedInfo>(charRow);
    entity.assign<CharacterGraphics>(charRow);
    entity.assign<CharacterInfo>(charRow, platinium, charId);

    // TODO : write the pat initialization code
    auto skills = entity.assign<Skills>();
    auto skillRes = conn(sqlpp::select(skillsTable.id, skillsTable.level)
            .from(skillsTable)
            .where(skillsTable.charId == charId));
    skills->loadFromResult(skillRes);

    // TODO : write the hotbar table and loading code
    entity.assign<Hotbar>();
    entity.assign<StatusEffects>();
    entity.assign<RidingItems>();
    entity.assign<BulletItems>();

    // TODO : write the inventory code
    auto inventory = entity.assign<Inventory>();

    auto invRes = conn(sqlpp::select(sqlpp::all_of(inventoryTable))
                .from(inventoryTable)
                .where(inventoryTable.charId == charId));
    inventory->loadFromResult(invRes);

    Systems::UpdateSystem::calculateSpeed(entity);

    entity.assign<Quests>();

    Core::WishTable wish;
    auto wishRes = conn(sqlpp::select(sqlpp::all_of(wish))
                        .from(wish)
                        .where(wish.charId == charId));
    auto wishlist = entity.assign<Wishlist>();
    wishlist->loadFromResult(wishRes);

    entity.assign<Lua>();

    systemManager_.get<Systems::LuaSystem>()->loadScript(entity, "function onInit()\ndisplay('test')\nend");

    registerEntity(entity);
    return entity;
}

void EntitySystem::saveCharacter(uint32_t charId, Entity entity) {
    if (!entity)
        return;
    auto conn = Core::connectionPool.getConnection(Core::osirose);
    Core::CharacterTable characters;

    using sqlpp::parameter;

    auto update = sqlpp::dynamic_update(conn.get(), characters).dynamic_set().where(characters.id == charId);
    entity.component<Position>()->commitToUpdate<decltype(characters)>(update);
    entity.component<BasicInfo>()->commitToUpdate<decltype(characters)>(update);
    entity.component<Stats>()->commitToUpdate<decltype(characters)>(update);
    entity.component<AdvancedInfo>()->commitToUpdate<decltype(characters)>(update);
    //entity.component<CharacterGraphics>()->commitToUpdate(update);
    entity.component<CharacterInfo>()->commitToUpdate<decltype(characters)>(update);
    //entity.component<Hotbar>()->commitToUpdate(update);
    //entity.component<StatusEffects>()->commitToUpdate(update);
    //entity.component<RidingItems>()->commitToUpdate(update);
    //entity.component<BulletItems>()->commitToUpdate(update);

    conn->run(update);

    //entity.component<Skills>()->commitToUpdate(updateSkills);

    Core::InventoryTable inv;
    auto invRes = conn(sqlpp::select(sqlpp::all_of(inv))
                       .from(inv)
                       .where(inv.charId == charId));

    const auto& items = entity.component<Inventory>()->items_;

    std::vector<size_t> toDelete;
    std::vector<size_t> toUpdate;
    std::set<size_t> modified;
    std::vector<size_t> toInsert;

    for (const auto& row : invRes) {
      if (row.slot >= Inventory::maxItems)
        toDelete.emplace_back(row.slot); //FIXME: that should never happen
      else if (!items[row.slot])
        toDelete.emplace_back(row.slot);
      else if (items[row.slot] != Item(row))
        toUpdate.emplace_back(row.slot);
      modified.insert(row.slot);
    }
    size_t i = 0;
    for (const auto& item : items) {
      if (item && modified.find(i) == modified.end())
        toInsert.emplace_back(i);
      ++i;
    }

    for (auto it : toDelete)
      conn(sqlpp::remove_from(inv).where(inv.charId == charId and inv.slot == it));
    for (auto it : toUpdate) {
      auto update = sqlpp::dynamic_update(conn.get(), inv).dynamic_set().where(inv.charId == charId and inv.slot == it);
      items[it].commitToUpdate<decltype(inv)>(update);
      conn->run(update);
    }
    for (auto it : toInsert) {
      auto insert = sqlpp::dynamic_insert_into(conn.get(), inv).dynamic_set();
      items[it].commitToInsert<decltype(inv)>(insert);
      insert.insert_list.add(inv.slot = it);
      insert.insert_list.add(inv.charId = charId);
      conn->run(insert);
    }
}
<commit_msg>Update entitysystem.cpp<commit_after>#include "entitysystem.h"
#include "systems/movementsystem.h"
#include "systems/updatesystem.h"
#include "systems/chatsystem.h"
#include "systems/inventorysystem.h"
#include "systems/partysystem.h"
#include "systems/mapsystem.h"
#include "systems/luasystem.h"
#include "connection.h"
#include "cmapclient.h"

#include <vector>
#include <set>

using namespace RoseCommon;
EntitySystem::EntitySystem() : systemManager_(*this) {
    systemManager_.add<Systems::MovementSystem>();
    systemManager_.add<Systems::UpdateSystem>();
    systemManager_.add<Systems::ChatSystem>();
    systemManager_.add<Systems::InventorySystem>();
    systemManager_.add<Systems::PartySystem>();
    systemManager_.add<Systems::MapSystem>();
    systemManager_.add<Systems::LuaSystem>();
}

EntityManager &EntitySystem::getEntityManager() {
    return entityManager_;
}

void EntitySystem::registerEntity(Entity entity) {
    if (!entity)
        return;
    auto basic = entity.component<BasicInfo>();
    if (!basic || basic->name_ == "" || !basic->id_)
        return;
    nameToEntity_[basic->name_] = entity;
    idToEntity_[basic->id_] = entity;
}

Entity EntitySystem::getEntity(const std::string &name) {
    return nameToEntity_[name];
}

Entity EntitySystem::getEntity(uint32_t charId) {
    return idToEntity_[charId];
}

void EntitySystem::update(double dt) {
    std::lock_guard<std::mutex> lock(access_);
    while (toDispatch_.size()) {
        auto tmp = std::move(toDispatch_.front());
        systemManager_.dispatch(tmp.first, *tmp.second);
        toDispatch_.pop();
    }
    systemManager_.update(dt);
    for (auto it : toDestroy_) {
        if (it) {
            saveCharacter(it.component<CharacterInfo>()->charId_, it);
          auto basic = it.component<BasicInfo>();
          nameToEntity_.erase(basic->name_);
          idToEntity_.erase(basic->id_);
          it.destroy();
        }
    }
    toDestroy_.clear();
}

void EntitySystem::destroy(Entity entity) {
    if (!entity)
        return;
    std::lock_guard<std::mutex> lock(access_);
    toDestroy_.push_back(entity);
}

Entity EntitySystem::create() {
    return entityManager_.create();
}

bool EntitySystem::isNearby(Entity a, Entity b) {
    return true; // FIXME : actually implement the sight calculation instead of the distance
    if (!a || !b)
        return false;
    auto posa = a.component<Position>();
    auto posb = b.component<Position>();
    if (!posa || !posb)
        return false; // FIXME : is it a bug if there is no position?
    if (posa->map_ != posb->map_)
        return false;
    double dist = (posa->x_ - posb->x_) * (posa->x_ - posb->x_) + (posa->y_ - posb->y_) * (posa->y_ - posb->y_);
    if (dist > NEARBY_DIST)
        return false;
    return true;
}

bool EntitySystem::dispatch(Entity entity, std::unique_ptr<RoseCommon::CRosePacket> packet) {
    if (!entity)
        return false;
    if (systemManager_.wouldDispatch(*packet)) {
        std::lock_guard<std::mutex> lock(access_);
        toDispatch_.emplace(std::make_pair(entity, std::move(packet)));
        return true;
    }
    return false;
}

Entity EntitySystem::loadCharacter(uint32_t charId, bool platinium, uint32_t id) {
    auto conn = Core::connectionPool.getConnection(Core::osirose);
    Core::CharacterTable characters;
    Core::InventoryTable inventoryTable;
    Core::SkillTable skillsTable;

    auto charRes = conn(sqlpp::select(sqlpp::count(characters.id), sqlpp::all_of(characters))
                .from(characters)
                .where(characters.id == charId));

    std::lock_guard<std::mutex> lock(access_);
    auto entity = create();
    if (static_cast<long>(charRes.front().count) != 1L) {
        entity.destroy();
        return Entity();
    }
    const auto &charRow = charRes.front();

    entity.assign<Position>(charRow);
    entity.assign<BasicInfo>(charRow, id);
    entity.assign<Stats>(charRow);
    entity.assign<AdvancedInfo>(charRow);
    entity.assign<CharacterGraphics>(charRow);
    entity.assign<CharacterInfo>(charRow, platinium, charId);

    // TODO : write the pat initialization code
    auto skills = entity.assign<Skills>();
    auto skillRes = conn(sqlpp::select(skillsTable.id, skillsTable.level)
            .from(skillsTable)
            .where(skillsTable.charId == charId));
    skills->loadFromResult(skillRes);

    // TODO : write the hotbar table and loading code
    entity.assign<Hotbar>();
    entity.assign<StatusEffects>();
    entity.assign<RidingItems>();
    entity.assign<BulletItems>();

    // TODO : write the inventory code
    auto inventory = entity.assign<Inventory>();

    auto invRes = conn(sqlpp::select(sqlpp::all_of(inventoryTable))
                .from(inventoryTable)
                .where(inventoryTable.charId == charId));
    inventory->loadFromResult(invRes);

    Systems::UpdateSystem::calculateSpeed(entity);

    entity.assign<Quests>();

    Core::WishTable wish;
    auto wishRes = conn(sqlpp::select(sqlpp::all_of(wish))
                        .from(wish)
                        .where(wish.charId == charId));
    auto wishlist = entity.assign<Wishlist>();
    wishlist->loadFromResult(wishRes);

    entity.assign<Lua<EntityAPI>>();

    systemManager_.get<Systems::LuaSystem>()->loadScript(entity, "function onInit()\ndisplay('test')\nend");

    registerEntity(entity);
    return entity;
}

void EntitySystem::saveCharacter(uint32_t charId, Entity entity) {
    if (!entity)
        return;
    auto conn = Core::connectionPool.getConnection(Core::osirose);
    Core::CharacterTable characters;

    using sqlpp::parameter;

    auto update = sqlpp::dynamic_update(conn.get(), characters).dynamic_set().where(characters.id == charId);
    entity.component<Position>()->commitToUpdate<decltype(characters)>(update);
    entity.component<BasicInfo>()->commitToUpdate<decltype(characters)>(update);
    entity.component<Stats>()->commitToUpdate<decltype(characters)>(update);
    entity.component<AdvancedInfo>()->commitToUpdate<decltype(characters)>(update);
    //entity.component<CharacterGraphics>()->commitToUpdate(update);
    entity.component<CharacterInfo>()->commitToUpdate<decltype(characters)>(update);
    //entity.component<Hotbar>()->commitToUpdate(update);
    //entity.component<StatusEffects>()->commitToUpdate(update);
    //entity.component<RidingItems>()->commitToUpdate(update);
    //entity.component<BulletItems>()->commitToUpdate(update);

    conn->run(update);

    //entity.component<Skills>()->commitToUpdate(updateSkills);

    Core::InventoryTable inv;
    auto invRes = conn(sqlpp::select(sqlpp::all_of(inv))
                       .from(inv)
                       .where(inv.charId == charId));

    const auto& items = entity.component<Inventory>()->items_;

    std::vector<size_t> toDelete;
    std::vector<size_t> toUpdate;
    std::set<size_t> modified;
    std::vector<size_t> toInsert;

    for (const auto& row : invRes) {
      if (row.slot >= Inventory::maxItems)
        toDelete.emplace_back(row.slot); //FIXME: that should never happen
      else if (!items[row.slot])
        toDelete.emplace_back(row.slot);
      else if (items[row.slot] != Item(row))
        toUpdate.emplace_back(row.slot);
      modified.insert(row.slot);
    }
    size_t i = 0;
    for (const auto& item : items) {
      if (item && modified.find(i) == modified.end())
        toInsert.emplace_back(i);
      ++i;
    }

    for (auto it : toDelete)
      conn(sqlpp::remove_from(inv).where(inv.charId == charId and inv.slot == it));
    for (auto it : toUpdate) {
      auto update = sqlpp::dynamic_update(conn.get(), inv).dynamic_set().where(inv.charId == charId and inv.slot == it);
      items[it].commitToUpdate<decltype(inv)>(update);
      conn->run(update);
    }
    for (auto it : toInsert) {
      auto insert = sqlpp::dynamic_insert_into(conn.get(), inv).dynamic_set();
      items[it].commitToInsert<decltype(inv)>(insert);
      insert.insert_list.add(inv.slot = it);
      insert.insert_list.add(inv.charId = charId);
      conn->run(insert);
    }
}
<|endoftext|>


<commit_before>//===- DataStructureAA.cpp - Data Structure Based Alias Analysis ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass uses the top-down data structure graphs to implement a simple
// context sensitive alias analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/DataStructure/DataStructure.h"
#include "llvm/Analysis/DataStructure/DSGraph.h"
using namespace llvm;

namespace {
  class DSAA : public ModulePass, public AliasAnalysis {
    TDDataStructures *TD;
    BUDataStructures *BU;
  public:
    DSAA() : TD(0) {}

    //------------------------------------------------
    // Implement the Pass API
    //

    // run - Build up the result graph, representing the pointer graph for the
    // program.
    //
    bool runOnModule(Module &M) {
      InitializeAliasAnalysis(this);
      TD = &getAnalysis<TDDataStructures>();
      BU = &getAnalysis<BUDataStructures>();
      return false;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      AU.setPreservesAll();                         // Does not transform code
      AU.addRequiredTransitive<TDDataStructures>(); // Uses TD Datastructures
      AU.addRequiredTransitive<BUDataStructures>(); // Uses BU Datastructures
    }

    //------------------------------------------------
    // Implement the AliasAnalysis API
    //

    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);

    void getMustAliases(Value *P, std::vector<Value*> &RetVals);

    ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
    ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) {
      return AliasAnalysis::getModRefInfo(CS1,CS2);
    }

    virtual void deleteValue(Value *V) {
      BU->deleteValue(V);
      TD->deleteValue(V);
    }

    virtual void copyValue(Value *From, Value *To) {
      if (From == To) return;
      BU->copyValue(From, To);
      TD->copyValue(From, To);
    }

  private:
    DSGraph *getGraphForValue(const Value *V);
  };

  // Register the pass...
  RegisterOpt<DSAA> X("ds-aa", "Data Structure Graph Based Alias Analysis");

  // Register as an implementation of AliasAnalysis
  RegisterAnalysisGroup<AliasAnalysis, DSAA> Y;
}

ModulePass *llvm::createDSAAPass() { return new DSAA(); }

// getGraphForValue - Return the DSGraph to use for queries about the specified
// value...
//
DSGraph *DSAA::getGraphForValue(const Value *V) {
  if (const Instruction *I = dyn_cast<Instruction>(V))
    return &TD->getDSGraph(*I->getParent()->getParent());
  else if (const Argument *A = dyn_cast<Argument>(V))
    return &TD->getDSGraph(*A->getParent());
  else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
    return &TD->getDSGraph(*BB->getParent());
  return 0;
}

#if 0
// isSinglePhysicalObject - For now, the only case that we know that there is
// only one memory object in the node is when there is a single global in the
// node, and the only composition bit set is Global.
//
static bool isSinglePhysicalObject(DSNode *N) {
  assert(N->isComplete() && "Can only tell if this is a complete object!");
  return N->isGlobalNode() && N->getGlobals().size() == 1 &&
         !N->isHeapNode() && !N->isAllocaNode() && !N->isUnknownNode();
}
#endif

// alias - This is the only method here that does anything interesting...
AliasAnalysis::AliasResult DSAA::alias(const Value *V1, unsigned V1Size,
                                       const Value *V2, unsigned V2Size) {
  if (V1 == V2) return MustAlias;

  DSGraph *G1 = getGraphForValue(V1);
  DSGraph *G2 = getGraphForValue(V2);
  assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?");

  // Get the graph to use...
  DSGraph &G = *(G1 ? G1 : (G2 ? G2 : &TD->getGlobalsGraph()));

  const DSGraph::ScalarMapTy &GSM = G.getScalarMap();
  DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)V1);
  if (I == GSM.end()) return NoAlias;

  DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)V2);
  if (J == GSM.end()) return NoAlias;

  DSNode  *N1 = I->second.getNode(),  *N2 = J->second.getNode();
  unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
  if (N1 == 0 || N2 == 0)
    return MayAlias;  // Can't tell whether anything aliases null.

  // We can only make a judgment of one of the nodes is complete...
  if (N1->isComplete() || N2->isComplete()) {
    if (N1 != N2)
      return NoAlias;   // Completely different nodes.

#if 0  // This does not correctly handle arrays!
    // Both point to the same node and same offset, and there is only one
    // physical memory object represented in the node, return must alias.
    //
    // FIXME: This isn't correct because we do not handle array indexing
    // correctly.

    if (O1 == O2 && isSinglePhysicalObject(N1))
      return MustAlias; // Exactly the same object & offset
#endif

    // See if they point to different offsets...  if so, we may be able to
    // determine that they do not alias...
    if (O1 != O2) {
      if (O2 < O1) {    // Ensure that O1 <= O2
        std::swap(V1, V2);
        std::swap(O1, O2);
        std::swap(V1Size, V2Size);
      }

      if (O1+V1Size <= O2)
        return NoAlias;
    }
  }

  // FIXME: we could improve on this by checking the globals graph for aliased
  // global queries...
  return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}

/// getModRefInfo - does a callsite modify or reference a value?
///
AliasAnalysis::ModRefResult
DSAA::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
  AliasAnalysis::ModRefResult Result =AliasAnalysis::getModRefInfo(CS, P, Size);
  Function *F = CS.getCalledFunction();

  if (!F || Result == NoModRef)
    return Result;

  if (F->isExternal()) {
    // If we are calling an external function, and if this global doesn't escape
    // the portion of the program we have analyzed, we can draw conclusions
    // based on whether the global escapes the program.
    Function *Caller = CS.getInstruction()->getParent()->getParent();
    DSGraph *G = &TD->getDSGraph(*Caller);
    DSScalarMap::iterator NI = G->getScalarMap().find(P);
    if (NI == G->getScalarMap().end()) {
      // If it wasn't in the local function graph, check the global graph.  This
      // can occur for globals who are locally reference but hoisted out to the
      // globals graph despite that.
      G = G->getGlobalsGraph();
      NI = G->getScalarMap().find(P);
      if (NI == G->getScalarMap().end())
        return Result;
    }

    // If we found a node and it's complete, it cannot be passed out to the
    // called function.
    if (NI->second.getNode()->isComplete())
      return NoModRef;
    return Result;
  }

  // Get the graphs for the callee and caller.  Note that we want the BU graph
  // for the callee because we don't want all caller's effects incorporated!
  const Function *Caller = CS.getInstruction()->getParent()->getParent();
  DSGraph &CallerTDGraph = TD->getDSGraph(*Caller);
  DSGraph &CalleeBUGraph = BU->getDSGraph(*F);

  // Figure out which node in the TD graph this pointer corresponds to.
  DSScalarMap &CallerSM = CallerTDGraph.getScalarMap();
  DSScalarMap::iterator NI = CallerSM.find(P);
  if (NI == CallerSM.end()) {
    if (isa<ConstantPointerNull>(P) || isa<UndefValue>(P))
      Result = NoModRef;                 // null is never modified :)
    else {
      assert(isa<GlobalVariable>(P) &&
    cast<GlobalVariable>(P)->getType()->getElementType()->isFirstClassType() &&
             "This isn't a global that DSA inconsiderately dropped "
             "from the graph?");

      DSGraph &GG = *CallerTDGraph.getGlobalsGraph();
      DSScalarMap::iterator NI = GG.getScalarMap().find(P);
      if (NI != GG.getScalarMap().end() && !NI->second.isNull()) {
        // Otherwise, if the node is only M or R, return this.  This can be
        // useful for globals that should be marked const but are not.
        DSNode *N = NI->second.getNode();
        if (!N->isModified())
          Result = (ModRefResult)(Result & ~Mod);
        if (!N->isRead())
          Result = (ModRefResult)(Result & ~Ref);
      }
    }
    return Result;
  }

  const DSNode *N = NI->second.getNode();
  assert(N && "Null pointer in scalar map??");

  // Compute the mapping from nodes in the callee graph to the nodes in the
  // caller graph for this call site.
  DSGraph::NodeMapTy CalleeCallerMap;
  DSCallSite DSCS = CallerTDGraph.getDSCallSiteForCallSite(CS);
  CallerTDGraph.computeCalleeCallerMapping(DSCS, *F, CalleeBUGraph,
                                           CalleeCallerMap);

  // Loop over all of the nodes in the callee that correspond to "N", keeping
  // track of aggregate mod/ref info.
  bool NeverReads = true, NeverWrites = true;
  for (DSGraph::NodeMapTy::iterator I = CalleeCallerMap.begin(),
         E = CalleeCallerMap.end(); I != E; ++I)
    if (I->second.getNode() == N) {
      if (I->first->isModified())
        NeverWrites = false;
      if (I->first->isRead())
        NeverReads = false;
      if (NeverReads == false && NeverWrites == false)
        return Result;
    }

  if (NeverWrites)      // We proved it was not modified.
    Result = ModRefResult(Result & ~Mod);
  if (NeverReads)       // We proved it was not read.
    Result = ModRefResult(Result & ~Ref);

  return Result;
}

/// getMustAliases - If there are any pointers known that must alias this
/// pointer, return them now.  This allows alias-set based alias analyses to
/// perform a form a value numbering (which is exposed by load-vn).  If an alias
/// analysis supports this, it should ADD any must aliased pointers to the
/// specified vector.
///
void DSAA::getMustAliases(Value *P, std::vector<Value*> &RetVals) {
#if 0    // This does not correctly handle arrays!
  // Currently the only must alias information we can provide is to say that
  // something is equal to a global value. If we already have a global value,
  // don't get worked up about it.
  if (!isa<GlobalValue>(P)) {
    DSGraph *G = getGraphForValue(P);
    if (!G) G = &TD->getGlobalsGraph();

    // The only must alias information we can currently determine occurs when
    // the node for P is a global node with only one entry.
    DSGraph::ScalarMapTy::const_iterator I = G->getScalarMap().find(P);
    if (I != G->getScalarMap().end()) {
      DSNode *N = I->second.getNode();
      if (N->isComplete() && isSinglePhysicalObject(N))
        RetVals.push_back(N->getGlobals()[0]);
    }
  }
#endif
  return AliasAnalysis::getMustAliases(P, RetVals);
}

<commit_msg>remove some unsafe code that has long been dead<commit_after>//===- DataStructureAA.cpp - Data Structure Based Alias Analysis ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass uses the top-down data structure graphs to implement a simple
// context sensitive alias analysis.
//
//===----------------------------------------------------------------------===//

#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/DataStructure/DataStructure.h"
#include "llvm/Analysis/DataStructure/DSGraph.h"
using namespace llvm;

namespace {
  class DSAA : public ModulePass, public AliasAnalysis {
    TDDataStructures *TD;
    BUDataStructures *BU;
  public:
    DSAA() : TD(0) {}

    //------------------------------------------------
    // Implement the Pass API
    //

    // run - Build up the result graph, representing the pointer graph for the
    // program.
    //
    bool runOnModule(Module &M) {
      InitializeAliasAnalysis(this);
      TD = &getAnalysis<TDDataStructures>();
      BU = &getAnalysis<BUDataStructures>();
      return false;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AliasAnalysis::getAnalysisUsage(AU);
      AU.setPreservesAll();                         // Does not transform code
      AU.addRequiredTransitive<TDDataStructures>(); // Uses TD Datastructures
      AU.addRequiredTransitive<BUDataStructures>(); // Uses BU Datastructures
    }

    //------------------------------------------------
    // Implement the AliasAnalysis API
    //

    AliasResult alias(const Value *V1, unsigned V1Size,
                      const Value *V2, unsigned V2Size);

    void getMustAliases(Value *P, std::vector<Value*> &RetVals);

    ModRefResult getModRefInfo(CallSite CS, Value *P, unsigned Size);
    ModRefResult getModRefInfo(CallSite CS1, CallSite CS2) {
      return AliasAnalysis::getModRefInfo(CS1,CS2);
    }

    virtual void deleteValue(Value *V) {
      BU->deleteValue(V);
      TD->deleteValue(V);
    }

    virtual void copyValue(Value *From, Value *To) {
      if (From == To) return;
      BU->copyValue(From, To);
      TD->copyValue(From, To);
    }

  private:
    DSGraph *getGraphForValue(const Value *V);
  };

  // Register the pass...
  RegisterOpt<DSAA> X("ds-aa", "Data Structure Graph Based Alias Analysis");

  // Register as an implementation of AliasAnalysis
  RegisterAnalysisGroup<AliasAnalysis, DSAA> Y;
}

ModulePass *llvm::createDSAAPass() { return new DSAA(); }

// getGraphForValue - Return the DSGraph to use for queries about the specified
// value...
//
DSGraph *DSAA::getGraphForValue(const Value *V) {
  if (const Instruction *I = dyn_cast<Instruction>(V))
    return &TD->getDSGraph(*I->getParent()->getParent());
  else if (const Argument *A = dyn_cast<Argument>(V))
    return &TD->getDSGraph(*A->getParent());
  else if (const BasicBlock *BB = dyn_cast<BasicBlock>(V))
    return &TD->getDSGraph(*BB->getParent());
  return 0;
}

AliasAnalysis::AliasResult DSAA::alias(const Value *V1, unsigned V1Size,
                                       const Value *V2, unsigned V2Size) {
  if (V1 == V2) return MustAlias;

  DSGraph *G1 = getGraphForValue(V1);
  DSGraph *G2 = getGraphForValue(V2);
  assert((!G1 || !G2 || G1 == G2) && "Alias query for 2 different functions?");

  // Get the graph to use...
  DSGraph &G = *(G1 ? G1 : (G2 ? G2 : &TD->getGlobalsGraph()));

  const DSGraph::ScalarMapTy &GSM = G.getScalarMap();
  DSGraph::ScalarMapTy::const_iterator I = GSM.find((Value*)V1);
  if (I == GSM.end()) return NoAlias;

  DSGraph::ScalarMapTy::const_iterator J = GSM.find((Value*)V2);
  if (J == GSM.end()) return NoAlias;

  DSNode  *N1 = I->second.getNode(),  *N2 = J->second.getNode();
  unsigned O1 = I->second.getOffset(), O2 = J->second.getOffset();
  if (N1 == 0 || N2 == 0)
    return MayAlias;  // Can't tell whether anything aliases null.

  // We can only make a judgment of one of the nodes is complete...
  if (N1->isComplete() || N2->isComplete()) {
    if (N1 != N2)
      return NoAlias;   // Completely different nodes.

    // See if they point to different offsets...  if so, we may be able to
    // determine that they do not alias...
    if (O1 != O2) {
      if (O2 < O1) {    // Ensure that O1 <= O2
        std::swap(V1, V2);
        std::swap(O1, O2);
        std::swap(V1Size, V2Size);
      }

      if (O1+V1Size <= O2)
        return NoAlias;
    }
  }

  // FIXME: we could improve on this by checking the globals graph for aliased
  // global queries...
  return AliasAnalysis::alias(V1, V1Size, V2, V2Size);
}

/// getModRefInfo - does a callsite modify or reference a value?
///
AliasAnalysis::ModRefResult
DSAA::getModRefInfo(CallSite CS, Value *P, unsigned Size) {
  AliasAnalysis::ModRefResult Result =AliasAnalysis::getModRefInfo(CS, P, Size);
  Function *F = CS.getCalledFunction();

  if (!F || Result == NoModRef)
    return Result;

  if (F->isExternal()) {
    // If we are calling an external function, and if this global doesn't escape
    // the portion of the program we have analyzed, we can draw conclusions
    // based on whether the global escapes the program.
    Function *Caller = CS.getInstruction()->getParent()->getParent();
    DSGraph *G = &TD->getDSGraph(*Caller);
    DSScalarMap::iterator NI = G->getScalarMap().find(P);
    if (NI == G->getScalarMap().end()) {
      // If it wasn't in the local function graph, check the global graph.  This
      // can occur for globals who are locally reference but hoisted out to the
      // globals graph despite that.
      G = G->getGlobalsGraph();
      NI = G->getScalarMap().find(P);
      if (NI == G->getScalarMap().end())
        return Result;
    }

    // If we found a node and it's complete, it cannot be passed out to the
    // called function.
    if (NI->second.getNode()->isComplete())
      return NoModRef;
    return Result;
  }

  // Get the graphs for the callee and caller.  Note that we want the BU graph
  // for the callee because we don't want all caller's effects incorporated!
  const Function *Caller = CS.getInstruction()->getParent()->getParent();
  DSGraph &CallerTDGraph = TD->getDSGraph(*Caller);
  DSGraph &CalleeBUGraph = BU->getDSGraph(*F);

  // Figure out which node in the TD graph this pointer corresponds to.
  DSScalarMap &CallerSM = CallerTDGraph.getScalarMap();
  DSScalarMap::iterator NI = CallerSM.find(P);
  if (NI == CallerSM.end()) {
    if (isa<ConstantPointerNull>(P) || isa<UndefValue>(P))
      Result = NoModRef;                 // null is never modified :)
    else {
      assert(isa<GlobalVariable>(P) &&
    cast<GlobalVariable>(P)->getType()->getElementType()->isFirstClassType() &&
             "This isn't a global that DSA inconsiderately dropped "
             "from the graph?");

      DSGraph &GG = *CallerTDGraph.getGlobalsGraph();
      DSScalarMap::iterator NI = GG.getScalarMap().find(P);
      if (NI != GG.getScalarMap().end() && !NI->second.isNull()) {
        // Otherwise, if the node is only M or R, return this.  This can be
        // useful for globals that should be marked const but are not.
        DSNode *N = NI->second.getNode();
        if (!N->isModified())
          Result = (ModRefResult)(Result & ~Mod);
        if (!N->isRead())
          Result = (ModRefResult)(Result & ~Ref);
      }
    }
    return Result;
  }

  const DSNode *N = NI->second.getNode();
  assert(N && "Null pointer in scalar map??");

  // Compute the mapping from nodes in the callee graph to the nodes in the
  // caller graph for this call site.
  DSGraph::NodeMapTy CalleeCallerMap;
  DSCallSite DSCS = CallerTDGraph.getDSCallSiteForCallSite(CS);
  CallerTDGraph.computeCalleeCallerMapping(DSCS, *F, CalleeBUGraph,
                                           CalleeCallerMap);

  // Loop over all of the nodes in the callee that correspond to "N", keeping
  // track of aggregate mod/ref info.
  bool NeverReads = true, NeverWrites = true;
  for (DSGraph::NodeMapTy::iterator I = CalleeCallerMap.begin(),
         E = CalleeCallerMap.end(); I != E; ++I)
    if (I->second.getNode() == N) {
      if (I->first->isModified())
        NeverWrites = false;
      if (I->first->isRead())
        NeverReads = false;
      if (NeverReads == false && NeverWrites == false)
        return Result;
    }

  if (NeverWrites)      // We proved it was not modified.
    Result = ModRefResult(Result & ~Mod);
  if (NeverReads)       // We proved it was not read.
    Result = ModRefResult(Result & ~Ref);

  return Result;
}

/// getMustAliases - If there are any pointers known that must alias this
/// pointer, return them now.  This allows alias-set based alias analyses to
/// perform a form a value numbering (which is exposed by load-vn).  If an alias
/// analysis supports this, it should ADD any must aliased pointers to the
/// specified vector.
///
void DSAA::getMustAliases(Value *P, std::vector<Value*> &RetVals) {
#if 0    // This does not correctly handle arrays!
  // Currently the only must alias information we can provide is to say that
  // something is equal to a global value. If we already have a global value,
  // don't get worked up about it.
  if (!isa<GlobalValue>(P)) {
    DSGraph *G = getGraphForValue(P);
    if (!G) G = &TD->getGlobalsGraph();

    // The only must alias information we can currently determine occurs when
    // the node for P is a global node with only one entry.
    DSGraph::ScalarMapTy::const_iterator I = G->getScalarMap().find(P);
    if (I != G->getScalarMap().end()) {
      DSNode *N = I->second.getNode();
      if (N->isComplete() && isSinglePhysicalObject(N))
        RetVals.push_back(N->getGlobals()[0]);
    }
  }
#endif
  return AliasAnalysis::getMustAliases(P, RetVals);
}

<|endoftext|>