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

#include "global.h"

#include "databasetools.h"

#include "randomvocabulary.h"
#include "simpleinterface.h"
#include "trainer.h"
#include "settingsproxy.h"
#include "fileutils.h"
#include "csvhandle.h"
#include "languageinterface.h"

#include <QtQuick>
#include <sailfishapp.h>
#include <QtQml>
#include <vector>
#include <QCoreApplication>
#include <QStandardPaths>

int main(int argc, char *argv[])
{
    QCoreApplication::setOrganizationName("harbour-vocabulary");
    QCoreApplication::setApplicationName("harbour-vocabulary");

    // Register QML types
    qmlRegisterType<Trainer>("harbour.vocabulary.Trainer", 1, 0, "Trainer");
    qmlRegisterType<SettingsProxy>("harbour.vocabulary.SettingsProxy", 1, 0, "SettingsProxy");
    qmlRegisterType<CSVHandle>("harbour.vocabulary.CSVHandle", 1, 0, "CSVHandle");

    // Connect to DB
    QString path = QString(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
    QDir dir(path);

    if(!dir.exists())
    {
        DEBUG("Creating directory" << path);
        dir.mkpath(path);
    }

    path.append("/database.sqlite3");
    QFile file(path);
    bool exists = file.exists();

    database.setDatabaseName(path);
    if(!database.open())
    {
        DEBUG(database.lastError().text());
        FATAL("Can not open database.sqlite3");
    }

    if(!exists)
    {
        if(!DatabaseTools::create_new_db())
        {
            database.close();
            file.remove();
            FATAL("Can't create database.sqlite3");
        }
    }
    else
    {
        if(!DatabaseTools::test_and_update_db())
        {
            database.close();
            file.remove();
            FATAL("Can't read/update database.sqlite3");
        }
    }

    // Add classes to QQuickView
    QGuiApplication *app = SailfishApp::application(argc, argv);
    QQuickView *view = SailfishApp::createView();

    RandomVocabulary random_vocabulary;
    SimpleInterface simple_interface;
    FileUtils file_utils;
    LanguageInterface language_interface;

    view->rootContext()->setContextProperty("random_vocabulary", &random_vocabulary);
    view->rootContext()->setContextProperty("simple_interface", &simple_interface);
    view->rootContext()->setContextProperty("file_utils", &file_utils);
    view->rootContext()->setContextProperty("language_interface", &language_interface);

    // Start application
    view->setSource(SailfishApp::pathTo("qml/harbour-vocabulary.qml"));
    view->show();

    int return_value = app->exec();
    database.close();
    return return_value;
}
<commit_msg>Secured database upgrade process<commit_after>/*
 * Copyright 2016,2017 Marcus Soll
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "global.h"

#include "databasetools.h"

#include "randomvocabulary.h"
#include "simpleinterface.h"
#include "trainer.h"
#include "settingsproxy.h"
#include "fileutils.h"
#include "csvhandle.h"
#include "languageinterface.h"

#include <QtQuick>
#include <sailfishapp.h>
#include <QtQml>
#include <vector>
#include <QCoreApplication>
#include <QStandardPaths>
#include <QDateTime>

int main(int argc, char *argv[])
{
    QCoreApplication::setOrganizationName("harbour-vocabulary");
    QCoreApplication::setApplicationName("harbour-vocabulary");

    // Register QML types
    qmlRegisterType<Trainer>("harbour.vocabulary.Trainer", 1, 0, "Trainer");
    qmlRegisterType<SettingsProxy>("harbour.vocabulary.SettingsProxy", 1, 0, "SettingsProxy");
    qmlRegisterType<CSVHandle>("harbour.vocabulary.CSVHandle", 1, 0, "CSVHandle");

    // Connect to DB
    QString path = QString(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
    QDir dir(path);

    if(!dir.exists())
    {
        DEBUG("Creating directory" << path);
        dir.mkpath(path);
    }

    path.append("/database.sqlite3");
    QFile file(path);
    bool exists = file.exists();

    database.setDatabaseName(path);
    if(!database.open())
    {
        DEBUG(database.lastError().text());
        FATAL("Can not open database.sqlite3");
    }

    if(!exists)
    {
        if(!DatabaseTools::create_new_db())
        {
            database.close();
            file.remove();
            FATAL("Can't create database.sqlite3");
        }
    }
    else
    {
        if(!DatabaseTools::test_and_update_db())
        {
            database.close();
            path.append("-UPGRADE_FAILED-");
            path.append(QDateTime::currentDateTime().toString(Qt::ISODate));
            if(file.rename(path))
            {
                FATAL(QString("Can't read/update database.sqlite3, moving to %1").arg(path));
            }
            else
            {
                if(file.remove())
                {
                    FATAL("Can't read/update database.sqlite3, removing it");
                }
                else
                {
                    FATAL("Can't read/update database.sqlite3, can not remove it! Please check your system");
                }
            }
        }
    }

    // Add classes to QQuickView
    QGuiApplication *app = SailfishApp::application(argc, argv);
    QQuickView *view = SailfishApp::createView();

    RandomVocabulary random_vocabulary;
    SimpleInterface simple_interface;
    FileUtils file_utils;
    LanguageInterface language_interface;

    view->rootContext()->setContextProperty("random_vocabulary", &random_vocabulary);
    view->rootContext()->setContextProperty("simple_interface", &simple_interface);
    view->rootContext()->setContextProperty("file_utils", &file_utils);
    view->rootContext()->setContextProperty("language_interface", &language_interface);

    // Start application
    view->setSource(SailfishApp::pathTo("qml/harbour-vocabulary.qml"));
    view->show();

    int return_value = app->exec();
    database.close();
    return return_value;
}

<|endoftext|>


<commit_before>/**
 * Madhav Datt - 14CS30015
 *
 * Software Engineering Lab - Assignment 3
 * Contains implementation of the DateFormat Class
 *
 */

#include <iostream>
#include <exception>
#include <cstdio>
#include <string>
#include <regex>
#include "date.h"

using namespace std;

typedef MAX_DATE_LENGTH 2
typedef MAX_MONTH_LENGTH 3
typedef MAX_YEAR_LENGTH 4

void formatter_date (const char* dateString, char* dateFormat)
{
    switch (strlen(dateString))
    {
        case 1:
            dateFormat = new char[2];
            strcpy (dateFormat, dateString);
            break;

        case 2:
            dateFormat = new char[2];
            strcpy (dateFormat, dateString);
            break;

        default:
            dateFormat = new char[2];
            strcpy (dateFormat, "0");
    };
}

void formatter_month (const char* dateString, char* dateFormat)
{
    if (strlen(dateString) == 1 || strlen(dateString) == 2)
        strcpy (dateFormat, dateString);
    else
        strcpy (dateFormat, "0");
}

void formatter_year (const char* dateString, char* dateFormat)
{
    if (strlen(dateString) == 1 || strlen(dateString) == 2)
        strcpy (dateFormat, dateString);
    else
        strcpy (dateFormat, "0");
}

// The parameters below takes designated values with the specified format semantics

// dateFormat:
// 0: No date. This is valid for output only.
// "d": single digit date in one digit, double digit date in two digits (7, 23)
// "dd": all dates in two digits with single digit dates with leading 0 (07, 23)
// monthFormat:
// 0: each month in its full name (February, November). This is valid for output only.
// "m": single digit month in one digit, double digit month in two digits (2, 11)
// "mm": all months in two digits with single digit months with leading 0 (02, 11)
// "mmm": each month with first three letters of its name (Feb, Nov). This is valid for output only.
// yearFormat:
// 0: No year. This is valid for output only.
// "yy": year in last two digits (1961 as 61, 2016 as 16)
// "yyyy": year in four digits (1961 as 1961, 2016 as 2016)
DateFormat::DateFormat (const char* dateFormat, const char* monthFormat, const char* yearFormat)
{
    DateFormat::dateFormat = new char[MAX_DATE_LENGTH];
    DateFormat::monthFormat = new char[MAX_MONTH_LENGTH];
    DateFormat::yearFormat = new char[MAX_YEAR_LENGTH];
}

// Single C-string format where dateFormat, monthFormat, and yearFormat are separated by ’-’
// Example: "dd-mmm-yy", "d-mm-yyyy", etc
DateFormat::DateFormat (const char* format)
{

}

// Default DateFormat created as "dd-mmm-yy"
DateFormat::DateFormat ()
{

}

// Destructor for the DateFormat class
DateFormat::~DateFormat ()
{

}
<commit_msg>date formatter added<commit_after>/**
 * Madhav Datt - 14CS30015
 *
 * Software Engineering Lab - Assignment 3
 * Contains implementation of the DateFormat Class
 *
 */

#include <iostream>
#include <exception>
#include <cstdio>
#include <string>
#include <ctime>

#include "date.h"
#include "date_comp.h"

using namespace std;

typedef MAX_DATE_LENGTH 2
typedef MAX_MONTH_LENGTH 3
typedef MAX_YEAR_LENGTH 4

void formatter_date (const char* dateString, char* dateFormat)
{
    switch (strlen(dateString))
    {
        case 1:
            dateFormat = new char[2];
            strcpy (dateFormat, dateString);
            break;

        case 2:
            dateFormat = new char[2];
            strcpy (dateFormat, dateString);
            break;

        default:
            dateFormat = new char[2];
            strcpy (dateFormat, "0");
    };
}

void formatter_month (const char* dateString, char* dateFormat)
{
    if (strlen(dateString) == 1 || strlen(dateString) == 2)
        strcpy (dateFormat, dateString);
    else
        strcpy (dateFormat, "0");
}

void formatter_year (const char* dateString, char* dateFormat)
{
    if (strlen(dateString) == 1 || strlen(dateString) == 2)
        strcpy (dateFormat, dateString);
    else
        strcpy (dateFormat, "0");
}

// The parameters below takes designated values with the specified format semantics

// dateFormat:
// 0: No date. This is valid for output only.
// "d": single digit date in one digit, double digit date in two digits (7, 23)
// "dd": all dates in two digits with single digit dates with leading 0 (07, 23)
// monthFormat:
// 0: each month in its full name (February, November). This is valid for output only.
// "m": single digit month in one digit, double digit month in two digits (2, 11)
// "mm": all months in two digits with single digit months with leading 0 (02, 11)
// "mmm": each month with first three letters of its name (Feb, Nov). This is valid for output only.
// yearFormat:
// 0: No year. This is valid for output only.
// "yy": year in last two digits (1961 as 61, 2016 as 16)
// "yyyy": year in four digits (1961 as 1961, 2016 as 2016)
DateFormat::DateFormat (const char* dateFormat, const char* monthFormat, const char* yearFormat)
{
    DateFormat::dateFormat = new char[MAX_DATE_LENGTH];
    DateFormat::monthFormat = new char[MAX_MONTH_LENGTH];
    DateFormat::yearFormat = new char[MAX_YEAR_LENGTH];
}

// Single C-string format where dateFormat, monthFormat, and yearFormat are separated by ’-’
// Example: "dd-mmm-yy", "d-mm-yyyy", etc
DateFormat::DateFormat (const char* format)
{

}

// Default DateFormat created as "dd-mmm-yy"
DateFormat::DateFormat ()
{
    // Get current date and time
    time_t current_time = time (0);
    struct tm* now = localtime (&current_time);

    // Assign date values to class members
    date = now -> tm_mday;
    month = now -> tm_mon + 1;
    year = now -> tm_year + 1900;
}

// Destructor for the DateFormat class
DateFormat::~DateFormat ()
{

}
<|endoftext|>


<commit_before>#ifndef CTHREAD_UNORDERED_MAP
#define CTHREAD_UNORDERED_MAP
#include<functional>	//equal_to, hash
#include<memory>	//allocator
#include<mutex>
#include<unordered_map>
#include<utility>	//forward, move

namespace nThread
{
	template<class Key,class T,class Hash=std::hash<Key>,class KeyEqual=std::equal_to<Key>,class Allocator=std::allocator<std::pair<const Key,T>>>
	class CThread_unordered_map
	{
		std::unordered_map<Key,T,Hash,KeyEqual,Allocator> map_;
		std::mutex mut_;
		template<class KeyFwdRef>
		T& subscript_(KeyFwdRef &&key)
		{
			std::lock_guard<std::mutex> lock{mut_};
			return map_[std::forward<KeyFwdRef>(key)];
		}
		template<class KeyFwdRef,class ... Args>
		bool try_emplace_(KeyFwdRef &&key,Args &&...args)
		{
			std::lock_guard<std::mutex> lock{mut_};
			if(!find(key))
			{
				map_.emplace(std::forward<KeyFwdRef>(key),std::forward<Args>(args)...);
				return true;
			}
			return false;
		}
		template<class KeyFwdRef,class Gen>
		bool try_emplace_gen_(KeyFwdRef &&key,const Gen gen)
		{
			std::lock_guard<std::mutex> lock{mut_};
			if(!find(key))
			{
				map_.emplace(std::forward<KeyFwdRef>(key),gen());
				return true;
			}
			return false;
		}
	public:
		CThread_unordered_map()=default;
		CThread_unordered_map(const CThread_unordered_map &)=delete;
		inline T& at(const Key &key)
		{
			return map_.at(key);
		}
		inline const T& at(const Key &key) const
		{
			return map_.at(key);
		}
		inline bool find(const Key &key) const
		{
			return map_.find(key)!=map_.end();
		}
		template<class ... Args>
		bool emplace(Args &&...args)
		{
			std::lock_guard<std::mutex> lock{mut_};
			return map_.emplace(std::forward<Args>(args)...).second;
		}
		template<class ... Args>
		inline bool try_emplace(const Key &key,Args &&...args)
		{
			return try_emplace_(key,std::forward<Args>(args)...);
		}
		template<class ... Args>
		inline bool try_emplace(Key &&key,Args &&...args)
		{
			return try_emplace_(std::move(key),std::forward<Args>(args)...);
		}
		template<class Gen>
		inline bool try_emplace_gen(const Key &key,const Gen gen)
		{
			return try_emplace_gen_(key,gen);
		}
		template<class Gen>
		inline bool try_emplace_gen(Key &&key,const Gen gen)
		{
			return try_emplace_gen_(std::move(key),gen);
		}
		CThread_unordered_map& operator=(const CThread_unordered_map &)=delete;
		inline T& operator[](const Key &key)
		{
			return subscript_(key);
		}
		inline T& operator[](Key &&key)
		{
			return subscript_(std::move(key));
		}
	};
}

#endif<commit_msg>remove constructor and assignment operator<commit_after>#ifndef CTHREAD_UNORDERED_MAP
#define CTHREAD_UNORDERED_MAP
#include<functional>	//equal_to, hash
#include<memory>	//allocator
#include<mutex>
#include<unordered_map>
#include<utility>	//forward, move

namespace nThread
{
	template<class Key,class T,class Hash=std::hash<Key>,class KeyEqual=std::equal_to<Key>,class Allocator=std::allocator<std::pair<const Key,T>>>
	class CThread_unordered_map
	{
		std::unordered_map<Key,T,Hash,KeyEqual,Allocator> map_;
		std::mutex mut_;
		template<class KeyFwdRef>
		T& subscript_(KeyFwdRef &&key)
		{
			std::lock_guard<std::mutex> lock{mut_};
			return map_[std::forward<KeyFwdRef>(key)];
		}
		template<class KeyFwdRef,class ... Args>
		bool try_emplace_(KeyFwdRef &&key,Args &&...args)
		{
			std::lock_guard<std::mutex> lock{mut_};
			if(!find(key))
			{
				map_.emplace(std::forward<KeyFwdRef>(key),std::forward<Args>(args)...);
				return true;
			}
			return false;
		}
		template<class KeyFwdRef,class Gen>
		bool try_emplace_gen_(KeyFwdRef &&key,const Gen gen)
		{
			std::lock_guard<std::mutex> lock{mut_};
			if(!find(key))
			{
				map_.emplace(std::forward<KeyFwdRef>(key),gen());
				return true;
			}
			return false;
		}
	public:
		inline T& at(const Key &key)
		{
			return map_.at(key);
		}
		inline const T& at(const Key &key) const
		{
			return map_.at(key);
		}
		inline bool find(const Key &key) const
		{
			return map_.find(key)!=map_.end();
		}
		template<class ... Args>
		bool emplace(Args &&...args)
		{
			std::lock_guard<std::mutex> lock{mut_};
			return map_.emplace(std::forward<Args>(args)...).second;
		}
		template<class ... Args>
		inline bool try_emplace(const Key &key,Args &&...args)
		{
			return try_emplace_(key,std::forward<Args>(args)...);
		}
		template<class ... Args>
		inline bool try_emplace(Key &&key,Args &&...args)
		{
			return try_emplace_(std::move(key),std::forward<Args>(args)...);
		}
		template<class Gen>
		inline bool try_emplace_gen(const Key &key,const Gen gen)
		{
			return try_emplace_gen_(key,gen);
		}
		template<class Gen>
		inline bool try_emplace_gen(Key &&key,const Gen gen)
		{
			return try_emplace_gen_(std::move(key),gen);
		}
		inline T& operator[](const Key &key)
		{
			return subscript_(key);
		}
		inline T& operator[](Key &&key)
		{
			return subscript_(std::move(key));
		}
	};
}

#endif<|endoftext|>


<commit_before>/*=========================================================================

  Library   : Image Registration Toolkit (IRTK)
  Module    : $Id$
  Copyright : Imperial College, Department of Computing
              Visual Information Processing (VIP), 2008 onwards
  Date      : $Date$
  Version   : $Revision$
  Changes   : $Author$

=========================================================================*/

#include <irtkImage.h>

char *input_name = NULL, *output_name = NULL;

void usage()
{
  cerr << "Usage: flip [in] [out] [-xy/-xz/-xt/-yz/-yz/-zt]" << endl;
  exit(1);
}

int main(int argc, char **argv)
{
  irtkGreyImage image;

  if (argc != 4) {
    usage();
  }

  input_name  = argv[1];
  argc--;
  argv++;
  output_name = argv[1];
  argc--;
  argv++;

  // Read input
  image.Read(input_name);

  if (strcmp("-xy", argv[1]) == 0) {
    image.FlipXY();
  } else {
    if (strcmp("-xz", argv[1]) == 0) {
      image.FlipXZ();
    } else {
      if (strcmp("-xt", argv[1]) == 0) {
        image.FlipXT();
      } else {
        if (strcmp("-yz", argv[1]) == 0) {
          image.FlipYZ();
        } else {
          if (strcmp("-yt", argv[1]) == 0) {
            image.FlipYT();
          } else {
            if (strcmp("-zt", argv[1]) == 0) {
              image.FlipZT();
            } else {
              usage();
            }
          }
        }
      }
    }
  }

  // Write region
  image.Write(output_name);

  return 0;
}
<commit_msg>Clarified usage and added parameter to Flip calls.<commit_after>/*=========================================================================

  Library   : Image Registration Toolkit (IRTK)
  Module    : $Id$
  Copyright : Imperial College, Department of Computing
              Visual Information Processing (VIP), 2008 onwards
  Date      : $Date$
  Version   : $Revision$
  Changes   : $Author$

=========================================================================*/

#include <irtkImage.h>

char *input_name = NULL, *output_name = NULL;

void usage()
{
  cerr << " Usage: flip [in] [out] [-xy/-xz/-xt/-yz/-yz/-zt]" << endl;
  cerr << " " << endl;
  cerr << " Swap the specified dimensions of the image grid _and_ " << endl;
  cerr << " swap the corresponding world coordinates of the centre " << endl;
  cerr << " of the grid (origin information in header)." << endl;
  exit(1);
}

int main(int argc, char **argv)
{
  irtkGreyImage image;

  if (argc != 4) {
    usage();
  }

  input_name  = argv[1];
  argc--;
  argv++;
  output_name = argv[1];
  argc--;
  argv++;

  // Read input
  image.Read(input_name);

  if (strcmp("-xy", argv[1]) == 0) {
    image.FlipXY(1);
  } else {
    if (strcmp("-xz", argv[1]) == 0) {
      image.FlipXZ(1);
    } else {
      if (strcmp("-xt", argv[1]) == 0) {
        image.FlipXT(1);
      } else {
        if (strcmp("-yz", argv[1]) == 0) {
          image.FlipYZ(1);
        } else {
          if (strcmp("-yt", argv[1]) == 0) {
            image.FlipYT(1);
          } else {
            if (strcmp("-zt", argv[1]) == 0) {
              image.FlipZT(1);
            } else {
              usage();
            }
          }
        }
      }
    }
  }

  // Write region
  image.Write(output_name);

  return 0;
}
<|endoftext|>


<commit_before>//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <cstdlib>
#include "db/db_test_util.h"
#include "port/stack_trace.h"

namespace rocksdb {

class DBTest2 : public DBTestBase {
 public:
  DBTest2() : DBTestBase("/db_test2") {}
};

TEST_F(DBTest2, IteratorPropertyVersionNumber) {
  Put("", "");
  Iterator* iter1 = db_->NewIterator(ReadOptions());
  std::string prop_value;
  ASSERT_OK(
      iter1->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number1 =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));

  Put("", "");
  Flush();

  Iterator* iter2 = db_->NewIterator(ReadOptions());
  ASSERT_OK(
      iter2->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number2 =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));

  ASSERT_GT(version_number2, version_number1);

  Put("", "");

  Iterator* iter3 = db_->NewIterator(ReadOptions());
  ASSERT_OK(
      iter3->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number3 =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));

  ASSERT_EQ(version_number2, version_number3);

  iter1->SeekToFirst();
  ASSERT_OK(
      iter1->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number1_new =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));
  ASSERT_EQ(version_number1, version_number1_new);

  delete iter1;
  delete iter2;
  delete iter3;
}

TEST_F(DBTest2, CacheIndexAndFilterWithDBRestart) {
  Options options = CurrentOptions();
  options.create_if_missing = true;
  options.statistics = rocksdb::CreateDBStatistics();
  BlockBasedTableOptions table_options;
  table_options.cache_index_and_filter_blocks = true;
  table_options.filter_policy.reset(NewBloomFilterPolicy(20));
  options.table_factory.reset(new BlockBasedTableFactory(table_options));
  CreateAndReopenWithCF({"pikachu"}, options);

  Put(1, "a", "begin");
  Put(1, "z", "end");
  ASSERT_OK(Flush(1));
  TryReopenWithColumnFamilies({"default", "pikachu"}, options);

  std::string value;
  value = Get(1, "a");
}
}  // namespace rocksdb

int main(int argc, char** argv) {
  rocksdb::port::InstallStackTraceHandler();
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Add test for Snapshot 0<commit_after>//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
#include <cstdlib>
#include "db/db_test_util.h"
#include "port/stack_trace.h"

namespace rocksdb {

class DBTest2 : public DBTestBase {
 public:
  DBTest2() : DBTestBase("/db_test2") {}
};

TEST_F(DBTest2, IteratorPropertyVersionNumber) {
  Put("", "");
  Iterator* iter1 = db_->NewIterator(ReadOptions());
  std::string prop_value;
  ASSERT_OK(
      iter1->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number1 =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));

  Put("", "");
  Flush();

  Iterator* iter2 = db_->NewIterator(ReadOptions());
  ASSERT_OK(
      iter2->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number2 =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));

  ASSERT_GT(version_number2, version_number1);

  Put("", "");

  Iterator* iter3 = db_->NewIterator(ReadOptions());
  ASSERT_OK(
      iter3->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number3 =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));

  ASSERT_EQ(version_number2, version_number3);

  iter1->SeekToFirst();
  ASSERT_OK(
      iter1->GetProperty("rocksdb.iterator.super-version-number", &prop_value));
  uint64_t version_number1_new =
      static_cast<uint64_t>(std::atoi(prop_value.c_str()));
  ASSERT_EQ(version_number1, version_number1_new);

  delete iter1;
  delete iter2;
  delete iter3;
}

TEST_F(DBTest2, CacheIndexAndFilterWithDBRestart) {
  Options options = CurrentOptions();
  options.create_if_missing = true;
  options.statistics = rocksdb::CreateDBStatistics();
  BlockBasedTableOptions table_options;
  table_options.cache_index_and_filter_blocks = true;
  table_options.filter_policy.reset(NewBloomFilterPolicy(20));
  options.table_factory.reset(new BlockBasedTableFactory(table_options));
  CreateAndReopenWithCF({"pikachu"}, options);

  Put(1, "a", "begin");
  Put(1, "z", "end");
  ASSERT_OK(Flush(1));
  TryReopenWithColumnFamilies({"default", "pikachu"}, options);

  std::string value;
  value = Get(1, "a");
}

TEST_F(DBTest2, DISABLED_FirstSnapshotTest) {
  Options options;
  options.write_buffer_size = 100000;  // Small write buffer
  options = CurrentOptions(options);
  CreateAndReopenWithCF({"pikachu"}, options);

  // This snapshot will have sequence number 0.  When compaction encounters
  // this snapshot, CompactionIterator::findEarliestVisibleSnapshot() will
  // assert as it expects non-zero snapshots.
  //
  // One fix would be to simply remove this assert.  However, a better fix
  // might
  // be to always have db sequence numbers start from 1 so that no code is
  // ever
  // confused by 0.
  const Snapshot* s1 = db_->GetSnapshot();

  Put(1, "k1", std::string(100000, 'x'));  // Fill memtable
  Put(1, "k2", std::string(100000, 'y'));  // Trigger flush

  db_->ReleaseSnapshot(s1);
}
}  // namespace rocksdb

int main(int argc, char** argv) {
  rocksdb::port::InstallStackTraceHandler();
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"

#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/test/ui_test_utils.h"

ExtensionApiTest::ResultCatcher::ResultCatcher() {
  registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED,
                 NotificationService::AllSources());
}

bool ExtensionApiTest::ResultCatcher::GetNextResult() {
  // Depending on the tests, multiple results can come in from a single call
  // to RunMessageLoop(), so we maintain a queue of results and just pull them
  // off as the test calls this, going to the run loop only when the queue is
  // empty.
  if (results_.empty())
    ui_test_utils::RunMessageLoop();

  if (!results_.empty()) {
    bool ret = results_.front();
    results_.pop_front();
    message_ = messages_.front();
    messages_.pop_front();
    return ret;
  }

  NOTREACHED();
  return false;
}

void ExtensionApiTest::ResultCatcher::Observe(
    NotificationType type, const NotificationSource& source,
    const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_TEST_PASSED:
      std::cout << "Got EXTENSION_TEST_PASSED notification.\n";
      results_.push_back(true);
      messages_.push_back("");
      MessageLoopForUI::current()->Quit();
      break;

    case NotificationType::EXTENSION_TEST_FAILED:
      std::cout << "Got EXTENSION_TEST_FAILED notification.\n";
      results_.push_back(false);
      messages_.push_back(*(Details<std::string>(details).ptr()));
      MessageLoopForUI::current()->Quit();
      break;

    default:
      NOTREACHED();
  }
}

bool ExtensionApiTest::RunExtensionTest(const char* extension_name) {
  return RunExtensionTestImpl(extension_name, "");
}

bool ExtensionApiTest::RunExtensionSubtest(const char* extension_name,
                                           const std::string& subtest_page) {
  DCHECK(!subtest_page.empty()) << "Argument subtest_page is required.";
  return RunExtensionTestImpl(extension_name, subtest_page);
}

// Load an extension and wait for it to notify of PASSED or FAILED.
bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
                                            const std::string& subtest_page) {
  ResultCatcher catcher;
  LOG(INFO) << "Running ExtensionApiTest with: " << extension_name;

  if (!LoadExtension(test_data_dir_.AppendASCII(extension_name))) {
    message_ = "Failed to load extension.";
    return false;
  }

  // If there is a subtest to load, navigate to teh subtest page.
  if (!subtest_page.empty()) {
    Extension* extension = GetSingleLoadedExtension();
    if (!extension)
      return false;  // message_ was set by GetSingleLoadedExtension().

    GURL url = extension->GetResourceURL(subtest_page);
    LOG(ERROR) << "Loading subtest page url: " << url.spec();
    ui_test_utils::NavigateToURL(browser(), url);
  }

  if (!catcher.GetNextResult()) {
    message_ = catcher.message();
    return false;
  } else {
    return true;
  }
}

// Test that exactly one extension loaded.
Extension* ExtensionApiTest::GetSingleLoadedExtension() {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();

  int found_extension_index = -1;
  for (size_t i = 0; i < service->extensions()->size(); ++i) {
    // Ignore any component extensions. They are automatically loaded into all
    // profiles and aren't the extension we're looking for here.
    if (service->extensions()->at(i)->location() == Extension::COMPONENT)
      continue;

    if (found_extension_index != -1) {
      message_ = StringPrintf(
          "Expected only one extension to be present.  Found %u.",
          static_cast<unsigned>(service->extensions()->size()));
      return NULL;
    }

    found_extension_index = static_cast<int>(i);
  }

  Extension* extension = service->extensions()->at(found_extension_index);
  if (!extension) {
    message_ = "extension pointer is NULL.";
    return NULL;
  }
  return extension;
}

void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
  ExtensionBrowserTest::SetUpCommandLine(command_line);
  test_data_dir_ = test_data_dir_.AppendASCII("api_test");
}
<commit_msg>Whitespace change to trigger the bots.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extension_apitest.h"

#include "base/string_util.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/test/ui_test_utils.h"

ExtensionApiTest::ResultCatcher::ResultCatcher() {
  registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED,
                 NotificationService::AllSources());
}

bool ExtensionApiTest::ResultCatcher::GetNextResult() {
  // Depending on the tests, multiple results can come in from a single call
  // to RunMessageLoop(), so we maintain a queue of results and just pull them
  // off as the test calls this, going to the run loop only when the queue is
  // empty.
  if (results_.empty())
    ui_test_utils::RunMessageLoop();

  if (!results_.empty()) {
    bool ret = results_.front();
    results_.pop_front();
    message_ = messages_.front();
    messages_.pop_front();
    return ret;
  }

  NOTREACHED();
  return false;
}

void ExtensionApiTest::ResultCatcher::Observe(
    NotificationType type, const NotificationSource& source,
    const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_TEST_PASSED:
      std::cout << "Got EXTENSION_TEST_PASSED notification.\n";
      results_.push_back(true);
      messages_.push_back("");
      MessageLoopForUI::current()->Quit();
      break;

    case NotificationType::EXTENSION_TEST_FAILED:
      std::cout << "Got EXTENSION_TEST_FAILED notification.\n";
      results_.push_back(false);
      messages_.push_back(*(Details<std::string>(details).ptr()));
      MessageLoopForUI::current()->Quit();
      break;

    default:
      NOTREACHED();
  }
}

bool ExtensionApiTest::RunExtensionTest(const char* extension_name) {
  return RunExtensionTestImpl(extension_name, "");
}

bool ExtensionApiTest::RunExtensionSubtest(const char* extension_name,
                                           const std::string& subtest_page) {
  DCHECK(!subtest_page.empty()) << "Argument subtest_page is required.";
  return RunExtensionTestImpl(extension_name, subtest_page);
}

// Load an extension and wait for it to notify of PASSED or FAILED.
bool ExtensionApiTest::RunExtensionTestImpl(const char* extension_name,
                                            const std::string& subtest_page) {
  ResultCatcher catcher;
  LOG(INFO) << "Running ExtensionApiTest with: " << extension_name;

  if (!LoadExtension(test_data_dir_.AppendASCII(extension_name))) {
    message_ = "Failed to load extension.";
    return false;
  }

  // If there is a subtest to load, navigate to the subtest page.
  if (!subtest_page.empty()) {
    Extension* extension = GetSingleLoadedExtension();
    if (!extension)
      return false;  // message_ was set by GetSingleLoadedExtension().

    GURL url = extension->GetResourceURL(subtest_page);
    LOG(ERROR) << "Loading subtest page url: " << url.spec();
    ui_test_utils::NavigateToURL(browser(), url);
  }

  if (!catcher.GetNextResult()) {
    message_ = catcher.message();
    return false;
  } else {
    return true;
  }
}

// Test that exactly one extension loaded.
Extension* ExtensionApiTest::GetSingleLoadedExtension() {
  ExtensionsService* service = browser()->profile()->GetExtensionsService();

  int found_extension_index = -1;
  for (size_t i = 0; i < service->extensions()->size(); ++i) {
    // Ignore any component extensions. They are automatically loaded into all
    // profiles and aren't the extension we're looking for here.
    if (service->extensions()->at(i)->location() == Extension::COMPONENT)
      continue;

    if (found_extension_index != -1) {
      message_ = StringPrintf(
          "Expected only one extension to be present.  Found %u.",
          static_cast<unsigned>(service->extensions()->size()));
      return NULL;
    }

    found_extension_index = static_cast<int>(i);
  }

  Extension* extension = service->extensions()->at(found_extension_index);
  if (!extension) {
    message_ = "extension pointer is NULL.";
    return NULL;
  }
  return extension;
}

void ExtensionApiTest::SetUpCommandLine(CommandLine* command_line) {
  ExtensionBrowserTest::SetUpCommandLine(command_line);
  test_data_dir_ = test_data_dir_.AppendASCII("api_test");
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/hung_renderer_dialog.h"

#include <gtk/gtk.h>

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/process_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/result_codes.h"
#include "gfx/gtk_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

namespace {

// A wrapper class that represents the Gtk dialog.
class HungRendererDialogGtk {
 public:
  HungRendererDialogGtk();
  void ShowForTabContents(TabContents* hung_contents);
  void EndForTabContents(TabContents* hung_contents);

 private:
  // The GtkTreeView column ids.
  enum {
    COL_FAVICON,
    COL_TITLE,
    COL_COUNT,
  };

  // Create the gtk dialog and add the widgets.
  void Init();

  static void OnDialogResponseThunk(GtkDialog* dialog, gint response_id,
                                    HungRendererDialogGtk* dialog_gtk) {
    dialog_gtk->OnDialogResponse(response_id);
  }
  void OnDialogResponse(gint response_id);

  GtkDialog* dialog_;
  GtkListStore* model_;
  TabContents* contents_;

  DISALLOW_COPY_AND_ASSIGN(HungRendererDialogGtk);
};

// We only support showing one of these at a time per app.
HungRendererDialogGtk* g_instance = NULL;

// The response ID for the "Kill pages" button.  Anything positive should be
// fine (the built in GtkResponseTypes are negative numbers).
const int kKillPagesButtonResponse = 1;

HungRendererDialogGtk::HungRendererDialogGtk()
    : dialog_(NULL), model_(NULL), contents_(NULL) {
  Init();
}

void HungRendererDialogGtk::Init() {
  dialog_ = GTK_DIALOG(gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_TITLE).c_str(),
      NULL,  // No parent because tabs can span multiple windows.
      GTK_DIALOG_NO_SEPARATOR,
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_END).c_str(),
      kKillPagesButtonResponse,
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_WAIT).c_str(),
      GTK_RESPONSE_OK,
      NULL));
  gtk_dialog_set_default_response(dialog_, GTK_RESPONSE_OK);
  g_signal_connect(dialog_, "response", G_CALLBACK(OnDialogResponseThunk),
                   this);

  // We have an hbox with the frozen icon on the left.  On the right,
  // we have a vbox with the unresponsive text on top and a table of
  // tabs on bottom.
  // ·-----------------------------------·
  // |·---------------------------------·|
  // ||·----·|·------------------------·||
  // |||icon|||                        |||
  // ||·----·|| The folowing page(s).. |||
  // ||      ||                        |||
  // ||      ||------------------------|||
  // ||      || table of tabs          |||
  // ||      |·------------------------·||
  // |·---------------------------------·|
  // |                                   |
  // |         kill button    wait button|
  // ·-----------------------------------·
  GtkWidget* contents_vbox = dialog_->vbox;
  gtk_box_set_spacing(GTK_BOX(contents_vbox), gtk_util::kContentAreaSpacing);

  GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
  gtk_box_pack_start(GTK_BOX(contents_vbox), hbox, TRUE, TRUE, 0);

  // Wrap the icon in a vbox so it stays top aligned.
  GtkWidget* icon_vbox = gtk_vbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), icon_vbox, FALSE, FALSE, 0);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  GdkPixbuf* icon_pixbuf = rb.GetPixbufNamed(IDR_FROZEN_TAB_ICON);
  GtkWidget* icon = gtk_image_new_from_pixbuf(icon_pixbuf);
  gtk_box_pack_start(GTK_BOX(icon_vbox), icon, FALSE, FALSE, 0);

  GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);

  GtkWidget* text = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER).c_str());
  gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, FALSE, 0);

  GtkWidget* scroll_list = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_list),
      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_list),
                                      GTK_SHADOW_ETCHED_IN);
  gtk_box_pack_start(GTK_BOX(vbox), scroll_list, TRUE, TRUE, 0);

  // The list of hung tabs is GtkTreeView with a GtkListStore as the model.
  model_ = gtk_list_store_new(COL_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING);
  GtkWidget* tree_view = gtk_tree_view_new_with_model(
      GTK_TREE_MODEL(model_));
  g_object_unref(model_);
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
  GtkTreeViewColumn* column = gtk_tree_view_column_new();
  GtkCellRenderer* renderer = gtk_cell_renderer_pixbuf_new();
  gtk_tree_view_column_pack_start(column, renderer, FALSE);
  gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", COL_FAVICON);
  renderer = gtk_cell_renderer_text_new();
  gtk_tree_view_column_pack_start(column, renderer, TRUE);
  gtk_tree_view_column_add_attribute(column, renderer, "text", COL_TITLE);

  gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
  gtk_container_add(GTK_CONTAINER(scroll_list), tree_view);
}

void HungRendererDialogGtk::ShowForTabContents(TabContents* hung_contents) {
  DCHECK(hung_contents && dialog_);
  contents_ = hung_contents;
  gtk_list_store_clear(model_);

  GtkTreeIter tree_iter;
  for (TabContentsIterator it; !it.done(); ++it) {
    if (it->GetRenderProcessHost() == hung_contents->GetRenderProcessHost()) {
      gtk_list_store_append(model_, &tree_iter);
      std::string title = UTF16ToUTF8(it->GetTitle());
      if (title.empty())
        title = UTF16ToUTF8(TabContents::GetDefaultTitle());
      SkBitmap favicon = it->GetFavIcon();

      GdkPixbuf* pixbuf = NULL;
      if (favicon.width() > 0)
        pixbuf = gfx::GdkPixbufFromSkBitmap(&favicon);
      gtk_list_store_set(model_, &tree_iter,
          COL_FAVICON, pixbuf,
          COL_TITLE, title.c_str(),
          -1);
      if (pixbuf)
        g_object_unref(pixbuf);
    }
  }
  gtk_util::ShowDialog(GTK_WIDGET(dialog_));
}

void HungRendererDialogGtk::EndForTabContents(TabContents* contents) {
  DCHECK(contents);
  if (contents_ && contents_->GetRenderProcessHost() ==
      contents->GetRenderProcessHost()) {
    gtk_widget_hide(GTK_WIDGET(dialog_));
    // Since we're closing, we no longer need this TabContents.
    contents_ = NULL;
  }
}

// When the user clicks a button on the dialog or closes the dialog, this
// callback is called.
void HungRendererDialogGtk::OnDialogResponse(gint response_id) {
  DCHECK(g_instance == this);
  switch (response_id) {
    case kKillPagesButtonResponse:
      // Kill the process.
      if (contents_ && contents_->GetRenderProcessHost()) {
        base::KillProcess(contents_->GetRenderProcessHost()->GetHandle(),
                          ResultCodes::HUNG, false);
      }
      break;

    case GTK_RESPONSE_OK:
    case GTK_RESPONSE_DELETE_EVENT:
      // Start waiting again for responsiveness.
      if (contents_ && contents_->render_view_host())
        contents_->render_view_host()->RestartHangMonitorTimeout();
      break;
    default:
      NOTREACHED();
  }

  gtk_widget_destroy(GTK_WIDGET(dialog_));
  delete g_instance;
  g_instance = NULL;
}

}  // namespace

namespace hung_renderer_dialog {

void ShowForTabContents(TabContents* contents) {
  if (!logging::DialogsAreSuppressed()) {
    if (!g_instance)
      g_instance = new HungRendererDialogGtk();
    g_instance->ShowForTabContents(contents);
  }
}

// static
void HideForTabContents(TabContents* contents) {
  if (!logging::DialogsAreSuppressed() && g_instance)
    g_instance->EndForTabContents(contents);
}

}  // namespace hung_renderer_dialog
<commit_msg>gtk: User CHROMEGTK macro in HungRendererDialogGtk.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/hung_renderer_dialog.h"

#include <gtk/gtk.h>

#include "app/gtk_signal.h"
#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/process_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/gtk/gtk_util.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/result_codes.h"
#include "gfx/gtk_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"

namespace {

// A wrapper class that represents the Gtk dialog.
class HungRendererDialogGtk {
 public:
  HungRendererDialogGtk();
  void ShowForTabContents(TabContents* hung_contents);
  void EndForTabContents(TabContents* hung_contents);

 private:
  // The GtkTreeView column ids.
  enum {
    COL_FAVICON,
    COL_TITLE,
    COL_COUNT,
  };

  // Create the gtk dialog and add the widgets.
  void Init();

  CHROMEGTK_CALLBACK_1(HungRendererDialogGtk, void, OnDialogResponse, gint);

  GtkDialog* dialog_;
  GtkListStore* model_;
  TabContents* contents_;

  DISALLOW_COPY_AND_ASSIGN(HungRendererDialogGtk);
};

// We only support showing one of these at a time per app.
HungRendererDialogGtk* g_instance = NULL;

// The response ID for the "Kill pages" button.  Anything positive should be
// fine (the built in GtkResponseTypes are negative numbers).
const int kKillPagesButtonResponse = 1;

HungRendererDialogGtk::HungRendererDialogGtk()
    : dialog_(NULL), model_(NULL), contents_(NULL) {
  Init();
}

void HungRendererDialogGtk::Init() {
  dialog_ = GTK_DIALOG(gtk_dialog_new_with_buttons(
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_TITLE).c_str(),
      NULL,  // No parent because tabs can span multiple windows.
      GTK_DIALOG_NO_SEPARATOR,
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_END).c_str(),
      kKillPagesButtonResponse,
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER_WAIT).c_str(),
      GTK_RESPONSE_OK,
      NULL));
  gtk_dialog_set_default_response(dialog_, GTK_RESPONSE_OK);
  g_signal_connect(dialog_, "response",
                   G_CALLBACK(OnDialogResponseThunk), this);

  // We have an hbox with the frozen icon on the left.  On the right,
  // we have a vbox with the unresponsive text on top and a table of
  // tabs on bottom.
  // ·-----------------------------------·
  // |·---------------------------------·|
  // ||·----·|·------------------------·||
  // |||icon|||                        |||
  // ||·----·|| The folowing page(s).. |||
  // ||      ||                        |||
  // ||      ||------------------------|||
  // ||      || table of tabs          |||
  // ||      |·------------------------·||
  // |·---------------------------------·|
  // |                                   |
  // |         kill button    wait button|
  // ·-----------------------------------·
  GtkWidget* contents_vbox = dialog_->vbox;
  gtk_box_set_spacing(GTK_BOX(contents_vbox), gtk_util::kContentAreaSpacing);

  GtkWidget* hbox = gtk_hbox_new(FALSE, 12);
  gtk_box_pack_start(GTK_BOX(contents_vbox), hbox, TRUE, TRUE, 0);

  // Wrap the icon in a vbox so it stays top aligned.
  GtkWidget* icon_vbox = gtk_vbox_new(FALSE, 0);
  gtk_box_pack_start(GTK_BOX(hbox), icon_vbox, FALSE, FALSE, 0);
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  GdkPixbuf* icon_pixbuf = rb.GetPixbufNamed(IDR_FROZEN_TAB_ICON);
  GtkWidget* icon = gtk_image_new_from_pixbuf(icon_pixbuf);
  gtk_box_pack_start(GTK_BOX(icon_vbox), icon, FALSE, FALSE, 0);

  GtkWidget* vbox = gtk_vbox_new(FALSE, gtk_util::kControlSpacing);
  gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);

  GtkWidget* text = gtk_label_new(
      l10n_util::GetStringUTF8(IDS_BROWSER_HANGMONITOR_RENDERER).c_str());
  gtk_label_set_line_wrap(GTK_LABEL(text), TRUE);
  gtk_box_pack_start(GTK_BOX(vbox), text, FALSE, FALSE, 0);

  GtkWidget* scroll_list = gtk_scrolled_window_new(NULL, NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_list),
      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll_list),
                                      GTK_SHADOW_ETCHED_IN);
  gtk_box_pack_start(GTK_BOX(vbox), scroll_list, TRUE, TRUE, 0);

  // The list of hung tabs is GtkTreeView with a GtkListStore as the model.
  model_ = gtk_list_store_new(COL_COUNT, GDK_TYPE_PIXBUF, G_TYPE_STRING);
  GtkWidget* tree_view = gtk_tree_view_new_with_model(
      GTK_TREE_MODEL(model_));
  g_object_unref(model_);
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE);
  GtkTreeViewColumn* column = gtk_tree_view_column_new();
  GtkCellRenderer* renderer = gtk_cell_renderer_pixbuf_new();
  gtk_tree_view_column_pack_start(column, renderer, FALSE);
  gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", COL_FAVICON);
  renderer = gtk_cell_renderer_text_new();
  gtk_tree_view_column_pack_start(column, renderer, TRUE);
  gtk_tree_view_column_add_attribute(column, renderer, "text", COL_TITLE);

  gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
  gtk_container_add(GTK_CONTAINER(scroll_list), tree_view);
}

void HungRendererDialogGtk::ShowForTabContents(TabContents* hung_contents) {
  DCHECK(hung_contents && dialog_);
  contents_ = hung_contents;
  gtk_list_store_clear(model_);

  GtkTreeIter tree_iter;
  for (TabContentsIterator it; !it.done(); ++it) {
    if (it->GetRenderProcessHost() == hung_contents->GetRenderProcessHost()) {
      gtk_list_store_append(model_, &tree_iter);
      std::string title = UTF16ToUTF8(it->GetTitle());
      if (title.empty())
        title = UTF16ToUTF8(TabContents::GetDefaultTitle());
      SkBitmap favicon = it->GetFavIcon();

      GdkPixbuf* pixbuf = NULL;
      if (favicon.width() > 0)
        pixbuf = gfx::GdkPixbufFromSkBitmap(&favicon);
      gtk_list_store_set(model_, &tree_iter,
          COL_FAVICON, pixbuf,
          COL_TITLE, title.c_str(),
          -1);
      if (pixbuf)
        g_object_unref(pixbuf);
    }
  }
  gtk_util::ShowDialog(GTK_WIDGET(dialog_));
}

void HungRendererDialogGtk::EndForTabContents(TabContents* contents) {
  DCHECK(contents);
  if (contents_ && contents_->GetRenderProcessHost() ==
      contents->GetRenderProcessHost()) {
    gtk_widget_hide(GTK_WIDGET(dialog_));
    // Since we're closing, we no longer need this TabContents.
    contents_ = NULL;
  }
}

// When the user clicks a button on the dialog or closes the dialog, this
// callback is called.
void HungRendererDialogGtk::OnDialogResponse(GtkWidget* widget,
                                             gint response_id) {
  DCHECK(g_instance == this);
  switch (response_id) {
    case kKillPagesButtonResponse:
      // Kill the process.
      if (contents_ && contents_->GetRenderProcessHost()) {
        base::KillProcess(contents_->GetRenderProcessHost()->GetHandle(),
                          ResultCodes::HUNG, false);
      }
      break;

    case GTK_RESPONSE_OK:
    case GTK_RESPONSE_DELETE_EVENT:
      // Start waiting again for responsiveness.
      if (contents_ && contents_->render_view_host())
        contents_->render_view_host()->RestartHangMonitorTimeout();
      break;
    default:
      NOTREACHED();
  }

  gtk_widget_destroy(GTK_WIDGET(dialog_));
  delete g_instance;
  g_instance = NULL;
}

}  // namespace

namespace hung_renderer_dialog {

void ShowForTabContents(TabContents* contents) {
  if (!logging::DialogsAreSuppressed()) {
    if (!g_instance)
      g_instance = new HungRendererDialogGtk();
    g_instance->ShowForTabContents(contents);
  }
}

// static
void HideForTabContents(TabContents* contents) {
  if (!logging::DialogsAreSuppressed() && g_instance)
    g_instance->EndForTabContents(contents);
}

}  // namespace hung_renderer_dialog
<|endoftext|>


<commit_before>#include "xid.h"

#include "epoch.h"

#include <unistd.h>

namespace TXN {

#if 0
} // disable autoindent
#endif

/* There are a fixed number of transaction contexts in the system
   (some thousands of them), and our primary task is to create unique
   XIDs and then assign them contexts in a way that no two XID map to
   the same context at the same time. We accomplish this as follows:

   The system maintains four bitmaps:

              00                    01
   00 |................|    |................|

   10 |................|    |................|

   One row of bitmaps identifies contexts that are available for
   immediate allocation, and the other identifies contexts that have
   been recently freed (keeping those separate reduces contention and
   avoids ABA issues).

   Whenever the allocation bitmap row is exhausted, the system swaps
   labels, turning the "recently-freed" bitmap (which should be pretty
   full) into the "available" map, and vice-versa. Each row thus has a
   bit that maps to a given context.

   Meanwhile, the columns divide the allocation process into
   epochs. Allocation can only change columns (and possibly rows as
   well) if all stragglers have finished, thus solving the ABA problem
   where a straggler manages to reallocate the same context in the
   same epoch, after the context has been used and freed.

   As a concrete example, the system starts allocating from bitmap 00
   (in epoch 0); once 00 is exhausted, it advances to epoch 1 and
   begins allocating from bitmap 01. Once bitmap 01 is empty, the
   system advances to bitmap 10 (logically swapping the rows) and
   begins recycling contexts that were allocated from bitmap 00 and
   have since been freed. Allocation continues through 10 and 11 and
   eventually wraps around to 00 again. Now we have to worry about
   stragglers (some really old transaction could have started in epoch
   0 and---not realizing we're now in epoch 4---might end up with a
   TID from epoch 0 that duplicates the tid from two allocation cycles
   ago. This is where the epoch manager comes in: it can track
   stragglers and restricts the number of concurrent epochs so that
   the problem cannot arise.
 */
static uint16_t const NCONTEXTS = 2048;
xid_context contexts[NCONTEXTS];

struct bitmap {
    static size_t const constexpr BITS_PER_WORD = 8*sizeof(uint64_t);
    static size_t const constexpr NWORDS = NCONTEXTS/2/BITS_PER_WORD;
    static_assert(not (NCONTEXTS % (2*BITS_PER_WORD)),
                  "NCONTEXTS must must divide cleanly by 128");

    uint64_t data[NWORDS];
    size_t widx;
};

static size_t const NBITMAPS = 4;
bitmap bitmaps[NBITMAPS];

struct thread_data {
    epoch_mgr::epoch_num epoch;
    uint64_t bitmap;
    uint16_t base_id;
    bool initialized;
};

__thread thread_data tls CACHE_ALIGNED;

XID
take_one(thread_data *t)
{
    ASSERT(t->bitmap);
    DEFER(t->bitmap &= (t->bitmap-1));
    auto id = t->base_id + __builtin_ctzll(t->bitmap);
    auto x = contexts[id].owner = XID::make(t->epoch, id);
#ifdef USE_PARALLEL_SSN
    contexts[id].sstamp = ~uint64_t{0};
#endif
#ifdef USE_PARALLEL_SSI
    contexts[id].ct3 = ~uint64_t{0};
#endif
    return x;
}

/***************************************
 * * * Callbacks for the epoch_mgr * * *
 ***************************************/
void
global_init(void*)
{
    /* Set the first row to all ones so we have something to allocate */
    for (int i=0; i < 2; i++) {
        for (auto &w : bitmaps[i].data)
            w = ~uint64_t(0);
    }
}

epoch_mgr::tls_storage *
get_tls(void*)
{
    static __thread epoch_mgr::tls_storage s;
    return &s;
}

void *
thread_registered(void*)
{
    tls.epoch = 0;
    tls.bitmap = 0;
    tls.base_id = 0;
    tls.initialized = true;
    return &tls;
}

void
thread_deregistered(void*, void *thread_cookie)
{
    auto *t = (thread_data*) thread_cookie;
    ASSERT(t == &tls);
    while (t->bitmap) {
        auto x = take_one(t);
        xid_free(x);
    }
    t->initialized = false;
}

/* Don't need these... we track resources a different way
 */
void *
epoch_ended(void*, epoch_mgr::epoch_num)
{
    return 0;
}
void *
epoch_ended_thread(void *, void *epoch_cookie, void *)
{
    return epoch_cookie;
}
void
epoch_reclaimed(void *, void *)
{
}

epoch_mgr xid_epochs{{
        nullptr, &global_init, &get_tls,
            &thread_registered, &thread_deregistered,
            &epoch_ended, &epoch_ended_thread,
            &epoch_reclaimed}};

os_mutex_pod xid_mutex = os_mutex_pod::static_init();

# if 0
{ // disable autoindent
#endif

XID
xid_alloc()
{
    if (not tls.initialized)
        xid_epochs.thread_init();

    while (not tls.bitmap) {
        /* Grab a whole machine word at a time. Use the epoch_mgr to
           protect us if we happen to straggle. Note that we may
           (through bad luck) acquire an empty word and need to retry.
         */
        auto e = xid_epochs.thread_enter();
        DEFER_UNLESS(exited, xid_epochs.thread_exit());
        auto &b = bitmaps[e % NBITMAPS];
        auto i = volatile_read(b.widx);
        ASSERT(i <= bitmap::NWORDS);
        while (i < bitmap::NWORDS) {
            auto j = __sync_val_compare_and_swap(&b.widx, i, i+1);
            if (j == i) {
                /* NOTE: no need for a goto: the compiler will thread
                   the jump so we skip the overflow check entirely
                */
                break;
            }
            i = j;
        }

        if (i == bitmap::NWORDS) {
            // overflow!
            xid_epochs.thread_exit();
            exited = true;

            xid_mutex.lock();
            DEFER(xid_mutex.unlock());

            if (e == xid_epochs.get_cur_epoch()) {
                /* Still at end, try to open a new epoch.

                   If there are stragglers (highly unlikely) then
                   sleep until they leave.
                 */
                bitmaps[(e+1) % NBITMAPS].widx = 0;
                while (not xid_epochs.new_epoch())
                    usleep(1000);

            }

            continue;
        }

        tls.epoch = e;
        tls.base_id = (e % 2)*NCONTEXTS/2 + i*bitmap::BITS_PER_WORD;
        std::swap(tls.bitmap, b.data[i]);
    }

    return take_one(&tls);
}

void xid_free(XID x) {
    auto id = x.local();
    ASSERT(id < NCONTEXTS);
    auto *ctx = &contexts[id];
    THROW_IF(ctx->owner != x, illegal_argument, "Invalid XID");
    // destroy the owner field (for SSN read-opt, which might
    // read very stale XID and try to find its context)
    ctx->owner._val = 0;

    auto &b = bitmaps[x.epoch() % NBITMAPS];
    auto &w = b.data[(id/bitmap::BITS_PER_WORD) % bitmap::NWORDS];
    auto bit = id % bitmap::BITS_PER_WORD;
    __sync_fetch_and_or(&w, uint64_t(1) << bit);
}

xid_context *
xid_get_context(XID x) {
    auto *ctx = &contexts[x.local()];
    // read a consistent copy of owner (in case xid_free is destroying
    // it while we're trying to use the epoch() fields)
    XID owner = volatile_read(ctx->owner);
    if (not owner._val)
        return NULL;
    ASSERT(owner.local() == x.local());
    if (owner.epoch() < x.epoch() or owner.epoch() >= x.epoch()+3)
        return NULL;
    return ctx;
}

#if defined(USE_PARALLEL_SSN) || defined(USE_PARALLEL_SSI)
bool __attribute__((noinline))
wait_for_commit_result(xid_context *xc) {
    while (volatile_read(xc->state) == TXN_COMMITTING) { /* spin */ }
    return volatile_read(xc->state) == TXN_CMMTD;
}
#endif

} // end of namespace
<commit_msg>SSN: fix pstamp initial value.<commit_after>#include "xid.h"

#include "epoch.h"

#include <unistd.h>

namespace TXN {

#if 0
} // disable autoindent
#endif

/* There are a fixed number of transaction contexts in the system
   (some thousands of them), and our primary task is to create unique
   XIDs and then assign them contexts in a way that no two XID map to
   the same context at the same time. We accomplish this as follows:

   The system maintains four bitmaps:

              00                    01
   00 |................|    |................|

   10 |................|    |................|

   One row of bitmaps identifies contexts that are available for
   immediate allocation, and the other identifies contexts that have
   been recently freed (keeping those separate reduces contention and
   avoids ABA issues).

   Whenever the allocation bitmap row is exhausted, the system swaps
   labels, turning the "recently-freed" bitmap (which should be pretty
   full) into the "available" map, and vice-versa. Each row thus has a
   bit that maps to a given context.

   Meanwhile, the columns divide the allocation process into
   epochs. Allocation can only change columns (and possibly rows as
   well) if all stragglers have finished, thus solving the ABA problem
   where a straggler manages to reallocate the same context in the
   same epoch, after the context has been used and freed.

   As a concrete example, the system starts allocating from bitmap 00
   (in epoch 0); once 00 is exhausted, it advances to epoch 1 and
   begins allocating from bitmap 01. Once bitmap 01 is empty, the
   system advances to bitmap 10 (logically swapping the rows) and
   begins recycling contexts that were allocated from bitmap 00 and
   have since been freed. Allocation continues through 10 and 11 and
   eventually wraps around to 00 again. Now we have to worry about
   stragglers (some really old transaction could have started in epoch
   0 and---not realizing we're now in epoch 4---might end up with a
   TID from epoch 0 that duplicates the tid from two allocation cycles
   ago. This is where the epoch manager comes in: it can track
   stragglers and restricts the number of concurrent epochs so that
   the problem cannot arise.
 */
static uint16_t const NCONTEXTS = 2048;
xid_context contexts[NCONTEXTS];

struct bitmap {
    static size_t const constexpr BITS_PER_WORD = 8*sizeof(uint64_t);
    static size_t const constexpr NWORDS = NCONTEXTS/2/BITS_PER_WORD;
    static_assert(not (NCONTEXTS % (2*BITS_PER_WORD)),
                  "NCONTEXTS must must divide cleanly by 128");

    uint64_t data[NWORDS];
    size_t widx;
};

static size_t const NBITMAPS = 4;
bitmap bitmaps[NBITMAPS];

struct thread_data {
    epoch_mgr::epoch_num epoch;
    uint64_t bitmap;
    uint16_t base_id;
    bool initialized;
};

__thread thread_data tls CACHE_ALIGNED;

XID
take_one(thread_data *t)
{
    ASSERT(t->bitmap);
    DEFER(t->bitmap &= (t->bitmap-1));
    auto id = t->base_id + __builtin_ctzll(t->bitmap);
    auto x = contexts[id].owner = XID::make(t->epoch, id);
#ifdef USE_PARALLEL_SSN
    contexts[id].sstamp = ~uint64_t{0};
    contexts[id].pstamp = 0;
#endif
#ifdef USE_PARALLEL_SSI
    contexts[id].ct3 = ~uint64_t{0};
#endif
    return x;
}

/***************************************
 * * * Callbacks for the epoch_mgr * * *
 ***************************************/
void
global_init(void*)
{
    /* Set the first row to all ones so we have something to allocate */
    for (int i=0; i < 2; i++) {
        for (auto &w : bitmaps[i].data)
            w = ~uint64_t(0);
    }
}

epoch_mgr::tls_storage *
get_tls(void*)
{
    static __thread epoch_mgr::tls_storage s;
    return &s;
}

void *
thread_registered(void*)
{
    tls.epoch = 0;
    tls.bitmap = 0;
    tls.base_id = 0;
    tls.initialized = true;
    return &tls;
}

void
thread_deregistered(void*, void *thread_cookie)
{
    auto *t = (thread_data*) thread_cookie;
    ASSERT(t == &tls);
    while (t->bitmap) {
        auto x = take_one(t);
        xid_free(x);
    }
    t->initialized = false;
}

/* Don't need these... we track resources a different way
 */
void *
epoch_ended(void*, epoch_mgr::epoch_num)
{
    return 0;
}
void *
epoch_ended_thread(void *, void *epoch_cookie, void *)
{
    return epoch_cookie;
}
void
epoch_reclaimed(void *, void *)
{
}

epoch_mgr xid_epochs{{
        nullptr, &global_init, &get_tls,
            &thread_registered, &thread_deregistered,
            &epoch_ended, &epoch_ended_thread,
            &epoch_reclaimed}};

os_mutex_pod xid_mutex = os_mutex_pod::static_init();

# if 0
{ // disable autoindent
#endif

XID
xid_alloc()
{
    if (not tls.initialized)
        xid_epochs.thread_init();

    while (not tls.bitmap) {
        /* Grab a whole machine word at a time. Use the epoch_mgr to
           protect us if we happen to straggle. Note that we may
           (through bad luck) acquire an empty word and need to retry.
         */
        auto e = xid_epochs.thread_enter();
        DEFER_UNLESS(exited, xid_epochs.thread_exit());
        auto &b = bitmaps[e % NBITMAPS];
        auto i = volatile_read(b.widx);
        ASSERT(i <= bitmap::NWORDS);
        while (i < bitmap::NWORDS) {
            auto j = __sync_val_compare_and_swap(&b.widx, i, i+1);
            if (j == i) {
                /* NOTE: no need for a goto: the compiler will thread
                   the jump so we skip the overflow check entirely
                */
                break;
            }
            i = j;
        }

        if (i == bitmap::NWORDS) {
            // overflow!
            xid_epochs.thread_exit();
            exited = true;

            xid_mutex.lock();
            DEFER(xid_mutex.unlock());

            if (e == xid_epochs.get_cur_epoch()) {
                /* Still at end, try to open a new epoch.

                   If there are stragglers (highly unlikely) then
                   sleep until they leave.
                 */
                bitmaps[(e+1) % NBITMAPS].widx = 0;
                while (not xid_epochs.new_epoch())
                    usleep(1000);

            }

            continue;
        }

        tls.epoch = e;
        tls.base_id = (e % 2)*NCONTEXTS/2 + i*bitmap::BITS_PER_WORD;
        std::swap(tls.bitmap, b.data[i]);
    }

    return take_one(&tls);
}

void xid_free(XID x) {
    auto id = x.local();
    ASSERT(id < NCONTEXTS);
    auto *ctx = &contexts[id];
    THROW_IF(ctx->owner != x, illegal_argument, "Invalid XID");
    // destroy the owner field (for SSN read-opt, which might
    // read very stale XID and try to find its context)
    ctx->owner._val = 0;

    auto &b = bitmaps[x.epoch() % NBITMAPS];
    auto &w = b.data[(id/bitmap::BITS_PER_WORD) % bitmap::NWORDS];
    auto bit = id % bitmap::BITS_PER_WORD;
    __sync_fetch_and_or(&w, uint64_t(1) << bit);
}

xid_context *
xid_get_context(XID x) {
    auto *ctx = &contexts[x.local()];
    // read a consistent copy of owner (in case xid_free is destroying
    // it while we're trying to use the epoch() fields)
    XID owner = volatile_read(ctx->owner);
    if (not owner._val)
        return NULL;
    ASSERT(owner.local() == x.local());
    if (owner.epoch() < x.epoch() or owner.epoch() >= x.epoch()+3)
        return NULL;
    return ctx;
}

#if defined(USE_PARALLEL_SSN) || defined(USE_PARALLEL_SSI)
bool __attribute__((noinline))
wait_for_commit_result(xid_context *xc) {
    while (volatile_read(xc->state) == TXN_COMMITTING) { /* spin */ }
    return volatile_read(xc->state) == TXN_CMMTD;
}
#endif

} // end of namespace
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <iosfwd>
#include <sstream>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/port.h"
#include "build/build_config.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
#include "testing/gtest/include/gtest/gtest.h"

using std::endl;
using std::ostream;
using std::string;
using std::stringstream;
using std::vector;

namespace {

class Pair;

struct TestEvent {
  Pair* source;
  enum {
    A_CHANGED, B_CHANGED, PAIR_BEING_DELETED,
  } what_happened;
  int old_value;
};

struct TestEventTraits {
  typedef TestEvent EventType;
  static bool IsChannelShutdownEvent(const TestEvent& event) {
    return TestEvent::PAIR_BEING_DELETED == event.what_happened;
  }
};

class Pair {
 public:
  typedef EventChannel<TestEventTraits> Channel;
  explicit Pair(const string& name) : name_(name), a_(0), b_(0) {
    TestEvent shutdown = { this, TestEvent::PAIR_BEING_DELETED, 0 };
    event_channel_ = new Channel(shutdown);
  }
  ~Pair() {
    delete event_channel_;
  }
  void set_a(int n) {
    TestEvent event = { this, TestEvent::A_CHANGED, a_ };
    a_ = n;
    event_channel_->NotifyListeners(event);
  }
  void set_b(int n) {
    TestEvent event = { this, TestEvent::B_CHANGED, b_ };
    b_ = n;
    event_channel_->NotifyListeners(event);
  }
  int a() const { return a_; }
  int b() const { return b_; }
  const string& name() { return name_; }
  Channel* event_channel() const { return event_channel_; }

 protected:
  const string name_;
  int a_;
  int b_;
  Channel* event_channel_;
};

class EventLogger {
 public:
  explicit EventLogger(ostream& out) : out_(out) { }
  ~EventLogger() {
    for (Hookups::iterator i = hookups_.begin(); i != hookups_.end(); ++i)
      delete *i;
  }

  void Hookup(const string name, Pair::Channel* channel) {
    hookups_.push_back(NewEventListenerHookup(channel, this,
                                              &EventLogger::HandlePairEvent,
                                              name));
  }

  void HandlePairEvent(const string& name, const TestEvent& event) {
    const char* what_changed = NULL;
    int new_value = 0;
    Hookups::iterator dead;
    switch (event.what_happened) {
    case TestEvent::A_CHANGED:
      what_changed = "A";
      new_value = event.source->a();
      break;
    case TestEvent::B_CHANGED:
      what_changed = "B";
      new_value = event.source->b();
      break;
    case TestEvent::PAIR_BEING_DELETED:
      out_ << name << " heard " << event.source->name() << " being deleted."
           << endl;
      return;
    default:
      LOG(FATAL) << "Bad event.what_happened: " << event.what_happened;
      break;
    }
    out_ << name << " heard " << event.source->name() << "'s " << what_changed
         << " change from "
         << event.old_value << " to " << new_value << endl;
  }

  typedef vector<EventListenerHookup*> Hookups;
  Hookups hookups_;
  ostream& out_;
};

const char golden_result[] = "Larry heard Sally's B change from 0 to 2\n"
"Larry heard Sally's A change from 1 to 3\n"
"Lewis heard Sam's B change from 0 to 5\n"
"Larry heard Sally's A change from 3 to 6\n"
"Larry heard Sally being deleted.\n";

TEST(EventSys, Basic) {
  Pair sally("Sally"), sam("Sam");
  sally.set_a(1);
  stringstream log;
  EventLogger logger(log);
  logger.Hookup("Larry", sally.event_channel());
  sally.set_b(2);
  sally.set_a(3);
  sam.set_a(4);
  logger.Hookup("Lewis", sam.event_channel());
  sam.set_b(5);
  sally.set_a(6);
  // Test that disconnect within callback doesn't deadlock.
  TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 };
  sally.event_channel()->NotifyListeners(event);
  sally.set_a(7);
  ASSERT_EQ(log.str(), golden_result);
}

// This goes pretty far beyond the normal use pattern, so don't use
// ThreadTester as an example of what to do.
class ThreadTester : public EventListener<TestEvent>,
                     public PlatformThread::Delegate {
 public:
  explicit ThreadTester(Pair* pair)
    : pair_(pair), remove_event_(&remove_event_mutex_),
      remove_event_bool_(false)  {
    pair_->event_channel()->AddListener(this);
  }
  ~ThreadTester() {
    pair_->event_channel()->RemoveListener(this);
    for (size_t i = 0; i < threads_.size(); i++) {
      PlatformThread::Join(threads_[i].thread);
    }
  }

  struct ThreadInfo {
    PlatformThreadHandle thread;
    bool* completed;
  };

  struct ThreadArgs {
    ConditionVariable* thread_running_cond;
    Lock* thread_running_mutex;
    bool thread_running;
    bool completed;
  };

  void Go() {
    Lock thread_running_mutex;
    ConditionVariable thread_running_cond(&thread_running_mutex);
    ThreadArgs args;
    ThreadInfo info;
    info.completed = false;
    args.completed = info.completed;
    args.thread_running_cond = &(thread_running_cond);
    args.thread_running_mutex = &(thread_running_mutex);
    args.thread_running = false;
    args_ = args;
    ASSERT_TRUE(PlatformThread::Create(0, this, &info.thread));
    thread_running_mutex.Acquire();
    while ((args_.thread_running) == false) {
      thread_running_cond.Wait();
    }
    thread_running_mutex.Release();
    threads_.push_back(info);
  }

  // PlatformThread::Delegate methods.
  virtual void ThreadMain() {
    // Make sure each thread gets a current MessageLoop in TLS.
    // This test should use chrome threads for testing, but I'll leave it like
    // this for the moment since it requires a big chunk of rewriting and I
    // want the test passing while I checkpoint my CL.  Technically speaking,
    // there should be no functional difference.
    MessageLoop message_loop;
    args_.thread_running_mutex->Acquire();
    args_.thread_running = true;
    args_.thread_running_mutex->Release();
    args_.thread_running_cond->Signal();

    remove_event_mutex_.Acquire();
    while (remove_event_bool_ == false) {
      remove_event_.Wait();
    }
    remove_event_mutex_.Release();

    // Normally, you'd just delete the hookup. This is very bad style, but
    // necessary for the test.
    pair_->event_channel()->RemoveListener(this);
    args_.completed = true;
  }

  void HandleEvent(const TestEvent& event) {
    remove_event_mutex_.Acquire();
    remove_event_bool_ = true;
    remove_event_mutex_.Release();
    remove_event_.Broadcast();

    PlatformThread::YieldCurrentThread();

    for (size_t i = 0; i < threads_.size(); i++) {
      if (threads_[i].completed)
        LOG(FATAL) << "A test thread exited too early.";
    }
  }

  Pair* pair_;
  ConditionVariable remove_event_;
  Lock remove_event_mutex_;
  bool remove_event_bool_;
  vector<ThreadInfo> threads_;
  ThreadArgs args_;
};

TEST(EventSys, Multithreaded) {
  Pair sally("Sally");
  ThreadTester a(&sally);
  for (int i = 0; i < 3; ++i)
    a.Go();
  sally.set_b(99);
}

class HookupDeleter {
 public:
  void HandleEvent(const TestEvent& event) {
    delete hookup_;
    hookup_ = NULL;
  }
  EventListenerHookup* hookup_;
};

TEST(EventSys, InHandlerDeletion) {
  Pair sally("Sally");
  HookupDeleter deleter;
  deleter.hookup_ = NewEventListenerHookup(sally.event_channel(),
                                           &deleter,
                                           &HookupDeleter::HandleEvent);
  sally.set_a(1);
  ASSERT_TRUE(NULL == deleter.hookup_);
}

}  // namespace
<commit_msg>Revert 31109 - Avoid calling PlatformThread::Sleep(1) from event_sys_unittests.cc<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <iosfwd>
#include <sstream>
#include <string>
#include <vector>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/platform_thread.h"
#include "base/port.h"
#include "build/build_config.h"
#include "chrome/browser/sync/util/event_sys-inl.h"
#include "testing/gtest/include/gtest/gtest.h"

using std::endl;
using std::ostream;
using std::string;
using std::stringstream;
using std::vector;

namespace {

class Pair;

struct TestEvent {
  Pair* source;
  enum {
    A_CHANGED, B_CHANGED, PAIR_BEING_DELETED,
  } what_happened;
  int old_value;
};

struct TestEventTraits {
  typedef TestEvent EventType;
  static bool IsChannelShutdownEvent(const TestEvent& event) {
    return TestEvent::PAIR_BEING_DELETED == event.what_happened;
  }
};

class Pair {
 public:
  typedef EventChannel<TestEventTraits> Channel;
  explicit Pair(const string& name) : name_(name), a_(0), b_(0) {
    TestEvent shutdown = { this, TestEvent::PAIR_BEING_DELETED, 0 };
    event_channel_ = new Channel(shutdown);
  }
  ~Pair() {
    delete event_channel_;
  }
  void set_a(int n) {
    TestEvent event = { this, TestEvent::A_CHANGED, a_ };
    a_ = n;
    event_channel_->NotifyListeners(event);
  }
  void set_b(int n) {
    TestEvent event = { this, TestEvent::B_CHANGED, b_ };
    b_ = n;
    event_channel_->NotifyListeners(event);
  }
  int a() const { return a_; }
  int b() const { return b_; }
  const string& name() { return name_; }
  Channel* event_channel() const { return event_channel_; }

 protected:
  const string name_;
  int a_;
  int b_;
  Channel* event_channel_;
};

class EventLogger {
 public:
  explicit EventLogger(ostream& out) : out_(out) { }
  ~EventLogger() {
    for (Hookups::iterator i = hookups_.begin(); i != hookups_.end(); ++i)
      delete *i;
  }

  void Hookup(const string name, Pair::Channel* channel) {
    hookups_.push_back(NewEventListenerHookup(channel, this,
                                              &EventLogger::HandlePairEvent,
                                              name));
  }

  void HandlePairEvent(const string& name, const TestEvent& event) {
    const char* what_changed = NULL;
    int new_value = 0;
    Hookups::iterator dead;
    switch (event.what_happened) {
    case TestEvent::A_CHANGED:
      what_changed = "A";
      new_value = event.source->a();
      break;
    case TestEvent::B_CHANGED:
      what_changed = "B";
      new_value = event.source->b();
      break;
    case TestEvent::PAIR_BEING_DELETED:
      out_ << name << " heard " << event.source->name() << " being deleted."
           << endl;
      return;
    default:
      LOG(FATAL) << "Bad event.what_happened: " << event.what_happened;
      break;
    }
    out_ << name << " heard " << event.source->name() << "'s " << what_changed
         << " change from "
         << event.old_value << " to " << new_value << endl;
  }

  typedef vector<EventListenerHookup*> Hookups;
  Hookups hookups_;
  ostream& out_;
};

const char golden_result[] = "Larry heard Sally's B change from 0 to 2\n"
"Larry heard Sally's A change from 1 to 3\n"
"Lewis heard Sam's B change from 0 to 5\n"
"Larry heard Sally's A change from 3 to 6\n"
"Larry heard Sally being deleted.\n";

TEST(EventSys, Basic) {
  Pair sally("Sally"), sam("Sam");
  sally.set_a(1);
  stringstream log;
  EventLogger logger(log);
  logger.Hookup("Larry", sally.event_channel());
  sally.set_b(2);
  sally.set_a(3);
  sam.set_a(4);
  logger.Hookup("Lewis", sam.event_channel());
  sam.set_b(5);
  sally.set_a(6);
  // Test that disconnect within callback doesn't deadlock.
  TestEvent event = {&sally, TestEvent::PAIR_BEING_DELETED, 0 };
  sally.event_channel()->NotifyListeners(event);
  sally.set_a(7);
  ASSERT_EQ(log.str(), golden_result);
}

// This goes pretty far beyond the normal use pattern, so don't use
// ThreadTester as an example of what to do.
class ThreadTester : public EventListener<TestEvent>,
                     public PlatformThread::Delegate {
 public:
  explicit ThreadTester(Pair* pair)
    : pair_(pair), remove_event_(&remove_event_mutex_),
      remove_event_bool_(false)  {
    pair_->event_channel()->AddListener(this);
  }
  ~ThreadTester() {
    pair_->event_channel()->RemoveListener(this);
    for (size_t i = 0; i < threads_.size(); i++) {
      PlatformThread::Join(threads_[i].thread);
    }
  }

  struct ThreadInfo {
    PlatformThreadHandle thread;
    bool* completed;
  };

  struct ThreadArgs {
    ConditionVariable* thread_running_cond;
    Lock* thread_running_mutex;
    bool thread_running;
    bool completed;
  };

  void Go() {
    Lock thread_running_mutex;
    ConditionVariable thread_running_cond(&thread_running_mutex);
    ThreadArgs args;
    ThreadInfo info;
    info.completed = false;
    args.completed = info.completed;
    args.thread_running_cond = &(thread_running_cond);
    args.thread_running_mutex = &(thread_running_mutex);
    args.thread_running = false;
    args_ = args;
    ASSERT_TRUE(PlatformThread::Create(0, this, &info.thread));
    thread_running_mutex.Acquire();
    while ((args_.thread_running) == false) {
      thread_running_cond.Wait();
    }
    thread_running_mutex.Release();
    threads_.push_back(info);
  }

  // PlatformThread::Delegate methods.
  virtual void ThreadMain() {
    // Make sure each thread gets a current MessageLoop in TLS.
    // This test should use chrome threads for testing, but I'll leave it like
    // this for the moment since it requires a big chunk of rewriting and I
    // want the test passing while I checkpoint my CL.  Technically speaking,
    // there should be no functional difference.
    MessageLoop message_loop;
    args_.thread_running_mutex->Acquire();
    args_.thread_running = true;
    args_.thread_running_mutex->Release();
    args_.thread_running_cond->Signal();

    remove_event_mutex_.Acquire();
    while (remove_event_bool_ == false) {
      remove_event_.Wait();
    }
    remove_event_mutex_.Release();

    // Normally, you'd just delete the hookup. This is very bad style, but
    // necessary for the test.
    pair_->event_channel()->RemoveListener(this);
    args_.completed = true;
  }

  void HandleEvent(const TestEvent& event) {
    remove_event_mutex_.Acquire();
    remove_event_bool_ = true;
    remove_event_mutex_.Release();
    remove_event_.Broadcast();

    PlatformThread::Sleep(1);

    for (size_t i = 0; i < threads_.size(); i++) {
      if (threads_[i].completed)
        LOG(FATAL) << "A test thread exited too early.";
    }
  }

  Pair* pair_;
  ConditionVariable remove_event_;
  Lock remove_event_mutex_;
  bool remove_event_bool_;
  vector<ThreadInfo> threads_;
  ThreadArgs args_;
};

TEST(EventSys, Multithreaded) {
  Pair sally("Sally");
  ThreadTester a(&sally);
  for (int i = 0; i < 3; ++i)
    a.Go();
  sally.set_b(99);
}

class HookupDeleter {
 public:
  void HandleEvent(const TestEvent& event) {
    delete hookup_;
    hookup_ = NULL;
  }
  EventListenerHookup* hookup_;
};

TEST(EventSys, InHandlerDeletion) {
  Pair sally("Sally");
  HookupDeleter deleter;
  deleter.hookup_ = NewEventListenerHookup(sally.event_channel(),
                                           &deleter,
                                           &HookupDeleter::HandleEvent);
  sally.set_a(1);
  ASSERT_TRUE(NULL == deleter.hookup_);
}

}  // namespace
<|endoftext|>


<commit_before>#include "Logging.h"

s64  GetTimeMillis(u64 PerformaceCounterFrequency)
{
    return SDL_GetPerformanceCounter()/(PerformaceCounterFrequency/1000);
}

struct MemoryMappedFile
{
#ifdef __WINDOWS__
    HANDLE MMFile;
    HANDLE File;
#else
    int File;
#endif
    unsigned char * MMapBuffer;
    s64  FileSize;
    u64  ModifiedTime;
};
inline u64  GetFileModifiedTime(const char * FileName);

MemoryMappedFile MemoryMapFile(const char * FileName)
{
    MemoryMappedFile MMFile={0};
#ifdef __LINUX__
    struct stat64 filestats;

    if(stat64(FileName,&filestats)==-1)
	return {0};
    MMFile.FileSize=filestats.st_size;
    MMFile.ModifiedTime=filestats.st_mtime;

    MMFile.File=open(FileName,O_RDONLY);
    if(MMFile.File==-1)
	return {0};

    MMFile.MMapBuffer=static_cast<unsigned char *>(mmap(MMFile.MMapBuffer,MMFile.FileSize,PROT_READ,MAP_SHARED,MMFile.File,0));
#else
#ifdef __WINDOWS__
    OFSTRUCT of;
    MMFile.File=(HANDLE)OpenFile(FileName,&of,OF_READ);
    if(MMFile.File==(HANDLE)HFILE_ERROR)
    {
	LogError("Could not get file handle for %s",FileName);
	return {0};
    }

    DWORD high=0;
    DWORD low=GetFileSize(MMFile.File,&high);
    MMFile.FileSize = low | (((s64 )high) << 32);
    MMFile.ModifiedTime = GetFileModifiedTime(FileName);
    MMFile.MMFile=CreateFileMapping(MMFile.File,NULL,PAGE_READONLY,0,0,NULL);
    if(!MMFile.MMFile)
    {
	return {0};
    }
    MMFile.MMapBuffer=static_cast<unsigned char *>(MapViewOfFile(MMFile.MMFile,FILE_MAP_READ,0,0,0));
#endif
#endif

    return MMFile;
}

void UnMapFile(MemoryMappedFile MMFile)
{
#ifdef __WINDOWS__
    UnmapViewOfFile(MMFile.MMapBuffer);
    CloseHandle(MMFile.MMFile);
    CloseHandle(MMFile.File);
#else
    close(MMFile.File);
    munmap(MMFile.MMapBuffer,MMFile.FileSize);
#endif
}

#ifdef __LINUX__
#include <png.h>
#endif
#include "zlib.h"

#ifdef __LINUX__
void SaveDataToPng(char * ImageData, char * FileName, int Width, int Height)
{
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL);
    if (!png_ptr)
    {
        LogError("Could not create PNG write stucture for %s",FileName);
	return;
    }
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
        LogError("Could not create PNG info stucture for %s",FileName);
	return;
    }
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        LogError("Could not set PNG jmp ptr for %s",FileName);
	return;
    }
    FILE *fp = fopen(FileName, "wb");
    if (!fp)
    {
        LogError("Failed to open %s",FileName);
	return;
    }
    png_init_io(png_ptr, fp);
    png_set_filter(png_ptr, 0,PNG_ALL_FILTERS);
    png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
    png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY);
    png_set_IHDR(png_ptr, info_ptr, Width, Height,8,PNG_COLOR_TYPE_RGB , PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT) ;
    png_write_info(png_ptr, info_ptr);
    png_write_flush(png_ptr);

    unsigned char ** row_pointers =new unsigned char*[Height];
    for (int i=0; i<Height; i++)
        row_pointers[i]=(unsigned char *)&(ImageData[(Height-1-i)*Width*3]);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);

    delete[] row_pointers;

}
#endif

#ifdef __LINUX__
#include <dirent.h>
static int IsUFO( const struct dirent * file)
{
    const char * fname=(char *)file->d_name;
    while(*++fname){}

    return *(fname-4)=='.' &&(*(fname-3)=='U' || *(fname-3) == 'u')
	&&(*(fname-2)=='F' || *(fname-2) == 'f')
	&&(*(fname-1)=='O' || *(fname-1) == 'o');
}
#endif

//NOTE(Christof): These should be plenty
const int MAX_UFO_FILES = 32;
const int MAX_UFO_NAME_LENGTH = 64;

struct UFOSearchResult
{
    int NumberOfFiles;
    char FileNames[MAX_UFO_FILES][MAX_UFO_NAME_LENGTH];
};
UFOSearchResult GetUfoFiles()
{
    UFOSearchResult Result={};
#ifdef __WINDOWS__
    WIN32_FIND_DATAA ffd;
    HANDLE find=FindFirstFileA(".\\data\\*.ufo", &ffd);
    if(find==INVALID_HANDLE_VALUE)
    {
	LogError("Failed to find .ufo files in data directory");
	return Result;
    }

    do
    {
	int length=(int)strlen(ffd.cFileName)+1;
	Assert(length <= MAX_UFO_NAME_LENGTH);

	memcpy(&Result.FileNames[Result.NumberOfFiles],ffd.cFileName,length);
	Result.NumberOfFiles++;
	Assert(Result.NumberOfFiles<=MAX_UFO_FILES);
    }while(FindNextFile(find,&ffd));
    FindClose(find);
#endif
#ifdef __LINUX__
    struct dirent **eps=0;

    Result.NumberOfFiles = scandir ("./data/", &eps, IsUFO, alphasort);
    Assert(Result.NumberOfFiles < MAX_UFO_FILES);
    if (Result.NumberOfFiles >= 0)
    {
	for(int i=0;i<Result.NumberOfFiles;i++)
	{
	    int length=strlen(eps[i]->d_name)+1;
	    Assert(length <= MAX_UFO_NAME_LENGTH);

	    memcpy(&Result.FileNames[i],eps[i]->d_name,length);
	    free(eps[i]);
	}
    }
    else
    {
	LogError("Failed to find .ufo files in data directory");
    }
    if(eps){free(eps);}
#endif
    return Result;
}

inline b32 CaseInsensitiveMatch(const char * String1, const char * String2)
{
    while(*String1 && *String2)
    {
	char pcomp=*String2, dcomp=*String1;
	if(pcomp >='a' && pcomp <='z')
	    pcomp+='A'-'a';
	if(dcomp >='a' && dcomp <='z')
	    dcomp+='A'-'a';
	if(dcomp!=pcomp)
	    return 0;

	String2++;
	String1++;
    }
    return *String1 == *String2;
}

inline b32 NameEndsWith(const char * Name, const char * EndsWith)
{
    char * End = (char*)Name;
    char * test = (char*)EndsWith;
    while(*++End){}

    while(*++test){}

    while((*End == *test || *End + 'A'-'a' == *test || *End == * test +'A'-'a') && End>=Name && test>=EndsWith)
    {
	--End;
	--test;
    }
    return test<EndsWith;
}

inline u64  GetCurrentFileTime()
{
#ifdef __WINDOWS__
    FILETIME CurrentFileTime;
    GetSystemTimeAsFileTime(&CurrentFileTime);
    ULARGE_INTEGER FileTimeAsLargeInt;
    FileTimeAsLargeInt.LowPart = CurrentFileTime.dwLowDateTime;
    FileTimeAsLargeInt.HighPart = CurrentFileTime.dwHighDateTime;
    return FileTimeAsLargeInt.QuadPart;
#endif
#ifdef __LINUX__
    struct timespec time;
    clock_gettime(CLOCK_REALTIME,&time);
    return (time.tv_sec)+(time.tv_nsec/1000/1000/1000);
#endif
}

inline u64  GetFileModifiedTime(const char * FileName)
{
#ifdef __WINDOWS__

    FILETIME FileTime={};
    WIN32_FILE_ATTRIBUTE_DATA Data;
    if(GetFileAttributesEx(FileName, GetFileExInfoStandard, &Data))
    {
        FileTime = Data.ftLastWriteTime;
    }
    else
    {
	LogError("Could not get file write time for %s",FileName);
    }

    ULARGE_INTEGER FileTimeAsLargeInt;
    FileTimeAsLargeInt.LowPart = FileTime.dwLowDateTime;
    FileTimeAsLargeInt.HighPart = FileTime.dwHighDateTime;
    return FileTimeAsLargeInt.QuadPart;
#endif
#ifdef __LINUX__
    struct stat64 filestats;

    if(stat64(FileName,&filestats)==-1)
	return {0};

    return filestats.st_mtime;

#endif
}

<commit_msg>Fix file opening on windows.<commit_after>#include "Logging.h"

s64  GetTimeMillis(u64 PerformaceCounterFrequency)
{
    return SDL_GetPerformanceCounter()/(PerformaceCounterFrequency/1000);
}

struct MemoryMappedFile
{
#ifdef __WINDOWS__
    HANDLE MMFile;
    HANDLE File;
#else
    int File;
#endif
    unsigned char * MMapBuffer;
    s64  FileSize;
    u64  ModifiedTime;
};
inline u64  GetFileModifiedTime(const char * FileName);

MemoryMappedFile MemoryMapFile(const char * FileName)
{
    MemoryMappedFile MMFile={};
#ifdef __LINUX__
    struct stat64 filestats;

    if(stat64(FileName,&filestats)==-1)
	return {};
    MMFile.FileSize=filestats.st_size;
    MMFile.ModifiedTime=filestats.st_mtime;

    MMFile.File=open(FileName,O_RDONLY);
    if(MMFile.File==-1)
	return {};

    MMFile.MMapBuffer=static_cast<unsigned char *>(mmap(MMFile.MMapBuffer,MMFile.FileSize,PROT_READ,MAP_SHARED,MMFile.File,0));
#else
#ifdef __WINDOWS__
    MMFile.File=CreateFileA(FileName,GENERIC_READ,0,0,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0);
    if(MMFile.File == INVALID_HANDLE_VALUE)
    {
	LogError("Could not get file handle for %s",FileName);
	return {};
    }

    DWORD high=0;
    DWORD low=GetFileSize(MMFile.File,&high);
    MMFile.FileSize = low | (((s64 )high) << 32);
    MMFile.ModifiedTime = GetFileModifiedTime(FileName);
    MMFile.MMFile=CreateFileMapping(MMFile.File,NULL,PAGE_READONLY,0,0,NULL);
    if(!MMFile.MMFile)
    {
	return {};
    }
    MMFile.MMapBuffer=static_cast<unsigned char *>(MapViewOfFile(MMFile.MMFile,FILE_MAP_READ,0,0,0));
#endif
#endif

    return MMFile;
}

void UnMapFile(MemoryMappedFile MMFile)
{
#ifdef __WINDOWS__
    UnmapViewOfFile(MMFile.MMapBuffer);
    CloseHandle(MMFile.MMFile);
    CloseHandle(MMFile.File);
#else
    close(MMFile.File);
    munmap(MMFile.MMapBuffer,MMFile.FileSize);
#endif
}

#ifdef __LINUX__
#include <png.h>
#endif
#include "zlib.h"

#ifdef __LINUX__
void SaveDataToPng(char * ImageData, char * FileName, int Width, int Height)
{
    png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL);
    if (!png_ptr)
    {
        LogError("Could not create PNG write stucture for %s",FileName);
	return;
    }
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        png_destroy_write_struct(&png_ptr,(png_infopp)NULL);
        LogError("Could not create PNG info stucture for %s",FileName);
	return;
    }
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_write_struct(&png_ptr, &info_ptr);
        LogError("Could not set PNG jmp ptr for %s",FileName);
	return;
    }
    FILE *fp = fopen(FileName, "wb");
    if (!fp)
    {
        LogError("Failed to open %s",FileName);
	return;
    }
    png_init_io(png_ptr, fp);
    png_set_filter(png_ptr, 0,PNG_ALL_FILTERS);
    png_set_compression_level(png_ptr,Z_DEFAULT_COMPRESSION);
    png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY);
    png_set_IHDR(png_ptr, info_ptr, Width, Height,8,PNG_COLOR_TYPE_RGB , PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT) ;
    png_write_info(png_ptr, info_ptr);
    png_write_flush(png_ptr);

    unsigned char ** row_pointers =new unsigned char*[Height];
    for (int i=0; i<Height; i++)
        row_pointers[i]=(unsigned char *)&(ImageData[(Height-1-i)*Width*3]);
    png_write_image(png_ptr, row_pointers);
    png_write_end(png_ptr, NULL);
    png_destroy_write_struct(&png_ptr, &info_ptr);
    fclose(fp);

    delete[] row_pointers;

}
#endif

#ifdef __LINUX__
#include <dirent.h>
static int IsUFO( const struct dirent * file)
{
    const char * fname=(char *)file->d_name;
    while(*++fname){}

    return *(fname-4)=='.' &&(*(fname-3)=='U' || *(fname-3) == 'u')
	&&(*(fname-2)=='F' || *(fname-2) == 'f')
	&&(*(fname-1)=='O' || *(fname-1) == 'o');
}
#endif

//NOTE(Christof): These should be plenty
const int MAX_UFO_FILES = 32;
const int MAX_UFO_NAME_LENGTH = 64;

struct UFOSearchResult
{
    int NumberOfFiles;
    char FileNames[MAX_UFO_FILES][MAX_UFO_NAME_LENGTH];
};
UFOSearchResult GetUfoFiles()
{
    UFOSearchResult Result={};
#ifdef __WINDOWS__
    WIN32_FIND_DATAA ffd;
    HANDLE find=FindFirstFileA(".\\data\\*.ufo", &ffd);
    if(find==INVALID_HANDLE_VALUE)
    {
	LogError("Failed to find .ufo files in data directory");
	return Result;
    }

    do
    {
	int length=(int)strlen(ffd.cFileName)+1;
	Assert(length <= MAX_UFO_NAME_LENGTH);

	memcpy(&Result.FileNames[Result.NumberOfFiles],ffd.cFileName,length);
	Result.NumberOfFiles++;
	Assert(Result.NumberOfFiles<=MAX_UFO_FILES);
    }while(FindNextFile(find,&ffd));
    FindClose(find);
#endif
#ifdef __LINUX__
    struct dirent **eps=0;

    Result.NumberOfFiles = scandir ("./data/", &eps, IsUFO, alphasort);
    Assert(Result.NumberOfFiles < MAX_UFO_FILES);
    if (Result.NumberOfFiles >= 0)
    {
	for(int i=0;i<Result.NumberOfFiles;i++)
	{
	    int length=strlen(eps[i]->d_name)+1;
	    Assert(length <= MAX_UFO_NAME_LENGTH);

	    memcpy(&Result.FileNames[i],eps[i]->d_name,length);
	    free(eps[i]);
	}
    }
    else
    {
	LogError("Failed to find .ufo files in data directory");
    }
    if(eps){free(eps);}
#endif
    return Result;
}

inline b32 CaseInsensitiveMatch(const char * String1, const char * String2)
{
    while(*String1 && *String2)
    {
	char pcomp=*String2, dcomp=*String1;
	if(pcomp >='a' && pcomp <='z')
	    pcomp+='A'-'a';
	if(dcomp >='a' && dcomp <='z')
	    dcomp+='A'-'a';
	if(dcomp!=pcomp)
	    return 0;

	String2++;
	String1++;
    }
    return *String1 == *String2;
}

inline b32 NameEndsWith(const char * Name, const char * EndsWith)
{
    char * End = (char*)Name;
    char * test = (char*)EndsWith;
    while(*++End){}

    while(*++test){}

    while((*End == *test || *End + 'A'-'a' == *test || *End == * test +'A'-'a') && End>=Name && test>=EndsWith)
    {
	--End;
	--test;
    }
    return test<EndsWith;
}

inline u64  GetCurrentFileTime()
{
#ifdef __WINDOWS__
    FILETIME CurrentFileTime;
    GetSystemTimeAsFileTime(&CurrentFileTime);
    ULARGE_INTEGER FileTimeAsLargeInt;
    FileTimeAsLargeInt.LowPart = CurrentFileTime.dwLowDateTime;
    FileTimeAsLargeInt.HighPart = CurrentFileTime.dwHighDateTime;
    return FileTimeAsLargeInt.QuadPart;
#endif
#ifdef __LINUX__
    struct timespec time;
    clock_gettime(CLOCK_REALTIME,&time);
    return (time.tv_sec)+(time.tv_nsec/1000/1000/1000);
#endif
}

inline u64  GetFileModifiedTime(const char * FileName)
{
#ifdef __WINDOWS__

    FILETIME FileTime={};
    WIN32_FILE_ATTRIBUTE_DATA Data;
    if(GetFileAttributesEx(FileName, GetFileExInfoStandard, &Data))
    {
        FileTime = Data.ftLastWriteTime;
    }
    else
    {
	LogError("Could not get file write time for %s",FileName);
    }

    ULARGE_INTEGER FileTimeAsLargeInt;
    FileTimeAsLargeInt.LowPart = FileTime.dwLowDateTime;
    FileTimeAsLargeInt.HighPart = FileTime.dwHighDateTime;
    return FileTimeAsLargeInt.QuadPart;
#endif
#ifdef __LINUX__
    struct stat64 filestats;

    if(stat64(FileName,&filestats)==-1)
	return {0};

    return filestats.st_mtime;

#endif
}
<|endoftext|>